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

kabc

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

Skip menu "kdepimlibs API Reference"
  • akonadi
  •   contact
  •   kmime
  •   socialutils
  • kabc
  • kalarmcal
  • kblog
  • kcal
  • kcalcore
  • kcalutils
  • kholidays
  • kimap
  • kldap
  • kmbox
  • kmime
  • kpimidentities
  • kpimtextedit
  • kresources
  • ktnef
  • kxmlrpcclient
  • microblog

Search



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