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