kaddressbook Library API Documentation

gnokii_xxport.cpp

00001 /* 00002 This file is part of KAddressbook. 00003 Copyright (c) 2003-2004 Helge Deller <deller@kde.org> 00004 00005 This program is free software; you can redistribute it and/or modify 00006 it under the terms of the GNU General Public License version 2 as 00007 published by the Free Software Foundation. 00008 00009 This program is distributed in the hope that it will be useful, 00010 but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 GNU General Public License for more details. 00013 00014 You should have received a copy of the GNU General Public License 00015 along with this program; if not, write to the Free Software 00016 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 00017 00018 As a special exception, permission is given to link this program 00019 with any edition of Qt, and distribute the resulting executable, 00020 without including the source code for Qt in the source distribution. 00021 */ 00022 00023 /* 00024 Description: 00025 This filter allows you to import and export the KDE addressbook entries 00026 to/from a mobile phone, which is accessible via gnokii. 00027 Gnokii homepage: http://www.gnokii.org 00028 00029 TODO: 00030 - create a log file and give user possibility to see it afterwards 00031 - handle callergroup value (Friend, VIP, Family, ...) better 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 // Locale conversion routines: 00070 // Gnokii uses the local 8 Bit encoding (based on LC_ALL), kaddressbook uses Unicode 00071 #define GN_FROM(x) QString::fromLocal8Bit(x) 00072 #define GN_TO(x) (x).local8Bit() 00073 00074 // static variables for GUI updates 00075 static GNOKIIXXPort *this_filter; 00076 static KProgressDialog *m_progressDlg; 00077 00078 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 /* import */ 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 // uncomment to debug all gnokii communication on stderr. 00139 // gn_log_debug_mask = GN_LOG_T_STDERR; 00140 00141 gn_data_clear(&data); 00142 00143 aux = gn_cfg_get(gn_cfg_info, "global", "use_locking"); 00144 // Defaults to 'no' 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 // Initialise the code for the GSM interface. 00155 int old_dcd = state.config.require_dcd; // work-around for older gnokii versions 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 // identify phone 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 // get number of entries in this phone memory type (internal/SIM-card) 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 // use at least 100 entries 00213 memstat->used = 0; 00214 memstat->free = 100; 00215 break; 00216 default: 00217 case GN_MT_ME: 00218 // Phone doesn't support ME (5110) 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 // read phone entry #index from memory #memtype 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 // read and evaluate all phone entries 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 // get number of entries in this phone memory type (internal/SIM-card) 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 // try to split Name into FamilyName and GivenName 00329 s = GN_FROM(entry.name).simplifyWhiteSpace(); 00330 a->setFormattedName(s); // set formatted name as in Phone 00331 if (s.find(',') == -1) { 00332 // assumed format: "givenname [... familyname]" 00333 addrlist = QStringList::split(' ', s); 00334 if (addrlist.count() == 1) { 00335 // only one string -> put it in the GivenName 00336 a->setGivenName(s); 00337 } else { 00338 // multiple strings -> split them. 00339 a->setFamilyName(addrlist.last().simplifyWhiteSpace()); 00340 addrlist.remove(addrlist.last()); 00341 a->setGivenName(addrlist.join(" ").simplifyWhiteSpace()); 00342 } 00343 } else { 00344 // assumed format: "familyname, ... givenname" 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 // set ProductId 00355 a->setProductId(PhoneProductId); 00356 00357 // evaluate timestamp (ignore timezone) 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 /* scan sub-entries */ 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 // assumed format: "Locality, ZIP, Country" 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 // no idea about the format, just store it. 00399 addr->setLocality(s); 00400 } 00401 } else { 00402 // assumed format: "POBox; Extended; Street; Locality; Region; ZIP [;Country] 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 //if (s == entry.number) 00432 // type = (KABC::PhoneNumber::Types) (phonetype | KABC::PhoneNumber::Pref); 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 } // switch() 00446 } // if(subentry) 00447 00448 // add only if entry was valid 00449 if (strlen(entry.name) || strlen(entry.number) || entry.subentries_count) 00450 addrList->append(*a); 00451 00452 // did we read all valid phonebook-entries ? 00453 num_read++; 00454 delete a; 00455 if (num_read >= memstat.used) 00456 break; // yes, all were read 00457 else 00458 continue; // no, we are still missing some. 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); // not honored yet - seems like bug in KProgressDialog 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); // internal phone memory 00516 read_phone_entries("SM", GN_MT_SM, &addrList); // SIM card 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 // export to phone 00530 00531 #ifdef HAVE_GNOKII_H 00532 00533 static QString makeValidPhone( const QString &number ) 00534 { 00535 // allowed chars: 0-9, *, #, p, w, + 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; // default group 00569 else 00570 entry.caller_group = cg.toInt(); 00571 entry.location = phone_location; 00572 00573 // set date/revision 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 // add all phone numbers 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; // Phonebook full 00617 } 00618 // add URL 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 // add E-Mails 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; // Phonebook full 00631 s = emails[n].simplifyWhiteSpace(); 00632 if (s.isEmpty()) continue; 00633 // only one email allowed if we have URLS, notes, addresses (to avoid phone limitations) 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 // add Adresses 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; // Phonebook full 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 // add Note 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 // debug output 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); // not honored yet - seems like bug in KProgressDialog 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; // internal phone memory 00761 00762 int phone_count; // num entries in phone 00763 bool overwrite_phone_entries = false; 00764 int phone_entry_no, entries_written; 00765 bool entry_empty; 00766 00767 // get number of entries in this phone memory 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; // try SIM card instead 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 // Now run the loop... 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 // don't write back SIM-card entries ! 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 // End of phone memory reached ? 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 // is this phone entry empty ? 00832 entry_empty = phone_entry_empty(phone_entry_no, memtype); 00833 if (overwrite_phone_entries) { 00834 // overwrite this phonebook entry ... 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 // add this phonebook entry if possible ... 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 // break if we got an error on the first entry 00854 if (error != GN_ERR_NONE && it==list.begin()) 00855 break; 00856 00857 } // for() 00858 00859 // if we wanted to overwrite all entries, make sure, that we also 00860 // delete all remaining entries in the mobile phone. 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 /* vim: set sts=4 ts=4 sw=4: */ 00921
KDE Logo
This file is part of the documentation for kaddressbook Library Version 3.3.0.
Documentation copyright © 1996-2004 the KDE developers.
Generated on Thu Oct 21 19:46:36 2004 by doxygen 1.3.7 written by Dimitri van Heesch, © 1997-2003