kaddressbook

vcard_xxport.cpp
1 /*
2  This file is part of KAddressbook.
3  Copyright (c) 2003 Tobias Koenig <tokoe@kde.org>
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9 
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU General Public License for more details.
14 
15  You should have received a copy of the GNU General Public License
16  along with this program; if not, write to the Free Software
17  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 
19  As a special exception, permission is given to link this program
20  with any edition of TQt, and distribute the resulting executable,
21  without including the source code for TQt in the source distribution.
22 */
23 
24 #include <tqcheckbox.h>
25 #include <tqfile.h>
26 #include <tqfont.h>
27 #include <tqlabel.h>
28 #include <tqlayout.h>
29 #include <tqpushbutton.h>
30 
31 #include <tdeabc/vcardconverter.h>
32 #include <kdialogbase.h>
33 #include <tdefiledialog.h>
34 #include <tdeio/netaccess.h>
35 #include <tdelocale.h>
36 #include <tdemessagebox.h>
37 #include <tdetempfile.h>
38 #include <kurl.h>
39 #include <tdeapplication.h>
40 #include <libtdepim/addresseeview.h>
41 
42 #include "config.h" // ??
43 
44 #include "gpgmepp/context.h"
45 #include "gpgmepp/data.h"
46 #include "gpgmepp/key.h"
47 #include "qgpgme/dataprovider.h"
48 
49 #include "xxportmanager.h"
50 
51 #include "vcard_xxport.h"
52 
53 K_EXPORT_KADDRESSBOOK_XXFILTER( libkaddrbk_vcard_xxport, VCardXXPort )
54 
55 class VCardViewerDialog : public KDialogBase
56 {
57  public:
58  VCardViewerDialog( const TDEABC::Addressee::List &list,
59  TQWidget *parent, const char *name = 0 );
60 
61  TDEABC::Addressee::List contacts() const;
62 
63  protected:
64  void slotUser1();
65  void slotUser2();
66  void slotApply();
67  void slotCancel();
68 
69  private:
70  void updateView();
71 
72  KPIM::AddresseeView *mView;
73 
74  TDEABC::Addressee::List mContacts;
75  TDEABC::Addressee::List::Iterator mIt;
76 };
77 
78 class VCardExportSelectionDialog : public KDialogBase
79 {
80  public:
81  VCardExportSelectionDialog( TQWidget *parent, const char *name = 0 );
82  ~VCardExportSelectionDialog();
83 
84  bool exportPrivateFields() const;
85  bool exportBusinessFields() const;
86  bool exportOtherFields() const;
87  bool exportEncryptionKeys() const;
88 
89  private:
90  TQCheckBox *mPrivateBox;
91  TQCheckBox *mBusinessBox;
92  TQCheckBox *mOtherBox;
93  TQCheckBox *mEncryptionKeys;
94 };
95 
96 VCardXXPort::VCardXXPort( TDEABC::AddressBook *ab, TQWidget *parent, const char *name )
97  : KAB::XXPort( ab, parent, name )
98 {
99  createImportAction( i18n( "Import vCard..." ) );
100  createExportAction( i18n( "Export vCard 2.1..." ), "v21" );
101  createExportAction( i18n( "Export vCard 3.0..." ), "v30" );
102 }
103 
104 bool VCardXXPort::exportContacts( const TDEABC::AddresseeList &addrList, const TQString &data )
105 {
106  TDEABC::VCardConverter converter;
107  KURL url;
108  TDEABC::AddresseeList list;
109 
110  list = filterContacts( addrList );
111 
112  bool ok = true;
113  if ( list.isEmpty() ) {
114  return ok;
115  } else if ( list.count() == 1 ) {
116  url = KFileDialog::getSaveURL( list[ 0 ].givenName() + "_" + list[ 0 ].familyName() + ".vcf" );
117  if ( url.isEmpty() )
118  return true;
119 
120  if ( data == "v21" )
121 #if defined(KABC_VCARD_ENCODING_FIX)
122  ok = doExport( url, converter.createVCardsRaw( list, TDEABC::VCardConverter::v2_1 ) );
123  else
124  ok = doExport( url, converter.createVCardsRaw( list, TDEABC::VCardConverter::v3_0 ) );
125 #else
126  ok = doExport( url, converter.createVCards( list, TDEABC::VCardConverter::v2_1 ) );
127  else
128  ok = doExport( url, converter.createVCards( list, TDEABC::VCardConverter::v3_0 ) );
129 #endif
130  } else {
131  TQString msg = i18n( "You have selected a list of contacts, shall they be "
132  "exported to several files?" );
133 
134  switch ( KMessageBox::questionYesNo( parentWidget(), msg, TQString(), i18n("Export to Several Files"), i18n("Export to One File") ) ) {
135  case KMessageBox::Yes: {
136  KURL baseUrl = KFileDialog::getExistingURL();
137  if ( baseUrl.isEmpty() )
138  return true;
139 
140  TDEABC::AddresseeList::ConstIterator it;
141  uint counter = 0;
142  for ( it = list.begin(); it != list.end(); ++it ) {
143  TQString testUrl;
144  if ( (*it).givenName().isEmpty() && (*it).familyName().isEmpty() )
145  testUrl = baseUrl.url() + "/" + (*it).organization();
146  else
147  testUrl = baseUrl.url() + "/" + (*it).givenName() + "_" + (*it).familyName();
148 
149  if ( TDEIO::NetAccess::exists( testUrl + (counter == 0 ? "" : TQString::number( counter )) + ".vcf", false, parentWidget() ) ) {
150  counter++;
151  url = testUrl + TQString::number( counter ) + ".vcf";
152  } else
153  url = testUrl + ".vcf";
154 
155  bool tmpOk;
156  TDEABC::AddresseeList tmpList;
157  tmpList.append( *it );
158 
159  if ( data == "v21" )
160 #if defined(KABC_VCARD_ENCODING_FIX)
161  tmpOk = doExport( url, converter.createVCardsRaw( tmpList, TDEABC::VCardConverter::v2_1 ) );
162  else
163  tmpOk = doExport( url, converter.createVCardsRaw( tmpList, TDEABC::VCardConverter::v3_0 ) );
164 #else
165  tmpOk = doExport( url, converter.createVCards( tmpList, TDEABC::VCardConverter::v2_1 ) );
166  else
167  tmpOk = doExport( url, converter.createVCards( tmpList, TDEABC::VCardConverter::v3_0 ) );
168 #endif
169  ok = ok && tmpOk;
170  }
171  break;
172  }
173  case KMessageBox::No:
174  default: {
175  url = KFileDialog::getSaveURL( "addressbook.vcf" );
176  if ( url.isEmpty() )
177  return true;
178 
179  if ( data == "v21" )
180 #if defined(KABC_VCARD_ENCODING_FIX)
181  ok = doExport( url, converter.createVCardsRaw( list, TDEABC::VCardConverter::v2_1 ) );
182  else
183  ok = doExport( url, converter.createVCardsRaw( list, TDEABC::VCardConverter::v3_0 ) );
184 #else
185  ok = doExport( url, converter.createVCards( list, TDEABC::VCardConverter::v2_1 ) );
186  else
187  ok = doExport( url, converter.createVCards( list, TDEABC::VCardConverter::v3_0 ) );
188 #endif
189  }
190  }
191  }
192 
193  return ok;
194 }
195 
196 TDEABC::AddresseeList VCardXXPort::importContacts( const TQString& ) const
197 {
198  TQString fileName;
199  TDEABC::AddresseeList addrList;
200  KURL::List urls;
201 
202  if ( !XXPortManager::importData.isEmpty() ) {
203 #if defined(KABC_VCARD_ENCODING_FIX)
204  TQCString data = XXPortManager::importData.ascii();
205  addrList = parseVCard( data );
206 #else
207  addrList = parseVCard( XXPortManager::importData );
208 #endif
209  } else {
210  if ( XXPortManager::importURL.isEmpty() )
211  urls = KFileDialog::getOpenURLs( TQString(), "*.vcf|vCards", parentWidget(),
212  i18n( "Select vCard to Import" ) );
213  else
214  urls.append( XXPortManager::importURL );
215 
216  if ( urls.count() == 0 )
217  return addrList;
218 
219  TQString caption( i18n( "vCard Import Failed" ) );
220  bool anyFailures = false;
221  KURL::List::Iterator it;
222  for ( it = urls.begin(); it != urls.end(); ++it ) {
223  if ( TDEIO::NetAccess::download( *it, fileName, parentWidget() ) ) {
224 
225  TQFile file( fileName );
226 
227  if ( file.open( IO_ReadOnly ) ) {
228 #if defined(KABC_VCARD_ENCODING_FIX)
229  TQByteArray data = file.readAll();
230  file.close();
231  if ( data.size() > 0 )
232  addrList += parseVCard( data );
233 #else
234  TQByteArray rawData = file.readAll();
235  file.close();
236  if ( rawData.size() > 0 ) {
237 
238  TQString vCardText;
239 
240  // With version 3.0, vCards are encoded with UTF-8 by default. Otherwise, use fromLatin1()
241  // and hope that are fields are encoded correctly.
242  bool useUtf8;
243  TQString tmp = TQString::fromLatin1(rawData).lower();
244  int ver = tmp.find("version:");
245  if (ver == -1) {
246  // no version info, assume utf8
247  useUtf8 = true;
248  }
249  else {
250  float vCardVersion = tmp.mid(ver + 8, tmp.find("\n", ver)).toFloat();
251  useUtf8 = (vCardVersion >= 3.0);
252  }
253 
254  if (useUtf8) {
255  vCardText = TQString::fromUtf8( rawData );
256  }
257  else {
258  vCardText = TQString::fromLatin1( rawData );
259  }
260  addrList += parseVCard( vCardText );
261  }
262 #endif
263  TDEIO::NetAccess::removeTempFile( fileName );
264  } else {
265  TQString text = i18n( "<qt>When trying to read the vCard, there was an error opening the file '%1': %2</qt>" );
266  text = text.arg( (*it).url() );
267  text = text.arg( kapp->translate( "TQFile",
268  TQString(file.errorString()).latin1() ) );
269  KMessageBox::error( parentWidget(), text, caption );
270  anyFailures = true;
271  }
272  } else {
273  TQString text = i18n( "<qt>Unable to access vCard: %1</qt>" );
274  text = text.arg( TDEIO::NetAccess::lastErrorString() );
275  KMessageBox::error( parentWidget(), text, caption );
276  anyFailures = true;
277  }
278  }
279 
280  if ( !XXPortManager::importURL.isEmpty() ) { // a vcard was passed via cmd
281  if ( addrList.isEmpty() ) {
282  if ( anyFailures && urls.count() > 1 )
283  KMessageBox::information( parentWidget(),
284  i18n( "No contacts were imported, due to errors with the vCards." ) );
285  else if ( !anyFailures )
286  KMessageBox::information( parentWidget(), i18n( "The vCard does not contain any contacts." ) );
287  } else {
288  VCardViewerDialog dlg( addrList, parentWidget() );
289  dlg.exec();
290  addrList = dlg.contacts();
291  }
292  }
293  }
294 
295  return addrList;
296 }
297 
298 #if defined(KABC_VCARD_ENCODING_FIX)
299 TDEABC::AddresseeList VCardXXPort::parseVCard( const TQByteArray &data ) const
300 {
301  TDEABC::VCardConverter converter;
302 
303  return converter.parseVCardsRaw( data.data() );
304 }
305 
306 bool VCardXXPort::doExport( const KURL &url, const TQByteArray &data )
307 {
308  if( TQFileInfo(url.path()).exists() ) {
309  if(KMessageBox::questionYesNo( parentWidget(), i18n("Do you want to overwrite file \"%1\"").arg( url.path()) ) == KMessageBox::No)
310  return false;
311  }
312  KTempFile tmpFile;
313  tmpFile.setAutoDelete( true );
314 
315  tmpFile.file()->writeBlock( data.data(), data.size() );
316  tmpFile.close();
317 
318  return TDEIO::NetAccess::upload( tmpFile.name(), url, parentWidget() );
319 }
320 #else
321 TDEABC::AddresseeList VCardXXPort::parseVCard( const TQString &data ) const
322 {
323  TDEABC::VCardConverter converter;
324 
325  return converter.parseVCards( data );
326 }
327 
328 bool VCardXXPort::doExport( const KURL &url, const TQString &data )
329 {
330  if( TQFileInfo(url.path()).exists() ) {
331  if(KMessageBox::questionYesNo( parentWidget(), i18n("Do you want to overwrite file \"%1\"").arg( url.path()) ) == KMessageBox::No)
332  return false;
333  }
334  KTempFile tmpFile;
335  tmpFile.setAutoDelete( true );
336 
337  TQTextStream stream( tmpFile.file() );
338  stream.setEncoding( TQTextStream::UnicodeUTF8 );
339 
340  stream << data;
341  tmpFile.close();
342 
343  return TDEIO::NetAccess::upload( tmpFile.name(), url, parentWidget() );
344 }
345 #endif
346 
347 TDEABC::AddresseeList VCardXXPort::filterContacts( const TDEABC::AddresseeList &addrList )
348 {
349  TDEABC::AddresseeList list;
350 
351  if ( addrList.isEmpty() )
352  return addrList;
353 
354  VCardExportSelectionDialog dlg( parentWidget() );
355  if ( !dlg.exec() )
356  return list;
357 
358  TDEABC::AddresseeList::ConstIterator it;
359  for ( it = addrList.begin(); it != addrList.end(); ++it ) {
360  TDEABC::Addressee addr;
361 
362  addr.setUid( (*it).uid() );
363  addr.setFormattedName( (*it).formattedName() );
364  addr.setPrefix( (*it).prefix() );
365  addr.setGivenName( (*it).givenName() );
366  addr.setAdditionalName( (*it).additionalName() );
367  addr.setFamilyName( (*it).familyName() );
368  addr.setSuffix( (*it).suffix() );
369  addr.setNickName( (*it).nickName() );
370  addr.setMailer( (*it).mailer() );
371  addr.setTimeZone( (*it).timeZone() );
372  addr.setGeo( (*it).geo() );
373  addr.setProductId( (*it).productId() );
374  addr.setSortString( (*it).sortString() );
375  addr.setUrl( (*it).url() );
376  addr.setSecrecy( (*it).secrecy() );
377  addr.setSound( (*it).sound() );
378  addr.setEmails( (*it).emails() );
379  addr.setCategories( (*it).categories() );
380 
381  if ( dlg.exportPrivateFields() ) {
382  addr.setBirthday( (*it).birthday() );
383  addr.setNote( (*it).note() );
384  addr.setPhoto( (*it).photo() );
385  }
386 
387  if ( dlg.exportBusinessFields() ) {
388  addr.setTitle( (*it).title() );
389  addr.setRole( (*it).role() );
390  addr.setOrganization( (*it).organization() );
391 
392  addr.setLogo( (*it).logo() );
393 
394  TDEABC::PhoneNumber::List phones = (*it).phoneNumbers( TDEABC::PhoneNumber::Work );
395  TDEABC::PhoneNumber::List::Iterator phoneIt;
396  for ( phoneIt = phones.begin(); phoneIt != phones.end(); ++phoneIt )
397  addr.insertPhoneNumber( *phoneIt );
398 
399  TDEABC::Address::List addresses = (*it).addresses( TDEABC::Address::Work );
400  TDEABC::Address::List::Iterator addrIt;
401  for ( addrIt = addresses.begin(); addrIt != addresses.end(); ++addrIt )
402  addr.insertAddress( *addrIt );
403  }
404 
405  TDEABC::PhoneNumber::List phones = (*it).phoneNumbers();
406  TDEABC::PhoneNumber::List::Iterator phoneIt;
407  for ( phoneIt = phones.begin(); phoneIt != phones.end(); ++phoneIt ) {
408  int type = (*phoneIt).type();
409 
410  if ( type & TDEABC::PhoneNumber::Home && dlg.exportPrivateFields() )
411  addr.insertPhoneNumber( *phoneIt );
412  else if ( type & TDEABC::PhoneNumber::Work && dlg.exportBusinessFields() )
413  addr.insertPhoneNumber( *phoneIt );
414  else if ( dlg.exportOtherFields() )
415  addr.insertPhoneNumber( *phoneIt );
416  }
417 
418  TDEABC::Address::List addresses = (*it).addresses();
419  TDEABC::Address::List::Iterator addrIt;
420  for ( addrIt = addresses.begin(); addrIt != addresses.end(); ++addrIt ) {
421  int type = (*addrIt).type();
422 
423  if ( type & TDEABC::Address::Home && dlg.exportPrivateFields() )
424  addr.insertAddress( *addrIt );
425  else if ( type & TDEABC::Address::Work && dlg.exportBusinessFields() )
426  addr.insertAddress( *addrIt );
427  else if ( dlg.exportOtherFields() )
428  addr.insertAddress( *addrIt );
429  }
430 
431  if ( dlg.exportOtherFields() )
432  addr.setCustoms( (*it).customs() );
433 
434  if ( dlg.exportEncryptionKeys() ) {
435  addKey( addr, TDEABC::Key::PGP );
436  addKey( addr, TDEABC::Key::X509 );
437  }
438 
439  list.append( addr );
440  }
441 
442  return list;
443 }
444 
445 void VCardXXPort::addKey( TDEABC::Addressee &addr, TDEABC::Key::Types type )
446 {
447  TQString fingerprint = addr.custom( "KADDRESSBOOK",
448  (type == TDEABC::Key::PGP ? "OPENPGPFP" : "SMIMEFP") );
449  if ( fingerprint.isEmpty() )
450  return;
451 
452  GpgME::Context * context = GpgME::Context::createForProtocol( GpgME::Context::OpenPGP );
453  if ( !context ) {
454  kdError() << "No context available" << endl;
455  return;
456  }
457 
458  context->setArmor( false );
459  context->setTextMode( false );
460 
461  QGpgME::TQByteArrayDataProvider dataProvider;
462  GpgME::Data dataObj( &dataProvider );
463  GpgME::Error error = context->exportPublicKeys( fingerprint.latin1(), dataObj );
464  delete context;
465 
466  if ( error ) {
467  kdError() << error.asString() << endl;
468  return;
469  }
470 
471  TDEABC::Key key;
472  key.setType( type );
473  key.setBinaryData( dataProvider.data() );
474 
475  addr.insertKey( key );
476 }
477 
478 // ---------- VCardViewer Dialog ---------------- //
479 
480 VCardViewerDialog::VCardViewerDialog( const TDEABC::Addressee::List &list,
481  TQWidget *parent, const char *name )
482  : KDialogBase( Plain, i18n( "Import vCard" ), Yes | No | Apply | Cancel, Yes,
483  parent, name, true, true, KStdGuiItem::no(), KStdGuiItem::yes() ),
484  mContacts( list )
485 {
486  TQFrame *page = plainPage();
487  TQVBoxLayout *layout = new TQVBoxLayout( page, marginHint(), spacingHint() );
488 
489  TQLabel *label = new TQLabel( i18n( "Do you want to import this contact in your address book?" ), page );
490  TQFont font = label->font();
491  font.setBold( true );
492  label->setFont( font );
493  layout->addWidget( label );
494 
495  mView = new KPIM::AddresseeView( page );
496  mView->enableLinks( 0 );
497  mView->setVScrollBarMode( TQScrollView::Auto );
498  layout->addWidget( mView );
499 
500  setButtonText( Apply, i18n( "Import All..." ) );
501 
502  mIt = mContacts.begin();
503 
504  updateView();
505 }
506 
507 TDEABC::Addressee::List VCardViewerDialog::contacts() const
508 {
509  return mContacts;
510 }
511 
512 void VCardViewerDialog::updateView()
513 {
514  mView->setAddressee( *mIt );
515 
516  TDEABC::Addressee::List::Iterator it = mIt;
517  actionButton( Apply )->setEnabled( (++it) != mContacts.end() );
518 }
519 
520 void VCardViewerDialog::slotUser1()
521 {
522  mIt = mContacts.remove( mIt );
523 
524  if ( mIt == mContacts.end() )
525  slotApply();
526 
527  updateView();
528 }
529 
530 void VCardViewerDialog::slotUser2()
531 {
532  mIt++;
533 
534  if ( mIt == mContacts.end() )
535  slotApply();
536 
537  updateView();
538 }
539 
540 void VCardViewerDialog::slotApply()
541 {
542  TQDialog::accept();
543 }
544 
545 void VCardViewerDialog::slotCancel()
546 {
547  mContacts.clear();
548  TQDialog::accept();
549 }
550 
551 // ---------- VCardExportSelection Dialog ---------------- //
552 
553 VCardExportSelectionDialog::VCardExportSelectionDialog( TQWidget *parent,
554  const char *name )
555  : KDialogBase( Plain, i18n( "Select vCard Fields" ), Ok | Cancel, Ok,
556  parent, name, true, true )
557 {
558  TQFrame *page = plainPage();
559 
560  TQVBoxLayout *layout = new TQVBoxLayout( page, marginHint(), spacingHint() );
561 
562  TQLabel *label = new TQLabel( i18n( "Select the fields which shall be exported in the vCard." ), page );
563  layout->addWidget( label );
564 
565  mPrivateBox = new TQCheckBox( i18n( "Private fields" ), page );
566  layout->addWidget( mPrivateBox );
567 
568  mBusinessBox = new TQCheckBox( i18n( "Business fields" ), page );
569  layout->addWidget( mBusinessBox );
570 
571  mOtherBox = new TQCheckBox( i18n( "Other fields" ), page );
572  layout->addWidget( mOtherBox );
573 
574  mEncryptionKeys = new TQCheckBox( i18n( "Encryption keys" ), page );
575  layout->addWidget( mEncryptionKeys );
576 
577  TDEConfig config( "kaddressbookrc" );
578  config.setGroup( "XXPortVCard" );
579 
580  mPrivateBox->setChecked( config.readBoolEntry( "ExportPrivateFields", true ) );
581  mBusinessBox->setChecked( config.readBoolEntry( "ExportBusinessFields", false ) );
582  mOtherBox->setChecked( config.readBoolEntry( "ExportOtherFields", false ) );
583  mEncryptionKeys->setChecked( config.readBoolEntry( "ExportEncryptionKeys", false ) );
584 }
585 
586 VCardExportSelectionDialog::~VCardExportSelectionDialog()
587 {
588  TDEConfig config( "kaddressbookrc" );
589  config.setGroup( "XXPortVCard" );
590 
591  config.writeEntry( "ExportPrivateFields", mPrivateBox->isChecked() );
592  config.writeEntry( "ExportBusinessFields", mBusinessBox->isChecked() );
593  config.writeEntry( "ExportOtherFields", mOtherBox->isChecked() );
594  config.writeEntry( "ExportEncryptionKeys", mEncryptionKeys->isChecked() );
595 }
596 
597 bool VCardExportSelectionDialog::exportPrivateFields() const
598 {
599  return mPrivateBox->isChecked();
600 }
601 
602 bool VCardExportSelectionDialog::exportBusinessFields() const
603 {
604  return mBusinessBox->isChecked();
605 }
606 
607 bool VCardExportSelectionDialog::exportOtherFields() const
608 {
609  return mOtherBox->isChecked();
610 }
611 
612 bool VCardExportSelectionDialog::exportEncryptionKeys() const
613 {
614  return mEncryptionKeys->isChecked();
615 }
616 
617 #include "vcard_xxport.moc"