kaddressbook

gnokii_xxport.cpp

00001 /*
00002     This file is part of KAddressbook.
00003     Copyright (c) 2003-2006 Helge Deller <deller@kde.org>
00004 
00005     This program is free software; you can redistribute it and/or modify
00006     it under the terms of the GNU General Public License version 2 as
00007     published by the Free Software Foundation.
00008 
00009     This program is distributed in the hope that it will be useful,
00010     but WITHOUT ANY WARRANTY; without even the implied warranty of
00011     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
00012     GNU General Public License for more details.
00013 
00014     You should have received a copy of the GNU General Public License
00015     along with this program; if not, write to the Free Software
00016     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017 
00018     As a special exception, permission is given to link this program
00019     with any edition of TQt, and distribute the resulting executable,
00020     without including the source code for TQt in the source distribution.
00021 */
00022 /*
00023     Description:
00024     This filter allows you to import and export the KDE addressbook entries
00025     to/from a mobile phone, which is accessible via gnokii.
00026     Gnokii homepage: http://www.gnokii.org
00027 
00028     TODO:
00029     - create a log file and give user possibility to see it afterwards
00030     - handle callergroup value (Friend, VIP, Family, ...) better
00031 */
00032 
00033 #include "config.h"
00034 
00035 #ifdef HAVE_GNOKII_H
00036 extern "C" {
00037 #include <gnokii.h>
00038 }
00039 #else
00040 #ifdef __GNUC__
00041 # warning "Please install gnokii (http://www.gnokii.org) development headers and libraries !"
00042 # warning "Please use at least version 0.6.13 or later of gnokii."
00043 #endif
00044 #endif
00045 
00046 #include <tqcursor.h>
00047 
00048 #include <kdebug.h>
00049 #include <klocale.h>
00050 #include <kmessagebox.h>
00051 #include <kprogress.h>
00052 #include <kguiitem.h>
00053 
00054 #include "gnokii_xxport.h"
00055 
00056 #define APP "GNOKII_XXPORT"
00057 
00058 #if 1 // !defined(NDEBUG)
00059  #define GNOKII_DEBUG(x)    do { kdWarning() << (x); } while (0)
00060 #else
00061  #define GNOKII_DEBUG(x)    do { } while (0)
00062 #endif
00063 #define GNOKII_CHECK_ERROR(error) \
00064     do { \
00065         if (error) \
00066             kdError() << TQString("ERROR %1: %2\n").arg(error).arg(gn_error_print(error));\
00067     } while (0)
00068 
00069 // Locale conversion routines:
00070 // Gnokii uses the local 8 Bit encoding (based on LC_ALL), kaddressbook uses Unicode
00071 #define GN_FROM(x)  TQString::fromLocal8Bit(x)
00072 #define GN_TO(x)    (x).local8Bit()
00073 
00074 // static variables for GUI updates
00075 static GNOKIIXXPort *this_filter;
00076 static KProgressDialog *m_progressDlg;
00077 
00078 K_EXPORT_KADDRESSBOOK_XXFILTER( libkaddrbk_gnokii_xxport, GNOKIIXXPort )
00079 
00080 GNOKIIXXPort::GNOKIIXXPort( KABC::AddressBook *ab, TQWidget *parent, const char *name )
00081   : KAB::XXPort( ab, parent, name )
00082 {
00083     this_filter = this;
00084     m_progressDlg = NULL;
00085     createImportAction( i18n( "Import From Mobile Phone..." ) );
00086     createExportAction( i18n( "Export to Mobile Phone..." ) );
00087 }
00088 
00089 
00090 #ifdef HAVE_GNOKII_H
00091 static TQString makeValidPhone( const TQString &number )
00092 {
00093     // allowed chars: 0-9, *, #, p, w, +
00094     TQString num = number.simplifyWhiteSpace();
00095     TQString allowed("0123456789*+#pw");
00096     for (unsigned int i=num.length(); i>=1; i--)
00097         if (allowed.find(num[i-1])==-1)
00098             num.remove(i-1,1);
00099     if (num.isEmpty())
00100         num = "0";
00101     return num;
00102 }
00103 #endif
00104 
00105 /******************************************************************************
00106  ******************************************************************************
00107  ******************************************************************************
00108  ******************************************************************************
00109  ******************************************************************************/
00110 
00111 #if defined(HAVE_GNOKII_H) && defined(LIBGNOKII_VERSION_MAJOR) && (LIBGNOKII_VERSION_MAJOR >= 3)
00112 
00113 /* NEW GNOKII LIBRARIES (>= 0.6.13) */
00114 
00115 static const char *manufacturer, *model, *revision, *imei;
00116 static struct gn_statemachine *state;
00117 
00118 static void busterminate(void)
00119 {
00120     gn_lib_phone_close(state);
00121     gn_lib_phoneprofile_free(&state);
00122     gn_lib_library_free();
00123 }
00124 
00125 static TQString businit(void)
00126 {
00127     GNOKII_DEBUG( "Using new gnokii version." );
00128 
00129     GNOKII_DEBUG( TQString("Compiled with libgnokii version 0x%1\n").arg(TQString::number(LIBGNOKII_VERSION,16)) );
00130     GNOKII_DEBUG( TQString("Using libgnokii runtime version 0x%1\n").arg(TQString::number(gn_lib_version(),16)) );
00131 
00132     gn_error error = gn_lib_phoneprofile_load(NULL, &state);
00133     if (error) 
00134         return i18n("Failed to initialize the gnokii library.");
00135 
00136     error = gn_lib_phone_open( state );
00137     GNOKII_CHECK_ERROR(error);
00138     if (error != GN_ERR_NONE) {
00139         busterminate();
00140         return i18n("<qt><center>Mobile Phone interface initialization failed.<br><br>"
00141             "The returned error message was:<br><b>%1</b><br><br>"
00142             "You might try to run \"gnokii --identify\" on the command line to "
00143             "check any cable/transport issues and to verify if your gnokii "
00144             "configuration is correct.</center></qt>")
00145             .arg(gn_error_print(error));
00146     }
00147 
00148     // identify phone
00149     manufacturer = gn_lib_get_phone_manufacturer(state);
00150     model        = gn_lib_get_phone_model(state);
00151     revision     = gn_lib_get_phone_revision(state);
00152     imei         = gn_lib_get_phone_imei(state);
00153 
00154     GNOKII_DEBUG( TQString("Found mobile phone: %1 %2, Revision: %3, IMEI: %4\n")
00155                 .arg(manufacturer, model, revision, imei) );
00156 
00157     return TQString();
00158 }
00159 
00160 
00161 // get number of entries in this phone memory type (internal/SIM-card)
00162 static gn_error read_phone_memstat( const gn_memory_type memtype, gn_memory_status *memstat )
00163 {
00164     gn_error error;
00165 
00166     error = gn_lib_addressbook_memstat(state, memtype, &memstat->used, &memstat->free);
00167 
00168     GNOKII_DEBUG( TQString("\n\nMobile phone memory status: Type: %1, used=%2, free=%3, total=%4\n\n")
00169                     .arg(memtype).arg(memstat->used).arg(memstat->free).arg(memstat->used+memstat->free) );
00170     return error;
00171 }
00172 
00173 
00174 static TQString buildPhoneInfoString( const gn_memory_status &memstat )
00175 {
00176     TQString format = TQString::fromLatin1("<tr><td><b>%1</b></td><td>%2</td></tr>");
00177 
00178     return TQString::fromLatin1("<b>%1</b><br><table>%2%3%4%5%6</table><br>")
00179         .arg(i18n("Mobile Phone information:"))
00180         .arg(format.arg(i18n("Manufacturer")).arg(GN_FROM(manufacturer)))
00181         .arg(format.arg(i18n("Phone model")).arg(GN_FROM(model)))
00182         .arg(format.arg(i18n("Revision")).arg(GN_FROM(revision)))
00183         .arg(format.arg(i18n("IMEI")).arg(GN_FROM(imei)))
00184         .arg(format.arg(i18n("Phonebook status"))
00185                .arg(i18n("%1 out of %2 contacts used").arg(memstat.used).arg(memstat.used+memstat.free)));
00186 }
00187 
00188 // read and evaluate all phone entries
00189 static gn_error read_phone_entries( const char *memtypestr, gn_memory_type memtype,
00190             KABC::AddresseeList *addrList )
00191 {
00192   gn_error error;
00193 
00194   if (m_progressDlg->wasCancelled())
00195     return GN_ERR_NONE;
00196 
00197   KProgress* progress = (KProgress*)m_progressDlg->progressBar();
00198 
00199   progress->setProgress(0);
00200   this_filter->processEvents();
00201 
00202   // get number of entries in this phone memory type (internal/SIM-card)
00203   gn_memory_status memstat;
00204   error = read_phone_memstat(memtype, &memstat);
00205 
00206   TQStringList addrlist;
00207   KABC::Address *addr;
00208   TQString s, country;
00209 
00210   progress->setTotalSteps(memstat.used);
00211   m_progressDlg->setLabel(i18n("<qt>Importing <b>%1</b> contacts from <b>%2</b> of the Mobile Phone.<br><br>%3</qt>")
00212         .arg(memstat.used)
00213         .arg(gn_memory_type2str(memtype))
00214         .arg(buildPhoneInfoString(memstat)) );
00215 
00216   int num_read = 0;
00217 
00218   for (int i = 1; !m_progressDlg->wasCancelled() && i <= memstat.used + memstat.free; i++) {
00219     error = gn_lib_phonebook_read_entry(state, memtype, i);
00220     GNOKII_CHECK_ERROR(error);
00221 
00222     progress->setProgress(num_read);
00223     this_filter->processEvents();
00224 
00225     if (error == GN_ERR_EMPTYLOCATION)
00226         continue;
00227     if (error == GN_ERR_INVALIDLOCATION)
00228         break;
00229     if (error == GN_ERR_INVALIDMEMORYTYPE)
00230         break;
00231     if (error == GN_ERR_NONE) {
00232         const int subentries_count = gn_lib_get_pb_num_subentries(state);
00233         const char *name = gn_lib_get_pb_name(state);
00234         const char *number = gn_lib_get_pb_number(state);
00235 
00236         GNOKII_DEBUG(TQString("%1: %2, num=%3, location=%4, group=%5, count=%6\n").arg(i)
00237             .arg(GN_FROM(name)).arg(GN_FROM(number))
00238             .arg(gn_lib_get_pb_location(state)).arg(gn_lib_get_pb_caller_group(state))
00239             .arg(subentries_count));
00240         KABC::Addressee *a = new KABC::Addressee();
00241 
00242         // try to split Name into FamilyName and GivenName
00243         s = GN_FROM(name).simplifyWhiteSpace();
00244         a->setFormattedName(s); // set formatted name as in Phone
00245         if (s.find(',') == -1) {
00246           // assumed format: "givenname [... familyname]"
00247           addrlist = TQStringList::split(' ', s);
00248           if (addrlist.count() == 1) {
00249             // only one string -> put it in the GivenName
00250             a->setGivenName(s);
00251           } else {
00252             // multiple strings -> split them.
00253             a->setFamilyName(addrlist.last().simplifyWhiteSpace());
00254             addrlist.remove(addrlist.last());
00255             a->setGivenName(addrlist.join(" ").simplifyWhiteSpace());
00256           }
00257         } else {
00258           // assumed format: "familyname, ... givenname"
00259           addrlist = TQStringList::split(',', s);
00260           a->setFamilyName(addrlist.first().simplifyWhiteSpace());
00261           addrlist.remove(addrlist.first());
00262           a->setGivenName(addrlist.join(" ").simplifyWhiteSpace());
00263         }
00264 
00265         a->insertCustom(APP, "X_GSM_CALLERGROUP", s.setNum(gn_lib_get_pb_caller_group(state)));
00266         a->insertCustom(APP, "X_GSM_STORE_AT", TQString("%1%2").arg(memtypestr).arg(gn_lib_get_pb_location(state)));
00267 
00268         // set ProductId
00269         a->setProductId(TQString("%1-%2-%3-%4").arg(APP).arg(model).arg(revision).arg(imei));
00270 
00271         // evaluate timestamp (ignore timezone)
00272         TQDateTime datetime;
00273         gn_timestamp ts = gn_lib_get_pb_date(state);
00274         if (ts.year<1998)
00275             datetime = TQDateTime::currentDateTime();
00276         else
00277             datetime = TQDateTime( TQDate(ts.year, ts.month, ts.day),
00278                               TQTime(ts.hour, ts.minute, ts.second) );
00279         GNOKII_DEBUG(TQString(" date=%1\n").arg(datetime.toString()));
00280         a->setRevision(datetime);
00281 
00282         if (!subentries_count)
00283           a->insertPhoneNumber(KABC::PhoneNumber(number,
00284                 KABC::PhoneNumber::Work | KABC::PhoneNumber::Pref));
00285 
00286         /* scan sub-entries */
00287         if (subentries_count)
00288          for (int n=0; n<subentries_count; n++) {
00289           gn_phonebook_entry_type entry_type;
00290           gn_phonebook_number_type number_type;
00291           const char *number;
00292 
00293           error = gn_lib_get_pb_subentry(state, n, &entry_type, &number_type, &number);
00294           GNOKII_CHECK_ERROR(error);
00295 
00296           TQString s = GN_FROM(number).simplifyWhiteSpace();
00297           GNOKII_DEBUG(TQString(" Subentry#%1, entry_type=%2, number_type=%3, number=%4\n")
00298                 .arg(n).arg(entry_type).arg(number_type).arg(s));
00299           if (s.isEmpty())
00300             continue;
00301           switch(entry_type) {
00302            case GN_PHONEBOOK_ENTRY_Name:
00303             a->setName(s);
00304             break;
00305            case GN_PHONEBOOK_ENTRY_Email:
00306             a->insertEmail(s);
00307             break;
00308            case GN_PHONEBOOK_ENTRY_Postal:
00309             addrlist = TQStringList::split(';', s, true);
00310             addr = new KABC::Address(KABC::Address::Work);
00311             if (addrlist.count() <= 1) {
00312                 addrlist = TQStringList::split(',', s, true);
00313                 if (addrlist.count() > 1 ) {
00314                     // assumed format: "Locality, ZIP, Country"
00315                     addr->setLocality(addrlist[0]);
00316                     addr->setPostalCode(addrlist[1]);
00317                     if (!addrlist[2].isEmpty())
00318                         addr->setCountry(i18n(GN_TO(addrlist[2])));
00319                 } else {
00320                     // no idea about the format, just store it.
00321                     addr->setLocality(s);
00322                 }
00323             } else {
00324                 // assumed format: "POBox; Extended; Street; Locality; Region; ZIP [;Country]
00325                 addr->setPostOfficeBox(addrlist[0]);
00326                 addr->setExtended(addrlist[1]);
00327                 addr->setStreet(addrlist[2]);
00328                 addr->setLocality(addrlist[3]);
00329                 addr->setRegion(addrlist[4]);
00330                 addr->setPostalCode(addrlist[5]);
00331                 country = addrlist[6];
00332                 if (!country.isEmpty())
00333                     addr->setCountry(i18n(GN_TO(country)));
00334             }
00335             a->insertAddress(*addr);
00336             delete addr;
00337             break;
00338            case GN_PHONEBOOK_ENTRY_Note:
00339             if (!a->note().isEmpty())
00340                 s = "\n" + s;
00341             a->setNote(a->note()+s);
00342             break;
00343            case GN_PHONEBOOK_ENTRY_Number:
00344             enum KABC::PhoneNumber::Types phonetype;
00345             switch (number_type) {
00346              case GN_PHONEBOOK_NUMBER_Mobile: phonetype = KABC::PhoneNumber::Cell; break;
00347              case GN_PHONEBOOK_NUMBER_Fax:    phonetype = KABC::PhoneNumber::Fax;  break;
00348              case GN_PHONEBOOK_NUMBER_General:
00349              case GN_PHONEBOOK_NUMBER_Work:   phonetype = KABC::PhoneNumber::Work; break;
00350              default:
00351              case GN_PHONEBOOK_NUMBER_Home:   phonetype = KABC::PhoneNumber::Home; break;
00352             }
00353             //if (s == entry.number)
00354             //  type = (KABC::PhoneNumber::Types) (phonetype | KABC::PhoneNumber::Pref);
00355             a->insertPhoneNumber(KABC::PhoneNumber(s, phonetype));
00356             break;
00357            case GN_PHONEBOOK_ENTRY_URL:
00358             a->setUrl(s);
00359             break;
00360            case GN_PHONEBOOK_ENTRY_Group:
00361             a->insertCategory(s);
00362             break;
00363            default:
00364             GNOKII_DEBUG(TQString(" Not handled id=%1, entry=%2\n")
00365                 .arg(entry_type).arg(s));
00366             break;
00367           } // switch()
00368         } // if(subentry)
00369 
00370         // add only if entry was valid
00371         if (strlen(name) || strlen(number) || subentries_count)
00372             addrList->append(*a);
00373 
00374         // did we read all valid phonebook-entries ?
00375         num_read++;
00376         delete a;
00377         if (num_read >= memstat.used)
00378             break;  // yes, all were read
00379         else
00380             continue; // no, we are still missing some.
00381     }
00382     GNOKII_CHECK_ERROR(error);
00383   }
00384 
00385   return GN_ERR_NONE;
00386 }
00387 
00388 // export to phone
00389 
00390 static gn_error xxport_phone_write_entry( int phone_location, gn_memory_type memtype,
00391             const KABC::Addressee *addr)
00392 {
00393     TQString s;
00394 
00395     /* initialize the phonebook entry values to zero */
00396     gn_lib_phonebook_prepare_write_entry(state);
00397 
00398     gn_lib_set_pb_location(state, phone_location);
00399 
00400     gn_lib_set_pb_name(state, GN_TO(addr->realName()));
00401     s = addr->phoneNumber(KABC::PhoneNumber::Pref).number();
00402     if (s.isEmpty())
00403         s = addr->phoneNumber(KABC::PhoneNumber::Work).number();
00404     if (s.isEmpty())
00405         s = addr->phoneNumber(KABC::PhoneNumber::Home).number();
00406     if (s.isEmpty())
00407         s = addr->phoneNumber(KABC::PhoneNumber::Cell).number();
00408     if (s.isEmpty() && addr->phoneNumbers().count()>0)
00409         s = (*addr->phoneNumbers().at(0)).number();
00410     s = makeValidPhone(s);
00411     gn_lib_set_pb_number(state, s.ascii());
00412     gn_lib_set_pb_memtype(state, memtype);
00413     TQString cg = addr->custom(APP, "X_GSM_CALLERGROUP");
00414     if (cg.isEmpty())
00415         gn_lib_set_pb_caller_group(state, GN_PHONEBOOK_GROUP_None); // default group
00416     else
00417         gn_lib_set_pb_caller_group(state, (gn_phonebook_group_type) cg.toInt());
00418 
00419     // set date/revision
00420     TQDateTime datetime = addr->revision();
00421     TQDate date(datetime.date());
00422     TQTime time(datetime.time());
00423     gn_timestamp ts;
00424     gn_timestamp_set( &ts, date.year(), date.month(), date.day(),
00425                    time.hour(), time.minute(), time.second(), 0 );
00426     gn_lib_set_pb_date(state, ts);
00427 
00428     GNOKII_DEBUG(TQString("Write #%1: name=%2, number=%3\n").arg(phone_location)
00429         .arg(GN_FROM(gn_lib_get_pb_name(state))).arg(GN_FROM(gn_lib_get_pb_number(state))));
00430 
00431     const KABC::Address homeAddr = addr->address(KABC::Address::Home);
00432     const KABC::Address workAddr = addr->address(KABC::Address::Work);
00433 
00434     // add all phone numbers
00435     const KABC::PhoneNumber::List phoneList = addr->phoneNumbers();
00436     KABC::PhoneNumber::List::ConstIterator it;
00437     for ( it = phoneList.begin(); it != phoneList.end(); ++it ) {
00438         const KABC::PhoneNumber *phonenumber = &(*it);
00439         s = phonenumber->number();
00440         if (s.isEmpty()) continue;
00441         gn_phonebook_number_type type;
00442         int pn_type = phonenumber->type();
00443         if ((pn_type & KABC::PhoneNumber::Cell))
00444             type = GN_PHONEBOOK_NUMBER_Mobile;
00445         else if ((pn_type & KABC::PhoneNumber::Fax))
00446             type = GN_PHONEBOOK_NUMBER_Fax;
00447         else if ((pn_type & KABC::PhoneNumber::Home))
00448             type = GN_PHONEBOOK_NUMBER_Home;
00449         else if ((pn_type & KABC::PhoneNumber::Work))
00450             type = GN_PHONEBOOK_NUMBER_Work;
00451         else type = GN_PHONEBOOK_NUMBER_General;
00452         gn_lib_set_pb_subentry(state, -1 /* index to append entry */,
00453             GN_PHONEBOOK_ENTRY_Number, type, makeValidPhone(s).ascii());
00454         /*subentry->id = phone_location<<8+entry.subentries_count;*/
00455     }
00456     // add URL
00457     s = addr->url().prettyURL();
00458     if (!s.isEmpty()) {
00459         gn_lib_set_pb_subentry(state, -1 /* index to append entry */,
00460             GN_PHONEBOOK_ENTRY_URL, GN_PHONEBOOK_NUMBER_General, GN_TO(s));
00461     }
00462     // add E-Mails
00463     TQStringList emails = addr->emails();
00464     for (unsigned int n=0; n<emails.count(); n++) {
00465         s = emails[n].simplifyWhiteSpace();
00466         if (s.isEmpty()) continue;
00467         // only one email allowed if we have URLS, notes, addresses (to avoid phone limitations)
00468         if (n && !addr->url().isEmpty() && !addr->note().isEmpty() && addr->addresses().count()) {
00469             GNOKII_DEBUG(TQString(" DROPPED email %1 in favor of URLs, notes and addresses.\n")
00470                     .arg(s));
00471             continue;
00472         }
00473         gn_lib_set_pb_subentry(state, -1 /* index to append entry */,
00474             GN_PHONEBOOK_ENTRY_Email, GN_PHONEBOOK_NUMBER_General, GN_TO(s));
00475     }
00476     // add Adresses
00477     const KABC::Address::List addresses = addr->addresses();
00478     KABC::Address::List::ConstIterator it2;
00479     for ( it2 = addresses.begin(); it2 != addresses.end(); ++it2 ) {
00480         const KABC::Address *Addr = &(*it2);
00481         if (Addr->isEmpty()) continue;
00482         TQStringList a;
00483         TQChar sem(';');
00484         TQString sem_repl(TQString::fromLatin1(","));
00485             a.append( Addr->postOfficeBox().replace( sem, sem_repl ) );
00486         a.append( Addr->extended()     .replace( sem, sem_repl ) );
00487         a.append( Addr->street()       .replace( sem, sem_repl ) );
00488         a.append( Addr->locality()     .replace( sem, sem_repl ) );
00489         a.append( Addr->region()       .replace( sem, sem_repl ) );
00490         a.append( Addr->postalCode()   .replace( sem, sem_repl ) );
00491         a.append( Addr->country()      .replace( sem, sem_repl ) );
00492         s = a.join(sem);
00493         gn_lib_set_pb_subentry(state, -1 /* index to append entry */,
00494             GN_PHONEBOOK_ENTRY_Postal, GN_PHONEBOOK_NUMBER_General, GN_TO(s));
00495     }
00496     // add Note
00497     s = addr->note().simplifyWhiteSpace();
00498     if (!s.isEmpty()) {
00499         gn_lib_set_pb_subentry(state, -1 /* index to append entry */,
00500             GN_PHONEBOOK_ENTRY_Note, GN_PHONEBOOK_NUMBER_General, GN_TO(s));
00501     }
00502 
00503     // debug output
00504     for (int st=0; st<gn_lib_get_pb_num_subentries(state); st++) {
00505         gn_phonebook_entry_type entry_type;
00506         gn_phonebook_number_type number_type;
00507         const char *number;
00508         gn_lib_get_pb_subentry(state, st, &entry_type, &number_type, &number);
00509         GNOKII_DEBUG(TQString(" SubTel #%1: entry_type=%2, number_type=%3, number=%4\n")
00510                         .arg(st).arg(entry_type)
00511                         .arg(number_type).arg(GN_FROM(number)));
00512     }
00513 
00514     gn_error error = gn_lib_phonebook_write_entry(state, memtype, phone_location);
00515     GNOKII_CHECK_ERROR(error);
00516 
00517     return error;
00518 }
00519 
00520 
00521 static gn_error xxport_phone_delete_entry( int phone_location, gn_memory_type memtype )
00522 {
00523     return gn_lib_phonebook_entry_delete(state, memtype, phone_location);
00524 }
00525 
00526 
00527 KABC::AddresseeList GNOKIIXXPort::importContacts( const TQString& ) const
00528 {
00529     KABC::AddresseeList addrList;
00530 
00531     if (KMessageBox::Continue != KMessageBox::warningContinueCancel(parentWidget(),
00532         i18n("<qt>Please connect your Mobile Phone to your computer and press "
00533              "<b>Continue</b> to start importing the personal contacts.<br><br>"
00534              "Please note that if your Mobile Phone is not properly connected "
00535              "the following detection phase might take up to two minutes, during which "
00536                      "KAddressbook will behave unresponsively.</qt>") ))
00537       return addrList;
00538 
00539     m_progressDlg = new KProgressDialog( parentWidget(), "importwidget",
00540         i18n("Mobile Phone Import"),
00541         i18n("<qt><center>Establishing connection to the Mobile Phone.<br><br>"
00542              "Please wait...</center></qt>") );
00543     m_progressDlg->setAllowCancel(true);
00544     m_progressDlg->progressBar()->setProgress(0);
00545     m_progressDlg->progressBar()->setCenterIndicator(true);
00546     m_progressDlg->setModal(true);
00547     m_progressDlg->setInitialSize(TQSize(450,350));
00548     m_progressDlg->show();
00549     processEvents();
00550 
00551     m_progressDlg->setCursor( TQt::BusyCursor );
00552     TQString errStr = businit();
00553     m_progressDlg->unsetCursor();
00554 
00555     if (!errStr.isEmpty()) {
00556         KMessageBox::error(parentWidget(), errStr);
00557         delete m_progressDlg;
00558         return addrList;
00559     }
00560 
00561     GNOKII_DEBUG("GNOKII import filter started.\n");
00562     m_progressDlg->setButtonText(i18n("&Stop Import"));
00563 
00564     read_phone_entries("ME", GN_MT_ME, &addrList); // internal phone memory
00565     read_phone_entries("SM", GN_MT_SM, &addrList); // SIM card
00566 
00567     GNOKII_DEBUG("GNOKII import filter finished.\n");
00568 
00569     busterminate();
00570     delete m_progressDlg;
00571 
00572     return addrList;
00573 }
00574 
00575 
00576 bool GNOKIIXXPort::exportContacts( const KABC::AddresseeList &list, const TQString & )
00577 {
00578     if (KMessageBox::Continue != KMessageBox::warningContinueCancel(parentWidget(),
00579         i18n("<qt>Please connect your Mobile Phone to your computer and press "
00580              "<b>Continue</b> to start exporting the selected personal contacts.<br><br>"
00581              "Please note that if your Mobile Phone is not properly connected "
00582              "the following detection phase might take up to two minutes, during which "
00583              "KAddressbook will behave unresponsively.</qt>") ))
00584       return false;
00585 
00586     m_progressDlg = new KProgressDialog( parentWidget(), "importwidget",
00587         i18n("Mobile Phone Export"),
00588         i18n("<qt><center>Establishing connection to the Mobile Phone.<br><br>"
00589              "Please wait...</center></qt>") );
00590     m_progressDlg->setAllowCancel(true);
00591     m_progressDlg->progressBar()->setProgress(0);
00592     m_progressDlg->progressBar()->setCenterIndicator(true);
00593     m_progressDlg->setModal(true);
00594     m_progressDlg->setInitialSize(TQSize(450,350));
00595     m_progressDlg->show();
00596     processEvents();
00597 
00598     KProgress* progress = (KProgress*)m_progressDlg->progressBar();
00599 
00600     KABC::AddresseeList::ConstIterator it;
00601     TQStringList failedList;
00602 
00603     gn_error error;
00604     bool deleteLabelInitialized = false;
00605 
00606     m_progressDlg->setCursor( TQt::BusyCursor );
00607     TQString errStr = businit();
00608     m_progressDlg->unsetCursor();
00609 
00610     if (!errStr.isEmpty()) {
00611         KMessageBox::error(parentWidget(), errStr);
00612         delete m_progressDlg;
00613         return false;
00614     }
00615 
00616     GNOKII_DEBUG("GNOKII export filter started.\n");
00617 
00618     gn_memory_type memtype = GN_MT_ME;  // internal phone memory
00619 
00620     int phone_count;    // num entries in phone
00621     bool overwrite_phone_entries = false;
00622     int phone_entry_no, entries_written;
00623     bool entry_empty;
00624 
00625     // get number of entries in this phone memory
00626     gn_memory_status memstat;
00627     error = read_phone_memstat(memtype, &memstat);
00628     if (error == GN_ERR_NONE) {
00629         GNOKII_DEBUG("Writing to internal phone memory.\n");
00630     } else {
00631         memtype = GN_MT_SM; // try SIM card instead
00632         error = read_phone_memstat(memtype, &memstat);
00633         if (error != GN_ERR_NONE)
00634             goto finish;
00635         GNOKII_DEBUG("Writing to SIM card memory.\n");
00636     }
00637     phone_count = memstat.used;
00638 
00639     if (memstat.free >= (int) list.count()) {
00640         if (KMessageBox::No == KMessageBox::questionYesNo(parentWidget(),
00641             i18n("<qt>Do you want the selected contacts to be <b>appended</b> to "
00642                  "the current mobile phonebook or should they <b>replace</b> all "
00643                  "currently existing phonebook entries ?<br><br>"
00644                  "Please note, that in case you choose to replace the phonebook "
00645                  "entries, every contact in your phone will be deleted and only "
00646                  "the newly exported contacts will be available from inside your phone.</qt>"),
00647             i18n("Export to Mobile Phone"),
00648             KGuiItem(i18n("&Append to Current Phonebook")),
00649             KGuiItem(i18n("&Replace Current Phonebook with New Contacts")) ) )
00650                 overwrite_phone_entries = true;
00651     }
00652 
00653     progress->setTotalSteps(list.count());
00654     entries_written = 0;
00655     progress->setProgress(entries_written);
00656     m_progressDlg->setButtonText(i18n("&Stop Export"));
00657     m_progressDlg->setLabel(i18n("<qt>Exporting <b>%1</b> contacts to the <b>%2</b> "
00658             "of the Mobile Phone.<br><br>%3</qt>")
00659         .arg(list.count())
00660         .arg(gn_memory_type2str(memtype))
00661         .arg(buildPhoneInfoString(memstat)) );
00662 
00663     // Now run the loop...
00664     phone_entry_no = 1;
00665     for ( it = list.begin(); it != list.end(); ++it ) {
00666         const KABC::Addressee *addr = &(*it);
00667         if (addr->isEmpty())
00668             continue;
00669         // don't write back SIM-card entries !
00670         if (addr->custom(APP, "X_GSM_STORE_AT").startsWith("SM"))
00671             continue;
00672 
00673         progress->setProgress(entries_written++);
00674 
00675 try_next_phone_entry:
00676         this_filter->processEvents();
00677         if (m_progressDlg->wasCancelled())
00678             break;
00679 
00680         // End of phone memory reached ?
00681         if (phone_entry_no > (memstat.used + memstat.free))
00682             break;
00683 
00684         GNOKII_DEBUG(TQString("Try to write entry '%1' at phone_entry_no=%2, phone_count=%3\n")
00685                 .arg(addr->realName()).arg(phone_entry_no).arg(phone_count));
00686 
00687         error = GN_ERR_NONE;
00688 
00689         // is this phone entry empty ?
00690         entry_empty = gn_lib_phonebook_entry_isempty(state, memtype, phone_entry_no);
00691         if (overwrite_phone_entries) {
00692             // overwrite this phonebook entry ...
00693             if (!entry_empty)
00694                 phone_count--;
00695             error = xxport_phone_write_entry( phone_entry_no, memtype, addr);
00696             phone_entry_no++;
00697         } else {
00698             // add this phonebook entry if possible ...
00699             if (entry_empty) {
00700                 error = xxport_phone_write_entry( phone_entry_no, memtype, addr);
00701                 phone_entry_no++;
00702             } else {
00703                 phone_entry_no++;
00704                 goto try_next_phone_entry;
00705             }
00706         }
00707 
00708         if (error != GN_ERR_NONE)
00709             failedList.append(addr->realName());
00710 
00711         // break if we got an error on the first entry
00712         if (error != GN_ERR_NONE && it==list.begin())
00713             break;
00714 
00715     } // for()
00716 
00717     // if we wanted to overwrite all entries, make sure, that we also
00718     // delete all remaining entries in the mobile phone.
00719     while (overwrite_phone_entries && error==GN_ERR_NONE && phone_count>0) {
00720         if (m_progressDlg->wasCancelled())
00721             break;
00722         if (!deleteLabelInitialized) {
00723             m_progressDlg->setLabel(
00724                 i18n("<qt><center>"
00725                      "All selected contacts have been sucessfully copied to "
00726                      "the Mobile Phone.<br><br>"
00727                      "Please wait until all remaining orphaned contacts from "
00728                      "the Mobile Phone have been deleted.</center></qt>") );
00729             m_progressDlg->setButtonText(i18n("&Stop Delete"));
00730             deleteLabelInitialized = true;
00731             progress->setTotalSteps(phone_count);
00732             entries_written = 0;
00733             progress->setProgress(entries_written);
00734             this_filter->processEvents();
00735         }
00736         if (phone_entry_no > (memstat.used + memstat.free))
00737             break;
00738         entry_empty = gn_lib_phonebook_entry_isempty(state, memtype, phone_entry_no);
00739         if (!entry_empty) {
00740             error = xxport_phone_delete_entry(phone_entry_no, memtype);
00741             phone_count--;
00742             progress->setProgress(++entries_written);
00743             this_filter->processEvents();
00744         }
00745         phone_entry_no++;
00746     }
00747 
00748 finish:
00749     m_progressDlg->setLabel(i18n("Export to phone finished."));
00750     this_filter->processEvents();
00751 
00752     GNOKII_DEBUG("GNOKII export filter finished.\n");
00753 
00754     busterminate();
00755     delete m_progressDlg;
00756 
00757     if (!failedList.isEmpty()) {
00758         GNOKII_DEBUG(TQString("Failed to export: %1\n").arg(failedList.join(", ")));
00759         KMessageBox::informationList(parentWidget(),
00760                         i18n("<qt>The following contacts could not be exported to the Mobile Phone. "
00761                  "Possible Reasons for this problem could be:<br><ul>"
00762                  "<li>The contacts contain more information per entry than the phone can store.</li>"
00763                  "<li>Your phone does not allow to store multiple addresses, emails, homepages, ...</li>"
00764                  "<li>other storage size related problems.</li>"
00765                  "</ul>"
00766                  "To avoid those kind of problems in the future please reduce the amount of different "
00767                  "fields in the above contacts.</qt>"),
00768             failedList,
00769             i18n("Mobile Phone Export") );
00770     }
00771 
00772 
00773     return true;
00774 }
00775 
00776 /******************************************************************************
00777  ******************************************************************************
00778  ******************************************************************************
00779  ******************************************************************************
00780  ******************************************************************************/
00781 
00782 #elif defined(HAVE_GNOKII_H)
00783 
00784 #ifdef __GNUC__
00785 # warning "Please upgrade your gnokii installation to at least version 0.6.13"
00786 # warning "Older gnokii versions below 0.6.13 are not binary compatible and"
00787 # warning "prevents KDE users to upgrade gnokii to newer versions later."
00788 #endif
00789 
00790 /* OLD GNOKII LIBRARIES (< 0.6.13) */
00791 
00792 /* import */
00793 static char *lockfile = NULL;
00794 static char manufacturer[64], model[GN_MODEL_MAX_LENGTH+1],
00795             revision[GN_REVISION_MAX_LENGTH+1], imei[GN_IMEI_MAX_LENGTH+1];
00796 static TQString PhoneProductId;
00797 
00798 static struct gn_statemachine state;
00799 static gn_data data;
00800 
00801 static void busterminate(void)
00802 {
00803     gn_sm_functions(GN_OP_Terminate, NULL, &state);
00804     if (lockfile) gn_device_unlock(lockfile);
00805 }
00806 
00807 static TQString businit(void)
00808 {
00809     gn_error error;
00810     char *aux;
00811 
00812     GNOKII_DEBUG( "Using old gnokii version." );
00813 
00814 #if defined(LIBGNOKII_VERSION)
00815     if (gn_cfg_read_default()<0)
00816 #else
00817     static char *BinDir;
00818     if (gn_cfg_read(&BinDir)<0)
00819 #endif
00820         return i18n("Failed to initialize the gnokii library.");
00821 
00822     if (!gn_cfg_phone_load("", &state))
00823         return i18n("Gnokii is not yet configured.");
00824 
00825     // uncomment to debug all gnokii communication on stderr.
00826     // gn_log_debug_mask = GN_LOG_T_STDERR;
00827 
00828     gn_data_clear(&data);
00829 
00830     aux = gn_cfg_get(gn_cfg_info, "global", "use_locking");
00831     // Defaults to 'no'
00832     if (aux && !strcmp(aux, "yes")) {
00833         lockfile = gn_device_lock(state.config.port_device);
00834         if (lockfile == NULL) {
00835             return i18n("Gnokii reports a 'Lock File Error'.\n "
00836             "Please exit all other running instances of gnokii, check if you have "
00837             "write permissions in the /var/lock directory and try again.");
00838         }
00839     }
00840 
00841     // Initialise the code for the GSM interface.
00842     int old_dcd = state.config.require_dcd; // work-around for older gnokii versions
00843     state.config.require_dcd = false;
00844     error = gn_gsm_initialise(&state);
00845     GNOKII_CHECK_ERROR(error);
00846     state.config.require_dcd = old_dcd;
00847     if (error != GN_ERR_NONE) {
00848         busterminate();
00849         return i18n("<qt><center>Mobile Phone interface initialization failed.<br><br>"
00850             "The returned error message was:<br><b>%1</b><br><br>"
00851             "You might try to run \"gnokii --identify\" on the command line to "
00852             "check any cable/transport issues and to verify if your gnokii "
00853             "configuration is correct.</center></qt>")
00854             .arg(gn_error_print(error));
00855     }
00856 
00857     // identify phone
00858     gn_data_clear(&data);
00859     data.manufacturer = manufacturer;
00860     data.model = model;
00861     data.revision = revision;
00862     data.imei = imei;
00863 
00864     TQCString unknown(GN_TO(i18n("Unknown")));
00865     qstrncpy(manufacturer, unknown, sizeof(manufacturer)-1);
00866     qstrncpy(model, unknown, sizeof(model)-1);
00867     qstrncpy(revision, unknown, sizeof(revision)-1);
00868     qstrncpy(imei, unknown, sizeof(imei)-1);
00869 
00870     if (m_progressDlg->wasCancelled())
00871         return TQString();
00872     else
00873         error = gn_sm_functions(GN_OP_Identify, &data, &state);
00874     GNOKII_CHECK_ERROR(error);
00875 
00876     GNOKII_DEBUG( TQString("Found mobile phone: %1 %2, Revision: %3, IMEI: %4\n")
00877                 .arg(manufacturer, model, revision, imei) );
00878 
00879     PhoneProductId = TQString("%1-%2-%3-%4").arg(APP).arg(model).arg(revision).arg(imei);
00880 
00881     return TQString();
00882 }
00883 
00884 
00885 // get number of entries in this phone memory type (internal/SIM-card)
00886 static gn_error read_phone_memstat( const gn_memory_type memtype, gn_memory_status *memstat )
00887 {
00888     gn_error error;
00889 
00890     gn_data_clear(&data);
00891     memset(memstat, 0, sizeof(*memstat));
00892     memstat->memory_type = memtype;
00893     data.memory_status = memstat;
00894     error = gn_sm_functions(GN_OP_GetMemoryStatus, &data, &state);
00895     GNOKII_CHECK_ERROR(error);
00896     if (error != GN_ERR_NONE) {
00897         switch (memtype) {
00898           case GN_MT_SM:
00899             // use at least 100 entries
00900             memstat->used = 0;
00901             memstat->free = 100;
00902             break;
00903           default:
00904           case GN_MT_ME:
00905             // Phone doesn't support ME (5110)
00906             memstat->used = memstat->free = 0;
00907             break;
00908         }
00909     }
00910     GNOKII_DEBUG( TQString("\n\nMobile phone memory status: Type: %1, used=%2, free=%3, total=%4\n\n")
00911                     .arg(memtype).arg(memstat->used).arg(memstat->free).arg(memstat->used+memstat->free) );
00912     return error;
00913 }
00914 
00915 
00916 // read phone entry #index from memory #memtype
00917 static gn_error read_phone_entry( const int index, const gn_memory_type memtype, gn_phonebook_entry *entry )
00918 {
00919     gn_error error;
00920     entry->memory_type = memtype;
00921     entry->location = index;
00922     data.phonebook_entry = entry;
00923     error = gn_sm_functions(GN_OP_ReadPhonebook, &data, &state);
00924     GNOKII_CHECK_ERROR(error);
00925     return error;
00926 }
00927 
00928 static bool phone_entry_empty( const int index, const gn_memory_type memtype )
00929 {
00930     gn_error error;
00931     gn_phonebook_entry entry;
00932     entry.memory_type = memtype;
00933     entry.location = index;
00934     data.phonebook_entry = &entry;
00935     error = gn_sm_functions(GN_OP_ReadPhonebook, &data, &state);
00936     if (error == GN_ERR_EMPTYLOCATION)
00937         return true;
00938     GNOKII_CHECK_ERROR(error);
00939     if (error == GN_ERR_NONE && entry.empty)
00940         return true;
00941     return false;
00942 }
00943 
00944 static TQString buildPhoneInfoString( const gn_memory_status &memstat )
00945 {
00946     TQString format = TQString::fromLatin1("<tr><td><b>%1</b></td><td>%2</td></tr>");
00947 
00948     return TQString::fromLatin1("<b>%1</b><br><table>%2%3%4%5%6</table><br>")
00949         .arg(i18n("Mobile Phone information:"))
00950         .arg(format.arg(i18n("Manufacturer")).arg(GN_FROM(manufacturer)))
00951         .arg(format.arg(i18n("Phone model")).arg(GN_FROM(model)))
00952         .arg(format.arg(i18n("Revision")).arg(GN_FROM(revision)))
00953         .arg(format.arg(i18n("IMEI")).arg(GN_FROM(imei)))
00954         .arg(format.arg(i18n("Phonebook status"))
00955                .arg(i18n("%1 out of %2 contacts used").arg(memstat.used).arg(memstat.used+memstat.free)));
00956 }
00957 
00958 static TQString buildMemoryTypeString( gn_memory_type memtype )
00959 {
00960     switch (memtype) {
00961     case GN_MT_ME:  return i18n("internal memory");
00962     case GN_MT_SM:  return i18n("SIM-card memory");
00963     default:    return i18n("unknown memory");
00964     }
00965 }
00966 
00967 // read and evaluate all phone entries
00968 static gn_error read_phone_entries( const char *memtypestr, gn_memory_type memtype,
00969             KABC::AddresseeList *addrList )
00970 {
00971   gn_error error;
00972 
00973   if (m_progressDlg->wasCancelled())
00974     return GN_ERR_NONE;
00975 
00976   KProgress* progress = (KProgress*)m_progressDlg->progressBar();
00977 
00978   progress->setProgress(0);
00979   this_filter->processEvents();
00980 
00981   // get number of entries in this phone memory type (internal/SIM-card)
00982   gn_memory_status memstat;
00983   error = read_phone_memstat(memtype, &memstat);
00984 
00985   gn_phonebook_entry entry;
00986   TQStringList addrlist;
00987   KABC::Address *addr;
00988   TQString s, country;
00989 
00990   progress->setTotalSteps(memstat.used);
00991   m_progressDlg->setLabel(i18n("<qt>Importing <b>%1</b> contacts from <b>%2</b> of the Mobile Phone.<br><br>%3</qt>")
00992         .arg(memstat.used)
00993         .arg(buildMemoryTypeString(memtype))
00994         .arg(buildPhoneInfoString(memstat)) );
00995 
00996   int num_read = 0;
00997 
00998   for (int i = 1; !m_progressDlg->wasCancelled() && i <= memstat.used + memstat.free; i++) {
00999     error = read_phone_entry( i, memtype, &entry );
01000 
01001     progress->setProgress(num_read);
01002     this_filter->processEvents();
01003 
01004     if (error == GN_ERR_EMPTYLOCATION)
01005         continue;
01006     if (error == GN_ERR_INVALIDLOCATION)
01007         break;
01008     if (error == GN_ERR_INVALIDMEMORYTYPE)
01009         break;
01010     if (error == GN_ERR_NONE) {
01011         GNOKII_DEBUG(TQString("%1: %2, num=%3, location=%4, group=%5, count=%6\n").arg(i).arg(GN_FROM(entry.name))
01012             .arg(GN_FROM(entry.number)).arg(entry.location).arg(entry.caller_group).arg(entry.subentries_count));
01013         KABC::Addressee *a = new KABC::Addressee();
01014 
01015         // try to split Name into FamilyName and GivenName
01016         s = GN_FROM(entry.name).simplifyWhiteSpace();
01017         a->setFormattedName(s); // set formatted name as in Phone
01018         if (s.find(',') == -1) {
01019           // assumed format: "givenname [... familyname]"
01020           addrlist = TQStringList::split(' ', s);
01021           if (addrlist.count() == 1) {
01022             // only one string -> put it in the GivenName
01023             a->setGivenName(s);
01024           } else {
01025             // multiple strings -> split them.
01026             a->setFamilyName(addrlist.last().simplifyWhiteSpace());
01027             addrlist.remove(addrlist.last());
01028             a->setGivenName(addrlist.join(" ").simplifyWhiteSpace());
01029           }
01030         } else {
01031           // assumed format: "familyname, ... givenname"
01032           addrlist = TQStringList::split(',', s);
01033           a->setFamilyName(addrlist.first().simplifyWhiteSpace());
01034           addrlist.remove(addrlist.first());
01035           a->setGivenName(addrlist.join(" ").simplifyWhiteSpace());
01036         }
01037 
01038         a->insertCustom(APP, "X_GSM_CALLERGROUP", s.setNum(entry.caller_group));
01039         a->insertCustom(APP, "X_GSM_STORE_AT", TQString("%1%2").arg(memtypestr).arg(entry.location));
01040 
01041         // set ProductId
01042         a->setProductId(PhoneProductId);
01043 
01044         // evaluate timestamp (ignore timezone)
01045         TQDateTime datetime;
01046         if (entry.date.year<1998)
01047             datetime = TQDateTime::currentDateTime();
01048         else
01049             datetime = TQDateTime( TQDate(entry.date.year, entry.date.month, entry.date.day),
01050                               TQTime(entry.date.hour, entry.date.minute, entry.date.second) );
01051         GNOKII_DEBUG(TQString(" date=%1\n").arg(datetime.toString()));
01052         a->setRevision(datetime);
01053 
01054         if (!entry.subentries_count)
01055           a->insertPhoneNumber(KABC::PhoneNumber(entry.number, KABC::PhoneNumber::Work | KABC::PhoneNumber::Pref));
01056 
01057         /* scan sub-entries */
01058         if (entry.subentries_count)
01059          for (int n=0; n<entry.subentries_count; n++) {
01060           TQString s = GN_FROM(entry.subentries[n].data.number).simplifyWhiteSpace();
01061           GNOKII_DEBUG(TQString(" Subentry#%1, entry_type=%2, number_type=%3, number=%4\n")
01062                 .arg(n).arg(entry.subentries[n].entry_type)
01063                 .arg(entry.subentries[n].number_type).arg(s));
01064           if (s.isEmpty())
01065             continue;
01066           switch(entry.subentries[n].entry_type) {
01067            case GN_PHONEBOOK_ENTRY_Name:
01068             a->setName(s);
01069             break;
01070            case GN_PHONEBOOK_ENTRY_Email:
01071             a->insertEmail(s);
01072             break;
01073            case GN_PHONEBOOK_ENTRY_Postal:
01074             addrlist = TQStringList::split(';', s, true);
01075             addr = new KABC::Address(KABC::Address::Work);
01076             if (addrlist.count() <= 1) {
01077                 addrlist = TQStringList::split(',', s, true);
01078                 if (addrlist.count() > 1 ) {
01079                     // assumed format: "Locality, ZIP, Country"
01080                     addr->setLocality(addrlist[0]);
01081                     addr->setPostalCode(addrlist[1]);
01082                     if (!addrlist[2].isEmpty())
01083                         addr->setCountry(i18n(GN_TO(addrlist[2])));
01084                 } else {
01085                     // no idea about the format, just store it.
01086                     addr->setLocality(s);
01087                 }
01088             } else {
01089                 // assumed format: "POBox; Extended; Street; Locality; Region; ZIP [;Country]
01090                 addr->setPostOfficeBox(addrlist[0]);
01091                 addr->setExtended(addrlist[1]);
01092                 addr->setStreet(addrlist[2]);
01093                 addr->setLocality(addrlist[3]);
01094                 addr->setRegion(addrlist[4]);
01095                 addr->setPostalCode(addrlist[5]);
01096                 country = addrlist[6];
01097                 if (!country.isEmpty())
01098                     addr->setCountry(i18n(GN_TO(country)));
01099             }
01100             a->insertAddress(*addr);
01101             delete addr;
01102             break;
01103            case GN_PHONEBOOK_ENTRY_Note:
01104             if (!a->note().isEmpty())
01105                 s = "\n" + s;
01106             a->setNote(a->note()+s);
01107             break;
01108            case GN_PHONEBOOK_ENTRY_Number:
01109             enum KABC::PhoneNumber::Types phonetype;
01110             switch (entry.subentries[n].number_type) {
01111              case GN_PHONEBOOK_NUMBER_Mobile: phonetype = KABC::PhoneNumber::Cell; break;
01112              case GN_PHONEBOOK_NUMBER_Fax:    phonetype = KABC::PhoneNumber::Fax;  break;
01113              case GN_PHONEBOOK_NUMBER_General:
01114              case GN_PHONEBOOK_NUMBER_Work:   phonetype = KABC::PhoneNumber::Work; break;
01115              default:
01116              case GN_PHONEBOOK_NUMBER_Home:   phonetype = KABC::PhoneNumber::Home; break;
01117             }
01118             //if (s == entry.number)
01119             //  type = (KABC::PhoneNumber::Types) (phonetype | KABC::PhoneNumber::Pref);
01120             a->insertPhoneNumber(KABC::PhoneNumber(s, phonetype));
01121             break;
01122            case GN_PHONEBOOK_ENTRY_URL:
01123             a->setUrl(s);
01124             break;
01125            case GN_PHONEBOOK_ENTRY_Group:
01126             a->insertCategory(s);
01127             break;
01128            default:
01129             GNOKII_DEBUG(TQString(" Not handled id=%1, entry=%2\n")
01130                 .arg(entry.subentries[n].entry_type).arg(s));
01131             break;
01132           } // switch()
01133         } // if(subentry)
01134 
01135         // add only if entry was valid
01136         if (strlen(entry.name) || strlen(entry.number) || entry.subentries_count)
01137             addrList->append(*a);
01138 
01139         // did we read all valid phonebook-entries ?
01140         num_read++;
01141         delete a;
01142         if (num_read >= memstat.used)
01143             break;  // yes, all were read
01144         else
01145             continue; // no, we are still missing some.
01146     }
01147     GNOKII_CHECK_ERROR(error);
01148   }
01149 
01150   return GN_ERR_NONE;
01151 }
01152 
01153 
01154 // export to phone
01155 
01156 static gn_error xxport_phone_write_entry( int phone_location, gn_memory_type memtype,
01157             const KABC::Addressee *addr)
01158 {
01159     gn_phonebook_entry entry;
01160     TQString s;
01161 
01162     memset(&entry, 0, sizeof(entry));
01163     strncpy(entry.name, GN_TO(addr->realName()), sizeof(entry.name)-1);
01164     s = addr->phoneNumber(KABC::PhoneNumber::Pref).number();
01165     if (s.isEmpty())
01166         s = addr->phoneNumber(KABC::PhoneNumber::Work).number();
01167     if (s.isEmpty())
01168         s = addr->phoneNumber(KABC::PhoneNumber::Home).number();
01169     if (s.isEmpty())
01170         s = addr->phoneNumber(KABC::PhoneNumber::Cell).number();
01171     if (s.isEmpty() && addr->phoneNumbers().count()>0)
01172         s = (*addr->phoneNumbers().at(0)).number();
01173     s = makeValidPhone(s);
01174     strncpy(entry.number, s.ascii(), sizeof(entry.number)-1);
01175     entry.memory_type = memtype;
01176     TQString cg = addr->custom(APP, "X_GSM_CALLERGROUP");
01177     if (cg.isEmpty())
01178         entry.caller_group = 5;     // default group
01179     else
01180         entry.caller_group = cg.toInt();
01181     entry.location = phone_location;
01182 
01183     // set date/revision
01184     TQDateTime datetime = addr->revision();
01185     TQDate date(datetime.date());
01186     TQTime time(datetime.time());
01187     entry.date.year = date.year();
01188     entry.date.month = date.month();
01189     entry.date.day = date.day();
01190     entry.date.hour = time.hour();
01191     entry.date.minute = time.minute();
01192     entry.date.second = time.second();
01193 
01194     GNOKII_DEBUG(TQString("Write #%1: name=%2, number=%3\n").arg(phone_location)
01195                     .arg(GN_FROM(entry.name)).arg(GN_FROM(entry.number)));
01196 
01197     const KABC::Address homeAddr = addr->address(KABC::Address::Home);
01198     const KABC::Address workAddr = addr->address(KABC::Address::Work);
01199 
01200     entry.subentries_count = 0;
01201     gn_phonebook_subentry *subentry = &entry.subentries[0];
01202     // add all phone numbers
01203     const KABC::PhoneNumber::List phoneList = addr->phoneNumbers();
01204     KABC::PhoneNumber::List::ConstIterator it;
01205     for ( it = phoneList.begin(); it != phoneList.end(); ++it ) {
01206         const KABC::PhoneNumber *phonenumber = &(*it);
01207         s = phonenumber->number();
01208         if (s.isEmpty()) continue;
01209         subentry->entry_type  = GN_PHONEBOOK_ENTRY_Number;
01210         gn_phonebook_number_type type;
01211         int pn_type = phonenumber->type();
01212         if ((pn_type & KABC::PhoneNumber::Cell))
01213             type = GN_PHONEBOOK_NUMBER_Mobile;
01214         else if ((pn_type & KABC::PhoneNumber::Fax))
01215             type = GN_PHONEBOOK_NUMBER_Fax;
01216         else if ((pn_type & KABC::PhoneNumber::Home))
01217             type = GN_PHONEBOOK_NUMBER_Home;
01218         else if ((pn_type & KABC::PhoneNumber::Work))
01219             type = GN_PHONEBOOK_NUMBER_Work;
01220         else type = GN_PHONEBOOK_NUMBER_General;
01221         subentry->number_type = type;
01222         strncpy(subentry->data.number, makeValidPhone(s).ascii(), sizeof(subentry->data.number)-1);
01223         subentry->id = phone_location<<8+entry.subentries_count;
01224         entry.subentries_count++;
01225         subentry++;
01226         if (entry.subentries_count >= GN_PHONEBOOK_SUBENTRIES_MAX_NUMBER)
01227             break; // Phonebook full
01228     }
01229     // add URL
01230     s = addr->url().prettyURL();
01231     if (!s.isEmpty() && (entry.subentries_count<GN_PHONEBOOK_SUBENTRIES_MAX_NUMBER)) {
01232         subentry->entry_type = GN_PHONEBOOK_ENTRY_URL;
01233         strncpy(subentry->data.number, GN_TO(s), sizeof(subentry->data.number)-1);
01234         entry.subentries_count++;
01235         subentry++;
01236     }
01237     // add E-Mails
01238     TQStringList emails = addr->emails();
01239     for (unsigned int n=0; n<emails.count(); n++) {
01240         if (entry.subentries_count >= GN_PHONEBOOK_SUBENTRIES_MAX_NUMBER)
01241             break; // Phonebook full
01242         s = emails[n].simplifyWhiteSpace();
01243         if (s.isEmpty()) continue;
01244         // only one email allowed if we have URLS, notes, addresses (to avoid phone limitations)
01245         if (n && !addr->url().isEmpty() && !addr->note().isEmpty() && addr->addresses().count()) {
01246             GNOKII_DEBUG(TQString(" DROPPED email %1 in favor of URLs, notes and addresses.\n")
01247                     .arg(s));
01248             continue;
01249         }
01250         subentry->entry_type  = GN_PHONEBOOK_ENTRY_Email;
01251         strncpy(subentry->data.number, GN_TO(s), sizeof(subentry->data.number)-1);
01252         entry.subentries_count++;
01253         subentry++;
01254     }
01255     // add Adresses
01256     const KABC::Address::List addresses = addr->addresses();
01257     KABC::Address::List::ConstIterator it2;
01258     for ( it2 = addresses.begin(); it2 != addresses.end(); ++it2 ) {
01259         if (entry.subentries_count >= GN_PHONEBOOK_SUBENTRIES_MAX_NUMBER)
01260             break; // Phonebook full
01261         const KABC::Address *Addr = &(*it2);
01262         if (Addr->isEmpty()) continue;
01263         subentry->entry_type  = GN_PHONEBOOK_ENTRY_Postal;
01264         TQStringList a;
01265         TQChar sem(';');
01266         TQString sem_repl(TQString::fromLatin1(","));
01267             a.append( Addr->postOfficeBox().replace( sem, sem_repl ) );
01268         a.append( Addr->extended()     .replace( sem, sem_repl ) );
01269         a.append( Addr->street()       .replace( sem, sem_repl ) );
01270         a.append( Addr->locality()     .replace( sem, sem_repl ) );
01271         a.append( Addr->region()       .replace( sem, sem_repl ) );
01272         a.append( Addr->postalCode()   .replace( sem, sem_repl ) );
01273         a.append( Addr->country()      .replace( sem, sem_repl ) );
01274         s = a.join(sem);
01275         strncpy(subentry->data.number, GN_TO(s), sizeof(subentry->data.number)-1);
01276         entry.subentries_count++;
01277         subentry++;
01278     }
01279     // add Note
01280     s = addr->note().simplifyWhiteSpace();
01281     if (!s.isEmpty() && (entry.subentries_count<GN_PHONEBOOK_SUBENTRIES_MAX_NUMBER)) {
01282         subentry->entry_type = GN_PHONEBOOK_ENTRY_Note;
01283         strncpy(subentry->data.number, GN_TO(s), sizeof(subentry->data.number)-1);
01284         entry.subentries_count++;
01285         subentry++;
01286     }
01287 
01288     // debug output
01289     for (int st=0; st<entry.subentries_count; st++) {
01290         gn_phonebook_subentry *subentry = &entry.subentries[st];
01291         GNOKII_DEBUG(TQString(" SubTel #%1: entry_type=%2, number_type=%3, number=%4\n")
01292                         .arg(st).arg(subentry->entry_type)
01293                         .arg(subentry->number_type).arg(GN_FROM(subentry->data.number)));
01294     }
01295 
01296     data.phonebook_entry = &entry;
01297     gn_error error = gn_sm_functions(GN_OP_WritePhonebook, &data, &state);
01298     GNOKII_CHECK_ERROR(error);
01299 
01300     return error;
01301 }
01302 
01303 
01304 static gn_error xxport_phone_delete_entry( int phone_location, gn_memory_type memtype )
01305 {
01306     gn_phonebook_entry entry;
01307     memset(&entry, 0, sizeof(entry));
01308     entry.empty = 1;
01309     entry.memory_type = memtype;
01310     entry.location = phone_location;
01311     data.phonebook_entry = &entry;
01312     GNOKII_DEBUG(TQString("Deleting entry %1\n").arg(phone_location));
01313     gn_error error = gn_sm_functions(GN_OP_WritePhonebook, &data, &state);
01314     GNOKII_CHECK_ERROR(error);
01315     return error;
01316 }
01317 
01318 KABC::AddresseeList GNOKIIXXPort::importContacts( const TQString& ) const
01319 {
01320     KABC::AddresseeList addrList;
01321 
01322     if (KMessageBox::Continue != KMessageBox::warningContinueCancel(parentWidget(),
01323         i18n("<qt>Please connect your Mobile Phone to your computer and press "
01324              "<b>Continue</b> to start importing the personal contacts.<br><br>"
01325              "Please note that if your Mobile Phone is not properly connected "
01326              "the following detection phase might take up to two minutes, during which "
01327                      "KAddressbook will behave unresponsively.</qt>") ))
01328       return addrList;
01329 
01330     m_progressDlg = new KProgressDialog( parentWidget(), "importwidget",
01331         i18n("Mobile Phone Import"),
01332         i18n("<qt><center>Establishing connection to the Mobile Phone.<br><br>"
01333              "Please wait...</center></qt>") );
01334     m_progressDlg->setAllowCancel(true);
01335     m_progressDlg->progressBar()->setProgress(0);
01336     m_progressDlg->progressBar()->setCenterIndicator(true);
01337     m_progressDlg->setModal(true);
01338     m_progressDlg->setInitialSize(TQSize(450,350));
01339     m_progressDlg->show();
01340     processEvents();
01341 
01342     m_progressDlg->setCursor( TQt::BusyCursor );
01343     TQString errStr = businit();
01344     m_progressDlg->unsetCursor();
01345 
01346     if (!errStr.isEmpty()) {
01347         KMessageBox::error(parentWidget(), errStr);
01348         delete m_progressDlg;
01349         return addrList;
01350     }
01351 
01352     GNOKII_DEBUG("GNOKII import filter started.\n");
01353     m_progressDlg->setButtonText(i18n("&Stop Import"));
01354 
01355     read_phone_entries("ME", GN_MT_ME, &addrList); // internal phone memory
01356     read_phone_entries("SM", GN_MT_SM, &addrList); // SIM card
01357 
01358     GNOKII_DEBUG("GNOKII import filter finished.\n");
01359 
01360     busterminate();
01361     delete m_progressDlg;
01362 
01363     return addrList;
01364 }
01365 
01366 
01367 bool GNOKIIXXPort::exportContacts( const KABC::AddresseeList &list, const TQString & )
01368 {
01369     if (KMessageBox::Continue != KMessageBox::warningContinueCancel(parentWidget(),
01370         i18n("<qt>Please connect your Mobile Phone to your computer and press "
01371              "<b>Continue</b> to start exporting the selected personal contacts.<br><br>"
01372              "Please note that if your Mobile Phone is not properly connected "
01373              "the following detection phase might take up to two minutes, during which "
01374              "KAddressbook will behave unresponsively.</qt>") ))
01375       return false;
01376 
01377     m_progressDlg = new KProgressDialog( parentWidget(), "importwidget",
01378         i18n("Mobile Phone Export"),
01379         i18n("<qt><center>Establishing connection to the Mobile Phone.<br><br>"
01380              "Please wait...</center></qt>") );
01381     m_progressDlg->setAllowCancel(true);
01382     m_progressDlg->progressBar()->setProgress(0);
01383     m_progressDlg->progressBar()->setCenterIndicator(true);
01384     m_progressDlg->setModal(true);
01385     m_progressDlg->setInitialSize(TQSize(450,350));
01386     m_progressDlg->show();
01387     processEvents();
01388 
01389     KProgress* progress = (KProgress*)m_progressDlg->progressBar();
01390 
01391     KABC::AddresseeList::ConstIterator it;
01392     TQStringList failedList;
01393 
01394     gn_error error;
01395     bool deleteLabelInitialized = false;
01396 
01397     m_progressDlg->setCursor( TQt::BusyCursor );
01398     TQString errStr = businit();
01399     m_progressDlg->unsetCursor();
01400 
01401     if (!errStr.isEmpty()) {
01402         KMessageBox::error(parentWidget(), errStr);
01403         delete m_progressDlg;
01404         return false;
01405     }
01406 
01407     GNOKII_DEBUG("GNOKII export filter started.\n");
01408 
01409     gn_memory_type memtype = GN_MT_ME;  // internal phone memory
01410 
01411     int phone_count;    // num entries in phone
01412     bool overwrite_phone_entries = false;
01413     int phone_entry_no, entries_written;
01414     bool entry_empty;
01415 
01416     // get number of entries in this phone memory
01417     gn_memory_status memstat;
01418     error = read_phone_memstat(memtype, &memstat);
01419     if (error == GN_ERR_NONE) {
01420         GNOKII_DEBUG("Writing to internal phone memory.\n");
01421     } else {
01422         memtype = GN_MT_SM; // try SIM card instead
01423         error = read_phone_memstat(memtype, &memstat);
01424         if (error != GN_ERR_NONE)
01425             goto finish;
01426         GNOKII_DEBUG("Writing to SIM card memory.\n");
01427     }
01428     phone_count = memstat.used;
01429 
01430     if (memstat.free >= (int) list.count()) {
01431         if (KMessageBox::No == KMessageBox::questionYesNo(parentWidget(),
01432             i18n("<qt>Do you want the selected contacts to be <b>appended</b> to "
01433                  "the current mobile phonebook or should they <b>replace</b> all "
01434                  "currently existing phonebook entries ?<br><br>"
01435                  "Please note, that in case you choose to replace the phonebook "
01436                  "entries, every contact in your phone will be deleted and only "
01437                  "the newly exported contacts will be available from inside your phone.</qt>"),
01438             i18n("Export to Mobile Phone"),
01439             KGuiItem(i18n("&Append to Current Phonebook")),
01440             KGuiItem(i18n("&Replace Current Phonebook with New Contacts")) ) )
01441                 overwrite_phone_entries = true;
01442     }
01443 
01444     progress->setTotalSteps(list.count());
01445     entries_written = 0;
01446     progress->setProgress(entries_written);
01447     m_progressDlg->setButtonText(i18n("&Stop Export"));
01448     m_progressDlg->setLabel(i18n("<qt>Exporting <b>%1</b> contacts to the <b>%2</b> "
01449             "of the Mobile Phone.<br><br>%3</qt>")
01450         .arg(list.count())
01451         .arg(buildMemoryTypeString(memtype))
01452         .arg(buildPhoneInfoString(memstat)) );
01453 
01454     // Now run the loop...
01455     phone_entry_no = 1;
01456     for ( it = list.begin(); it != list.end(); ++it ) {
01457         const KABC::Addressee *addr = &(*it);
01458         if (addr->isEmpty())
01459             continue;
01460         // don't write back SIM-card entries !
01461         if (addr->custom(APP, "X_GSM_STORE_AT").startsWith("SM"))
01462             continue;
01463 
01464         progress->setProgress(entries_written++);
01465 
01466 try_next_phone_entry:
01467         this_filter->processEvents();
01468         if (m_progressDlg->wasCancelled())
01469             break;
01470 
01471         // End of phone memory reached ?
01472         if (phone_entry_no > (memstat.used + memstat.free))
01473             break;
01474 
01475         GNOKII_DEBUG(TQString("Try to write entry '%1' at phone_entry_no=%2, phone_count=%3\n")
01476                 .arg(addr->realName()).arg(phone_entry_no).arg(phone_count));
01477 
01478         error = GN_ERR_NONE;
01479 
01480         // is this phone entry empty ?
01481         entry_empty = phone_entry_empty(phone_entry_no, memtype);
01482         if (overwrite_phone_entries) {
01483             // overwrite this phonebook entry ...
01484             if (!entry_empty)
01485                 phone_count--;
01486             error = xxport_phone_write_entry( phone_entry_no, memtype, addr);
01487             phone_entry_no++;
01488         } else {
01489             // add this phonebook entry if possible ...
01490             if (entry_empty) {
01491                 error = xxport_phone_write_entry( phone_entry_no, memtype, addr);
01492                 phone_entry_no++;
01493             } else {
01494                 phone_entry_no++;
01495                 goto try_next_phone_entry;
01496             }
01497         }
01498 
01499         if (error != GN_ERR_NONE)
01500             failedList.append(addr->realName());
01501 
01502         // break if we got an error on the first entry
01503         if (error != GN_ERR_NONE && it==list.begin())
01504             break;
01505 
01506     } // for()
01507 
01508     // if we wanted to overwrite all entries, make sure, that we also
01509     // delete all remaining entries in the mobile phone.
01510     while (overwrite_phone_entries && error==GN_ERR_NONE && phone_count>0) {
01511         if (m_progressDlg->wasCancelled())
01512             break;
01513         if (!deleteLabelInitialized) {
01514             m_progressDlg->setLabel(
01515                 i18n("<qt><center>"
01516                      "All selected contacts have been sucessfully copied to "
01517                      "the Mobile Phone.<br><br>"
01518                      "Please wait until all remaining orphaned contacts from "
01519                      "the Mobile Phone have been deleted.</center></qt>") );
01520             m_progressDlg->setButtonText(i18n("&Stop Delete"));
01521             deleteLabelInitialized = true;
01522             progress->setTotalSteps(phone_count);
01523             entries_written = 0;
01524             progress->setProgress(entries_written);
01525             this_filter->processEvents();
01526         }
01527         if (phone_entry_no > (memstat.used + memstat.free))
01528             break;
01529         entry_empty = phone_entry_empty(phone_entry_no, memtype);
01530         if (!entry_empty) {
01531             error = xxport_phone_delete_entry(phone_entry_no, memtype);
01532             phone_count--;
01533             progress->setProgress(++entries_written);
01534             this_filter->processEvents();
01535         }
01536         phone_entry_no++;
01537     }
01538 
01539 finish:
01540     m_progressDlg->setLabel(i18n("Export to phone finished."));
01541     this_filter->processEvents();
01542 
01543     GNOKII_DEBUG("GNOKII export filter finished.\n");
01544 
01545     busterminate();
01546     delete m_progressDlg;
01547 
01548     if (!failedList.isEmpty()) {
01549         GNOKII_DEBUG(TQString("Failed to export: %1\n").arg(failedList.join(", ")));
01550         KMessageBox::informationList(parentWidget(),
01551                         i18n("<qt>The following contacts could not be exported to the Mobile Phone. "
01552                  "Possible Reasons for this problem could be:<br><ul>"
01553                  "<li>The contacts contain more information per entry than the phone can store.</li>"
01554                  "<li>Your phone does not allow to store multiple addresses, emails, homepages, ...</li>"
01555                  "<li>other storage size related problems.</li>"
01556                  "</ul>"
01557                  "To avoid those kind of problems in the future please reduce the amount of different "
01558                  "fields in the above contacts.</qt>"),
01559             failedList,
01560             i18n("Mobile Phone Export") );
01561     }
01562 
01563     return true;
01564 }
01565 
01566 
01567 /******************************************************************************
01568  ******************************************************************************
01569  ******************************************************************************
01570  ******************************************************************************
01571  ******************************************************************************/
01572 
01573 #else  /* no gnokii installed */
01574 
01575 KABC::AddresseeList GNOKIIXXPort::importContacts( const TQString& ) const
01576 {
01577     KABC::AddresseeList addrList;
01578     KMessageBox::error(parentWidget(), i18n("Gnokii interface is not available.\n"
01579         "Please ask your distributor to add gnokii at compile time."));
01580     return addrList;
01581 }
01582 
01583 bool GNOKIIXXPort::exportContacts( const KABC::AddresseeList &list, const TQString & )
01584 {
01585     Q_UNUSED(list);
01586     KMessageBox::error(parentWidget(), i18n("Gnokii interface is not available.\n"
01587         "Please ask your distributor to add gnokii at compile time."));
01588     return true;
01589 }
01590 
01591 #endif /* END OF GNOKII LIB SWITCH */
01592 
01593 /******************************************************************************
01594  ******************************************************************************
01595  ******************************************************************************
01596  ******************************************************************************
01597  ******************************************************************************/
01598 
01599 #include "gnokii_xxport.moc"
01600 
01601 /* vim: set sts=4 ts=4 sw=4: */