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