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