TDE personal information management applications
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1602 lines
54KB

  1. /*
  2. This file is part of KAddressbook.
  3. Copyright (c) 2003-2006 Helge Deller <deller@kde.org>
  4. This program is free software; you can redistribute it and/or modify
  5. it under the terms of the GNU General Public License version 2 as
  6. published by the Free Software Foundation.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  10. GNU General Public License for more details.
  11. You should have received a copy of the GNU General Public License
  12. along with this program; if not, write to the Free Software
  13. Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  14. As a special exception, permission is given to link this program
  15. with any edition of TQt, and distribute the resulting executable,
  16. without including the source code for TQt in the source distribution.
  17. */
  18. /*
  19. Description:
  20. This filter allows you to import and export the KDE addressbook entries
  21. to/from a mobile phone, which is accessible via gnokii.
  22. Gnokii homepage: http://www.gnokii.org
  23. TODO:
  24. - create a log file and give user possibility to see it afterwards
  25. - handle callergroup value (Friend, VIP, Family, ...) better
  26. */
  27. #include "config.h"
  28. #ifdef HAVE_GNOKII_H
  29. extern "C" {
  30. #include <gnokii.h>
  31. }
  32. #else
  33. #ifdef __GNUC__
  34. # warning "Please install gnokii (http://www.gnokii.org) development headers and libraries !"
  35. # warning "Please use at least version 0.6.13 or later of gnokii."
  36. #endif
  37. #endif
  38. #include <tqcursor.h>
  39. #include <kdebug.h>
  40. #include <klocale.h>
  41. #include <kmessagebox.h>
  42. #include <kprogress.h>
  43. #include <kguiitem.h>
  44. #include "gnokii_xxport.h"
  45. #define APP "GNOKII_XXPORT"
  46. #if 1 // !defined(NDEBUG)
  47. #define GNOKII_DEBUG(x) do { kdWarning() << (x); } while (0)
  48. #else
  49. #define GNOKII_DEBUG(x) do { } while (0)
  50. #endif
  51. #define GNOKII_CHECK_ERROR(error) \
  52. do { \
  53. if (error) \
  54. kdError() << TQString("ERROR %1: %2\n").tqarg(error).tqarg(gn_error_print(error));\
  55. } while (0)
  56. // Locale conversion routines:
  57. // Gnokii uses the local 8 Bit encoding (based on LC_ALL), kaddressbook uses Unicode
  58. #define GN_FROM(x) TQString::fromLocal8Bit(x)
  59. #define GN_TO(x) (x).local8Bit()
  60. // static variables for GUI updates
  61. static GNOKIIXXPort *this_filter;
  62. static KProgressDialog *m_progressDlg;
  63. K_EXPORT_KADDRESSBOOK_XXFILTER( libkaddrbk_gnokii_xxport, GNOKIIXXPort )
  64. GNOKIIXXPort::GNOKIIXXPort( KABC::AddressBook *ab, TQWidget *parent, const char *name )
  65. : KAB::XXPort( ab, parent, name )
  66. {
  67. this_filter = this;
  68. m_progressDlg = NULL;
  69. createImportAction( i18n( "Import From Mobile Phone..." ) );
  70. createExportAction( i18n( "Export to Mobile Phone..." ) );
  71. }
  72. #ifdef HAVE_GNOKII_H
  73. static TQString makeValidPhone( const TQString &number )
  74. {
  75. // allowed chars: 0-9, *, #, p, w, +
  76. TQString num = number.simplifyWhiteSpace();
  77. TQString allowed("0123456789*+#pw");
  78. for (unsigned int i=num.length(); i>=1; i--)
  79. if (allowed.find(num[i-1])==-1)
  80. num.remove(i-1,1);
  81. if (num.isEmpty())
  82. num = "0";
  83. return num;
  84. }
  85. #endif
  86. /******************************************************************************
  87. ******************************************************************************
  88. ******************************************************************************
  89. ******************************************************************************
  90. ******************************************************************************/
  91. #if defined(HAVE_GNOKII_H) && defined(LIBGNOKII_VERSION_MAJOR) && (LIBGNOKII_VERSION_MAJOR >= 3)
  92. /* NEW GNOKII LIBRARIES (>= 0.6.13) */
  93. static const char *manufacturer, *model, *revision, *imei;
  94. static struct gn_statemachine *state;
  95. static void busterminate(void)
  96. {
  97. gn_lib_phone_close(state);
  98. gn_lib_phoneprofile_free(&state);
  99. gn_lib_library_free();
  100. }
  101. static TQString businit(void)
  102. {
  103. GNOKII_DEBUG( "Using new gnokii version." );
  104. GNOKII_DEBUG( TQString("Compiled with libgnokii version 0x%1\n").tqarg(TQString::number(LIBGNOKII_VERSION,16)) );
  105. GNOKII_DEBUG( TQString("Using libgnokii runtime version 0x%1\n").tqarg(TQString::number(gn_lib_version(),16)) );
  106. gn_error error = gn_lib_phoneprofile_load(NULL, &state);
  107. if (error)
  108. return i18n("Failed to initialize the gnokii library.");
  109. error = gn_lib_phone_open( state );
  110. GNOKII_CHECK_ERROR(error);
  111. if (error != GN_ERR_NONE) {
  112. busterminate();
  113. return i18n("<qt><center>Mobile Phone interface initialization failed.<br><br>"
  114. "The returned error message was:<br><b>%1</b><br><br>"
  115. "You might try to run \"gnokii --identify\" on the command line to "
  116. "check any cable/transport issues and to verify if your gnokii "
  117. "configuration is correct.</center></qt>")
  118. .tqarg(gn_error_print(error));
  119. }
  120. // identify phone
  121. manufacturer = gn_lib_get_phone_manufacturer(state);
  122. model = gn_lib_get_phone_model(state);
  123. revision = gn_lib_get_phone_revision(state);
  124. imei = gn_lib_get_phone_imei(state);
  125. GNOKII_DEBUG( TQString("Found mobile phone: %1 %2, Revision: %3, IMEI: %4\n")
  126. .tqarg(manufacturer, model, revision, imei) );
  127. return TQString();
  128. }
  129. // get number of entries in this phone memory type (internal/SIM-card)
  130. static gn_error read_phone_memstat( const gn_memory_type memtype, gn_memory_status *memstat )
  131. {
  132. gn_error error;
  133. error = gn_lib_addressbook_memstat(state, memtype, &memstat->used, &memstat->free);
  134. GNOKII_DEBUG( TQString("\n\nMobile phone memory status: Type: %1, used=%2, free=%3, total=%4\n\n")
  135. .tqarg(memtype).tqarg(memstat->used).tqarg(memstat->free).tqarg(memstat->used+memstat->free) );
  136. return error;
  137. }
  138. static TQString buildPhoneInfoString( const gn_memory_status &memstat )
  139. {
  140. TQString format = TQString::tqfromLatin1("<tr><td><b>%1</b></td><td>%2</td></tr>");
  141. return TQString::tqfromLatin1("<b>%1</b><br><table>%2%3%4%5%6</table><br>")
  142. .tqarg(i18n("Mobile Phone information:"))
  143. .tqarg(format.tqarg(i18n("Manufacturer")).tqarg(GN_FROM(manufacturer)))
  144. .tqarg(format.tqarg(i18n("Phone model")).tqarg(GN_FROM(model)))
  145. .tqarg(format.tqarg(i18n("Revision")).tqarg(GN_FROM(revision)))
  146. .tqarg(format.tqarg(i18n("IMEI")).tqarg(GN_FROM(imei)))
  147. .tqarg(format.tqarg(i18n("Phonebook status"))
  148. .tqarg(i18n("%1 out of %2 contacts used").tqarg(memstat.used).tqarg(memstat.used+memstat.free)));
  149. }
  150. // read and evaluate all phone entries
  151. static gn_error read_phone_entries( const char *memtypestr, gn_memory_type memtype,
  152. KABC::AddresseeList *addrList )
  153. {
  154. gn_error error;
  155. if (m_progressDlg->wasCancelled())
  156. return GN_ERR_NONE;
  157. KProgress* progress = (KProgress*)m_progressDlg->progressBar();
  158. progress->setProgress(0);
  159. this_filter->processEvents();
  160. // get number of entries in this phone memory type (internal/SIM-card)
  161. gn_memory_status memstat;
  162. error = read_phone_memstat(memtype, &memstat);
  163. TQStringList addrlist;
  164. KABC::Address *addr;
  165. TQString s, country;
  166. progress->setTotalSteps(memstat.used);
  167. m_progressDlg->setLabel(i18n("<qt>Importing <b>%1</b> contacts from <b>%2</b> of the Mobile Phone.<br><br>%3</qt>")
  168. .tqarg(memstat.used)
  169. .tqarg(gn_memory_type2str(memtype))
  170. .tqarg(buildPhoneInfoString(memstat)) );
  171. int num_read = 0;
  172. for (int i = 1; !m_progressDlg->wasCancelled() && i <= memstat.used + memstat.free; i++) {
  173. error = gn_lib_phonebook_read_entry(state, memtype, i);
  174. GNOKII_CHECK_ERROR(error);
  175. progress->setProgress(num_read);
  176. this_filter->processEvents();
  177. if (error == GN_ERR_EMPTYLOCATION)
  178. continue;
  179. if (error == GN_ERR_INVALIDLOCATION)
  180. break;
  181. if (error == GN_ERR_INVALIDMEMORYTYPE)
  182. break;
  183. if (error == GN_ERR_NONE) {
  184. const int subentries_count = gn_lib_get_pb_num_subentries(state);
  185. const char *name = gn_lib_get_pb_name(state);
  186. const char *number = gn_lib_get_pb_number(state);
  187. GNOKII_DEBUG(TQString("%1: %2, num=%3, location=%4, group=%5, count=%6\n").tqarg(i)
  188. .tqarg(GN_FROM(name)).tqarg(GN_FROM(number))
  189. .tqarg(gn_lib_get_pb_location(state)).tqarg(gn_lib_get_pb_caller_group(state))
  190. .tqarg(subentries_count));
  191. KABC::Addressee *a = new KABC::Addressee();
  192. // try to split Name into FamilyName and GivenName
  193. s = GN_FROM(name).simplifyWhiteSpace();
  194. a->setFormattedName(s); // set formatted name as in Phone
  195. if (s.find(',') == -1) {
  196. // assumed format: "givenname [... familyname]"
  197. addrlist = TQStringList::split(' ', s);
  198. if (addrlist.count() == 1) {
  199. // only one string -> put it in the GivenName
  200. a->setGivenName(s);
  201. } else {
  202. // multiple strings -> split them.
  203. a->setFamilyName(addrlist.last().simplifyWhiteSpace());
  204. addrlist.remove(addrlist.last());
  205. a->setGivenName(addrlist.join(" ").simplifyWhiteSpace());
  206. }
  207. } else {
  208. // assumed format: "familyname, ... givenname"
  209. addrlist = TQStringList::split(',', s);
  210. a->setFamilyName(addrlist.first().simplifyWhiteSpace());
  211. addrlist.remove(addrlist.first());
  212. a->setGivenName(addrlist.join(" ").simplifyWhiteSpace());
  213. }
  214. a->insertCustom(APP, "X_GSM_CALLERGROUP", s.setNum(gn_lib_get_pb_caller_group(state)));
  215. a->insertCustom(APP, "X_GSM_STORE_AT", TQString("%1%2").tqarg(memtypestr).tqarg(gn_lib_get_pb_location(state)));
  216. // set ProductId
  217. a->setProductId(TQString("%1-%2-%3-%4").tqarg(APP).tqarg(model).tqarg(revision).tqarg(imei));
  218. // evaluate timestamp (ignore timezone)
  219. TQDateTime datetime;
  220. gn_timestamp ts = gn_lib_get_pb_date(state);
  221. if (ts.year<1998)
  222. datetime = TQDateTime::tqcurrentDateTime();
  223. else
  224. datetime = TQDateTime( TQDate(ts.year, ts.month, ts.day),
  225. TQTime(ts.hour, ts.minute, ts.second) );
  226. GNOKII_DEBUG(TQString(" date=%1\n").tqarg(datetime.toString()));
  227. a->setRevision(datetime);
  228. if (!subentries_count)
  229. a->insertPhoneNumber(KABC::PhoneNumber(number,
  230. KABC::PhoneNumber::Work | KABC::PhoneNumber::Pref));
  231. /* scan sub-entries */
  232. if (subentries_count)
  233. for (int n=0; n<subentries_count; n++) {
  234. gn_phonebook_entry_type entry_type;
  235. gn_phonebook_number_type number_type;
  236. const char *number;
  237. error = gn_lib_get_pb_subentry(state, n, &entry_type, &number_type, &number);
  238. GNOKII_CHECK_ERROR(error);
  239. TQString s = GN_FROM(number).simplifyWhiteSpace();
  240. GNOKII_DEBUG(TQString(" Subentry#%1, entry_type=%2, number_type=%3, number=%4\n")
  241. .tqarg(n).tqarg(entry_type).tqarg(number_type).tqarg(s));
  242. if (s.isEmpty())
  243. continue;
  244. switch(entry_type) {
  245. case GN_PHONEBOOK_ENTRY_Name:
  246. a->setName(s);
  247. break;
  248. case GN_PHONEBOOK_ENTRY_Email:
  249. a->insertEmail(s);
  250. break;
  251. case GN_PHONEBOOK_ENTRY_Postal:
  252. addrlist = TQStringList::split(';', s, true);
  253. addr = new KABC::Address(KABC::Address::Work);
  254. if (addrlist.count() <= 1) {
  255. addrlist = TQStringList::split(',', s, true);
  256. if (addrlist.count() > 1 ) {
  257. // assumed format: "Locality, ZIP, Country"
  258. addr->setLocality(addrlist[0]);
  259. addr->setPostalCode(addrlist[1]);
  260. if (!addrlist[2].isEmpty())
  261. addr->setCountry(i18n(GN_TO(addrlist[2])));
  262. } else {
  263. // no idea about the format, just store it.
  264. addr->setLocality(s);
  265. }
  266. } else {
  267. // assumed format: "POBox; Extended; Street; Locality; Region; ZIP [;Country]
  268. addr->setPostOfficeBox(addrlist[0]);
  269. addr->setExtended(addrlist[1]);
  270. addr->setStreet(addrlist[2]);
  271. addr->setLocality(addrlist[3]);
  272. addr->setRegion(addrlist[4]);
  273. addr->setPostalCode(addrlist[5]);
  274. country = addrlist[6];
  275. if (!country.isEmpty())
  276. addr->setCountry(i18n(GN_TO(country)));
  277. }
  278. a->insertAddress(*addr);
  279. delete addr;
  280. break;
  281. case GN_PHONEBOOK_ENTRY_Note:
  282. if (!a->note().isEmpty())
  283. s = "\n" + s;
  284. a->setNote(a->note()+s);
  285. break;
  286. case GN_PHONEBOOK_ENTRY_Number:
  287. enum KABC::PhoneNumber::Types phonetype;
  288. switch (number_type) {
  289. case GN_PHONEBOOK_NUMBER_Mobile: phonetype = KABC::PhoneNumber::Cell; break;
  290. case GN_PHONEBOOK_NUMBER_Fax: phonetype = KABC::PhoneNumber::Fax; break;
  291. case GN_PHONEBOOK_NUMBER_General:
  292. case GN_PHONEBOOK_NUMBER_Work: phonetype = KABC::PhoneNumber::Work; break;
  293. default:
  294. case GN_PHONEBOOK_NUMBER_Home: phonetype = KABC::PhoneNumber::Home; break;
  295. }
  296. //if (s == entry.number)
  297. // type = (KABC::PhoneNumber::Types) (phonetype | KABC::PhoneNumber::Pref);
  298. a->insertPhoneNumber(KABC::PhoneNumber(s, phonetype));
  299. break;
  300. case GN_PHONEBOOK_ENTRY_URL:
  301. a->setUrl(s);
  302. break;
  303. case GN_PHONEBOOK_ENTRY_Group:
  304. a->insertCategory(s);
  305. break;
  306. default:
  307. GNOKII_DEBUG(TQString(" Not handled id=%1, entry=%2\n")
  308. .tqarg(entry_type).tqarg(s));
  309. break;
  310. } // switch()
  311. } // if(subentry)
  312. // add only if entry was valid
  313. if (strlen(name) || strlen(number) || subentries_count)
  314. addrList->append(*a);
  315. // did we read all valid phonebook-entries ?
  316. num_read++;
  317. delete a;
  318. if (num_read >= memstat.used)
  319. break; // yes, all were read
  320. else
  321. continue; // no, we are still missing some.
  322. }
  323. GNOKII_CHECK_ERROR(error);
  324. }
  325. return GN_ERR_NONE;
  326. }
  327. // export to phone
  328. static gn_error xxport_phone_write_entry( int phone_location, gn_memory_type memtype,
  329. const KABC::Addressee *addr)
  330. {
  331. TQString s;
  332. /* initialize the phonebook entry values to zero */
  333. gn_lib_phonebook_prepare_write_entry(state);
  334. gn_lib_set_pb_location(state, phone_location);
  335. gn_lib_set_pb_name(state, GN_TO(addr->realName()));
  336. s = addr->phoneNumber(KABC::PhoneNumber::Pref).number();
  337. if (s.isEmpty())
  338. s = addr->phoneNumber(KABC::PhoneNumber::Work).number();
  339. if (s.isEmpty())
  340. s = addr->phoneNumber(KABC::PhoneNumber::Home).number();
  341. if (s.isEmpty())
  342. s = addr->phoneNumber(KABC::PhoneNumber::Cell).number();
  343. if (s.isEmpty() && addr->phoneNumbers().count()>0)
  344. s = (*addr->phoneNumbers().at(0)).number();
  345. s = makeValidPhone(s);
  346. gn_lib_set_pb_number(state, s.ascii());
  347. gn_lib_set_pb_memtype(state, memtype);
  348. TQString cg = addr->custom(APP, "X_GSM_CALLERGROUP");
  349. if (cg.isEmpty())
  350. gn_lib_set_pb_caller_group(state, GN_PHONEBOOK_GROUP_None); // default group
  351. else
  352. gn_lib_set_pb_caller_group(state, (gn_phonebook_group_type) cg.toInt());
  353. // set date/revision
  354. TQDateTime datetime = addr->revision();
  355. TQDate date(datetime.date());
  356. TQTime time(datetime.time());
  357. gn_timestamp ts;
  358. gn_timestamp_set( &ts, date.year(), date.month(), date.day(),
  359. time.hour(), time.minute(), time.second(), 0 );
  360. gn_lib_set_pb_date(state, ts);
  361. GNOKII_DEBUG(TQString("Write #%1: name=%2, number=%3\n").tqarg(phone_location)
  362. .tqarg(GN_FROM(gn_lib_get_pb_name(state))).tqarg(GN_FROM(gn_lib_get_pb_number(state))));
  363. const KABC::Address homeAddr = addr->address(KABC::Address::Home);
  364. const KABC::Address workAddr = addr->address(KABC::Address::Work);
  365. // add all phone numbers
  366. const KABC::PhoneNumber::List phoneList = addr->phoneNumbers();
  367. KABC::PhoneNumber::List::ConstIterator it;
  368. for ( it = phoneList.begin(); it != phoneList.end(); ++it ) {
  369. const KABC::PhoneNumber *phonenumber = &(*it);
  370. s = phonenumber->number();
  371. if (s.isEmpty()) continue;
  372. gn_phonebook_number_type type;
  373. int pn_type = phonenumber->type();
  374. if ((pn_type & KABC::PhoneNumber::Cell))
  375. type = GN_PHONEBOOK_NUMBER_Mobile;
  376. else if ((pn_type & KABC::PhoneNumber::Fax))
  377. type = GN_PHONEBOOK_NUMBER_Fax;
  378. else if ((pn_type & KABC::PhoneNumber::Home))
  379. type = GN_PHONEBOOK_NUMBER_Home;
  380. else if ((pn_type & KABC::PhoneNumber::Work))
  381. type = GN_PHONEBOOK_NUMBER_Work;
  382. else type = GN_PHONEBOOK_NUMBER_General;
  383. gn_lib_set_pb_subentry(state, -1 /* index to append entry */,
  384. GN_PHONEBOOK_ENTRY_Number, type, makeValidPhone(s).ascii());
  385. /*subentry->id = phone_location<<8+entry.subentries_count;*/
  386. }
  387. // add URL
  388. s = addr->url().prettyURL();
  389. if (!s.isEmpty()) {
  390. gn_lib_set_pb_subentry(state, -1 /* index to append entry */,
  391. GN_PHONEBOOK_ENTRY_URL, GN_PHONEBOOK_NUMBER_General, GN_TO(s));
  392. }
  393. // add E-Mails
  394. TQStringList emails = addr->emails();
  395. for (unsigned int n=0; n<emails.count(); n++) {
  396. s = emails[n].simplifyWhiteSpace();
  397. if (s.isEmpty()) continue;
  398. // only one email allowed if we have URLS, notes, addresses (to avoid phone limitations)
  399. if (n && !addr->url().isEmpty() && !addr->note().isEmpty() && addr->addresses().count()) {
  400. GNOKII_DEBUG(TQString(" DROPPED email %1 in favor of URLs, notes and addresses.\n")
  401. .tqarg(s));
  402. continue;
  403. }
  404. gn_lib_set_pb_subentry(state, -1 /* index to append entry */,
  405. GN_PHONEBOOK_ENTRY_Email, GN_PHONEBOOK_NUMBER_General, GN_TO(s));
  406. }
  407. // add Adresses
  408. const KABC::Address::List addresses = addr->addresses();
  409. KABC::Address::List::ConstIterator it2;
  410. for ( it2 = addresses.begin(); it2 != addresses.end(); ++it2 ) {
  411. const KABC::Address *Addr = &(*it2);
  412. if (Addr->isEmpty()) continue;
  413. TQStringList a;
  414. TQChar sem(';');
  415. TQString sem_repl(TQString::tqfromLatin1(","));
  416. a.append( Addr->postOfficeBox().replace( sem, sem_repl ) );
  417. a.append( Addr->extended() .replace( sem, sem_repl ) );
  418. a.append( Addr->street() .replace( sem, sem_repl ) );
  419. a.append( Addr->locality() .replace( sem, sem_repl ) );
  420. a.append( Addr->region() .replace( sem, sem_repl ) );
  421. a.append( Addr->postalCode() .replace( sem, sem_repl ) );
  422. a.append( Addr->country() .replace( sem, sem_repl ) );
  423. s = a.join(sem);
  424. gn_lib_set_pb_subentry(state, -1 /* index to append entry */,
  425. GN_PHONEBOOK_ENTRY_Postal, GN_PHONEBOOK_NUMBER_General, GN_TO(s));
  426. }
  427. // add Note
  428. s = addr->note().simplifyWhiteSpace();
  429. if (!s.isEmpty()) {
  430. gn_lib_set_pb_subentry(state, -1 /* index to append entry */,
  431. GN_PHONEBOOK_ENTRY_Note, GN_PHONEBOOK_NUMBER_General, GN_TO(s));
  432. }
  433. // debug output
  434. for (int st=0; st<gn_lib_get_pb_num_subentries(state); st++) {
  435. gn_phonebook_entry_type entry_type;
  436. gn_phonebook_number_type number_type;
  437. const char *number;
  438. gn_lib_get_pb_subentry(state, st, &entry_type, &number_type, &number);
  439. GNOKII_DEBUG(TQString(" SubTel #%1: entry_type=%2, number_type=%3, number=%4\n")
  440. .tqarg(st).tqarg(entry_type)
  441. .tqarg(number_type).tqarg(GN_FROM(number)));
  442. }
  443. gn_error error = gn_lib_phonebook_write_entry(state, memtype, phone_location);
  444. GNOKII_CHECK_ERROR(error);
  445. return error;
  446. }
  447. static gn_error xxport_phone_delete_entry( int phone_location, gn_memory_type memtype )
  448. {
  449. return gn_lib_phonebook_entry_delete(state, memtype, phone_location);
  450. }
  451. KABC::AddresseeList GNOKIIXXPort::importContacts( const TQString& ) const
  452. {
  453. KABC::AddresseeList addrList;
  454. if (KMessageBox::Continue != KMessageBox::warningContinueCancel(parentWidget(),
  455. i18n("<qt>Please connect your Mobile Phone to your computer and press "
  456. "<b>Continue</b> to start importing the personal contacts.<br><br>"
  457. "Please note that if your Mobile Phone is not properly connected "
  458. "the following detection phase might take up to two minutes, during which "
  459. "KAddressbook will behave unresponsively.</qt>") ))
  460. return addrList;
  461. m_progressDlg = new KProgressDialog( parentWidget(), "importwidget",
  462. i18n("Mobile Phone Import"),
  463. i18n("<qt><center>Establishing connection to the Mobile Phone.<br><br>"
  464. "Please wait...</center></qt>") );
  465. m_progressDlg->setAllowCancel(true);
  466. m_progressDlg->progressBar()->setProgress(0);
  467. m_progressDlg->progressBar()->setCenterIndicator(true);
  468. m_progressDlg->setModal(true);
  469. m_progressDlg->setInitialSize(TQSize(450,350));
  470. m_progressDlg->show();
  471. processEvents();
  472. m_progressDlg->setCursor( TQt::BusyCursor );
  473. TQString errStr = businit();
  474. m_progressDlg->unsetCursor();
  475. if (!errStr.isEmpty()) {
  476. KMessageBox::error(parentWidget(), errStr);
  477. delete m_progressDlg;
  478. return addrList;
  479. }
  480. GNOKII_DEBUG("GNOKII import filter started.\n");
  481. m_progressDlg->setButtonText(i18n("&Stop Import"));
  482. read_phone_entries("ME", GN_MT_ME, &addrList); // internal phone memory
  483. read_phone_entries("SM", GN_MT_SM, &addrList); // SIM card
  484. GNOKII_DEBUG("GNOKII import filter finished.\n");
  485. busterminate();
  486. delete m_progressDlg;
  487. return addrList;
  488. }
  489. bool GNOKIIXXPort::exportContacts( const KABC::AddresseeList &list, const TQString & )
  490. {
  491. if (KMessageBox::Continue != KMessageBox::warningContinueCancel(parentWidget(),
  492. i18n("<qt>Please connect your Mobile Phone to your computer and press "
  493. "<b>Continue</b> to start exporting the selected personal contacts.<br><br>"
  494. "Please note that if your Mobile Phone is not properly connected "
  495. "the following detection phase might take up to two minutes, during which "
  496. "KAddressbook will behave unresponsively.</qt>") ))
  497. return false;
  498. m_progressDlg = new KProgressDialog( parentWidget(), "importwidget",
  499. i18n("Mobile Phone Export"),
  500. i18n("<qt><center>Establishing connection to the Mobile Phone.<br><br>"
  501. "Please wait...</center></qt>") );
  502. m_progressDlg->setAllowCancel(true);
  503. m_progressDlg->progressBar()->setProgress(0);
  504. m_progressDlg->progressBar()->setCenterIndicator(true);
  505. m_progressDlg->setModal(true);
  506. m_progressDlg->setInitialSize(TQSize(450,350));
  507. m_progressDlg->show();
  508. processEvents();
  509. KProgress* progress = (KProgress*)m_progressDlg->progressBar();
  510. KABC::AddresseeList::ConstIterator it;
  511. TQStringList failedList;
  512. gn_error error;
  513. bool deleteLabelInitialized = false;
  514. m_progressDlg->setCursor( TQt::BusyCursor );
  515. TQString errStr = businit();
  516. m_progressDlg->unsetCursor();
  517. if (!errStr.isEmpty()) {
  518. KMessageBox::error(parentWidget(), errStr);
  519. delete m_progressDlg;
  520. return false;
  521. }
  522. GNOKII_DEBUG("GNOKII export filter started.\n");
  523. gn_memory_type memtype = GN_MT_ME; // internal phone memory
  524. int phone_count; // num entries in phone
  525. bool overwrite_phone_entries = false;
  526. int phone_entry_no, entries_written;
  527. bool entry_empty;
  528. // get number of entries in this phone memory
  529. gn_memory_status memstat;
  530. error = read_phone_memstat(memtype, &memstat);
  531. if (error == GN_ERR_NONE) {
  532. GNOKII_DEBUG("Writing to internal phone memory.\n");
  533. } else {
  534. memtype = GN_MT_SM; // try SIM card instead
  535. error = read_phone_memstat(memtype, &memstat);
  536. if (error != GN_ERR_NONE)
  537. goto finish;
  538. GNOKII_DEBUG("Writing to SIM card memory.\n");
  539. }
  540. phone_count = memstat.used;
  541. if (memstat.free >= (int) list.count()) {
  542. if (KMessageBox::No == KMessageBox::questionYesNo(parentWidget(),
  543. i18n("<qt>Do you want the selected contacts to be <b>appended</b> to "
  544. "the current mobile phonebook or should they <b>replace</b> all "
  545. "currently existing phonebook entries ?<br><br>"
  546. "Please note, that in case you choose to replace the phonebook "
  547. "entries, every contact in your phone will be deleted and only "
  548. "the newly exported contacts will be available from inside your phone.</qt>"),
  549. i18n("Export to Mobile Phone"),
  550. KGuiItem(i18n("&Append to Current Phonebook")),
  551. KGuiItem(i18n("&Replace Current Phonebook with New Contacts")) ) )
  552. overwrite_phone_entries = true;
  553. }
  554. progress->setTotalSteps(list.count());
  555. entries_written = 0;
  556. progress->setProgress(entries_written);
  557. m_progressDlg->setButtonText(i18n("&Stop Export"));
  558. m_progressDlg->setLabel(i18n("<qt>Exporting <b>%1</b> contacts to the <b>%2</b> "
  559. "of the Mobile Phone.<br><br>%3</qt>")
  560. .tqarg(list.count())
  561. .tqarg(gn_memory_type2str(memtype))
  562. .tqarg(buildPhoneInfoString(memstat)) );
  563. // Now run the loop...
  564. phone_entry_no = 1;
  565. for ( it = list.begin(); it != list.end(); ++it ) {
  566. const KABC::Addressee *addr = &(*it);
  567. if (addr->isEmpty())
  568. continue;
  569. // don't write back SIM-card entries !
  570. if (addr->custom(APP, "X_GSM_STORE_AT").startsWith("SM"))
  571. continue;
  572. progress->setProgress(entries_written++);
  573. try_next_phone_entry:
  574. this_filter->processEvents();
  575. if (m_progressDlg->wasCancelled())
  576. break;
  577. // End of phone memory reached ?
  578. if (phone_entry_no > (memstat.used + memstat.free))
  579. break;
  580. GNOKII_DEBUG(TQString("Try to write entry '%1' at phone_entry_no=%2, phone_count=%3\n")
  581. .tqarg(addr->realName()).tqarg(phone_entry_no).tqarg(phone_count));
  582. error = GN_ERR_NONE;
  583. // is this phone entry empty ?
  584. entry_empty = gn_lib_phonebook_entry_isempty(state, memtype, phone_entry_no);
  585. if (overwrite_phone_entries) {
  586. // overwrite this phonebook entry ...
  587. if (!entry_empty)
  588. phone_count--;
  589. error = xxport_phone_write_entry( phone_entry_no, memtype, addr);
  590. phone_entry_no++;
  591. } else {
  592. // add this phonebook entry if possible ...
  593. if (entry_empty) {
  594. error = xxport_phone_write_entry( phone_entry_no, memtype, addr);
  595. phone_entry_no++;
  596. } else {
  597. phone_entry_no++;
  598. goto try_next_phone_entry;
  599. }
  600. }
  601. if (error != GN_ERR_NONE)
  602. failedList.append(addr->realName());
  603. // break if we got an error on the first entry
  604. if (error != GN_ERR_NONE && it==list.begin())
  605. break;
  606. } // for()
  607. // if we wanted to overwrite all entries, make sure, that we also
  608. // delete all remaining entries in the mobile phone.
  609. while (overwrite_phone_entries && error==GN_ERR_NONE && phone_count>0) {
  610. if (m_progressDlg->wasCancelled())
  611. break;
  612. if (!deleteLabelInitialized) {
  613. m_progressDlg->setLabel(
  614. i18n("<qt><center>"
  615. "All selected contacts have been sucessfully copied to "
  616. "the Mobile Phone.<br><br>"
  617. "Please wait until all remaining orphaned contacts from "
  618. "the Mobile Phone have been deleted.</center></qt>") );
  619. m_progressDlg->setButtonText(i18n("&Stop Delete"));
  620. deleteLabelInitialized = true;
  621. progress->setTotalSteps(phone_count);
  622. entries_written = 0;
  623. progress->setProgress(entries_written);
  624. this_filter->processEvents();
  625. }
  626. if (phone_entry_no > (memstat.used + memstat.free))
  627. break;
  628. entry_empty = gn_lib_phonebook_entry_isempty(state, memtype, phone_entry_no);
  629. if (!entry_empty) {
  630. error = xxport_phone_delete_entry(phone_entry_no, memtype);
  631. phone_count--;
  632. progress->setProgress(++entries_written);
  633. this_filter->processEvents();
  634. }
  635. phone_entry_no++;
  636. }
  637. finish:
  638. m_progressDlg->setLabel(i18n("Export to phone finished."));
  639. this_filter->processEvents();
  640. GNOKII_DEBUG("GNOKII export filter finished.\n");
  641. busterminate();
  642. delete m_progressDlg;
  643. if (!failedList.isEmpty()) {
  644. GNOKII_DEBUG(TQString("Failed to export: %1\n").tqarg(failedList.join(", ")));
  645. KMessageBox::informationList(parentWidget(),
  646. i18n("<qt>The following contacts could not be exported to the Mobile Phone. "
  647. "Possible Reasons for this problem could be:<br><ul>"
  648. "<li>The contacts contain more information per entry than the phone can store.</li>"
  649. "<li>Your phone does not allow to store multiple addresses, emails, homepages, ...</li>"
  650. "<li>other storage size related problems.</li>"
  651. "</ul>"
  652. "To avoid those kind of problems in the future please reduce the amount of different "
  653. "fields in the above contacts.</qt>"),
  654. failedList,
  655. i18n("Mobile Phone Export") );
  656. }
  657. return true;
  658. }
  659. /******************************************************************************
  660. ******************************************************************************
  661. ******************************************************************************
  662. ******************************************************************************
  663. ******************************************************************************/
  664. #elif defined(HAVE_GNOKII_H)
  665. #ifdef __GNUC__
  666. # warning "Please upgrade your gnokii installation to at least version 0.6.13"
  667. # warning "Older gnokii versions below 0.6.13 are not binary compatible and"
  668. # warning "prevents KDE users to upgrade gnokii to newer versions later."
  669. #endif
  670. /* OLD GNOKII LIBRARIES (< 0.6.13) */
  671. /* import */
  672. static char *lockfile = NULL;
  673. static char manufacturer[64], model[GN_MODEL_MAX_LENGTH+1],
  674. revision[GN_REVISION_MAX_LENGTH+1], imei[GN_IMEI_MAX_LENGTH+1];
  675. static TQString PhoneProductId;
  676. static struct gn_statemachine state;
  677. static gn_data data;
  678. static void busterminate(void)
  679. {
  680. gn_sm_functions(GN_OP_Terminate, NULL, &state);
  681. if (lockfile) gn_tqdevice_unlock(lockfile);
  682. }
  683. static TQString businit(void)
  684. {
  685. gn_error error;
  686. char *aux;
  687. GNOKII_DEBUG( "Using old gnokii version." );
  688. #if defined(LIBGNOKII_VERSION)
  689. if (gn_cfg_read_default()<0)
  690. #else
  691. static char *BinDir;
  692. if (gn_cfg_read(&BinDir)<0)
  693. #endif
  694. return i18n("Failed to initialize the gnokii library.");
  695. if (!gn_cfg_phone_load("", &state))
  696. return i18n("Gnokii is not yet configured.");
  697. // uncomment to debug all gnokii communication on stderr.
  698. // gn_log_debug_mask = GN_LOG_T_STDERR;
  699. gn_data_clear(&data);
  700. aux = gn_cfg_get(gn_cfg_info, "global", "use_locking");
  701. // Defaults to 'no'
  702. if (aux && !strcmp(aux, "yes")) {
  703. lockfile = gn_tqdevice_lock(state.config.port_tqdevice);
  704. if (lockfile == NULL) {
  705. return i18n("Gnokii reports a 'Lock File Error'.\n "
  706. "Please exit all other running instances of gnokii, check if you have "
  707. "write permissions in the /var/lock directory and try again.");
  708. }
  709. }
  710. // Initialise the code for the GSM interface.
  711. int old_dcd = state.config.require_dcd; // work-around for older gnokii versions
  712. state.config.require_dcd = false;
  713. error = gn_gsm_initialise(&state);
  714. GNOKII_CHECK_ERROR(error);
  715. state.config.require_dcd = old_dcd;
  716. if (error != GN_ERR_NONE) {
  717. busterminate();
  718. return i18n("<qt><center>Mobile Phone interface initialization failed.<br><br>"
  719. "The returned error message was:<br><b>%1</b><br><br>"
  720. "You might try to run \"gnokii --identify\" on the command line to "
  721. "check any cable/transport issues and to verify if your gnokii "
  722. "configuration is correct.</center></qt>")
  723. .tqarg(gn_error_print(error));
  724. }
  725. // identify phone
  726. gn_data_clear(&data);
  727. data.manufacturer = manufacturer;
  728. data.model = model;
  729. data.revision = revision;
  730. data.imei = imei;
  731. TQCString unknown(GN_TO(i18n("Unknown")));
  732. qstrncpy(manufacturer, unknown, sizeof(manufacturer)-1);
  733. qstrncpy(model, unknown, sizeof(model)-1);
  734. qstrncpy(revision, unknown, sizeof(revision)-1);
  735. qstrncpy(imei, unknown, sizeof(imei)-1);
  736. if (m_progressDlg->wasCancelled())
  737. return TQString();
  738. else
  739. error = gn_sm_functions(GN_OP_Identify, &data, &state);
  740. GNOKII_CHECK_ERROR(error);
  741. GNOKII_DEBUG( TQString("Found mobile phone: %1 %2, Revision: %3, IMEI: %4\n")
  742. .tqarg(manufacturer, model, revision, imei) );
  743. PhoneProductId = TQString("%1-%2-%3-%4").tqarg(APP).tqarg(model).tqarg(revision).tqarg(imei);
  744. return TQString();
  745. }
  746. // get number of entries in this phone memory type (internal/SIM-card)
  747. static gn_error read_phone_memstat( const gn_memory_type memtype, gn_memory_status *memstat )
  748. {
  749. gn_error error;
  750. gn_data_clear(&data);
  751. memset(memstat, 0, sizeof(*memstat));
  752. memstat->memory_type = memtype;
  753. data.memory_status = memstat;
  754. error = gn_sm_functions(GN_OP_GetMemorytqStatus, &data, &state);
  755. GNOKII_CHECK_ERROR(error);
  756. if (error != GN_ERR_NONE) {
  757. switch (memtype) {
  758. case GN_MT_SM:
  759. // use at least 100 entries
  760. memstat->used = 0;
  761. memstat->free = 100;
  762. break;
  763. default:
  764. case GN_MT_ME:
  765. // Phone doesn't support ME (5110)
  766. memstat->used = memstat->free = 0;
  767. break;
  768. }
  769. }
  770. GNOKII_DEBUG( TQString("\n\nMobile phone memory status: Type: %1, used=%2, free=%3, total=%4\n\n")
  771. .tqarg(memtype).tqarg(memstat->used).tqarg(memstat->free).tqarg(memstat->used+memstat->free) );
  772. return error;
  773. }
  774. // read phone entry #index from memory #memtype
  775. static gn_error read_phone_entry( const int index, const gn_memory_type memtype, gn_phonebook_entry *entry )
  776. {
  777. gn_error error;
  778. entry->memory_type = memtype;
  779. entry->location = index;
  780. data.phonebook_entry = entry;
  781. error = gn_sm_functions(GN_OP_ReadPhonebook, &data, &state);
  782. GNOKII_CHECK_ERROR(error);
  783. return error;
  784. }
  785. static bool phone_entry_empty( const int index, const gn_memory_type memtype )
  786. {
  787. gn_error error;
  788. gn_phonebook_entry entry;
  789. entry.memory_type = memtype;
  790. entry.location = index;
  791. data.phonebook_entry = &entry;
  792. error = gn_sm_functions(GN_OP_ReadPhonebook, &data, &state);
  793. if (error == GN_ERR_EMPTYLOCATION)
  794. return true;
  795. GNOKII_CHECK_ERROR(error);
  796. if (error == GN_ERR_NONE && entry.empty)
  797. return true;
  798. return false;
  799. }
  800. static TQString buildPhoneInfoString( const gn_memory_status &memstat )
  801. {
  802. TQString format = TQString::tqfromLatin1("<tr><td><b>%1</b></td><td>%2</td></tr>");
  803. return TQString::tqfromLatin1("<b>%1</b><br><table>%2%3%4%5%6</table><br>")
  804. .tqarg(i18n("Mobile Phone information:"))
  805. .tqarg(format.tqarg(i18n("Manufacturer")).tqarg(GN_FROM(manufacturer)))
  806. .tqarg(format.tqarg(i18n("Phone model")).tqarg(GN_FROM(model)))
  807. .tqarg(format.tqarg(i18n("Revision")).tqarg(GN_FROM(revision)))
  808. .tqarg(format.tqarg(i18n("IMEI")).tqarg(GN_FROM(imei)))
  809. .tqarg(format.tqarg(i18n("Phonebook status"))
  810. .tqarg(i18n("%1 out of %2 contacts used").tqarg(memstat.used).tqarg(memstat.used+memstat.free)));
  811. }
  812. static TQString buildMemoryTypeString( gn_memory_type memtype )
  813. {
  814. switch (memtype) {
  815. case GN_MT_ME: return i18n("internal memory");
  816. case GN_MT_SM: return i18n("SIM-card memory");
  817. default: return i18n("unknown memory");
  818. }
  819. }
  820. // read and evaluate all phone entries
  821. static gn_error read_phone_entries( const char *memtypestr, gn_memory_type memtype,
  822. KABC::AddresseeList *addrList )
  823. {
  824. gn_error error;
  825. if (m_progressDlg->wasCancelled())
  826. return GN_ERR_NONE;
  827. KProgress* progress = (KProgress*)m_progressDlg->progressBar();
  828. progress->setProgress(0);
  829. this_filter->processEvents();
  830. // get number of entries in this phone memory type (internal/SIM-card)
  831. gn_memory_status memstat;
  832. error = read_phone_memstat(memtype, &memstat);
  833. gn_phonebook_entry entry;
  834. TQStringList addrlist;
  835. KABC::Address *addr;
  836. TQString s, country;
  837. progress->setTotalSteps(memstat.used);
  838. m_progressDlg->setLabel(i18n("<qt>Importing <b>%1</b> contacts from <b>%2</b> of the Mobile Phone.<br><br>%3</qt>")
  839. .tqarg(memstat.used)
  840. .tqarg(buildMemoryTypeString(memtype))
  841. .tqarg(buildPhoneInfoString(memstat)) );
  842. int num_read = 0;
  843. for (int i = 1; !m_progressDlg->wasCancelled() && i <= memstat.used + memstat.free; i++) {
  844. error = read_phone_entry( i, memtype, &entry );
  845. progress->setProgress(num_read);
  846. this_filter->processEvents();
  847. if (error == GN_ERR_EMPTYLOCATION)
  848. continue;
  849. if (error == GN_ERR_INVALIDLOCATION)
  850. break;
  851. if (error == GN_ERR_INVALIDMEMORYTYPE)
  852. break;
  853. if (error == GN_ERR_NONE) {
  854. GNOKII_DEBUG(TQString("%1: %2, num=%3, location=%4, group=%5, count=%6\n").tqarg(i).tqarg(GN_FROM(entry.name))
  855. .tqarg(GN_FROM(entry.number)).tqarg(entry.location).tqarg(entry.caller_group).tqarg(entry.subentries_count));
  856. KABC::Addressee *a = new KABC::Addressee();
  857. // try to split Name into FamilyName and GivenName
  858. s = GN_FROM(entry.name).simplifyWhiteSpace();
  859. a->setFormattedName(s); // set formatted name as in Phone
  860. if (s.find(',') == -1) {
  861. // assumed format: "givenname [... familyname]"
  862. addrlist = TQStringList::split(' ', s);
  863. if (addrlist.count() == 1) {
  864. // only one string -> put it in the GivenName
  865. a->setGivenName(s);
  866. } else {
  867. // multiple strings -> split them.
  868. a->setFamilyName(addrlist.last().simplifyWhiteSpace());
  869. addrlist.remove(addrlist.last());
  870. a->setGivenName(addrlist.join(" ").simplifyWhiteSpace());
  871. }
  872. } else {
  873. // assumed format: "familyname, ... givenname"
  874. addrlist = TQStringList::split(',', s);
  875. a->setFamilyName(addrlist.first().simplifyWhiteSpace());
  876. addrlist.remove(addrlist.first());
  877. a->setGivenName(addrlist.join(" ").simplifyWhiteSpace());
  878. }
  879. a->insertCustom(APP, "X_GSM_CALLERGROUP", s.setNum(entry.caller_group));
  880. a->insertCustom(APP, "X_GSM_STORE_AT", TQString("%1%2").tqarg(memtypestr).tqarg(entry.location));
  881. // set ProductId
  882. a->setProductId(PhoneProductId);
  883. // evaluate timestamp (ignore timezone)
  884. TQDateTime datetime;
  885. if (entry.date.year<1998)
  886. datetime = TQDateTime::tqcurrentDateTime();
  887. else
  888. datetime = TQDateTime( TQDate(entry.date.year, entry.date.month, entry.date.day),
  889. TQTime(entry.date.hour, entry.date.minute, entry.date.second) );
  890. GNOKII_DEBUG(TQString(" date=%1\n").tqarg(datetime.toString()));
  891. a->setRevision(datetime);
  892. if (!entry.subentries_count)
  893. a->insertPhoneNumber(KABC::PhoneNumber(entry.number, KABC::PhoneNumber::Work | KABC::PhoneNumber::Pref));
  894. /* scan sub-entries */
  895. if (entry.subentries_count)
  896. for (int n=0; n<entry.subentries_count; n++) {
  897. TQString s = GN_FROM(entry.subentries[n].data.number).simplifyWhiteSpace();
  898. GNOKII_DEBUG(TQString(" Subentry#%1, entry_type=%2, number_type=%3, number=%4\n")
  899. .tqarg(n).tqarg(entry.subentries[n].entry_type)
  900. .tqarg(entry.subentries[n].number_type).tqarg(s));
  901. if (s.isEmpty())
  902. continue;
  903. switch(entry.subentries[n].entry_type) {
  904. case GN_PHONEBOOK_ENTRY_Name:
  905. a->setName(s);
  906. break;
  907. case GN_PHONEBOOK_ENTRY_Email:
  908. a->insertEmail(s);
  909. break;
  910. case GN_PHONEBOOK_ENTRY_Postal:
  911. addrlist = TQStringList::split(';', s, true);
  912. addr = new KABC::Address(KABC::Address::Work);
  913. if (addrlist.count() <= 1) {
  914. addrlist = TQStringList::split(',', s, true);
  915. if (addrlist.count() > 1 ) {
  916. // assumed format: "Locality, ZIP, Country"
  917. addr->setLocality(addrlist[0]);
  918. addr->setPostalCode(addrlist[1]);
  919. if (!addrlist[2].isEmpty())
  920. addr->setCountry(i18n(GN_TO(addrlist[2])));
  921. } else {
  922. // no idea about the format, just store it.
  923. addr->setLocality(s);
  924. }
  925. } else {
  926. // assumed format: "POBox; Extended; Street; Locality; Region; ZIP [;Country]
  927. addr->setPostOfficeBox(addrlist[0]);
  928. addr->setExtended(addrlist[1]);
  929. addr->setStreet(addrlist[2]);
  930. addr->setLocality(addrlist[3]);
  931. addr->setRegion(addrlist[4]);
  932. addr->setPostalCode(addrlist[5]);
  933. country = addrlist[6];
  934. if (!country.isEmpty())
  935. addr->setCountry(i18n(GN_TO(country)));
  936. }
  937. a->insertAddress(*addr);
  938. delete addr;
  939. break;
  940. case GN_PHONEBOOK_ENTRY_Note:
  941. if (!a->note().isEmpty())
  942. s = "\n" + s;
  943. a->setNote(a->note()+s);
  944. break;
  945. case GN_PHONEBOOK_ENTRY_Number:
  946. enum KABC::PhoneNumber::Types phonetype;
  947. switch (entry.subentries[n].number_type) {
  948. case GN_PHONEBOOK_NUMBER_Mobile: phonetype = KABC::PhoneNumber::Cell; break;
  949. case GN_PHONEBOOK_NUMBER_Fax: phonetype = KABC::PhoneNumber::Fax; break;
  950. case GN_PHONEBOOK_NUMBER_General:
  951. case GN_PHONEBOOK_NUMBER_Work: phonetype = KABC::PhoneNumber::Work; break;
  952. default:
  953. case GN_PHONEBOOK_NUMBER_Home: phonetype = KABC::PhoneNumber::Home; break;
  954. }
  955. //if (s == entry.number)
  956. // type = (KABC::PhoneNumber::Types) (phonetype | KABC::PhoneNumber::Pref);
  957. a->insertPhoneNumber(KABC::PhoneNumber(s, phonetype));
  958. break;
  959. case GN_PHONEBOOK_ENTRY_URL:
  960. a->setUrl(s);
  961. break;
  962. case GN_PHONEBOOK_ENTRY_Group:
  963. a->insertCategory(s);
  964. break;
  965. default:
  966. GNOKII_DEBUG(TQString(" Not handled id=%1, entry=%2\n")
  967. .tqarg(entry.subentries[n].entry_type).tqarg(s));
  968. break;
  969. } // switch()
  970. } // if(subentry)
  971. // add only if entry was valid
  972. if (strlen(entry.name) || strlen(entry.number) || entry.subentries_count)
  973. addrList->append(*a);
  974. // did we read all valid phonebook-entries ?
  975. num_read++;
  976. delete a;
  977. if (num_read >= memstat.used)
  978. break; // yes, all were read
  979. else
  980. continue; // no, we are still missing some.
  981. }
  982. GNOKII_CHECK_ERROR(error);
  983. }
  984. return GN_ERR_NONE;
  985. }
  986. // export to phone
  987. static gn_error xxport_phone_write_entry( int phone_location, gn_memory_type memtype,
  988. const KABC::Addressee *addr)
  989. {
  990. gn_phonebook_entry entry;
  991. TQString s;
  992. memset(&entry, 0, sizeof(entry));
  993. strncpy(entry.name, GN_TO(addr->realName()), sizeof(entry.name)-1);
  994. s = addr->phoneNumber(KABC::PhoneNumber::Pref).number();
  995. if (s.isEmpty())
  996. s = addr->phoneNumber(KABC::PhoneNumber::Work).number();
  997. if (s.isEmpty())
  998. s = addr->phoneNumber(KABC::PhoneNumber::Home).number();
  999. if (s.isEmpty())
  1000. s = addr->phoneNumber(KABC::PhoneNumber::Cell).number();
  1001. if (s.isEmpty() && addr->phoneNumbers().count()>0)
  1002. s = (*addr->phoneNumbers().at(0)).number();
  1003. s = makeValidPhone(s);
  1004. strncpy(entry.number, s.ascii(), sizeof(entry.number)-1);
  1005. entry.memory_type = memtype;
  1006. TQString cg = addr->custom(APP, "X_GSM_CALLERGROUP");
  1007. if (cg.isEmpty())
  1008. entry.caller_group = 5; // default group
  1009. else
  1010. entry.caller_group = cg.toInt();
  1011. entry.location = phone_location;
  1012. // set date/revision
  1013. TQDateTime datetime = addr->revision();
  1014. TQDate date(datetime.date());
  1015. TQTime time(datetime.time());
  1016. entry.date.year = date.year();
  1017. entry.date.month = date.month();
  1018. entry.date.day = date.day();
  1019. entry.date.hour = time.hour();
  1020. entry.date.minute = time.minute();
  1021. entry.date.second = time.second();
  1022. GNOKII_DEBUG(TQString("Write #%1: name=%2, number=%3\n").tqarg(phone_location)
  1023. .tqarg(GN_FROM(entry.name)).tqarg(GN_FROM(entry.number)));
  1024. const KABC::Address homeAddr = addr->address(KABC::Address::Home);
  1025. const KABC::Address workAddr = addr->address(KABC::Address::Work);
  1026. entry.subentries_count = 0;
  1027. gn_phonebook_subentry *subentry = &entry.subentries[0];
  1028. // add all phone numbers
  1029. const KABC::PhoneNumber::List phoneList = addr->phoneNumbers();
  1030. KABC::PhoneNumber::List::ConstIterator it;
  1031. for ( it = phoneList.begin(); it != phoneList.end(); ++it ) {
  1032. const KABC::PhoneNumber *phonenumber = &(*it);
  1033. s = phonenumber->number();
  1034. if (s.isEmpty()) continue;
  1035. subentry->entry_type = GN_PHONEBOOK_ENTRY_Number;
  1036. gn_phonebook_number_type type;
  1037. int pn_type = phonenumber->type();
  1038. if ((pn_type & KABC::PhoneNumber::Cell))
  1039. type = GN_PHONEBOOK_NUMBER_Mobile;
  1040. else if ((pn_type & KABC::PhoneNumber::Fax))
  1041. type = GN_PHONEBOOK_NUMBER_Fax;
  1042. else if ((pn_type & KABC::PhoneNumber::Home))
  1043. type = GN_PHONEBOOK_NUMBER_Home;
  1044. else if ((pn_type & KABC::PhoneNumber::Work))
  1045. type = GN_PHONEBOOK_NUMBER_Work;
  1046. else type = GN_PHONEBOOK_NUMBER_General;
  1047. subentry->number_type = type;
  1048. strncpy(subentry->data.number, makeValidPhone(s).ascii(), sizeof(subentry->data.number)-1);
  1049. subentry->id = phone_location<<8+entry.subentries_count;
  1050. entry.subentries_count++;
  1051. subentry++;
  1052. if (entry.subentries_count >= GN_PHONEBOOK_SUBENTRIES_MAX_NUMBER)
  1053. break; // Phonebook full
  1054. }
  1055. // add URL
  1056. s = addr->url().prettyURL();
  1057. if (!s.isEmpty() && (entry.subentries_count<GN_PHONEBOOK_SUBENTRIES_MAX_NUMBER)) {
  1058. subentry->entry_type = GN_PHONEBOOK_ENTRY_URL;
  1059. strncpy(subentry->data.number, GN_TO(s), sizeof(subentry->data.number)-1);
  1060. entry.subentries_count++;
  1061. subentry++;
  1062. }
  1063. // add E-Mails
  1064. TQStringList emails = addr->emails();
  1065. for (unsigned int n=0; n<emails.count(); n++) {
  1066. if (entry.subentries_count >= GN_PHONEBOOK_SUBENTRIES_MAX_NUMBER)
  1067. break; // Phonebook full
  1068. s = emails[n].simplifyWhiteSpace();
  1069. if (s.isEmpty()) continue;
  1070. // only one email allowed if we have URLS, notes, addresses (to avoid phone limitations)
  1071. if (n && !addr->url().isEmpty() && !addr->note().isEmpty() && addr->addresses().count()) {
  1072. GNOKII_DEBUG(TQString(" DROPPED email %1 in favor of URLs, notes and addresses.\n")
  1073. .tqarg(s));
  1074. continue;
  1075. }
  1076. subentry->entry_type = GN_PHONEBOOK_ENTRY_Email;
  1077. strncpy(subentry->data.number, GN_TO(s), sizeof(subentry->data.number)-1);
  1078. entry.subentries_count++;
  1079. subentry++;
  1080. }
  1081. // add Adresses
  1082. const KABC::Address::List addresses = addr->addresses();
  1083. KABC::Address::List::ConstIterator it2;
  1084. for ( it2 = addresses.begin(); it2 != addresses.end(); ++it2 ) {
  1085. if (entry.subentries_count >= GN_PHONEBOOK_SUBENTRIES_MAX_NUMBER)
  1086. break; // Phonebook full
  1087. const KABC::Address *Addr = &(*it2);
  1088. if (Addr->isEmpty()) continue;
  1089. subentry->entry_type = GN_PHONEBOOK_ENTRY_Postal;
  1090. TQStringList a;
  1091. TQChar sem(';');
  1092. TQString sem_repl(TQString::tqfromLatin1(","));
  1093. a.append( Addr->postOfficeBox().replace( sem, sem_repl ) );
  1094. a.append( Addr->extended() .replace( sem, sem_repl ) );
  1095. a.append( Addr->street() .replace( sem, sem_repl ) );
  1096. a.append( Addr->locality() .replace( sem, sem_repl ) );
  1097. a.append( Addr->region() .replace( sem, sem_repl ) );
  1098. a.append( Addr->postalCode() .replace( sem, sem_repl ) );
  1099. a.append( Addr->country() .replace( sem, sem_repl ) );
  1100. s = a.join(sem);
  1101. strncpy(subentry->data.number, GN_TO(s), sizeof(subentry->data.number)-1);
  1102. entry.subentries_count++;
  1103. subentry++;
  1104. }
  1105. // add Note
  1106. s = addr->note().simplifyWhiteSpace();
  1107. if (!s.isEmpty() && (entry.subentries_count<GN_PHONEBOOK_SUBENTRIES_MAX_NUMBER)) {
  1108. subentry->entry_type = GN_PHONEBOOK_ENTRY_Note;
  1109. strncpy(subentry->data.number, GN_TO(s), sizeof(subentry->data.number)-1);
  1110. entry.subentries_count++;
  1111. subentry++;
  1112. }
  1113. // debug output
  1114. for (int st=0; st<entry.subentries_count; st++) {
  1115. gn_phonebook_subentry *subentry = &entry.subentries[st];
  1116. GNOKII_DEBUG(TQString(" SubTel #%1: entry_type=%2, number_type=%3, number=%4\n")
  1117. .tqarg(st).tqarg(subentry->entry_type)
  1118. .tqarg(subentry->number_type).tqarg(GN_FROM(subentry->data.number)));
  1119. }
  1120. data.phonebook_entry = &entry;
  1121. gn_error error = gn_sm_functions(GN_OP_WritePhonebook, &data, &state);
  1122. GNOKII_CHECK_ERROR(error);
  1123. return error;
  1124. }
  1125. static gn_error xxport_phone_delete_entry( int phone_location, gn_memory_type memtype )
  1126. {
  1127. gn_phonebook_entry entry;
  1128. memset(&entry, 0, sizeof(entry));
  1129. entry.empty = 1;
  1130. entry.memory_type = memtype;
  1131. entry.location = phone_location;
  1132. data.phonebook_entry = &entry;
  1133. GNOKII_DEBUG(TQString("Deleting entry %1\n").tqarg(phone_location));
  1134. gn_error error = gn_sm_functions(GN_OP_WritePhonebook, &data, &state);
  1135. GNOKII_CHECK_ERROR(error);
  1136. return error;
  1137. }
  1138. KABC::AddresseeList GNOKIIXXPort::importContacts( const TQString& ) const
  1139. {
  1140. KABC::AddresseeList addrList;
  1141. if (KMessageBox::Continue != KMessageBox::warningContinueCancel(parentWidget(),
  1142. i18n("<qt>Please connect your Mobile Phone to your computer and press "
  1143. "<b>Continue</b> to start importing the personal contacts.<br><br>"
  1144. "Please note that if your Mobile Phone is not properly connected "
  1145. "the following detection phase might take up to two minutes, during which "
  1146. "KAddressbook will behave unresponsively.</qt>") ))
  1147. return addrList;
  1148. m_progressDlg = new KProgressDialog( parentWidget(), "importwidget",
  1149. i18n("Mobile Phone Import"),
  1150. i18n("<qt><center>Establishing connection to the Mobile Phone.<br><br>"
  1151. "Please wait...</center></qt>") );
  1152. m_progressDlg->setAllowCancel(true);
  1153. m_progressDlg->progressBar()->setProgress(0);
  1154. m_progressDlg->progressBar()->setCenterIndicator(true);
  1155. m_progressDlg->setModal(true);
  1156. m_progressDlg->setInitialSize(TQSize(450,350));
  1157. m_progressDlg->show();
  1158. processEvents();
  1159. m_progressDlg->setCursor( TQt::BusyCursor );
  1160. TQString errStr = businit();
  1161. m_progressDlg->unsetCursor();
  1162. if (!errStr.isEmpty()) {
  1163. KMessageBox::error(parentWidget(), errStr);
  1164. delete m_progressDlg;
  1165. return addrList;
  1166. }
  1167. GNOKII_DEBUG("GNOKII import filter started.\n");
  1168. m_progressDlg->setButtonText(i18n("&Stop Import"));
  1169. read_phone_entries("ME", GN_MT_ME, &addrList); // internal phone memory
  1170. read_phone_entries("SM", GN_MT_SM, &addrList); // SIM card
  1171. GNOKII_DEBUG("GNOKII import filter finished.\n");
  1172. busterminate();
  1173. delete m_progressDlg;
  1174. return addrList;
  1175. }
  1176. bool GNOKIIXXPort::exportContacts( const KABC::AddresseeList &list, const TQString & )
  1177. {
  1178. if (KMessageBox::Continue != KMessageBox::warningContinueCancel(parentWidget(),
  1179. i18n("<qt>Please connect your Mobile Phone to your computer and press "
  1180. "<b>Continue</b> to start exporting the selected personal contacts.<br><br>"
  1181. "Please note that if your Mobile Phone is not properly connected "
  1182. "the following detection phase might take up to two minutes, during which "
  1183. "KAddressbook will behave unresponsively.</qt>") ))
  1184. return false;
  1185. m_progressDlg = new KProgressDialog( parentWidget(), "importwidget",
  1186. i18n("Mobile Phone Export"),
  1187. i18n("<qt><center>Establishing connection to the Mobile Phone.<br><br>"
  1188. "Please wait...</center></qt>") );
  1189. m_progressDlg->setAllowCancel(true);
  1190. m_progressDlg->progressBar()->setProgress(0);
  1191. m_progressDlg->progressBar()->setCenterIndicator(true);
  1192. m_progressDlg->setModal(true);
  1193. m_progressDlg->setInitialSize(TQSize(450,350));
  1194. m_progressDlg->show();
  1195. processEvents();
  1196. KProgress* progress = (KProgress*)m_progressDlg->progressBar();
  1197. KABC::AddresseeList::ConstIterator it;
  1198. TQStringList failedList;
  1199. gn_error error;
  1200. bool deleteLabelInitialized = false;
  1201. m_progressDlg->setCursor( TQt::BusyCursor );
  1202. TQString errStr = businit();
  1203. m_progressDlg->unsetCursor();
  1204. if (!errStr.isEmpty()) {
  1205. KMessageBox::error(parentWidget(), errStr);
  1206. delete m_progressDlg;
  1207. return false;
  1208. }
  1209. GNOKII_DEBUG("GNOKII export filter started.\n");
  1210. gn_memory_type memtype = GN_MT_ME; // internal phone memory
  1211. int phone_count; // num entries in phone
  1212. bool overwrite_phone_entries = false;
  1213. int phone_entry_no, entries_written;
  1214. bool entry_empty;
  1215. // get number of entries in this phone memory
  1216. gn_memory_status memstat;
  1217. error = read_phone_memstat(memtype, &memstat);
  1218. if (error == GN_ERR_NONE) {
  1219. GNOKII_DEBUG("Writing to internal phone memory.\n");
  1220. } else {
  1221. memtype = GN_MT_SM; // try SIM card instead
  1222. error = read_phone_memstat(memtype, &memstat);
  1223. if (error != GN_ERR_NONE)
  1224. goto finish;
  1225. GNOKII_DEBUG("Writing to SIM card memory.\n");
  1226. }
  1227. phone_count = memstat.used;
  1228. if (memstat.free >= (int) list.count()) {
  1229. if (KMessageBox::No == KMessageBox::questionYesNo(parentWidget(),
  1230. i18n("<qt>Do you want the selected contacts to be <b>appended</b> to "
  1231. "the current mobile phonebook or should they <b>replace</b> all "
  1232. "currently existing phonebook entries ?<br><br>"
  1233. "Please note, that in case you choose to replace the phonebook "
  1234. "entries, every contact in your phone will be deleted and only "
  1235. "the newly exported contacts will be available from inside your phone.</qt>"),
  1236. i18n("Export to Mobile Phone"),
  1237. KGuiItem(i18n("&Append to Current Phonebook")),
  1238. KGuiItem(i18n("&Replace Current Phonebook with New Contacts")) ) )
  1239. overwrite_phone_entries = true;
  1240. }
  1241. progress->setTotalSteps(list.count());
  1242. entries_written = 0;
  1243. progress->setProgress(entries_written);
  1244. m_progressDlg->setButtonText(i18n("&Stop Export"));
  1245. m_progressDlg->setLabel(i18n("<qt>Exporting <b>%1</b> contacts to the <b>%2</b> "
  1246. "of the Mobile Phone.<br><br>%3</qt>")
  1247. .tqarg(list.count())
  1248. .tqarg(buildMemoryTypeString(memtype))
  1249. .tqarg(buildPhoneInfoString(memstat)) );
  1250. // Now run the loop...
  1251. phone_entry_no = 1;
  1252. for ( it = list.begin(); it != list.end(); ++it ) {
  1253. const KABC::Addressee *addr = &(*it);
  1254. if (addr->isEmpty())
  1255. continue;
  1256. // don't write back SIM-card entries !
  1257. if (addr->custom(APP, "X_GSM_STORE_AT").startsWith("SM"))
  1258. continue;
  1259. progress->setProgress(entries_written++);
  1260. try_next_phone_entry:
  1261. this_filter->processEvents();
  1262. if (m_progressDlg->wasCancelled())
  1263. break;
  1264. // End of phone memory reached ?
  1265. if (phone_entry_no > (memstat.used + memstat.free))
  1266. break;
  1267. GNOKII_DEBUG(TQString("Try to write entry '%1' at phone_entry_no=%2, phone_count=%3\n")
  1268. .tqarg(addr->realName()).tqarg(phone_entry_no).tqarg(phone_count));
  1269. error = GN_ERR_NONE;
  1270. // is this phone entry empty ?
  1271. entry_empty = phone_entry_empty(phone_entry_no, memtype);
  1272. if (overwrite_phone_entries) {
  1273. // overwrite this phonebook entry ...
  1274. if (!entry_empty)
  1275. phone_count--;
  1276. error = xxport_phone_write_entry( phone_entry_no, memtype, addr);
  1277. phone_entry_no++;
  1278. } else {
  1279. // add this phonebook entry if possible ...
  1280. if (entry_empty) {
  1281. error = xxport_phone_write_entry( phone_entry_no, memtype, addr);
  1282. phone_entry_no++;
  1283. } else {
  1284. phone_entry_no++;
  1285. goto try_next_phone_entry;
  1286. }
  1287. }
  1288. if (error != GN_ERR_NONE)
  1289. failedList.append(addr->realName());
  1290. // break if we got an error on the first entry
  1291. if (error != GN_ERR_NONE && it==list.begin())
  1292. break;
  1293. } // for()
  1294. // if we wanted to overwrite all entries, make sure, that we also
  1295. // delete all remaining entries in the mobile phone.
  1296. while (overwrite_phone_entries && error==GN_ERR_NONE && phone_count>0) {
  1297. if (m_progressDlg->wasCancelled())
  1298. break;
  1299. if (!deleteLabelInitialized) {
  1300. m_progressDlg->setLabel(
  1301. i18n("<qt><center>"
  1302. "All selected contacts have been sucessfully copied to "
  1303. "the Mobile Phone.<br><br>"
  1304. "Please wait until all remaining orphaned contacts from "
  1305. "the Mobile Phone have been deleted.</center></qt>") );
  1306. m_progressDlg->setButtonText(i18n("&Stop Delete"));
  1307. deleteLabelInitialized = true;
  1308. progress->setTotalSteps(phone_count);
  1309. entries_written = 0;
  1310. progress->setProgress(entries_written);
  1311. this_filter->processEvents();
  1312. }
  1313. if (phone_entry_no > (memstat.used + memstat.free))
  1314. break;
  1315. entry_empty = phone_entry_empty(phone_entry_no, memtype);
  1316. if (!entry_empty) {
  1317. error = xxport_phone_delete_entry(phone_entry_no, memtype);
  1318. phone_count--;
  1319. progress->setProgress(++entries_written);
  1320. this_filter->processEvents();
  1321. }
  1322. phone_entry_no++;
  1323. }
  1324. finish:
  1325. m_progressDlg->setLabel(i18n("Export to phone finished."));
  1326. this_filter->processEvents();
  1327. GNOKII_DEBUG("GNOKII export filter finished.\n");
  1328. busterminate();
  1329. delete m_progressDlg;
  1330. if (!failedList.isEmpty()) {
  1331. GNOKII_DEBUG(TQString("Failed to export: %1\n").tqarg(failedList.join(", ")));
  1332. KMessageBox::informationList(parentWidget(),
  1333. i18n("<qt>The following contacts could not be exported to the Mobile Phone. "
  1334. "Possible Reasons for this problem could be:<br><ul>"
  1335. "<li>The contacts contain more information per entry than the phone can store.</li>"
  1336. "<li>Your phone does not allow to store multiple addresses, emails, homepages, ...</li>"
  1337. "<li>other storage size related problems.</li>"
  1338. "</ul>"
  1339. "To avoid those kind of problems in the future please reduce the amount of different "
  1340. "fields in the above contacts.</qt>"),
  1341. failedList,
  1342. i18n("Mobile Phone Export") );
  1343. }
  1344. return true;
  1345. }
  1346. /******************************************************************************
  1347. ******************************************************************************
  1348. ******************************************************************************
  1349. ******************************************************************************
  1350. ******************************************************************************/
  1351. #else /* no gnokii installed */
  1352. KABC::AddresseeList GNOKIIXXPort::importContacts( const TQString& ) const
  1353. {
  1354. KABC::AddresseeList addrList;
  1355. KMessageBox::error(parentWidget(), i18n("Gnokii interface is not available.\n"
  1356. "Please ask your distributor to add gnokii at compile time."));
  1357. return addrList;
  1358. }
  1359. bool GNOKIIXXPort::exportContacts( const KABC::AddresseeList &list, const TQString & )
  1360. {
  1361. Q_UNUSED(list);
  1362. KMessageBox::error(parentWidget(), i18n("Gnokii interface is not available.\n"
  1363. "Please ask your distributor to add gnokii at compile time."));
  1364. return true;
  1365. }
  1366. #endif /* END OF GNOKII LIB SWITCH */
  1367. /******************************************************************************
  1368. ******************************************************************************
  1369. ******************************************************************************
  1370. ******************************************************************************
  1371. ******************************************************************************/
  1372. #include "gnokii_xxport.moc"
  1373. /* vim: set sts=4 ts=4 sw=4: */