00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034 #include "config.h"
00035
00036 #include <qcursor.h>
00037
00038 #include <kdebug.h>
00039 #include <klocale.h>
00040 #include <kmessagebox.h>
00041 #include <kprogress.h>
00042 #include <kguiitem.h>
00043
00044 #ifdef HAVE_GNOKII_H
00045 extern "C" {
00046 #include <gnokii.h>
00047 }
00048 #else
00049 #ifdef __GNUC__
00050 # warning "Please install the gnokii development headers and libraries !"
00051 #endif
00052 #endif
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 class GNOKIIXXPortFactory : public KAB::XXPortFactory
00079 {
00080 public:
00081 KAB::XXPort *xxportObject( KABC::AddressBook *ab, QWidget *parent, const char *name )
00082 {
00083 return new GNOKIIXXPort( ab, parent, name );
00084 }
00085 };
00086
00087 extern "C"
00088 {
00089 void *init_libkaddrbk_gnokii_xxport()
00090 {
00091 return ( new GNOKIIXXPortFactory() );
00092 }
00093 }
00094
00095
00096 GNOKIIXXPort::GNOKIIXXPort( KABC::AddressBook *ab, QWidget *parent, const char *name )
00097 : KAB::XXPort( ab, parent, name )
00098 {
00099 this_filter = this;
00100 m_progressDlg = NULL;
00101 createImportAction( i18n( "Import From Nokia Mobile Phone..." ) );
00102 createExportAction( i18n( "Export to Nokia Mobile Phone..." ) );
00103 }
00104
00105
00106
00107 #ifdef HAVE_GNOKII_H
00108 static char *lockfile = NULL;
00109 static char manufacturer[64], model[GN_MODEL_MAX_LENGTH+1],
00110 revision[GN_REVISION_MAX_LENGTH+1], imei[GN_IMEI_MAX_LENGTH+1];
00111 static QString PhoneProductId;
00112
00113 static struct gn_statemachine state;
00114 static gn_data data;
00115
00116 static void busterminate(void)
00117 {
00118 gn_sm_functions(GN_OP_Terminate, NULL, &state);
00119 if (lockfile) gn_device_unlock(lockfile);
00120 }
00121
00122 static QString businit(void)
00123 {
00124 gn_error error;
00125 char *aux;
00126
00127 #if defined(LIBGNOKII_VERSION)
00128 if (gn_cfg_read_default()<0)
00129 #else
00130 static char *BinDir;
00131 if (gn_cfg_read(&BinDir)<0)
00132 #endif
00133 return i18n("Failed to initialize the gnokii library.");
00134
00135 if (!gn_cfg_phone_load("", &state))
00136 return i18n("Gnokii is not yet configured.");
00137
00138
00139
00140
00141 gn_data_clear(&data);
00142
00143 aux = gn_cfg_get(gn_cfg_info, "global", "use_locking");
00144
00145 if (aux && !strcmp(aux, "yes")) {
00146 lockfile = gn_device_lock(state.config.port_device);
00147 if (lockfile == NULL) {
00148 return i18n("Gnokii reports a 'Lock File Error'.\n "
00149 "Please exit all other running instances of gnokii, check if you have "
00150 "write permissions in the /var/lock directory and try again.");
00151 }
00152 }
00153
00154
00155 int old_dcd = state.config.require_dcd;
00156 state.config.require_dcd = false;
00157 error = gn_gsm_initialise(&state);
00158 GNOKII_CHECK_ERROR(error);
00159 state.config.require_dcd = old_dcd;
00160 if (error != GN_ERR_NONE) {
00161 busterminate();
00162 return i18n("<qt><center>Mobile Phone interface initialization failed.<br><br>"
00163 "The returned error message was:<br><b>%1</b><br><br>"
00164 "You might try to run \"gnokii --identify\" on the command line to "
00165 "check any cable/transport issues and to verify if your gnokii "
00166 "configuration is correct.</center></qt>")
00167 .arg(gn_error_print(error));
00168 }
00169
00170
00171 gn_data_clear(&data);
00172 data.manufacturer = manufacturer;
00173 data.model = model;
00174 data.revision = revision;
00175 data.imei = imei;
00176
00177 QCString unknown(GN_TO(i18n("Unknown")));
00178 qstrncpy(manufacturer, unknown, sizeof(manufacturer)-1);
00179 qstrncpy(model, unknown, sizeof(model)-1);
00180 qstrncpy(revision, unknown, sizeof(revision)-1);
00181 qstrncpy(imei, unknown, sizeof(imei)-1);
00182
00183 if (m_progressDlg->wasCancelled())
00184 return QString::null;
00185 else
00186 error = gn_sm_functions(GN_OP_Identify, &data, &state);
00187 GNOKII_CHECK_ERROR(error);
00188
00189 GNOKII_DEBUG( QString("Found mobile phone: %1 %2, Revision: %3, IMEI: %4\n")
00190 .arg(manufacturer, model, revision, imei) );
00191
00192 PhoneProductId = QString("%1-%2-%3-%4").arg(APP).arg(model).arg(revision).arg(imei);
00193
00194 return QString::null;
00195 }
00196
00197
00198
00199 static gn_error read_phone_memstat( const gn_memory_type memtype, gn_memory_status *memstat )
00200 {
00201 gn_error error;
00202
00203 gn_data_clear(&data);
00204 memset(memstat, 0, sizeof(*memstat));
00205 memstat->memory_type = memtype;
00206 data.memory_status = memstat;
00207 error = gn_sm_functions(GN_OP_GetMemoryStatus, &data, &state);
00208 GNOKII_CHECK_ERROR(error);
00209 if (error != GN_ERR_NONE) {
00210 switch (memtype) {
00211 case GN_MT_SM:
00212
00213 memstat->used = 0;
00214 memstat->free = 100;
00215 break;
00216 default:
00217 case GN_MT_ME:
00218
00219 memstat->used = memstat->free = 0;
00220 break;
00221 }
00222 }
00223 GNOKII_DEBUG( QString("\n\nMobile phone memory status: Type: %1, used=%2, free=%3, total=%4\n\n")
00224 .arg(memtype).arg(memstat->used).arg(memstat->free).arg(memstat->used+memstat->free) );
00225 return error;
00226 }
00227
00228
00229
00230 static gn_error read_phone_entry( const int index, const gn_memory_type memtype, gn_phonebook_entry *entry )
00231 {
00232 gn_error error;
00233 entry->memory_type = memtype;
00234 entry->location = index;
00235 data.phonebook_entry = entry;
00236 error = gn_sm_functions(GN_OP_ReadPhonebook, &data, &state);
00237 GNOKII_CHECK_ERROR(error);
00238 return error;
00239 }
00240
00241 static bool phone_entry_empty( const int index, const gn_memory_type memtype )
00242 {
00243 gn_error error;
00244 gn_phonebook_entry entry;
00245 entry.memory_type = memtype;
00246 entry.location = index;
00247 data.phonebook_entry = &entry;
00248 error = gn_sm_functions(GN_OP_ReadPhonebook, &data, &state);
00249 if (error == GN_ERR_EMPTYLOCATION)
00250 return true;
00251 GNOKII_CHECK_ERROR(error);
00252 if (error == GN_ERR_NONE && entry.empty)
00253 return true;
00254 return false;
00255 }
00256
00257 static QString buildPhoneInfoString( const gn_memory_status &memstat )
00258 {
00259 QString format = QString::fromLatin1("<tr><td><b>%1</b></td><td>%2</td></tr>");
00260
00261 return QString::fromLatin1("<b>%1</b><br><table>%2%3%4%5%6</table><br>")
00262 .arg(i18n("Mobile Phone information:"))
00263 .arg(format.arg(i18n("Manufacturer")).arg(GN_FROM(manufacturer)))
00264 .arg(format.arg(i18n("Phone model")).arg(GN_FROM(model)))
00265 .arg(format.arg(i18n("Revision")).arg(GN_FROM(revision)))
00266 .arg(format.arg(i18n("IMEI")).arg(GN_FROM(imei)))
00267 .arg(format.arg(i18n("Phonebook status"))
00268 .arg(i18n("%1 out of %2 contacts used").arg(memstat.used).arg(memstat.used+memstat.free)));
00269 }
00270
00271 static QString buildMemoryTypeString( gn_memory_type memtype )
00272 {
00273 switch (memtype) {
00274 case GN_MT_ME: return i18n("internal memory");
00275 case GN_MT_SM: return i18n("SIM-card memory");
00276 default: return i18n("unknown memory");
00277 }
00278 }
00279
00280
00281 static gn_error read_phone_entries( const char *memtypestr, gn_memory_type memtype,
00282 KABC::AddresseeList *addrList )
00283 {
00284 gn_error error;
00285
00286 if (m_progressDlg->wasCancelled())
00287 return GN_ERR_NONE;
00288
00289 KProgress* progress = (KProgress*)m_progressDlg->progressBar();
00290
00291 progress->setProgress(0);
00292 this_filter->processEvents();
00293
00294
00295 gn_memory_status memstat;
00296 error = read_phone_memstat(memtype, &memstat);
00297
00298 gn_phonebook_entry entry;
00299 QStringList addrlist;
00300 KABC::Address *addr;
00301 QString s, country;
00302
00303 progress->setTotalSteps(memstat.used);
00304 m_progressDlg->setLabel(i18n("<qt>Importing <b>%1</b> contacts from <b>%2</b> of the Mobile Phone.<br><br>%3</qt>")
00305 .arg(memstat.used)
00306 .arg(buildMemoryTypeString(memtype))
00307 .arg(buildPhoneInfoString(memstat)) );
00308
00309 int num_read = 0;
00310
00311 for (int i = 1; !m_progressDlg->wasCancelled() && i <= memstat.used + memstat.free; i++) {
00312 error = read_phone_entry( i, memtype, &entry );
00313
00314 progress->setProgress(num_read);
00315 this_filter->processEvents();
00316
00317 if (error == GN_ERR_EMPTYLOCATION)
00318 continue;
00319 if (error == GN_ERR_INVALIDLOCATION)
00320 break;
00321 if (error == GN_ERR_INVALIDMEMORYTYPE)
00322 break;
00323 if (error == GN_ERR_NONE) {
00324 GNOKII_DEBUG(QString("%1: %2, num=%3, location=%4, group=%5, count=%6\n").arg(i).arg(GN_FROM(entry.name))
00325 .arg(GN_FROM(entry.number)).arg(entry.location).arg(entry.caller_group).arg(entry.subentries_count));
00326 KABC::Addressee *a = new KABC::Addressee();
00327
00328
00329 s = GN_FROM(entry.name).simplifyWhiteSpace();
00330 a->setFormattedName(s);
00331 if (s.find(',') == -1) {
00332
00333 addrlist = QStringList::split(' ', s);
00334 if (addrlist.count() == 1) {
00335
00336 a->setGivenName(s);
00337 } else {
00338
00339 a->setFamilyName(addrlist.last().simplifyWhiteSpace());
00340 addrlist.remove(addrlist.last());
00341 a->setGivenName(addrlist.join(" ").simplifyWhiteSpace());
00342 }
00343 } else {
00344
00345 addrlist = QStringList::split(',', s);
00346 a->setFamilyName(addrlist.first().simplifyWhiteSpace());
00347 addrlist.remove(addrlist.first());
00348 a->setGivenName(addrlist.join(" ").simplifyWhiteSpace());
00349 }
00350
00351 a->insertCustom(APP, "X_GSM_CALLERGROUP", s.setNum(entry.caller_group));
00352 a->insertCustom(APP, "X_GSM_STORE_AT", QString("%1%2").arg(memtypestr).arg(entry.location));
00353
00354
00355 a->setProductId(PhoneProductId);
00356
00357
00358 QDateTime datetime;
00359 if (entry.date.year<1998)
00360 datetime = QDateTime::currentDateTime();
00361 else
00362 datetime = QDateTime( QDate(entry.date.year, entry.date.month, entry.date.day),
00363 QTime(entry.date.hour, entry.date.minute, entry.date.second) );
00364 GNOKII_DEBUG(QString(" date=%1\n").arg(datetime.toString()));
00365 a->setRevision(datetime);
00366
00367 if (!entry.subentries_count)
00368 a->insertPhoneNumber(KABC::PhoneNumber(entry.number, KABC::PhoneNumber::Work | KABC::PhoneNumber::Pref));
00369
00370
00371 if (entry.subentries_count)
00372 for (int n=0; n<entry.subentries_count; n++) {
00373 QString s = GN_FROM(entry.subentries[n].data.number).simplifyWhiteSpace();
00374 GNOKII_DEBUG(QString(" Subentry#%1, entry_type=%2, number_type=%3, number=%4\n")
00375 .arg(n).arg(entry.subentries[n].entry_type)
00376 .arg(entry.subentries[n].number_type).arg(s));
00377 if (s.isEmpty())
00378 continue;
00379 switch(entry.subentries[n].entry_type) {
00380 case GN_PHONEBOOK_ENTRY_Name:
00381 a->setName(s);
00382 break;
00383 case GN_PHONEBOOK_ENTRY_Email:
00384 a->insertEmail(s);
00385 break;
00386 case GN_PHONEBOOK_ENTRY_Postal:
00387 addrlist = QStringList::split(';', s, true);
00388 addr = new KABC::Address(KABC::Address::Work);
00389 if (addrlist.count() <= 1) {
00390 addrlist = QStringList::split(',', s, true);
00391 if (addrlist.count() > 1 ) {
00392
00393 addr->setLocality(addrlist[0]);
00394 addr->setPostalCode(addrlist[1]);
00395 if (!addrlist[2].isEmpty())
00396 addr->setCountry(i18n(GN_TO(addrlist[2])));
00397 } else {
00398
00399 addr->setLocality(s);
00400 }
00401 } else {
00402
00403 addr->setPostOfficeBox(addrlist[0]);
00404 addr->setExtended(addrlist[1]);
00405 addr->setStreet(addrlist[2]);
00406 addr->setLocality(addrlist[3]);
00407 addr->setRegion(addrlist[4]);
00408 addr->setPostalCode(addrlist[5]);
00409 country = addrlist[6];
00410 if (!country.isEmpty())
00411 addr->setCountry(i18n(GN_TO(country)));
00412 }
00413 a->insertAddress(*addr);
00414 delete addr;
00415 break;
00416 case GN_PHONEBOOK_ENTRY_Note:
00417 if (!a->note().isEmpty())
00418 s = "\n" + s;
00419 a->setNote(a->note()+s);
00420 break;
00421 case GN_PHONEBOOK_ENTRY_Number:
00422 enum KABC::PhoneNumber::Types phonetype;
00423 switch (entry.subentries[n].number_type) {
00424 case GN_PHONEBOOK_NUMBER_Mobile: phonetype = KABC::PhoneNumber::Cell; break;
00425 case GN_PHONEBOOK_NUMBER_Fax: phonetype = KABC::PhoneNumber::Fax; break;
00426 case GN_PHONEBOOK_NUMBER_General:
00427 case GN_PHONEBOOK_NUMBER_Work: phonetype = KABC::PhoneNumber::Work; break;
00428 default:
00429 case GN_PHONEBOOK_NUMBER_Home: phonetype = KABC::PhoneNumber::Home; break;
00430 }
00431
00432
00433 a->insertPhoneNumber(KABC::PhoneNumber(s, phonetype));
00434 break;
00435 case GN_PHONEBOOK_ENTRY_URL:
00436 a->setUrl(s);
00437 break;
00438 case GN_PHONEBOOK_ENTRY_Group:
00439 a->insertCategory(s);
00440 break;
00441 default:
00442 GNOKII_DEBUG(QString(" Not handled id=%1, entry=%2\n")
00443 .arg(entry.subentries[n].entry_type).arg(s));
00444 break;
00445 }
00446 }
00447
00448
00449 if (strlen(entry.name) || strlen(entry.number) || entry.subentries_count)
00450 addrList->append(*a);
00451
00452
00453 num_read++;
00454 delete a;
00455 if (num_read >= memstat.used)
00456 break;
00457 else
00458 continue;
00459 }
00460 GNOKII_CHECK_ERROR(error);
00461 }
00462
00463 return GN_ERR_NONE;
00464 }
00465 #endif
00466
00467
00468
00469 KABC::AddresseeList GNOKIIXXPort::importContacts( const QString& ) const
00470 {
00471 KABC::AddresseeList addrList;
00472
00473 #ifndef HAVE_GNOKII_H
00474
00475 KMessageBox::error(parentWidget(), i18n("Gnokii interface is not available.\n"
00476 "Please ask your distributor to add gnokii at compile time."));
00477
00478 #else
00479
00480 if (KMessageBox::Continue != KMessageBox::warningContinueCancel(parentWidget(),
00481 i18n("<qt>Please connect your Mobile Phone to your computer and press "
00482 "<b>Continue</b> to start importing the personal contacts.<br><br>"
00483 "Please note that if your mobile phone is not properly connected "
00484 "the following detection phase might take up to two minutes, during which "
00485 "KAddressbook will behave unresponsively.</qt>") ))
00486 return addrList;
00487
00488 m_progressDlg = new KProgressDialog( parentWidget(), "importwidget",
00489 i18n("Mobile Phone Import"),
00490 i18n("<qt><center>Establishing connection to the Mobile Phone.<br><br>"
00491 "Please wait...</center></qt>") );
00492 m_progressDlg->setAllowCancel(true);
00493 m_progressDlg->progressBar()->setProgress(0);
00494 m_progressDlg->progressBar()->setCenterIndicator(true);
00495 m_progressDlg->setModal(true);
00496 m_progressDlg->setMinimumSize(450,350);
00497 m_progressDlg->show();
00498 processEvents();
00499
00500 #if (QT_VERSION >= 0x030300)
00501 m_progressDlg->setCursor( Qt::BusyCursor );
00502 #endif
00503 QString errStr = businit();
00504 m_progressDlg->unsetCursor();
00505
00506 if (!errStr.isEmpty()) {
00507 KMessageBox::error(parentWidget(), errStr);
00508 delete m_progressDlg;
00509 return addrList;
00510 }
00511
00512 GNOKII_DEBUG("GNOKII import filter started.\n");
00513 m_progressDlg->setButtonText(i18n("&Stop Import"));
00514
00515 read_phone_entries("ME", GN_MT_ME, &addrList);
00516 read_phone_entries("SM", GN_MT_SM, &addrList);
00517
00518 GNOKII_DEBUG("GNOKII import filter finished.\n");
00519
00520 busterminate();
00521 delete m_progressDlg;
00522
00523 #endif
00524
00525 return addrList;
00526 }
00527
00528
00529
00530
00531 #ifdef HAVE_GNOKII_H
00532
00533 static QString makeValidPhone( const QString &number )
00534 {
00535
00536 QString num = number.simplifyWhiteSpace();
00537 QString allowed("0123456789*+#pw");
00538 for (unsigned int i=num.length(); i>=1; i--)
00539 if (allowed.find(num[i-1])==-1)
00540 num.remove(i-1,1);
00541 if (num.isEmpty())
00542 num = "0";
00543 return num;
00544 }
00545
00546 static gn_error xxport_phone_write_entry( int phone_location, gn_memory_type memtype,
00547 const KABC::Addressee *addr)
00548 {
00549 gn_phonebook_entry entry;
00550 QString s;
00551
00552 memset(&entry, 0, sizeof(entry));
00553 strncpy(entry.name, GN_TO(addr->realName()), sizeof(entry.name)-1);
00554 s = addr->phoneNumber(KABC::PhoneNumber::Pref).number();
00555 if (s.isEmpty())
00556 s = addr->phoneNumber(KABC::PhoneNumber::Work).number();
00557 if (s.isEmpty())
00558 s = addr->phoneNumber(KABC::PhoneNumber::Home).number();
00559 if (s.isEmpty())
00560 s = addr->phoneNumber(KABC::PhoneNumber::Cell).number();
00561 if (s.isEmpty() && addr->phoneNumbers().count()>0)
00562 s = (*addr->phoneNumbers().at(0)).number();
00563 s = makeValidPhone(s);
00564 strncpy(entry.number, s.ascii(), sizeof(entry.number)-1);
00565 entry.memory_type = memtype;
00566 QString cg = addr->custom(APP, "X_GSM_CALLERGROUP");
00567 if (cg.isEmpty())
00568 entry.caller_group = 5;
00569 else
00570 entry.caller_group = cg.toInt();
00571 entry.location = phone_location;
00572
00573
00574 QDateTime datetime = addr->revision();
00575 QDate date(datetime.date());
00576 QTime time(datetime.time());
00577 entry.date.year = date.year();
00578 entry.date.month = date.month();
00579 entry.date.day = date.day();
00580 entry.date.hour = time.hour();
00581 entry.date.minute = time.minute();
00582 entry.date.second = time.second();
00583
00584 GNOKII_DEBUG(QString("Write #%1: name=%2, number=%3\n").arg(phone_location)
00585 .arg(GN_FROM(entry.name)).arg(GN_FROM(entry.number)));
00586
00587 const KABC::Address homeAddr = addr->address(KABC::Address::Home);
00588 const KABC::Address workAddr = addr->address(KABC::Address::Work);
00589
00590 entry.subentries_count = 0;
00591 gn_phonebook_subentry *subentry = &entry.subentries[0];
00592
00593 const KABC::PhoneNumber::List phoneList = addr->phoneNumbers();
00594 KABC::PhoneNumber::List::ConstIterator it;
00595 for ( it = phoneList.begin(); it != phoneList.end(); ++it ) {
00596 const KABC::PhoneNumber *phonenumber = &(*it);
00597 s = phonenumber->number();
00598 if (s.isEmpty()) continue;
00599 subentry->entry_type = GN_PHONEBOOK_ENTRY_Number;
00600 gn_phonebook_number_type type;
00601 switch (phonenumber->type() & ~KABC::PhoneNumber::Pref) {
00602 case KABC::PhoneNumber::Home: type = GN_PHONEBOOK_NUMBER_Home; break;
00603 case KABC::PhoneNumber::Voice:
00604 case KABC::PhoneNumber::Work: type = GN_PHONEBOOK_NUMBER_Work; break;
00605 case KABC::PhoneNumber::Pager:
00606 case KABC::PhoneNumber::Cell: type = GN_PHONEBOOK_NUMBER_Mobile; break;
00607 case KABC::PhoneNumber::Fax: type = GN_PHONEBOOK_NUMBER_Fax; break;
00608 default: type = GN_PHONEBOOK_NUMBER_General; break;
00609 }
00610 subentry->number_type = type;
00611 strncpy(subentry->data.number, makeValidPhone(s).ascii(), sizeof(subentry->data.number)-1);
00612 subentry->id = phone_location<<8+entry.subentries_count;
00613 entry.subentries_count++;
00614 subentry++;
00615 if (entry.subentries_count >= GN_PHONEBOOK_SUBENTRIES_MAX_NUMBER)
00616 break;
00617 }
00618
00619 s = addr->url().prettyURL();
00620 if (!s.isEmpty() && (entry.subentries_count<GN_PHONEBOOK_SUBENTRIES_MAX_NUMBER)) {
00621 subentry->entry_type = GN_PHONEBOOK_ENTRY_URL;
00622 strncpy(subentry->data.number, GN_TO(s), sizeof(subentry->data.number)-1);
00623 entry.subentries_count++;
00624 subentry++;
00625 }
00626
00627 QStringList emails = addr->emails();
00628 for (unsigned int n=0; n<emails.count(); n++) {
00629 if (entry.subentries_count >= GN_PHONEBOOK_SUBENTRIES_MAX_NUMBER)
00630 break;
00631 s = emails[n].simplifyWhiteSpace();
00632 if (s.isEmpty()) continue;
00633
00634 if (n && !addr->url().isEmpty() && !addr->note().isEmpty() && addr->addresses().count()) {
00635 GNOKII_DEBUG(QString(" DROPPED email %1 in favor of URLs, notes and addresses.\n")
00636 .arg(s));
00637 continue;
00638 }
00639 subentry->entry_type = GN_PHONEBOOK_ENTRY_Email;
00640 strncpy(subentry->data.number, GN_TO(s), sizeof(subentry->data.number)-1);
00641 entry.subentries_count++;
00642 subentry++;
00643 }
00644
00645 const KABC::Address::List addresses = addr->addresses();
00646 KABC::Address::List::ConstIterator it2;
00647 for ( it2 = addresses.begin(); it2 != addresses.end(); ++it2 ) {
00648 if (entry.subentries_count >= GN_PHONEBOOK_SUBENTRIES_MAX_NUMBER)
00649 break;
00650 const KABC::Address *Addr = &(*it2);
00651 if (Addr->isEmpty()) continue;
00652 subentry->entry_type = GN_PHONEBOOK_ENTRY_Postal;
00653 QStringList a;
00654 QChar sem(';');
00655 QString sem_repl(QString::fromLatin1(","));
00656 a.append( Addr->postOfficeBox().replace( sem, sem_repl ) );
00657 a.append( Addr->extended() .replace( sem, sem_repl ) );
00658 a.append( Addr->street() .replace( sem, sem_repl ) );
00659 a.append( Addr->locality() .replace( sem, sem_repl ) );
00660 a.append( Addr->region() .replace( sem, sem_repl ) );
00661 a.append( Addr->postalCode() .replace( sem, sem_repl ) );
00662 a.append( Addr->country() .replace( sem, sem_repl ) );
00663 s = a.join(sem);
00664 strncpy(subentry->data.number, GN_TO(s), sizeof(subentry->data.number)-1);
00665 entry.subentries_count++;
00666 subentry++;
00667 }
00668
00669 s = addr->note().simplifyWhiteSpace();
00670 if (!s.isEmpty() && (entry.subentries_count<GN_PHONEBOOK_SUBENTRIES_MAX_NUMBER)) {
00671 subentry->entry_type = GN_PHONEBOOK_ENTRY_Note;
00672 strncpy(subentry->data.number, GN_TO(s), sizeof(subentry->data.number)-1);
00673 entry.subentries_count++;
00674 subentry++;
00675 }
00676
00677
00678 for (int st=0; st<entry.subentries_count; st++) {
00679 gn_phonebook_subentry *subentry = &entry.subentries[st];
00680 GNOKII_DEBUG(QString(" SubTel #%1: entry_type=%2, number_type=%3, number=%4\n")
00681 .arg(st).arg(subentry->entry_type)
00682 .arg(subentry->number_type).arg(GN_FROM(subentry->data.number)));
00683 }
00684
00685 data.phonebook_entry = &entry;
00686 gn_error error = gn_sm_functions(GN_OP_WritePhonebook, &data, &state);
00687 GNOKII_CHECK_ERROR(error);
00688
00689 return error;
00690 }
00691
00692
00693 static gn_error xxport_phone_delete_entry( int phone_location, gn_memory_type memtype )
00694 {
00695 gn_phonebook_entry entry;
00696 memset(&entry, 0, sizeof(entry));
00697 entry.empty = 1;
00698 entry.memory_type = memtype;
00699 entry.location = phone_location;
00700 data.phonebook_entry = &entry;
00701 GNOKII_DEBUG(QString("Deleting entry %1\n").arg(phone_location));
00702 gn_error error = gn_sm_functions(GN_OP_WritePhonebook, &data, &state);
00703 GNOKII_CHECK_ERROR(error);
00704 return error;
00705 }
00706
00707 #endif
00708
00709 bool GNOKIIXXPort::exportContacts( const KABC::AddresseeList &list, const QString & )
00710 {
00711 #ifndef HAVE_GNOKII_H
00712
00713 Q_UNUSED(list);
00714 KMessageBox::error(parentWidget(), i18n("Gnokii interface is not available.\n"
00715 "Please ask your distributor to add gnokii at compile time."));
00716
00717 #else
00718 if (KMessageBox::Continue != KMessageBox::warningContinueCancel(parentWidget(),
00719 i18n("<qt>Please connect your Mobile Phone to your computer and press "
00720 "<b>Continue</b> to start exporting the selected personal contacts.<br><br>"
00721 "Please note that if your Mobile Phone is not properly connected "
00722 "the following detection phase might take up to two minutes, during which "
00723 "KAddressbook will behave unresponsively.</qt>") ))
00724 return false;
00725
00726 m_progressDlg = new KProgressDialog( parentWidget(), "importwidget",
00727 i18n("Mobile Phone Export"),
00728 i18n("<qt><center>Establishing connection to the Mobile Phone.<br><br>"
00729 "Please wait...</center></qt>") );
00730 m_progressDlg->setAllowCancel(true);
00731 m_progressDlg->progressBar()->setProgress(0);
00732 m_progressDlg->progressBar()->setCenterIndicator(true);
00733 m_progressDlg->setModal(true);
00734 m_progressDlg->setMinimumSize(450,350);
00735 m_progressDlg->show();
00736 processEvents();
00737
00738 KProgress* progress = (KProgress*)m_progressDlg->progressBar();
00739
00740 KABC::AddresseeList::ConstIterator it;
00741 QStringList failedList;
00742
00743 gn_error error;
00744 bool deleteLabelInitialized = false;
00745
00746 #if (QT_VERSION >= 0x030300)
00747 m_progressDlg->setCursor( Qt::BusyCursor );
00748 #endif
00749 QString errStr = businit();
00750 m_progressDlg->unsetCursor();
00751
00752 if (!errStr.isEmpty()) {
00753 KMessageBox::error(parentWidget(), errStr);
00754 delete m_progressDlg;
00755 return false;
00756 }
00757
00758 GNOKII_DEBUG("GNOKII export filter started.\n");
00759
00760 gn_memory_type memtype = GN_MT_ME;
00761
00762 int phone_count;
00763 bool overwrite_phone_entries = false;
00764 int phone_entry_no, entries_written;
00765 bool entry_empty;
00766
00767
00768 gn_memory_status memstat;
00769 error = read_phone_memstat(memtype, &memstat);
00770 if (error == GN_ERR_NONE) {
00771 GNOKII_DEBUG("Writing to internal phone memory.\n");
00772 } else {
00773 memtype = GN_MT_SM;
00774 error = read_phone_memstat(memtype, &memstat);
00775 if (error != GN_ERR_NONE)
00776 goto finish;
00777 GNOKII_DEBUG("Writing to SIM card memory.\n");
00778 }
00779 phone_count = memstat.used;
00780
00781 if (memstat.free >= (int) list.count()) {
00782 if (KMessageBox::No == KMessageBox::questionYesNo(parentWidget(),
00783 i18n("<qt>Do you want the selected contacts to be <b>appended</b> to "
00784 "the current mobile phonebook or should they <b>replace</b> all "
00785 "currently existing phonebook entries ?<br><br>"
00786 "Please note, that in case you choose to replace the phonebook "
00787 "entries, every contact in your phone will be deleted and only "
00788 "the newly exported contacts will be available from inside your phone.</qt>"),
00789 i18n("Export to Mobile Phone"),
00790 KGuiItem(i18n("&Append to Current Phonebook")),
00791 KGuiItem(i18n("&Replace Current Phonebook with New Contacts")) ) )
00792 overwrite_phone_entries = true;
00793 }
00794
00795 progress->setTotalSteps(list.count());
00796 entries_written = 0;
00797 progress->setProgress(entries_written);
00798 m_progressDlg->setButtonText(i18n("&Stop Export"));
00799 m_progressDlg->setLabel(i18n("<qt>Exporting <b>%1</b> contacts to the <b>%2</b> "
00800 "of the Mobile Phone.<br><br>%3</qt>")
00801 .arg(list.count())
00802 .arg(buildMemoryTypeString(memtype))
00803 .arg(buildPhoneInfoString(memstat)) );
00804
00805
00806 phone_entry_no = 1;
00807 for ( it = list.begin(); it != list.end(); ++it ) {
00808 const KABC::Addressee *addr = &(*it);
00809 if (addr->isEmpty())
00810 continue;
00811
00812 if (addr->custom(APP, "X_GSM_STORE_AT").startsWith("SM"))
00813 continue;
00814
00815 progress->setProgress(entries_written++);
00816
00817 try_next_phone_entry:
00818 this_filter->processEvents();
00819 if (m_progressDlg->wasCancelled())
00820 break;
00821
00822
00823 if (phone_entry_no > (memstat.used + memstat.free))
00824 break;
00825
00826 GNOKII_DEBUG(QString("Try to write entry '%1' at phone_entry_no=%2, phone_count=%3\n")
00827 .arg(addr->realName()).arg(phone_entry_no).arg(phone_count));
00828
00829 error = GN_ERR_NONE;
00830
00831
00832 entry_empty = phone_entry_empty(phone_entry_no, memtype);
00833 if (overwrite_phone_entries) {
00834
00835 if (!entry_empty)
00836 phone_count--;
00837 error = xxport_phone_write_entry( phone_entry_no, memtype, addr);
00838 phone_entry_no++;
00839 } else {
00840
00841 if (entry_empty) {
00842 error = xxport_phone_write_entry( phone_entry_no, memtype, addr);
00843 phone_entry_no++;
00844 } else {
00845 phone_entry_no++;
00846 goto try_next_phone_entry;
00847 }
00848 }
00849
00850 if (error != GN_ERR_NONE)
00851 failedList.append(addr->realName());
00852
00853
00854 if (error != GN_ERR_NONE && it==list.begin())
00855 break;
00856
00857 }
00858
00859
00860
00861 while (overwrite_phone_entries && error==GN_ERR_NONE && phone_count>0) {
00862 if (m_progressDlg->wasCancelled())
00863 break;
00864 if (!deleteLabelInitialized) {
00865 m_progressDlg->setLabel(
00866 i18n("<qt><center>"
00867 "All selected contacts have been sucessfully copied to "
00868 "the Mobile Phone.<br><br>"
00869 "Please wait until all remaining orphaned contacts from "
00870 "the Mobile Phone have been deleted.</center></qt>") );
00871 m_progressDlg->setButtonText(i18n("&Stop Delete"));
00872 deleteLabelInitialized = true;
00873 progress->setTotalSteps(phone_count);
00874 entries_written = 0;
00875 progress->setProgress(entries_written);
00876 this_filter->processEvents();
00877 }
00878 if (phone_entry_no > (memstat.used + memstat.free))
00879 break;
00880 entry_empty = phone_entry_empty(phone_entry_no, memtype);
00881 if (!entry_empty) {
00882 error = xxport_phone_delete_entry(phone_entry_no, memtype);
00883 phone_count--;
00884 progress->setProgress(++entries_written);
00885 this_filter->processEvents();
00886 }
00887 phone_entry_no++;
00888 }
00889
00890 finish:
00891 m_progressDlg->setLabel(i18n("Export to phone finished."));
00892 this_filter->processEvents();
00893
00894 GNOKII_DEBUG("GNOKII export filter finished.\n");
00895
00896 busterminate();
00897 delete m_progressDlg;
00898
00899 if (!failedList.isEmpty()) {
00900 GNOKII_DEBUG(QString("Failed to export: %1\n").arg(failedList.join(", ")));
00901 KMessageBox::informationList(parentWidget(),
00902 i18n("<qt>The following contacts could not be exported to the Mobile Phone. "
00903 "Possible Reasons for this problem could be:<br><ul>"
00904 "<li>The contacts contain more information per entry than the phone can store.</li>"
00905 "<li>Your phone does not allow to store multiple addresses, emails, homepages, ...</li>"
00906 "<li>other storage size related problems.</li>"
00907 "</ul>"
00908 "To avoid those kind of problems in the future please reduce the amount of different "
00909 "fields in the above contacts.</qt>"),
00910 failedList,
00911 i18n("Mobile Phone Export") );
00912 }
00913
00914 #endif
00915
00916 return true;
00917 }
00918
00919 #include "gnokii_xxport.moc"
00920
00921