• Skip to content
  • Skip to link menu
  • KDE API Reference
  • kdepimlibs-4.10.5 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  }
36  str.replace( '\r', (char *)"\\r" );
37  str.replace( '\n', (char *)"\\n" );
38 }
39 
40 static void removeEscapes( QByteArray &str )
41 {
42  str.replace( (char *)"\\n", "\n" );
43  str.replace( (char *)"\\N", "\n" );
44  str.replace( (char *)"\\r", "\r" );
45  str.replace( (char *)"\\,", "," );
46  str.replace( (char *)"\\\\", "\\" );
47 }
48 
49 VCardParser::VCardParser()
50  : d(0)
51 {
52 }
53 
54 VCardParser::~VCardParser()
55 {
56 }
57 
58 VCard::List VCardParser::parseVCards( const QByteArray &text )
59 {
60  VCard currentVCard;
61  VCard::List vCardList;
62  QByteArray currentLine;
63 
64  QList<QByteArray> lines = text.split( '\n' );
65 
66  bool inVCard = false;
67  QList<QByteArray>::Iterator it( lines.begin() );
68  QList<QByteArray>::Iterator linesEnd( lines.end() );
69  for ( ; it != linesEnd; ++it ) {
70  // remove the trailing \r, left from \r\n
71  if ( ( *it ).endsWith( '\r' ) ) {
72  ( *it ).chop( 1 );
73  }
74 
75  if ( ( *it ).startsWith( ' ' ) ||
76  ( *it ).startsWith( '\t' ) ) { //folded line => append to previous
77  currentLine.append( ( *it ).mid( 1 ) );
78  continue;
79  } else {
80  if ( ( *it ).trimmed().isEmpty() ) { // empty line
81  continue;
82  }
83  if ( inVCard && !currentLine.isEmpty() ) { // now parse the line
84  int colon = currentLine.indexOf( ':' );
85  if ( colon == -1 ) { // invalid line
86  currentLine = ( *it );
87  continue;
88  }
89 
90  VCardLine vCardLine;
91  const QByteArray key = currentLine.left( colon ).trimmed();
92  QByteArray value = currentLine.mid( colon + 1 );
93 
94  QList<QByteArray> params = key.split( ';' );
95 
96  // check for group
97  int groupPos = params[ 0 ].indexOf( '.' );
98  if ( groupPos != -1 ) {
99  vCardLine.setGroup( QString::fromLatin1( params[ 0 ].left( groupPos ) ) );
100  vCardLine.setIdentifier( QString::fromLatin1( params[ 0 ].mid( groupPos + 1 ) ) );
101  } else {
102  vCardLine.setIdentifier( QString::fromLatin1( params[ 0 ] ) );
103  }
104 
105  if ( params.count() > 1 ) { // find all parameters
106  QList<QByteArray>::ConstIterator paramIt( params.constBegin() );
107  for ( ++paramIt; paramIt != params.constEnd(); ++paramIt ) {
108  QList<QByteArray> pair = ( *paramIt ).split( '=' );
109  if ( pair.count() == 1 ) {
110  // correct the fucking 2.1 'standard'
111  if ( pair[ 0 ].toLower() == "quoted-printable" ) {
112  pair[ 0 ] = "encoding";
113  pair.append( "quoted-printable" );
114  } else if ( pair[ 0 ].toLower() == "base64" ) {
115  pair[ 0 ] = "encoding";
116  pair.append( "base64" );
117  } else {
118  pair.prepend( "type" );
119  }
120  }
121  if ( pair[ 1 ].indexOf( ',' ) != -1 ) { // parameter in type=x,y,z format
122  const QList<QByteArray> args = pair[ 1 ].split( ',' );
123  QList<QByteArray>::ConstIterator argIt;
124  QList<QByteArray>::ConstIterator argEnd( args.constEnd() );
125  for ( argIt = args.constBegin(); argIt != argEnd; ++argIt ) {
126  vCardLine.addParameter( QString::fromLatin1( pair[ 0 ].toLower() ),
127  QString::fromLatin1( *argIt ) );
128  }
129  } else {
130  vCardLine.addParameter( QString::fromLatin1( pair[ 0 ].toLower() ),
131  QString::fromLatin1( pair[ 1 ] ) );
132  }
133  }
134  }
135 
136  removeEscapes( value );
137 
138  QByteArray output;
139  bool wasBase64Encoded = false;
140 
141  if ( vCardLine.parameterList().contains( QLatin1String( "encoding" ) ) ) {
142  const QString encoding = vCardLine.parameter( QLatin1String( "encoding" ) ).toLower();
143 
144  // have to decode the data
145  if ( encoding == QLatin1String( "b" ) || encoding == QLatin1String( "base64" ) ) {
146  output = QByteArray::fromBase64( value );
147  wasBase64Encoded = true;
148  }
149  else if ( encoding == QLatin1String( "quoted-printable" ) ) {
150  // join any qp-folded lines
151  while ( value.endsWith( '=' ) && it != linesEnd ) {
152  value.chop( 1 ); // remove the '='
153  value.append( *it );
154  ++it;
155  }
156  KCodecs::quotedPrintableDecode( value, output );
157  } else if ( encoding == QLatin1String( "8bit" ) ) {
158  output = value;
159  } else {
160  qDebug( "Unknown vcard encoding type!" );
161  }
162  } else {
163  output = value;
164  }
165 
166  if ( vCardLine.parameterList().contains( QLatin1String( "charset" ) ) ) {
167  // have to convert the data
168  QTextCodec *codec = QTextCodec::codecForName(
169  vCardLine.parameter( QLatin1String( "charset" ) ).toLatin1() );
170  if ( codec ) {
171  vCardLine.setValue( codec->toUnicode( output ) );
172  } else {
173  vCardLine.setValue( QString::fromUtf8( output ) );
174  }
175  } else if ( wasBase64Encoded ) {
176  vCardLine.setValue( output );
177  } else {
178  vCardLine.setValue( QString::fromUtf8( output ) );
179  }
180 
181  currentVCard.addLine( vCardLine );
182  }
183 
184  // we do not save the start and end tag as vcardline
185  if ( ( *it ).toLower().startsWith( "begin:vcard" ) ) { //krazy:exclude=strings
186  inVCard = true;
187  currentLine.clear();
188  currentVCard.clear(); // flush vcard
189  continue;
190  }
191 
192  if ( ( *it ).toLower().startsWith( "end:vcard" ) ) { //krazy:exclude=strings
193  inVCard = false;
194  vCardList.append( currentVCard );
195  currentLine.clear();
196  currentVCard.clear(); // flush vcard
197  continue;
198  }
199 
200  currentLine = ( *it );
201  }
202  }
203 
204  return vCardList;
205 }
206 
207 QByteArray VCardParser::createVCards( const VCard::List &list )
208 {
209  QByteArray text;
210  QByteArray textLine;
211  QString encodingType;
212  QStringList idents;
213  QStringList params;
214  QStringList values;
215  QStringList::ConstIterator identIt;
216  QStringList::Iterator paramIt;
217  QStringList::ConstIterator valueIt;
218 
219  VCardLine::List lines;
220  VCardLine::List::ConstIterator lineIt;
221  VCard::List::ConstIterator cardIt;
222 
223  bool hasEncoding;
224 
225  text.reserve( list.size() * 300 ); // reserve memory to be more efficient
226 
227  // iterate over the cards
228  VCard::List::ConstIterator listEnd( list.end() );
229  for ( cardIt = list.begin(); cardIt != listEnd; ++cardIt ) {
230  text.append( "BEGIN:VCARD\r\n" );
231 
232  idents = ( *cardIt ).identifiers();
233  for ( identIt = idents.constBegin(); identIt != idents.constEnd(); ++identIt ) {
234  lines = ( *cardIt ).lines( ( *identIt ) );
235 
236  // iterate over the lines
237  for ( lineIt = lines.constBegin(); lineIt != lines.constEnd(); ++lineIt ) {
238  QVariant val = ( *lineIt ).value();
239  if ( val.isValid() ) {
240  if ( ( *lineIt ).hasGroup() ) {
241  textLine = ( *lineIt ).group().toLatin1() + '.' + ( *lineIt ).identifier().toLatin1();
242  } else {
243  textLine = ( *lineIt ).identifier().toLatin1();
244  }
245 
246  params = ( *lineIt ).parameterList();
247  hasEncoding = false;
248  if ( !params.isEmpty() ) { // we have parameters
249  for ( paramIt = params.begin(); paramIt != params.end(); ++paramIt ) {
250  if ( ( *paramIt ) == QLatin1String( "encoding" ) ) {
251  hasEncoding = true;
252  encodingType = ( *lineIt ).parameter( QLatin1String( "encoding" ) ).toLower();
253  }
254 
255  values = ( *lineIt ).parameters( *paramIt );
256  for ( valueIt = values.constBegin(); valueIt != values.constEnd(); ++valueIt ) {
257  textLine.append( ';' + ( *paramIt ).toLatin1().toUpper() );
258  if ( !( *valueIt ).isEmpty() ) {
259  textLine.append( '=' + ( *valueIt ).toLatin1() );
260  }
261  }
262  }
263  }
264 
265  QByteArray input, output;
266 
267  // handle charset
268  if ( ( *lineIt ).parameterList().contains( QLatin1String( "charset" ) ) ) {
269  // have to convert the data
270  const QString value = ( *lineIt ).value().toString();
271  QTextCodec *codec = QTextCodec::codecForName(
272  ( *lineIt ).parameter( QLatin1String( "charset" ) ).toLatin1() );
273  if ( codec ) {
274  input = codec->fromUnicode( value );
275  } else {
276  input = value.toUtf8();
277  }
278  } else if ( ( *lineIt ).value().type() == QVariant::ByteArray ) {
279  input = ( *lineIt ).value().toByteArray();
280  } else {
281  input = ( *lineIt ).value().toString().toUtf8();
282  }
283 
284  // handle encoding
285  if ( hasEncoding ) { // have to encode the data
286  if ( encodingType == QLatin1String( "b" ) ) {
287  output = input.toBase64();
288  } else if ( encodingType == QLatin1String( "quoted-printable" ) ) {
289  KCodecs::quotedPrintableEncode( input, output, false );
290  }
291  } else {
292  output = input;
293  }
294  addEscapes( output, ( *lineIt ).identifier() == QLatin1String( "CATEGORIES" ) );
295 
296  if ( !output.isEmpty() ) {
297  textLine.append( ':' + output );
298 
299  if ( textLine.length() > FOLD_WIDTH ) { // we have to fold the line
300  for ( int i = 0; i <= ( textLine.length() / FOLD_WIDTH ); ++i ) {
301  text.append(
302  ( i == 0 ? "" : " " ) + textLine.mid( i * FOLD_WIDTH, FOLD_WIDTH ) + "\r\n" );
303  }
304  } else {
305  text.append( textLine + "\r\n" );
306  }
307  }
308  }
309  }
310  }
311 
312  text.append( "END:VCARD\r\n" );
313  text.append( "\r\n" );
314  }
315 
316  return text;
317 }
This file is part of the KDE documentation.
Documentation copyright © 1996-2013 The KDE developers.
Generated on Sat Jul 13 2013 01:29:42 by doxygen 1.8.3.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.10.5 API Reference

Skip menu "kdepimlibs-4.10.5 API Reference"
  • akonadi
  •   contact
  •   kmime
  •   socialutils
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kioslave
  •   imap4
  •   mbox
  •   nntp
  • kldap
  • kmbox
  • kmime
  • kontactinterface
  • kpimidentities
  • kpimtextedit
  • 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