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  if ( TQString::fromLatin1( rawData ).lower().contains( "version:3.0" ) ) {
243  vCardText = TQString::fromUtf8( rawData );
244  } else {
245  vCardText = TQString::fromLatin1( rawData );
246  }
247  addrList += parseVCard( vCardText );
248  }
249 #endif
250  TDEIO::NetAccess::removeTempFile( fileName );
251  } else {
252  TQString text = i18n( "<qt>When trying to read the vCard, there was an error opening the file '%1': %2</qt>" );
253  text = text.arg( (*it).url() );
254  text = text.arg( kapp->translate( "TQFile",
255  TQString(file.errorString()).latin1() ) );
256  KMessageBox::error( parentWidget(), text, caption );
257  anyFailures = true;
258  }
259  } else {
260  TQString text = i18n( "<qt>Unable to access vCard: %1</qt>" );
261  text = text.arg( TDEIO::NetAccess::lastErrorString() );
262  KMessageBox::error( parentWidget(), text, caption );
263  anyFailures = true;
264  }
265  }
266 
267  if ( !XXPortManager::importURL.isEmpty() ) { // a vcard was passed via cmd
268  if ( addrList.isEmpty() ) {
269  if ( anyFailures && urls.count() > 1 )
270  KMessageBox::information( parentWidget(),
271  i18n( "No contacts were imported, due to errors with the vCards." ) );
272  else if ( !anyFailures )
273  KMessageBox::information( parentWidget(), i18n( "The vCard does not contain any contacts." ) );
274  } else {
275  VCardViewerDialog dlg( addrList, parentWidget() );
276  dlg.exec();
277  addrList = dlg.contacts();
278  }
279  }
280  }
281 
282  return addrList;
283 }
284 
285 #if defined(KABC_VCARD_ENCODING_FIX)
286 TDEABC::AddresseeList VCardXXPort::parseVCard( const TQByteArray &data ) const
287 {
288  TDEABC::VCardConverter converter;
289 
290  return converter.parseVCardsRaw( data.data() );
291 }
292 
293 bool VCardXXPort::doExport( const KURL &url, const TQByteArray &data )
294 {
295  if( TQFileInfo(url.path()).exists() ) {
296  if(KMessageBox::questionYesNo( parentWidget(), i18n("Do you want to overwrite file \"%1\"").arg( url.path()) ) == KMessageBox::No)
297  return false;
298  }
299  KTempFile tmpFile;
300  tmpFile.setAutoDelete( true );
301 
302  tmpFile.file()->writeBlock( data.data(), data.size() );
303  tmpFile.close();
304 
305  return TDEIO::NetAccess::upload( tmpFile.name(), url, parentWidget() );
306 }
307 #else
308 TDEABC::AddresseeList VCardXXPort::parseVCard( const TQString &data ) const
309 {
310  TDEABC::VCardConverter converter;
311 
312  return converter.parseVCards( data );
313 }
314 
315 bool VCardXXPort::doExport( const KURL &url, const TQString &data )
316 {
317  if( TQFileInfo(url.path()).exists() ) {
318  if(KMessageBox::questionYesNo( parentWidget(), i18n("Do you want to overwrite file \"%1\"").arg( url.path()) ) == KMessageBox::No)
319  return false;
320  }
321  KTempFile tmpFile;
322  tmpFile.setAutoDelete( true );
323 
324  TQTextStream stream( tmpFile.file() );
325  stream.setEncoding( TQTextStream::UnicodeUTF8 );
326 
327  stream << data;
328  tmpFile.close();
329 
330  return TDEIO::NetAccess::upload( tmpFile.name(), url, parentWidget() );
331 }
332 #endif
333 
334 TDEABC::AddresseeList VCardXXPort::filterContacts( const TDEABC::AddresseeList &addrList )
335 {
336  TDEABC::AddresseeList list;
337 
338  if ( addrList.isEmpty() )
339  return addrList;
340 
341  VCardExportSelectionDialog dlg( parentWidget() );
342  if ( !dlg.exec() )
343  return list;
344 
345  TDEABC::AddresseeList::ConstIterator it;
346  for ( it = addrList.begin(); it != addrList.end(); ++it ) {
347  TDEABC::Addressee addr;
348 
349  addr.setUid( (*it).uid() );
350  addr.setFormattedName( (*it).formattedName() );
351  addr.setPrefix( (*it).prefix() );
352  addr.setGivenName( (*it).givenName() );
353  addr.setAdditionalName( (*it).additionalName() );
354  addr.setFamilyName( (*it).familyName() );
355  addr.setSuffix( (*it).suffix() );
356  addr.setNickName( (*it).nickName() );
357  addr.setMailer( (*it).mailer() );
358  addr.setTimeZone( (*it).timeZone() );
359  addr.setGeo( (*it).geo() );
360  addr.setProductId( (*it).productId() );
361  addr.setSortString( (*it).sortString() );
362  addr.setUrl( (*it).url() );
363  addr.setSecrecy( (*it).secrecy() );
364  addr.setSound( (*it).sound() );
365  addr.setEmails( (*it).emails() );
366  addr.setCategories( (*it).categories() );
367 
368  if ( dlg.exportPrivateFields() ) {
369  addr.setBirthday( (*it).birthday() );
370  addr.setNote( (*it).note() );
371  addr.setPhoto( (*it).photo() );
372  }
373 
374  if ( dlg.exportBusinessFields() ) {
375  addr.setTitle( (*it).title() );
376  addr.setRole( (*it).role() );
377  addr.setOrganization( (*it).organization() );
378 
379  addr.setLogo( (*it).logo() );
380 
381  TDEABC::PhoneNumber::List phones = (*it).phoneNumbers( TDEABC::PhoneNumber::Work );
382  TDEABC::PhoneNumber::List::Iterator phoneIt;
383  for ( phoneIt = phones.begin(); phoneIt != phones.end(); ++phoneIt )
384  addr.insertPhoneNumber( *phoneIt );
385 
386  TDEABC::Address::List addresses = (*it).addresses( TDEABC::Address::Work );
387  TDEABC::Address::List::Iterator addrIt;
388  for ( addrIt = addresses.begin(); addrIt != addresses.end(); ++addrIt )
389  addr.insertAddress( *addrIt );
390  }
391 
392  TDEABC::PhoneNumber::List phones = (*it).phoneNumbers();
393  TDEABC::PhoneNumber::List::Iterator phoneIt;
394  for ( phoneIt = phones.begin(); phoneIt != phones.end(); ++phoneIt ) {
395  int type = (*phoneIt).type();
396 
397  if ( type & TDEABC::PhoneNumber::Home && dlg.exportPrivateFields() )
398  addr.insertPhoneNumber( *phoneIt );
399  else if ( type & TDEABC::PhoneNumber::Work && dlg.exportBusinessFields() )
400  addr.insertPhoneNumber( *phoneIt );
401  else if ( dlg.exportOtherFields() )
402  addr.insertPhoneNumber( *phoneIt );
403  }
404 
405  TDEABC::Address::List addresses = (*it).addresses();
406  TDEABC::Address::List::Iterator addrIt;
407  for ( addrIt = addresses.begin(); addrIt != addresses.end(); ++addrIt ) {
408  int type = (*addrIt).type();
409 
410  if ( type & TDEABC::Address::Home && dlg.exportPrivateFields() )
411  addr.insertAddress( *addrIt );
412  else if ( type & TDEABC::Address::Work && dlg.exportBusinessFields() )
413  addr.insertAddress( *addrIt );
414  else if ( dlg.exportOtherFields() )
415  addr.insertAddress( *addrIt );
416  }
417 
418  if ( dlg.exportOtherFields() )
419  addr.setCustoms( (*it).customs() );
420 
421  if ( dlg.exportEncryptionKeys() ) {
422  addKey( addr, TDEABC::Key::PGP );
423  addKey( addr, TDEABC::Key::X509 );
424  }
425 
426  list.append( addr );
427  }
428 
429  return list;
430 }
431 
432 void VCardXXPort::addKey( TDEABC::Addressee &addr, TDEABC::Key::Types type )
433 {
434  TQString fingerprint = addr.custom( "KADDRESSBOOK",
435  (type == TDEABC::Key::PGP ? "OPENPGPFP" : "SMIMEFP") );
436  if ( fingerprint.isEmpty() )
437  return;
438 
439  GpgME::Context * context = GpgME::Context::createForProtocol( GpgME::Context::OpenPGP );
440  if ( !context ) {
441  kdError() << "No context available" << endl;
442  return;
443  }
444 
445  context->setArmor( false );
446  context->setTextMode( false );
447 
448  QGpgME::TQByteArrayDataProvider dataProvider;
449  GpgME::Data dataObj( &dataProvider );
450  GpgME::Error error = context->exportPublicKeys( fingerprint.latin1(), dataObj );
451  delete context;
452 
453  if ( error ) {
454  kdError() << error.asString() << endl;
455  return;
456  }
457 
458  TDEABC::Key key;
459  key.setType( type );
460  key.setBinaryData( dataProvider.data() );
461 
462  addr.insertKey( key );
463 }
464 
465 // ---------- VCardViewer Dialog ---------------- //
466 
467 VCardViewerDialog::VCardViewerDialog( const TDEABC::Addressee::List &list,
468  TQWidget *parent, const char *name )
469  : KDialogBase( Plain, i18n( "Import vCard" ), Yes | No | Apply | Cancel, Yes,
470  parent, name, true, true, KStdGuiItem::no(), KStdGuiItem::yes() ),
471  mContacts( list )
472 {
473  TQFrame *page = plainPage();
474  TQVBoxLayout *layout = new TQVBoxLayout( page, marginHint(), spacingHint() );
475 
476  TQLabel *label = new TQLabel( i18n( "Do you want to import this contact in your address book?" ), page );
477  TQFont font = label->font();
478  font.setBold( true );
479  label->setFont( font );
480  layout->addWidget( label );
481 
482  mView = new KPIM::AddresseeView( page );
483  mView->enableLinks( 0 );
484  mView->setVScrollBarMode( TQScrollView::Auto );
485  layout->addWidget( mView );
486 
487  setButtonText( Apply, i18n( "Import All..." ) );
488 
489  mIt = mContacts.begin();
490 
491  updateView();
492 }
493 
494 TDEABC::Addressee::List VCardViewerDialog::contacts() const
495 {
496  return mContacts;
497 }
498 
499 void VCardViewerDialog::updateView()
500 {
501  mView->setAddressee( *mIt );
502 
503  TDEABC::Addressee::List::Iterator it = mIt;
504  actionButton( Apply )->setEnabled( (++it) != mContacts.end() );
505 }
506 
507 void VCardViewerDialog::slotUser1()
508 {
509  mIt = mContacts.remove( mIt );
510 
511  if ( mIt == mContacts.end() )
512  slotApply();
513 
514  updateView();
515 }
516 
517 void VCardViewerDialog::slotUser2()
518 {
519  mIt++;
520 
521  if ( mIt == mContacts.end() )
522  slotApply();
523 
524  updateView();
525 }
526 
527 void VCardViewerDialog::slotApply()
528 {
529  TQDialog::accept();
530 }
531 
532 void VCardViewerDialog::slotCancel()
533 {
534  mContacts.clear();
535  TQDialog::accept();
536 }
537 
538 // ---------- VCardExportSelection Dialog ---------------- //
539 
540 VCardExportSelectionDialog::VCardExportSelectionDialog( TQWidget *parent,
541  const char *name )
542  : KDialogBase( Plain, i18n( "Select vCard Fields" ), Ok | Cancel, Ok,
543  parent, name, true, true )
544 {
545  TQFrame *page = plainPage();
546 
547  TQVBoxLayout *layout = new TQVBoxLayout( page, marginHint(), spacingHint() );
548 
549  TQLabel *label = new TQLabel( i18n( "Select the fields which shall be exported in the vCard." ), page );
550  layout->addWidget( label );
551 
552  mPrivateBox = new TQCheckBox( i18n( "Private fields" ), page );
553  layout->addWidget( mPrivateBox );
554 
555  mBusinessBox = new TQCheckBox( i18n( "Business fields" ), page );
556  layout->addWidget( mBusinessBox );
557 
558  mOtherBox = new TQCheckBox( i18n( "Other fields" ), page );
559  layout->addWidget( mOtherBox );
560 
561  mEncryptionKeys = new TQCheckBox( i18n( "Encryption keys" ), page );
562  layout->addWidget( mEncryptionKeys );
563 
564  TDEConfig config( "kaddressbookrc" );
565  config.setGroup( "XXPortVCard" );
566 
567  mPrivateBox->setChecked( config.readBoolEntry( "ExportPrivateFields", true ) );
568  mBusinessBox->setChecked( config.readBoolEntry( "ExportBusinessFields", false ) );
569  mOtherBox->setChecked( config.readBoolEntry( "ExportOtherFields", false ) );
570  mEncryptionKeys->setChecked( config.readBoolEntry( "ExportEncryptionKeys", false ) );
571 }
572 
573 VCardExportSelectionDialog::~VCardExportSelectionDialog()
574 {
575  TDEConfig config( "kaddressbookrc" );
576  config.setGroup( "XXPortVCard" );
577 
578  config.writeEntry( "ExportPrivateFields", mPrivateBox->isChecked() );
579  config.writeEntry( "ExportBusinessFields", mBusinessBox->isChecked() );
580  config.writeEntry( "ExportOtherFields", mOtherBox->isChecked() );
581  config.writeEntry( "ExportEncryptionKeys", mEncryptionKeys->isChecked() );
582 }
583 
584 bool VCardExportSelectionDialog::exportPrivateFields() const
585 {
586  return mPrivateBox->isChecked();
587 }
588 
589 bool VCardExportSelectionDialog::exportBusinessFields() const
590 {
591  return mBusinessBox->isChecked();
592 }
593 
594 bool VCardExportSelectionDialog::exportOtherFields() const
595 {
596  return mOtherBox->isChecked();
597 }
598 
599 bool VCardExportSelectionDialog::exportEncryptionKeys() const
600 {
601  return mEncryptionKeys->isChecked();
602 }
603 
604 #include "vcard_xxport.moc"