• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.9.1 API Reference
  • KDE Home
  • Contact Us
 

kabc

  • kabc
  • vcardparser
vcardparser.cpp
1 /*
2  This file is part of libkabc.
3  Copyright (c) 2003 Tobias Koenig <tokoe@kde.org>
4 
5  This library is free software; you can redistribute it and/or
6  modify it under the terms of the GNU Library General Public
7  License as published by the Free Software Foundation; either
8  version 2 of the License, or (at your option) any later version.
9 
10  This library 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 GNU
13  Library General Public License for more details.
14 
15  You should have received a copy of the GNU Library General Public License
16  along with this library; see the file COPYING.LIB. If not, write to
17  the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  Boston, MA 02110-1301, USA.
19 */
20 
21 #include "vcardparser.h"
22 #include <kcodecs.h>
23 #include <kdebug.h>
24 #include <QtCore/QTextCodec>
25 
26 #define FOLD_WIDTH 75
27 
28 using namespace KABC;
29 
30 static void addEscapes( QByteArray &str, bool excludeEscapteComma )
31 {
32  str.replace( '\\', (char *)"\\\\" );
33  if(!excludeEscapteComma)
34  str.replace( ',', (char *)"\\," );
35  str.replace( '\r', (char *)"\\r" );
36  str.replace( '\n', (char *)"\\n" );
37 }
38 
39 static void removeEscapes( QByteArray &str )
40 {
41  str.replace( (char *)"\\n", "\n" );
42  str.replace( (char *)"\\N", "\n" );
43  str.replace( (char *)"\\r", "\r" );
44  str.replace( (char *)"\\,", "," );
45  str.replace( (char *)"\\\\", "\\" );
46 }
47 
48 VCardParser::VCardParser()
49 {
50 }
51 
52 VCardParser::~VCardParser()
53 {
54 }
55 
56 VCard::List VCardParser::parseVCards( const QByteArray &text )
57 {
58  VCard currentVCard;
59  VCard::List vCardList;
60  QByteArray currentLine;
61 
62  QList<QByteArray> lines = text.split( '\n' );
63 
64  bool inVCard = false;
65  QList<QByteArray>::Iterator it( lines.begin() );
66  QList<QByteArray>::Iterator linesEnd( lines.end() );
67  for ( ; it != linesEnd; ++it ) {
68  // remove the trailing \r, left from \r\n
69  if ( (*it).endsWith( '\r' ) ) {
70  (*it).chop( 1 );
71  }
72 
73  if ( (*it).startsWith( ' ' ) || (*it).startsWith( '\t' ) ) { //folded line => append to previous
74  currentLine.append( (*it).mid( 1 ) );
75  continue;
76  } else {
77  if ( (*it).trimmed().isEmpty() ) { // empty line
78  continue;
79  }
80  if ( inVCard && !currentLine.isEmpty() ) { // now parse the line
81  int colon = currentLine.indexOf( ':' );
82  if ( colon == -1 ) { // invalid line
83  currentLine = (*it);
84  continue;
85  }
86 
87  VCardLine vCardLine;
88  const QByteArray key = currentLine.left( colon ).trimmed();
89  QByteArray value = currentLine.mid( colon + 1 );
90 
91  QList<QByteArray> params = key.split( ';' );
92 
93  // check for group
94  int groupPos = params[ 0 ].indexOf( '.' );
95  if ( groupPos != -1 ) {
96  vCardLine.setGroup( QString::fromLatin1( params[ 0 ].left( groupPos ) ) );
97  vCardLine.setIdentifier( QString::fromLatin1( params[ 0 ].mid( groupPos + 1 ) ) );
98  } else {
99  vCardLine.setIdentifier( QString::fromLatin1( params[ 0 ] ) );
100  }
101 
102  if ( params.count() > 1 ) { // find all parameters
103  QList<QByteArray>::ConstIterator paramIt( params.constBegin() );
104  for ( ++paramIt; paramIt != params.constEnd(); ++paramIt ) {
105  QList<QByteArray> pair = (*paramIt).split( '=' );
106  if ( pair.count() == 1 ) {
107  // correct the fucking 2.1 'standard'
108  if ( pair[ 0 ].toLower() == "quoted-printable" ) {
109  pair[ 0 ] = "encoding";
110  pair.append( "quoted-printable" );
111  } else if ( pair[ 0 ].toLower() == "base64" ) {
112  pair[ 0 ] = "encoding";
113  pair.append( "base64" );
114  } else {
115  pair.prepend( "type" );
116  }
117  }
118  if ( pair[ 1 ].indexOf( ',' ) != -1 ) { // parameter in type=x,y,z format
119  const QList<QByteArray> args = pair[ 1 ].split( ',' );
120  QList<QByteArray>::ConstIterator argIt;
121  for ( argIt = args.constBegin(); argIt != args.constEnd(); ++argIt ) {
122  vCardLine.addParameter( QString::fromLatin1( pair[ 0 ].toLower() ),
123  QString::fromLatin1( *argIt ) );
124  }
125  } else {
126  vCardLine.addParameter( QString::fromLatin1( pair[ 0 ].toLower() ),
127  QString::fromLatin1( pair[ 1 ] ) );
128  }
129  }
130  }
131 
132  removeEscapes( value );
133 
134  QByteArray output;
135  bool wasBase64Encoded = false;
136 
137  if ( vCardLine.parameterList().contains( QLatin1String( "encoding" ) ) ) {
138  const QString encoding = vCardLine.parameter( QLatin1String( "encoding" ) ).toLower();
139 
140  // have to decode the data
141  if ( encoding == QLatin1String( "b" ) || encoding == QLatin1String( "base64" ) ) {
142  output = QByteArray::fromBase64( value );
143  wasBase64Encoded = true;
144  }
145  else if ( encoding == QLatin1String( "quoted-printable" ) ) {
146  // join any qp-folded lines
147  while ( value.endsWith( '=' ) && it != linesEnd ) {
148  value.chop( 1 ); // remove the '='
149  value.append( *it );
150  ++it;
151  }
152  KCodecs::quotedPrintableDecode( value, output );
153  } else if ( encoding == QLatin1String( "8bit" ) ) {
154  output = value;
155  } else {
156  qDebug( "Unknown vcard encoding type!" );
157  }
158  } else {
159  output = value;
160  }
161 
162  if ( vCardLine.parameterList().contains( QLatin1String( "charset" ) ) ) {
163  // have to convert the data
164  QTextCodec *codec = QTextCodec::codecForName(
165  vCardLine.parameter( QLatin1String( "charset" ) ).toLatin1() );
166  if ( codec ) {
167  vCardLine.setValue( codec->toUnicode( output ) );
168  } else {
169  vCardLine.setValue( QString::fromUtf8( output ) );
170  }
171  } else if ( wasBase64Encoded ) {
172  vCardLine.setValue( output );
173  } else {
174  vCardLine.setValue( QString::fromUtf8( output ) );
175  }
176 
177  currentVCard.addLine( vCardLine );
178  }
179 
180  // we do not save the start and end tag as vcardline
181  if ( (*it).toLower().startsWith( "begin:vcard" ) ) { //krazy:exclude=strings
182  inVCard = true;
183  currentLine.clear();
184  currentVCard.clear(); // flush vcard
185  continue;
186  }
187 
188  if ( (*it).toLower().startsWith( "end:vcard" ) ) { //krazy:exclude=strings
189  inVCard = false;
190  vCardList.append( currentVCard );
191  currentLine.clear();
192  currentVCard.clear(); // flush vcard
193  continue;
194  }
195 
196  currentLine = (*it);
197  }
198  }
199 
200  return vCardList;
201 }
202 
203 QByteArray VCardParser::createVCards( const VCard::List &list )
204 {
205  QByteArray text;
206  QByteArray textLine;
207  QString encodingType;
208  QStringList idents;
209  QStringList params;
210  QStringList values;
211  QStringList::ConstIterator identIt;
212  QStringList::Iterator paramIt;
213  QStringList::ConstIterator valueIt;
214 
215  VCardLine::List lines;
216  VCardLine::List::ConstIterator lineIt;
217  VCard::List::ConstIterator cardIt;
218 
219  bool hasEncoding;
220 
221  text.reserve( list.size() * 300 ); // reserve memory to be more efficient
222 
223  // iterate over the cards
224  VCard::List::ConstIterator listEnd( list.end() );
225  for ( cardIt = list.begin(); cardIt != listEnd; ++cardIt ) {
226  text.append( "BEGIN:VCARD\r\n" );
227 
228  idents = (*cardIt).identifiers();
229  for ( identIt = idents.constBegin(); identIt != idents.constEnd(); ++identIt ) {
230  lines = (*cardIt).lines( (*identIt) );
231 
232  // iterate over the lines
233  for ( lineIt = lines.constBegin(); lineIt != lines.constEnd(); ++lineIt ) {
234  QVariant val = (*lineIt).value();
235  if ( val.isValid() ) {
236  if ( (*lineIt).hasGroup() ) {
237  textLine = (*lineIt).group().toLatin1() + '.' + (*lineIt).identifier().toLatin1();
238  } else {
239  textLine = (*lineIt).identifier().toLatin1();
240  }
241 
242  params = (*lineIt).parameterList();
243  hasEncoding = false;
244  if ( params.count() > 0 ) { // we have parameters
245  for ( paramIt = params.begin(); paramIt != params.end(); ++paramIt ) {
246  if ( (*paramIt) == QLatin1String( "encoding" ) ) {
247  hasEncoding = true;
248  encodingType = (*lineIt).parameter( QLatin1String( "encoding" ) ).toLower();
249  }
250 
251  values = (*lineIt).parameters( *paramIt );
252  for ( valueIt = values.constBegin(); valueIt != values.constEnd(); ++valueIt ) {
253  textLine.append( ';' + (*paramIt).toLatin1().toUpper() );
254  if ( !(*valueIt).isEmpty() ) {
255  textLine.append( '=' + (*valueIt).toLatin1() );
256  }
257  }
258  }
259  }
260 
261  QByteArray input, output;
262 
263  // handle charset
264  if ( (*lineIt).parameterList().contains( QLatin1String( "charset" ) ) ) {
265  // have to convert the data
266  const QString value = (*lineIt).value().toString();
267  QTextCodec *codec = QTextCodec::codecForName(
268  (*lineIt).parameter( QLatin1String( "charset" ) ).toLatin1() );
269  if ( codec ) {
270  input = codec->fromUnicode( value );
271  } else {
272  input = value.toUtf8();
273  }
274  } else if ( (*lineIt).value().type() == QVariant::ByteArray ) {
275  input = (*lineIt).value().toByteArray();
276  } else {
277  input = (*lineIt).value().toString().toUtf8();
278  }
279 
280  // handle encoding
281  if ( hasEncoding ) { // have to encode the data
282  if ( encodingType == QLatin1String( "b" ) ) {
283  output = input.toBase64();
284  } else if ( encodingType == QLatin1String( "quoted-printable" ) ) {
285  KCodecs::quotedPrintableEncode( input, output, false );
286  }
287  } else {
288  output = input;
289  }
290  addEscapes( output, (*lineIt).identifier() == QLatin1String("CATEGORIES") );
291 
292  if ( !output.isEmpty() ) {
293  textLine.append( ':' + output );
294 
295  if ( textLine.length() > FOLD_WIDTH ) { // we have to fold the line
296  for ( int i = 0; i <= ( textLine.length() / FOLD_WIDTH ); ++i ) {
297  text.append(
298  ( i == 0 ? "" : " " ) + textLine.mid( i * FOLD_WIDTH, FOLD_WIDTH ) + "\r\n" );
299  }
300  } else {
301  text.append( textLine + "\r\n" );
302  }
303  }
304  }
305  }
306  }
307 
308  text.append( "END:VCARD\r\n" );
309  text.append( "\r\n" );
310  }
311 
312  return text;
313 }
This file is part of the KDE documentation.
Documentation copyright © 1996-2012 The KDE developers.
Generated on Mon Sep 24 2012 09:09:51 by doxygen 1.8.1.1 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

kabc

Skip menu "kabc"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • Related Pages

kdepimlibs-4.9.1 API Reference

Skip menu "kdepimlibs-4.9.1 API Reference"
  • akonadi
  •   contact
  •   kmime
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  •   richtextbuilders
  • kpimutils
  • kresources
  • ktnef
  • kxmlrpcclient
  • mailtransport
  • microblog
  • qgpgme
  • syndication
  •   atom
  •   rdf
  •   rss2
Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal