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
53K_EXPORT_KADDRESSBOOK_XXFILTER( libkaddrbk_vcard_xxport, VCardXXPort )
54
55class 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
78class 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
96VCardXXPort::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
104bool 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
196TDEABC::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( tdeApp->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)
299TDEABC::AddresseeList VCardXXPort::parseVCard( const TQByteArray &data ) const
300{
301 TDEABC::VCardConverter converter;
302
303 return converter.parseVCardsRaw( data.data() );
304}
305
306bool 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
321TDEABC::AddresseeList VCardXXPort::parseVCard( const TQString &data ) const
322{
323 TDEABC::VCardConverter converter;
324
325 return converter.parseVCards( data );
326}
327
328bool 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
347TDEABC::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
445void 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
480VCardViewerDialog::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
507TDEABC::Addressee::List VCardViewerDialog::contacts() const
508{
509 return mContacts;
510}
511
512void VCardViewerDialog::updateView()
513{
514 mView->setAddressee( *mIt );
515
516 TDEABC::Addressee::List::Iterator it = mIt;
517 actionButton( Apply )->setEnabled( (++it) != mContacts.end() );
518}
519
520void VCardViewerDialog::slotUser1()
521{
522 mIt = mContacts.remove( mIt );
523
524 if ( mIt == mContacts.end() )
525 slotApply();
526
527 updateView();
528}
529
530void VCardViewerDialog::slotUser2()
531{
532 mIt++;
533
534 if ( mIt == mContacts.end() )
535 slotApply();
536
537 updateView();
538}
539
540void VCardViewerDialog::slotApply()
541{
542 TQDialog::accept();
543}
544
545void VCardViewerDialog::slotCancel()
546{
547 mContacts.clear();
548 TQDialog::accept();
549}
550
551// ---------- VCardExportSelection Dialog ---------------- //
552
553VCardExportSelectionDialog::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
586VCardExportSelectionDialog::~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
597bool VCardExportSelectionDialog::exportPrivateFields() const
598{
599 return mPrivateBox->isChecked();
600}
601
602bool VCardExportSelectionDialog::exportBusinessFields() const
603{
604 return mBusinessBox->isChecked();
605}
606
607bool VCardExportSelectionDialog::exportOtherFields() const
608{
609 return mOtherBox->isChecked();
610}
611
612bool VCardExportSelectionDialog::exportEncryptionKeys() const
613{
614 return mEncryptionKeys->isChecked();
615}
616
617#include "vcard_xxport.moc"