00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033 #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 <qcursor.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() << QString("ERROR %1: %2\n").arg(error).arg(gn_error_print(error));\
00067 } while (0)
00068
00069
00070
00071 #define GN_FROM(x) QString::fromLocal8Bit(x)
00072 #define GN_TO(x) (x).local8Bit()
00073
00074
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, QWidget *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 QString makeValidPhone( const QString &number )
00092 {
00093
00094 QString num = number.simplifyWhiteSpace();
00095 QString 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
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 QString businit(void)
00126 {
00127 GNOKII_DEBUG( "Using new gnokii version." );
00128
00129 GNOKII_DEBUG( QString("Compiled with libgnokii version 0x%1\n").arg(QString::number(LIBGNOKII_VERSION,16)) );
00130 GNOKII_DEBUG( QString("Using libgnokii runtime version 0x%1\n").arg(QString::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
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( QString("Found mobile phone: %1 %2, Revision: %3, IMEI: %4\n")
00155 .arg(manufacturer, model, revision, imei) );
00156
00157 return QString::null;
00158 }
00159
00160
00161
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( QString("\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 QString buildPhoneInfoString( const gn_memory_status &memstat )
00175 {
00176 QString format = QString::fromLatin1("<tr><td><b>%1</b></td><td>%2</td></tr>");
00177
00178 return QString::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
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
00203 gn_memory_status memstat;
00204 error = read_phone_memstat(memtype, &memstat);
00205
00206 QStringList addrlist;
00207 KABC::Address *addr;
00208 QString 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(QString("%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
00243 s = GN_FROM(name).simplifyWhiteSpace();
00244 a->setFormattedName(s);
00245 if (s.find(',') == -1) {
00246
00247 addrlist = QStringList::split(' ', s);
00248 if (addrlist.count() == 1) {
00249
00250 a->setGivenName(s);
00251 } else {
00252
00253 a->setFamilyName(addrlist.last().simplifyWhiteSpace());
00254 addrlist.remove(addrlist.last());
00255 a->setGivenName(addrlist.join(" ").simplifyWhiteSpace());
00256 }
00257 } else {
00258
00259 addrlist = QStringList::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", QString("%1%2").arg(memtypestr).arg(gn_lib_get_pb_location(state)));
00267
00268
00269 a->setProductId(QString("%1-%2-%3-%4").arg(APP).arg(model).arg(revision).arg(imei));
00270
00271
00272 QDateTime datetime;
00273 gn_timestamp ts = gn_lib_get_pb_date(state);
00274 if (ts.year<1998)
00275 datetime = QDateTime::currentDateTime();
00276 else
00277 datetime = QDateTime( QDate(ts.year, ts.month, ts.day),
00278 QTime(ts.hour, ts.minute, ts.second) );
00279 GNOKII_DEBUG(QString(" 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
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 QString s = GN_FROM(number).simplifyWhiteSpace();
00297 GNOKII_DEBUG(QString(" 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 = QStringList::split(';', s, true);
00310 addr = new KABC::Address(KABC::Address::Work);
00311 if (addrlist.count() <= 1) {
00312 addrlist = QStringList::split(',', s, true);
00313 if (addrlist.count() > 1 ) {
00314
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
00321 addr->setLocality(s);
00322 }
00323 } else {
00324
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
00354
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(QString(" Not handled id=%1, entry=%2\n")
00365 .arg(entry_type).arg(s));
00366 break;
00367 }
00368 }
00369
00370
00371 if (strlen(name) || strlen(number) || subentries_count)
00372 addrList->append(*a);
00373
00374
00375 num_read++;
00376 delete a;
00377 if (num_read >= memstat.used)
00378 break;
00379 else
00380 continue;
00381 }
00382 GNOKII_CHECK_ERROR(error);
00383 }
00384
00385 return GN_ERR_NONE;
00386 }
00387
00388
00389
00390 static gn_error xxport_phone_write_entry( int phone_location, gn_memory_type memtype,
00391 const KABC::Addressee *addr)
00392 {
00393 QString s;
00394
00395
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 QString cg = addr->custom(APP, "X_GSM_CALLERGROUP");
00414 if (cg.isEmpty())
00415 gn_lib_set_pb_caller_group(state, GN_PHONEBOOK_GROUP_None);
00416 else
00417 gn_lib_set_pb_caller_group(state, (gn_phonebook_group_type) cg.toInt());
00418
00419
00420 QDateTime datetime = addr->revision();
00421 QDate date(datetime.date());
00422 QTime 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(QString("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
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 ,
00453 GN_PHONEBOOK_ENTRY_Number, type, makeValidPhone(s).ascii());
00454
00455 }
00456
00457 s = addr->url().prettyURL();
00458 if (!s.isEmpty()) {
00459 gn_lib_set_pb_subentry(state, -1 ,
00460 GN_PHONEBOOK_ENTRY_URL, GN_PHONEBOOK_NUMBER_General, GN_TO(s));
00461 }
00462
00463 QStringList emails = addr->emails();
00464 for (unsigned int n=0; n<emails.count(); n++) {
00465 s = emails[n].simplifyWhiteSpace();
00466 if (s.isEmpty()) continue;
00467
00468 if (n && !addr->url().isEmpty() && !addr->note().isEmpty() && addr->addresses().count()) {
00469 GNOKII_DEBUG(QString(" 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 ,
00474 GN_PHONEBOOK_ENTRY_Email, GN_PHONEBOOK_NUMBER_General, GN_TO(s));
00475 }
00476
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 QStringList a;
00483 QChar sem(';');
00484 QString sem_repl(QString::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 ,
00494 GN_PHONEBOOK_ENTRY_Postal, GN_PHONEBOOK_NUMBER_General, GN_TO(s));
00495 }
00496
00497 s = addr->note().simplifyWhiteSpace();
00498 if (!s.isEmpty()) {
00499 gn_lib_set_pb_subentry(state, -1 ,
00500 GN_PHONEBOOK_ENTRY_Note, GN_PHONEBOOK_NUMBER_General, GN_TO(s));
00501 }
00502
00503
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(QString(" 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 QString& ) 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(QSize(450,350));
00548 m_progressDlg->show();
00549 processEvents();
00550
00551 #if (QT_VERSION >= 0x030300)
00552 m_progressDlg->setCursor( Qt::BusyCursor );
00553 #endif
00554 QString errStr = businit();
00555 m_progressDlg->unsetCursor();
00556
00557 if (!errStr.isEmpty()) {
00558 KMessageBox::error(parentWidget(), errStr);
00559 delete m_progressDlg;
00560 return addrList;
00561 }
00562
00563 GNOKII_DEBUG("GNOKII import filter started.\n");
00564 m_progressDlg->setButtonText(i18n("&Stop Import"));
00565
00566 read_phone_entries("ME", GN_MT_ME, &addrList);
00567 read_phone_entries("SM", GN_MT_SM, &addrList);
00568
00569 GNOKII_DEBUG("GNOKII import filter finished.\n");
00570
00571 busterminate();
00572 delete m_progressDlg;
00573
00574 return addrList;
00575 }
00576
00577
00578 bool GNOKIIXXPort::exportContacts( const KABC::AddresseeList &list, const QString & )
00579 {
00580 if (KMessageBox::Continue != KMessageBox::warningContinueCancel(parentWidget(),
00581 i18n("<qt>Please connect your Mobile Phone to your computer and press "
00582 "<b>Continue</b> to start exporting the selected personal contacts.<br><br>"
00583 "Please note that if your Mobile Phone is not properly connected "
00584 "the following detection phase might take up to two minutes, during which "
00585 "KAddressbook will behave unresponsively.</qt>") ))
00586 return false;
00587
00588 m_progressDlg = new KProgressDialog( parentWidget(), "importwidget",
00589 i18n("Mobile Phone Export"),
00590 i18n("<qt><center>Establishing connection to the Mobile Phone.<br><br>"
00591 "Please wait...</center></qt>") );
00592 m_progressDlg->setAllowCancel(true);
00593 m_progressDlg->progressBar()->setProgress(0);
00594 m_progressDlg->progressBar()->setCenterIndicator(true);
00595 m_progressDlg->setModal(true);
00596 m_progressDlg->setInitialSize(QSize(450,350));
00597 m_progressDlg->show();
00598 processEvents();
00599
00600 KProgress* progress = (KProgress*)m_progressDlg->progressBar();
00601
00602 KABC::AddresseeList::ConstIterator it;
00603 QStringList failedList;
00604
00605 gn_error error;
00606 bool deleteLabelInitialized = false;
00607
00608 #if (QT_VERSION >= 0x030300)
00609 m_progressDlg->setCursor( Qt::BusyCursor );
00610 #endif
00611 QString errStr = businit();
00612 m_progressDlg->unsetCursor();
00613
00614 if (!errStr.isEmpty()) {
00615 KMessageBox::error(parentWidget(), errStr);
00616 delete m_progressDlg;
00617 return false;
00618 }
00619
00620 GNOKII_DEBUG("GNOKII export filter started.\n");
00621
00622 gn_memory_type memtype = GN_MT_ME;
00623
00624 int phone_count;
00625 bool overwrite_phone_entries = false;
00626 int phone_entry_no, entries_written;
00627 bool entry_empty;
00628
00629
00630 gn_memory_status memstat;
00631 error = read_phone_memstat(memtype, &memstat);
00632 if (error == GN_ERR_NONE) {
00633 GNOKII_DEBUG("Writing to internal phone memory.\n");
00634 } else {
00635 memtype = GN_MT_SM;
00636 error = read_phone_memstat(memtype, &memstat);
00637 if (error != GN_ERR_NONE)
00638 goto finish;
00639 GNOKII_DEBUG("Writing to SIM card memory.\n");
00640 }
00641 phone_count = memstat.used;
00642
00643 if (memstat.free >= (int) list.count()) {
00644 if (KMessageBox::No == KMessageBox::questionYesNo(parentWidget(),
00645 i18n("<qt>Do you want the selected contacts to be <b>appended</b> to "
00646 "the current mobile phonebook or should they <b>replace</b> all "
00647 "currently existing phonebook entries ?<br><br>"
00648 "Please note, that in case you choose to replace the phonebook "
00649 "entries, every contact in your phone will be deleted and only "
00650 "the newly exported contacts will be available from inside your phone.</qt>"),
00651 i18n("Export to Mobile Phone"),
00652 KGuiItem(i18n("&Append to Current Phonebook")),
00653 KGuiItem(i18n("&Replace Current Phonebook with New Contacts")) ) )
00654 overwrite_phone_entries = true;
00655 }
00656
00657 progress->setTotalSteps(list.count());
00658 entries_written = 0;
00659 progress->setProgress(entries_written);
00660 m_progressDlg->setButtonText(i18n("&Stop Export"));
00661 m_progressDlg->setLabel(i18n("<qt>Exporting <b>%1</b> contacts to the <b>%2</b> "
00662 "of the Mobile Phone.<br><br>%3</qt>")
00663 .arg(list.count())
00664 .arg(gn_memory_type2str(memtype))
00665 .arg(buildPhoneInfoString(memstat)) );
00666
00667
00668 phone_entry_no = 1;
00669 for ( it = list.begin(); it != list.end(); ++it ) {
00670 const KABC::Addressee *addr = &(*it);
00671 if (addr->isEmpty())
00672 continue;
00673
00674 if (addr->custom(APP, "X_GSM_STORE_AT").startsWith("SM"))
00675 continue;
00676
00677 progress->setProgress(entries_written++);
00678
00679 try_next_phone_entry:
00680 this_filter->processEvents();
00681 if (m_progressDlg->wasCancelled())
00682 break;
00683
00684
00685 if (phone_entry_no > (memstat.used + memstat.free))
00686 break;
00687
00688 GNOKII_DEBUG(QString("Try to write entry '%1' at phone_entry_no=%2, phone_count=%3\n")
00689 .arg(addr->realName()).arg(phone_entry_no).arg(phone_count));
00690
00691 error = GN_ERR_NONE;
00692
00693
00694 entry_empty = gn_lib_phonebook_entry_isempty(state, memtype, phone_entry_no);
00695 if (overwrite_phone_entries) {
00696
00697 if (!entry_empty)
00698 phone_count--;
00699 error = xxport_phone_write_entry( phone_entry_no, memtype, addr);
00700 phone_entry_no++;
00701 } else {
00702
00703 if (entry_empty) {
00704 error = xxport_phone_write_entry( phone_entry_no, memtype, addr);
00705 phone_entry_no++;
00706 } else {
00707 phone_entry_no++;
00708 goto try_next_phone_entry;
00709 }
00710 }
00711
00712 if (error != GN_ERR_NONE)
00713 failedList.append(addr->realName());
00714
00715
00716 if (error != GN_ERR_NONE && it==list.begin())
00717 break;
00718
00719 }
00720
00721
00722
00723 while (overwrite_phone_entries && error==GN_ERR_NONE && phone_count>0) {
00724 if (m_progressDlg->wasCancelled())
00725 break;
00726 if (!deleteLabelInitialized) {
00727 m_progressDlg->setLabel(
00728 i18n("<qt><center>"
00729 "All selected contacts have been sucessfully copied to "
00730 "the Mobile Phone.<br><br>"
00731 "Please wait until all remaining orphaned contacts from "
00732 "the Mobile Phone have been deleted.</center></qt>") );
00733 m_progressDlg->setButtonText(i18n("&Stop Delete"));
00734 deleteLabelInitialized = true;
00735 progress->setTotalSteps(phone_count);
00736 entries_written = 0;
00737 progress->setProgress(entries_written);
00738 this_filter->processEvents();
00739 }
00740 if (phone_entry_no > (memstat.used + memstat.free))
00741 break;
00742 entry_empty = gn_lib_phonebook_entry_isempty(state, memtype, phone_entry_no);
00743 if (!entry_empty) {
00744 error = xxport_phone_delete_entry(phone_entry_no, memtype);
00745 phone_count--;
00746 progress->setProgress(++entries_written);
00747 this_filter->processEvents();
00748 }
00749 phone_entry_no++;
00750 }
00751
00752 finish:
00753 m_progressDlg->setLabel(i18n("Export to phone finished."));
00754 this_filter->processEvents();
00755
00756 GNOKII_DEBUG("GNOKII export filter finished.\n");
00757
00758 busterminate();
00759 delete m_progressDlg;
00760
00761 if (!failedList.isEmpty()) {
00762 GNOKII_DEBUG(QString("Failed to export: %1\n").arg(failedList.join(", ")));
00763 KMessageBox::informationList(parentWidget(),
00764 i18n("<qt>The following contacts could not be exported to the Mobile Phone. "
00765 "Possible Reasons for this problem could be:<br><ul>"
00766 "<li>The contacts contain more information per entry than the phone can store.</li>"
00767 "<li>Your phone does not allow to store multiple addresses, emails, homepages, ...</li>"
00768 "<li>other storage size related problems.</li>"
00769 "</ul>"
00770 "To avoid those kind of problems in the future please reduce the amount of different "
00771 "fields in the above contacts.</qt>"),
00772 failedList,
00773 i18n("Mobile Phone Export") );
00774 }
00775
00776
00777 return true;
00778 }
00779
00780
00781
00782
00783
00784
00785
00786 #elif defined(HAVE_GNOKII_H)
00787
00788 #ifdef __GNUC__
00789 # warning "Please upgrade your gnokii installation to at least version 0.6.13"
00790 # warning "Older gnokii versions below 0.6.13 are not binary compatible and"
00791 # warning "prevents KDE users to upgrade gnokii to newer versions later."
00792 #endif
00793
00794
00795
00796
00797 static char *lockfile = NULL;
00798 static char manufacturer[64], model[GN_MODEL_MAX_LENGTH+1],
00799 revision[GN_REVISION_MAX_LENGTH+1], imei[GN_IMEI_MAX_LENGTH+1];
00800 static QString PhoneProductId;
00801
00802 static struct gn_statemachine state;
00803 static gn_data data;
00804
00805 static void busterminate(void)
00806 {
00807 gn_sm_functions(GN_OP_Terminate, NULL, &state);
00808 if (lockfile) gn_device_unlock(lockfile);
00809 }
00810
00811 static QString businit(void)
00812 {
00813 gn_error error;
00814 char *aux;
00815
00816 GNOKII_DEBUG( "Using old gnokii version." );
00817
00818 #if defined(LIBGNOKII_VERSION)
00819 if (gn_cfg_read_default()<0)
00820 #else
00821 static char *BinDir;
00822 if (gn_cfg_read(&BinDir)<0)
00823 #endif
00824 return i18n("Failed to initialize the gnokii library.");
00825
00826 if (!gn_cfg_phone_load("", &state))
00827 return i18n("Gnokii is not yet configured.");
00828
00829
00830
00831
00832 gn_data_clear(&data);
00833
00834 aux = gn_cfg_get(gn_cfg_info, "global", "use_locking");
00835
00836 if (aux && !strcmp(aux, "yes")) {
00837 lockfile = gn_device_lock(state.config.port_device);
00838 if (lockfile == NULL) {
00839 return i18n("Gnokii reports a 'Lock File Error'.\n "
00840 "Please exit all other running instances of gnokii, check if you have "
00841 "write permissions in the /var/lock directory and try again.");
00842 }
00843 }
00844
00845
00846 int old_dcd = state.config.require_dcd;
00847 state.config.require_dcd = false;
00848 error = gn_gsm_initialise(&state);
00849 GNOKII_CHECK_ERROR(error);
00850 state.config.require_dcd = old_dcd;
00851 if (error != GN_ERR_NONE) {
00852 busterminate();
00853 return i18n("<qt><center>Mobile Phone interface initialization failed.<br><br>"
00854 "The returned error message was:<br><b>%1</b><br><br>"
00855 "You might try to run \"gnokii --identify\" on the command line to "
00856 "check any cable/transport issues and to verify if your gnokii "
00857 "configuration is correct.</center></qt>")
00858 .arg(gn_error_print(error));
00859 }
00860
00861
00862 gn_data_clear(&data);
00863 data.manufacturer = manufacturer;
00864 data.model = model;
00865 data.revision = revision;
00866 data.imei = imei;
00867
00868 QCString unknown(GN_TO(i18n("Unknown")));
00869 qstrncpy(manufacturer, unknown, sizeof(manufacturer)-1);
00870 qstrncpy(model, unknown, sizeof(model)-1);
00871 qstrncpy(revision, unknown, sizeof(revision)-1);
00872 qstrncpy(imei, unknown, sizeof(imei)-1);
00873
00874 if (m_progressDlg->wasCancelled())
00875 return QString::null;
00876 else
00877 error = gn_sm_functions(GN_OP_Identify, &data, &state);
00878 GNOKII_CHECK_ERROR(error);
00879
00880 GNOKII_DEBUG( QString("Found mobile phone: %1 %2, Revision: %3, IMEI: %4\n")
00881 .arg(manufacturer, model, revision, imei) );
00882
00883 PhoneProductId = QString("%1-%2-%3-%4").arg(APP).arg(model).arg(revision).arg(imei);
00884
00885 return QString::null;
00886 }
00887
00888
00889
00890 static gn_error read_phone_memstat( const gn_memory_type memtype, gn_memory_status *memstat )
00891 {
00892 gn_error error;
00893
00894 gn_data_clear(&data);
00895 memset(memstat, 0, sizeof(*memstat));
00896 memstat->memory_type = memtype;
00897 data.memory_status = memstat;
00898 error = gn_sm_functions(GN_OP_GetMemoryStatus, &data, &state);
00899 GNOKII_CHECK_ERROR(error);
00900 if (error != GN_ERR_NONE) {
00901 switch (memtype) {
00902 case GN_MT_SM:
00903
00904 memstat->used = 0;
00905 memstat->free = 100;
00906 break;
00907 default:
00908 case GN_MT_ME:
00909
00910 memstat->used = memstat->free = 0;
00911 break;
00912 }
00913 }
00914 GNOKII_DEBUG( QString("\n\nMobile phone memory status: Type: %1, used=%2, free=%3, total=%4\n\n")
00915 .arg(memtype).arg(memstat->used).arg(memstat->free).arg(memstat->used+memstat->free) );
00916 return error;
00917 }
00918
00919
00920
00921 static gn_error read_phone_entry( const int index, const gn_memory_type memtype, gn_phonebook_entry *entry )
00922 {
00923 gn_error error;
00924 entry->memory_type = memtype;
00925 entry->location = index;
00926 data.phonebook_entry = entry;
00927 error = gn_sm_functions(GN_OP_ReadPhonebook, &data, &state);
00928 GNOKII_CHECK_ERROR(error);
00929 return error;
00930 }
00931
00932 static bool phone_entry_empty( const int index, const gn_memory_type memtype )
00933 {
00934 gn_error error;
00935 gn_phonebook_entry entry;
00936 entry.memory_type = memtype;
00937 entry.location = index;
00938 data.phonebook_entry = &entry;
00939 error = gn_sm_functions(GN_OP_ReadPhonebook, &data, &state);
00940 if (error == GN_ERR_EMPTYLOCATION)
00941 return true;
00942 GNOKII_CHECK_ERROR(error);
00943 if (error == GN_ERR_NONE && entry.empty)
00944 return true;
00945 return false;
00946 }
00947
00948 static QString buildPhoneInfoString( const gn_memory_status &memstat )
00949 {
00950 QString format = QString::fromLatin1("<tr><td><b>%1</b></td><td>%2</td></tr>");
00951
00952 return QString::fromLatin1("<b>%1</b><br><table>%2%3%4%5%6</table><br>")
00953 .arg(i18n("Mobile Phone information:"))
00954 .arg(format.arg(i18n("Manufacturer")).arg(GN_FROM(manufacturer)))
00955 .arg(format.arg(i18n("Phone model")).arg(GN_FROM(model)))
00956 .arg(format.arg(i18n("Revision")).arg(GN_FROM(revision)))
00957 .arg(format.arg(i18n("IMEI")).arg(GN_FROM(imei)))
00958 .arg(format.arg(i18n("Phonebook status"))
00959 .arg(i18n("%1 out of %2 contacts used").arg(memstat.used).arg(memstat.used+memstat.free)));
00960 }
00961
00962 static QString buildMemoryTypeString( gn_memory_type memtype )
00963 {
00964 switch (memtype) {
00965 case GN_MT_ME: return i18n("internal memory");
00966 case GN_MT_SM: return i18n("SIM-card memory");
00967 default: return i18n("unknown memory");
00968 }
00969 }
00970
00971
00972 static gn_error read_phone_entries( const char *memtypestr, gn_memory_type memtype,
00973 KABC::AddresseeList *addrList )
00974 {
00975 gn_error error;
00976
00977 if (m_progressDlg->wasCancelled())
00978 return GN_ERR_NONE;
00979
00980 KProgress* progress = (KProgress*)m_progressDlg->progressBar();
00981
00982 progress->setProgress(0);
00983 this_filter->processEvents();
00984
00985
00986 gn_memory_status memstat;
00987 error = read_phone_memstat(memtype, &memstat);
00988
00989 gn_phonebook_entry entry;
00990 QStringList addrlist;
00991 KABC::Address *addr;
00992 QString s, country;
00993
00994 progress->setTotalSteps(memstat.used);
00995 m_progressDlg->setLabel(i18n("<qt>Importing <b>%1</b> contacts from <b>%2</b> of the Mobile Phone.<br><br>%3</qt>")
00996 .arg(memstat.used)
00997 .arg(buildMemoryTypeString(memtype))
00998 .arg(buildPhoneInfoString(memstat)) );
00999
01000 int num_read = 0;
01001
01002 for (int i = 1; !m_progressDlg->wasCancelled() && i <= memstat.used + memstat.free; i++) {
01003 error = read_phone_entry( i, memtype, &entry );
01004
01005 progress->setProgress(num_read);
01006 this_filter->processEvents();
01007
01008 if (error == GN_ERR_EMPTYLOCATION)
01009 continue;
01010 if (error == GN_ERR_INVALIDLOCATION)
01011 break;
01012 if (error == GN_ERR_INVALIDMEMORYTYPE)
01013 break;
01014 if (error == GN_ERR_NONE) {
01015 GNOKII_DEBUG(QString("%1: %2, num=%3, location=%4, group=%5, count=%6\n").arg(i).arg(GN_FROM(entry.name))
01016 .arg(GN_FROM(entry.number)).arg(entry.location).arg(entry.caller_group).arg(entry.subentries_count));
01017 KABC::Addressee *a = new KABC::Addressee();
01018
01019
01020 s = GN_FROM(entry.name).simplifyWhiteSpace();
01021 a->setFormattedName(s);
01022 if (s.find(',') == -1) {
01023
01024 addrlist = QStringList::split(' ', s);
01025 if (addrlist.count() == 1) {
01026
01027 a->setGivenName(s);
01028 } else {
01029
01030 a->setFamilyName(addrlist.last().simplifyWhiteSpace());
01031 addrlist.remove(addrlist.last());
01032 a->setGivenName(addrlist.join(" ").simplifyWhiteSpace());
01033 }
01034 } else {
01035
01036 addrlist = QStringList::split(',', s);
01037 a->setFamilyName(addrlist.first().simplifyWhiteSpace());
01038 addrlist.remove(addrlist.first());
01039 a->setGivenName(addrlist.join(" ").simplifyWhiteSpace());
01040 }
01041
01042 a->insertCustom(APP, "X_GSM_CALLERGROUP", s.setNum(entry.caller_group));
01043 a->insertCustom(APP, "X_GSM_STORE_AT", QString("%1%2").arg(memtypestr).arg(entry.location));
01044
01045
01046 a->setProductId(PhoneProductId);
01047
01048
01049 QDateTime datetime;
01050 if (entry.date.year<1998)
01051 datetime = QDateTime::currentDateTime();
01052 else
01053 datetime = QDateTime( QDate(entry.date.year, entry.date.month, entry.date.day),
01054 QTime(entry.date.hour, entry.date.minute, entry.date.second) );
01055 GNOKII_DEBUG(QString(" date=%1\n").arg(datetime.toString()));
01056 a->setRevision(datetime);
01057
01058 if (!entry.subentries_count)
01059 a->insertPhoneNumber(KABC::PhoneNumber(entry.number, KABC::PhoneNumber::Work | KABC::PhoneNumber::Pref));
01060
01061
01062 if (entry.subentries_count)
01063 for (int n=0; n<entry.subentries_count; n++) {
01064 QString s = GN_FROM(entry.subentries[n].data.number).simplifyWhiteSpace();
01065 GNOKII_DEBUG(QString(" Subentry#%1, entry_type=%2, number_type=%3, number=%4\n")
01066 .arg(n).arg(entry.subentries[n].entry_type)
01067 .arg(entry.subentries[n].number_type).arg(s));
01068 if (s.isEmpty())
01069 continue;
01070 switch(entry.subentries[n].entry_type) {
01071 case GN_PHONEBOOK_ENTRY_Name:
01072 a->setName(s);
01073 break;
01074 case GN_PHONEBOOK_ENTRY_Email:
01075 a->insertEmail(s);
01076 break;
01077 case GN_PHONEBOOK_ENTRY_Postal:
01078 addrlist = QStringList::split(';', s, true);
01079 addr = new KABC::Address(KABC::Address::Work);
01080 if (addrlist.count() <= 1) {
01081 addrlist = QStringList::split(',', s, true);
01082 if (addrlist.count() > 1 ) {
01083
01084 addr->setLocality(addrlist[0]);
01085 addr->setPostalCode(addrlist[1]);
01086 if (!addrlist[2].isEmpty())
01087 addr->setCountry(i18n(GN_TO(addrlist[2])));
01088 } else {
01089
01090 addr->setLocality(s);
01091 }
01092 } else {
01093
01094 addr->setPostOfficeBox(addrlist[0]);
01095 addr->setExtended(addrlist[1]);
01096 addr->setStreet(addrlist[2]);
01097 addr->setLocality(addrlist[3]);
01098 addr->setRegion(addrlist[4]);
01099 addr->setPostalCode(addrlist[5]);
01100 country = addrlist[6];
01101 if (!country.isEmpty())
01102 addr->setCountry(i18n(GN_TO(country)));
01103 }
01104 a->insertAddress(*addr);
01105 delete addr;
01106 break;
01107 case GN_PHONEBOOK_ENTRY_Note:
01108 if (!a->note().isEmpty())
01109 s = "\n" + s;
01110 a->setNote(a->note()+s);
01111 break;
01112 case GN_PHONEBOOK_ENTRY_Number:
01113 enum KABC::PhoneNumber::Types phonetype;
01114 switch (entry.subentries[n].number_type) {
01115 case GN_PHONEBOOK_NUMBER_Mobile: phonetype = KABC::PhoneNumber::Cell; break;
01116 case GN_PHONEBOOK_NUMBER_Fax: phonetype = KABC::PhoneNumber::Fax; break;
01117 case GN_PHONEBOOK_NUMBER_General:
01118 case GN_PHONEBOOK_NUMBER_Work: phonetype = KABC::PhoneNumber::Work; break;
01119 default:
01120 case GN_PHONEBOOK_NUMBER_Home: phonetype = KABC::PhoneNumber::Home; break;
01121 }
01122
01123
01124 a->insertPhoneNumber(KABC::PhoneNumber(s, phonetype));
01125 break;
01126 case GN_PHONEBOOK_ENTRY_URL:
01127 a->setUrl(s);
01128 break;
01129 case GN_PHONEBOOK_ENTRY_Group:
01130 a->insertCategory(s);
01131 break;
01132 default:
01133 GNOKII_DEBUG(QString(" Not handled id=%1, entry=%2\n")
01134 .arg(entry.subentries[n].entry_type).arg(s));
01135 break;
01136 }
01137 }
01138
01139
01140 if (strlen(entry.name) || strlen(entry.number) || entry.subentries_count)
01141 addrList->append(*a);
01142
01143
01144 num_read++;
01145 delete a;
01146 if (num_read >= memstat.used)
01147 break;
01148 else
01149 continue;
01150 }
01151 GNOKII_CHECK_ERROR(error);
01152 }
01153
01154 return GN_ERR_NONE;
01155 }
01156
01157
01158
01159
01160 static gn_error xxport_phone_write_entry( int phone_location, gn_memory_type memtype,
01161 const KABC::Addressee *addr)
01162 {
01163 gn_phonebook_entry entry;
01164 QString s;
01165
01166 memset(&entry, 0, sizeof(entry));
01167 strncpy(entry.name, GN_TO(addr->realName()), sizeof(entry.name)-1);
01168 s = addr->phoneNumber(KABC::PhoneNumber::Pref).number();
01169 if (s.isEmpty())
01170 s = addr->phoneNumber(KABC::PhoneNumber::Work).number();
01171 if (s.isEmpty())
01172 s = addr->phoneNumber(KABC::PhoneNumber::Home).number();
01173 if (s.isEmpty())
01174 s = addr->phoneNumber(KABC::PhoneNumber::Cell).number();
01175 if (s.isEmpty() && addr->phoneNumbers().count()>0)
01176 s = (*addr->phoneNumbers().at(0)).number();
01177 s = makeValidPhone(s);
01178 strncpy(entry.number, s.ascii(), sizeof(entry.number)-1);
01179 entry.memory_type = memtype;
01180 QString cg = addr->custom(APP, "X_GSM_CALLERGROUP");
01181 if (cg.isEmpty())
01182 entry.caller_group = 5;
01183 else
01184 entry.caller_group = cg.toInt();
01185 entry.location = phone_location;
01186
01187
01188 QDateTime datetime = addr->revision();
01189 QDate date(datetime.date());
01190 QTime time(datetime.time());
01191 entry.date.year = date.year();
01192 entry.date.month = date.month();
01193 entry.date.day = date.day();
01194 entry.date.hour = time.hour();
01195 entry.date.minute = time.minute();
01196 entry.date.second = time.second();
01197
01198 GNOKII_DEBUG(QString("Write #%1: name=%2, number=%3\n").arg(phone_location)
01199 .arg(GN_FROM(entry.name)).arg(GN_FROM(entry.number)));
01200
01201 const KABC::Address homeAddr = addr->address(KABC::Address::Home);
01202 const KABC::Address workAddr = addr->address(KABC::Address::Work);
01203
01204 entry.subentries_count = 0;
01205 gn_phonebook_subentry *subentry = &entry.subentries[0];
01206
01207 const KABC::PhoneNumber::List phoneList = addr->phoneNumbers();
01208 KABC::PhoneNumber::List::ConstIterator it;
01209 for ( it = phoneList.begin(); it != phoneList.end(); ++it ) {
01210 const KABC::PhoneNumber *phonenumber = &(*it);
01211 s = phonenumber->number();
01212 if (s.isEmpty()) continue;
01213 subentry->entry_type = GN_PHONEBOOK_ENTRY_Number;
01214 gn_phonebook_number_type type;
01215 int pn_type = phonenumber->type();
01216 if ((pn_type & KABC::PhoneNumber::Cell))
01217 type = GN_PHONEBOOK_NUMBER_Mobile;
01218 else if ((pn_type & KABC::PhoneNumber::Fax))
01219 type = GN_PHONEBOOK_NUMBER_Fax;
01220 else if ((pn_type & KABC::PhoneNumber::Home))
01221 type = GN_PHONEBOOK_NUMBER_Home;
01222 else if ((pn_type & KABC::PhoneNumber::Work))
01223 type = GN_PHONEBOOK_NUMBER_Work;
01224 else type = GN_PHONEBOOK_NUMBER_General;
01225 subentry->number_type = type;
01226 strncpy(subentry->data.number, makeValidPhone(s).ascii(), sizeof(subentry->data.number)-1);
01227 subentry->id = phone_location<<8+entry.subentries_count;
01228 entry.subentries_count++;
01229 subentry++;
01230 if (entry.subentries_count >= GN_PHONEBOOK_SUBENTRIES_MAX_NUMBER)
01231 break;
01232 }
01233
01234 s = addr->url().prettyURL();
01235 if (!s.isEmpty() && (entry.subentries_count<GN_PHONEBOOK_SUBENTRIES_MAX_NUMBER)) {
01236 subentry->entry_type = GN_PHONEBOOK_ENTRY_URL;
01237 strncpy(subentry->data.number, GN_TO(s), sizeof(subentry->data.number)-1);
01238 entry.subentries_count++;
01239 subentry++;
01240 }
01241
01242 QStringList emails = addr->emails();
01243 for (unsigned int n=0; n<emails.count(); n++) {
01244 if (entry.subentries_count >= GN_PHONEBOOK_SUBENTRIES_MAX_NUMBER)
01245 break;
01246 s = emails[n].simplifyWhiteSpace();
01247 if (s.isEmpty()) continue;
01248
01249 if (n && !addr->url().isEmpty() && !addr->note().isEmpty() && addr->addresses().count()) {
01250 GNOKII_DEBUG(QString(" DROPPED email %1 in favor of URLs, notes and addresses.\n")
01251 .arg(s));
01252 continue;
01253 }
01254 subentry->entry_type = GN_PHONEBOOK_ENTRY_Email;
01255 strncpy(subentry->data.number, GN_TO(s), sizeof(subentry->data.number)-1);
01256 entry.subentries_count++;
01257 subentry++;
01258 }
01259
01260 const KABC::Address::List addresses = addr->addresses();
01261 KABC::Address::List::ConstIterator it2;
01262 for ( it2 = addresses.begin(); it2 != addresses.end(); ++it2 ) {
01263 if (entry.subentries_count >= GN_PHONEBOOK_SUBENTRIES_MAX_NUMBER)
01264 break;
01265 const KABC::Address *Addr = &(*it2);
01266 if (Addr->isEmpty()) continue;
01267 subentry->entry_type = GN_PHONEBOOK_ENTRY_Postal;
01268 QStringList a;
01269 QChar sem(';');
01270 QString sem_repl(QString::fromLatin1(","));
01271 a.append( Addr->postOfficeBox().replace( sem, sem_repl ) );
01272 a.append( Addr->extended() .replace( sem, sem_repl ) );
01273 a.append( Addr->street() .replace( sem, sem_repl ) );
01274 a.append( Addr->locality() .replace( sem, sem_repl ) );
01275 a.append( Addr->region() .replace( sem, sem_repl ) );
01276 a.append( Addr->postalCode() .replace( sem, sem_repl ) );
01277 a.append( Addr->country() .replace( sem, sem_repl ) );
01278 s = a.join(sem);
01279 strncpy(subentry->data.number, GN_TO(s), sizeof(subentry->data.number)-1);
01280 entry.subentries_count++;
01281 subentry++;
01282 }
01283
01284 s = addr->note().simplifyWhiteSpace();
01285 if (!s.isEmpty() && (entry.subentries_count<GN_PHONEBOOK_SUBENTRIES_MAX_NUMBER)) {
01286 subentry->entry_type = GN_PHONEBOOK_ENTRY_Note;
01287 strncpy(subentry->data.number, GN_TO(s), sizeof(subentry->data.number)-1);
01288 entry.subentries_count++;
01289 subentry++;
01290 }
01291
01292
01293 for (int st=0; st<entry.subentries_count; st++) {
01294 gn_phonebook_subentry *subentry = &entry.subentries[st];
01295 GNOKII_DEBUG(QString(" SubTel #%1: entry_type=%2, number_type=%3, number=%4\n")
01296 .arg(st).arg(subentry->entry_type)
01297 .arg(subentry->number_type).arg(GN_FROM(subentry->data.number)));
01298 }
01299
01300 data.phonebook_entry = &entry;
01301 gn_error error = gn_sm_functions(GN_OP_WritePhonebook, &data, &state);
01302 GNOKII_CHECK_ERROR(error);
01303
01304 return error;
01305 }
01306
01307
01308 static gn_error xxport_phone_delete_entry( int phone_location, gn_memory_type memtype )
01309 {
01310 gn_phonebook_entry entry;
01311 memset(&entry, 0, sizeof(entry));
01312 entry.empty = 1;
01313 entry.memory_type = memtype;
01314 entry.location = phone_location;
01315 data.phonebook_entry = &entry;
01316 GNOKII_DEBUG(QString("Deleting entry %1\n").arg(phone_location));
01317 gn_error error = gn_sm_functions(GN_OP_WritePhonebook, &data, &state);
01318 GNOKII_CHECK_ERROR(error);
01319 return error;
01320 }
01321
01322 KABC::AddresseeList GNOKIIXXPort::importContacts( const QString& ) const
01323 {
01324 KABC::AddresseeList addrList;
01325
01326 if (KMessageBox::Continue != KMessageBox::warningContinueCancel(parentWidget(),
01327 i18n("<qt>Please connect your Mobile Phone to your computer and press "
01328 "<b>Continue</b> to start importing the personal contacts.<br><br>"
01329 "Please note that if your Mobile Phone is not properly connected "
01330 "the following detection phase might take up to two minutes, during which "
01331 "KAddressbook will behave unresponsively.</qt>") ))
01332 return addrList;
01333
01334 m_progressDlg = new KProgressDialog( parentWidget(), "importwidget",
01335 i18n("Mobile Phone Import"),
01336 i18n("<qt><center>Establishing connection to the Mobile Phone.<br><br>"
01337 "Please wait...</center></qt>") );
01338 m_progressDlg->setAllowCancel(true);
01339 m_progressDlg->progressBar()->setProgress(0);
01340 m_progressDlg->progressBar()->setCenterIndicator(true);
01341 m_progressDlg->setModal(true);
01342 m_progressDlg->setInitialSize(QSize(450,350));
01343 m_progressDlg->show();
01344 processEvents();
01345
01346 #if (QT_VERSION >= 0x030300)
01347 m_progressDlg->setCursor( Qt::BusyCursor );
01348 #endif
01349 QString errStr = businit();
01350 m_progressDlg->unsetCursor();
01351
01352 if (!errStr.isEmpty()) {
01353 KMessageBox::error(parentWidget(), errStr);
01354 delete m_progressDlg;
01355 return addrList;
01356 }
01357
01358 GNOKII_DEBUG("GNOKII import filter started.\n");
01359 m_progressDlg->setButtonText(i18n("&Stop Import"));
01360
01361 read_phone_entries("ME", GN_MT_ME, &addrList);
01362 read_phone_entries("SM", GN_MT_SM, &addrList);
01363
01364 GNOKII_DEBUG("GNOKII import filter finished.\n");
01365
01366 busterminate();
01367 delete m_progressDlg;
01368
01369 return addrList;
01370 }
01371
01372
01373 bool GNOKIIXXPort::exportContacts( const KABC::AddresseeList &list, const QString & )
01374 {
01375 if (KMessageBox::Continue != KMessageBox::warningContinueCancel(parentWidget(),
01376 i18n("<qt>Please connect your Mobile Phone to your computer and press "
01377 "<b>Continue</b> to start exporting the selected personal contacts.<br><br>"
01378 "Please note that if your Mobile Phone is not properly connected "
01379 "the following detection phase might take up to two minutes, during which "
01380 "KAddressbook will behave unresponsively.</qt>") ))
01381 return false;
01382
01383 m_progressDlg = new KProgressDialog( parentWidget(), "importwidget",
01384 i18n("Mobile Phone Export"),
01385 i18n("<qt><center>Establishing connection to the Mobile Phone.<br><br>"
01386 "Please wait...</center></qt>") );
01387 m_progressDlg->setAllowCancel(true);
01388 m_progressDlg->progressBar()->setProgress(0);
01389 m_progressDlg->progressBar()->setCenterIndicator(true);
01390 m_progressDlg->setModal(true);
01391 m_progressDlg->setInitialSize(QSize(450,350));
01392 m_progressDlg->show();
01393 processEvents();
01394
01395 KProgress* progress = (KProgress*)m_progressDlg->progressBar();
01396
01397 KABC::AddresseeList::ConstIterator it;
01398 QStringList failedList;
01399
01400 gn_error error;
01401 bool deleteLabelInitialized = false;
01402
01403 #if (QT_VERSION >= 0x030300)
01404 m_progressDlg->setCursor( Qt::BusyCursor );
01405 #endif
01406 QString errStr = businit();
01407 m_progressDlg->unsetCursor();
01408
01409 if (!errStr.isEmpty()) {
01410 KMessageBox::error(parentWidget(), errStr);
01411 delete m_progressDlg;
01412 return false;
01413 }
01414
01415 GNOKII_DEBUG("GNOKII export filter started.\n");
01416
01417 gn_memory_type memtype = GN_MT_ME;
01418
01419 int phone_count;
01420 bool overwrite_phone_entries = false;
01421 int phone_entry_no, entries_written;
01422 bool entry_empty;
01423
01424
01425 gn_memory_status memstat;
01426 error = read_phone_memstat(memtype, &memstat);
01427 if (error == GN_ERR_NONE) {
01428 GNOKII_DEBUG("Writing to internal phone memory.\n");
01429 } else {
01430 memtype = GN_MT_SM;
01431 error = read_phone_memstat(memtype, &memstat);
01432 if (error != GN_ERR_NONE)
01433 goto finish;
01434 GNOKII_DEBUG("Writing to SIM card memory.\n");
01435 }
01436 phone_count = memstat.used;
01437
01438 if (memstat.free >= (int) list.count()) {
01439 if (KMessageBox::No == KMessageBox::questionYesNo(parentWidget(),
01440 i18n("<qt>Do you want the selected contacts to be <b>appended</b> to "
01441 "the current mobile phonebook or should they <b>replace</b> all "
01442 "currently existing phonebook entries ?<br><br>"
01443 "Please note, that in case you choose to replace the phonebook "
01444 "entries, every contact in your phone will be deleted and only "
01445 "the newly exported contacts will be available from inside your phone.</qt>"),
01446 i18n("Export to Mobile Phone"),
01447 KGuiItem(i18n("&Append to Current Phonebook")),
01448 KGuiItem(i18n("&Replace Current Phonebook with New Contacts")) ) )
01449 overwrite_phone_entries = true;
01450 }
01451
01452 progress->setTotalSteps(list.count());
01453 entries_written = 0;
01454 progress->setProgress(entries_written);
01455 m_progressDlg->setButtonText(i18n("&Stop Export"));
01456 m_progressDlg->setLabel(i18n("<qt>Exporting <b>%1</b> contacts to the <b>%2</b> "
01457 "of the Mobile Phone.<br><br>%3</qt>")
01458 .arg(list.count())
01459 .arg(buildMemoryTypeString(memtype))
01460 .arg(buildPhoneInfoString(memstat)) );
01461
01462
01463 phone_entry_no = 1;
01464 for ( it = list.begin(); it != list.end(); ++it ) {
01465 const KABC::Addressee *addr = &(*it);
01466 if (addr->isEmpty())
01467 continue;
01468
01469 if (addr->custom(APP, "X_GSM_STORE_AT").startsWith("SM"))
01470 continue;
01471
01472 progress->setProgress(entries_written++);
01473
01474 try_next_phone_entry:
01475 this_filter->processEvents();
01476 if (m_progressDlg->wasCancelled())
01477 break;
01478
01479
01480 if (phone_entry_no > (memstat.used + memstat.free))
01481 break;
01482
01483 GNOKII_DEBUG(QString("Try to write entry '%1' at phone_entry_no=%2, phone_count=%3\n")
01484 .arg(addr->realName()).arg(phone_entry_no).arg(phone_count));
01485
01486 error = GN_ERR_NONE;
01487
01488
01489 entry_empty = phone_entry_empty(phone_entry_no, memtype);
01490 if (overwrite_phone_entries) {
01491
01492 if (!entry_empty)
01493 phone_count--;
01494 error = xxport_phone_write_entry( phone_entry_no, memtype, addr);
01495 phone_entry_no++;
01496 } else {
01497
01498 if (entry_empty) {
01499 error = xxport_phone_write_entry( phone_entry_no, memtype, addr);
01500 phone_entry_no++;
01501 } else {
01502 phone_entry_no++;
01503 goto try_next_phone_entry;
01504 }
01505 }
01506
01507 if (error != GN_ERR_NONE)
01508 failedList.append(addr->realName());
01509
01510
01511 if (error != GN_ERR_NONE && it==list.begin())
01512 break;
01513
01514 }
01515
01516
01517
01518 while (overwrite_phone_entries && error==GN_ERR_NONE && phone_count>0) {
01519 if (m_progressDlg->wasCancelled())
01520 break;
01521 if (!deleteLabelInitialized) {
01522 m_progressDlg->setLabel(
01523 i18n("<qt><center>"
01524 "All selected contacts have been sucessfully copied to "
01525 "the Mobile Phone.<br><br>"
01526 "Please wait until all remaining orphaned contacts from "
01527 "the Mobile Phone have been deleted.</center></qt>") );
01528 m_progressDlg->setButtonText(i18n("&Stop Delete"));
01529 deleteLabelInitialized = true;
01530 progress->setTotalSteps(phone_count);
01531 entries_written = 0;
01532 progress->setProgress(entries_written);
01533 this_filter->processEvents();
01534 }
01535 if (phone_entry_no > (memstat.used + memstat.free))
01536 break;
01537 entry_empty = phone_entry_empty(phone_entry_no, memtype);
01538 if (!entry_empty) {
01539 error = xxport_phone_delete_entry(phone_entry_no, memtype);
01540 phone_count--;
01541 progress->setProgress(++entries_written);
01542 this_filter->processEvents();
01543 }
01544 phone_entry_no++;
01545 }
01546
01547 finish:
01548 m_progressDlg->setLabel(i18n("Export to phone finished."));
01549 this_filter->processEvents();
01550
01551 GNOKII_DEBUG("GNOKII export filter finished.\n");
01552
01553 busterminate();
01554 delete m_progressDlg;
01555
01556 if (!failedList.isEmpty()) {
01557 GNOKII_DEBUG(QString("Failed to export: %1\n").arg(failedList.join(", ")));
01558 KMessageBox::informationList(parentWidget(),
01559 i18n("<qt>The following contacts could not be exported to the Mobile Phone. "
01560 "Possible Reasons for this problem could be:<br><ul>"
01561 "<li>The contacts contain more information per entry than the phone can store.</li>"
01562 "<li>Your phone does not allow to store multiple addresses, emails, homepages, ...</li>"
01563 "<li>other storage size related problems.</li>"
01564 "</ul>"
01565 "To avoid those kind of problems in the future please reduce the amount of different "
01566 "fields in the above contacts.</qt>"),
01567 failedList,
01568 i18n("Mobile Phone Export") );
01569 }
01570
01571 return true;
01572 }
01573
01574
01575
01576
01577
01578
01579
01580
01581 #else
01582
01583 KABC::AddresseeList GNOKIIXXPort::importContacts( const QString& ) const
01584 {
01585 KABC::AddresseeList addrList;
01586 KMessageBox::error(parentWidget(), i18n("Gnokii interface is not available.\n"
01587 "Please ask your distributor to add gnokii at compile time."));
01588 return addrList;
01589 }
01590
01591 bool GNOKIIXXPort::exportContacts( const KABC::AddresseeList &list, const QString & )
01592 {
01593 Q_UNUSED(list);
01594 KMessageBox::error(parentWidget(), i18n("Gnokii interface is not available.\n"
01595 "Please ask your distributor to add gnokii at compile time."));
01596 return true;
01597 }
01598
01599 #endif
01600
01601
01602
01603
01604
01605
01606
01607 #include "gnokii_xxport.moc"
01608
01609