21#include "vcardparser.h"
24#include <QtCore/QTextCodec>
29 QString fromLatin1(
const QByteArray &value)
31 if (value.isEmpty()) {
35 QHash<QByteArray, QString>::const_iterator it = m_values.constFind(value);
36 if (it != m_values.constEnd()) {
40 QString
string = QString::fromLatin1(value, value.size());
41 m_values.insert(value,
string);
46 QHash<QByteArray, QString> m_values;
53static void addEscapes( QByteArray &str,
bool excludeEscapteComma )
55 str.replace(
'\\', (
char *)
"\\\\" );
56 if ( !excludeEscapteComma ) {
57 str.replace(
',', (
char *)
"\\," );
59 str.replace(
'\r', (
char *)
"\\r" );
60 str.replace(
'\n', (
char *)
"\\n" );
63static void removeEscapes( QByteArray &str )
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 *)
"\\\\",
"\\" );
72VCardParser::VCardParser()
77VCardParser::~VCardParser()
81VCard::List VCardParser::parseVCards(
const QByteArray &text )
84 VCard::List vCardList;
85 QByteArray currentLine;
87 QList<QByteArray> lines = text.split(
'\n' );
90 QList<QByteArray>::Iterator it( lines.begin() );
91 QList<QByteArray>::Iterator linesEnd( lines.end() );
95 for ( ; it != linesEnd; ++it ) {
97 if ( ( *it ).endsWith(
'\r' ) ) {
101 if ( ( *it ).startsWith(
' ' ) ||
102 ( *it ).startsWith(
'\t' ) ) {
103 currentLine.append( ( *it ).mid( 1 ) );
106 if ( ( *it ).trimmed().isEmpty() ) {
109 if ( inVCard && !currentLine.isEmpty() ) {
110 int colon = currentLine.indexOf(
':' );
112 currentLine = ( *it );
117 const QByteArray key = currentLine.left( colon ).trimmed();
118 QByteArray value = currentLine.mid( colon + 1 );
120 QList<QByteArray> params = key.split(
';' );
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 ) ) );
128 vCardLine.setIdentifier( cache.fromLatin1( params[ 0 ] ) );
131 if ( params.count() > 1 ) {
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 ) {
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" );
144 pair.prepend(
"type" );
147 if ( pair[ 1 ].indexOf(
',' ) != -1 ) {
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 ) );
156 vCardLine.addParameter( cache.fromLatin1( pair[ 0 ].toLower() ),
157 cache.fromLatin1( pair[ 1 ] ) );
162 removeEscapes( value );
165 bool wasBase64Encoded =
false;
167 if ( vCardLine.parameterList().contains( QLatin1String(
"encoding" ) ) ) {
168 const QString encoding = vCardLine.parameter( QLatin1String(
"encoding" ) ).toLower();
171 if ( encoding == QLatin1String(
"b" ) || encoding == QLatin1String(
"base64" ) ) {
172 output = QByteArray::fromBase64( value );
173 wasBase64Encoded =
true;
175 else if ( encoding == QLatin1String(
"quoted-printable" ) ) {
177 while ( value.endsWith(
'=' ) && it != linesEnd ) {
182 if ( (*it).endsWith(
'\r') ) {
186 KCodecs::quotedPrintableDecode( value, output );
187 }
else if ( encoding == QLatin1String(
"8bit" ) ) {
190 qDebug(
"Unknown vcard encoding type!" );
196 if ( vCardLine.parameterList().contains( QLatin1String(
"charset" ) ) ) {
198 QTextCodec *codec = QTextCodec::codecForName(
199 vCardLine.parameter( QLatin1String(
"charset" ) ).toLatin1() );
201 vCardLine.setValue( codec->toUnicode( output ) );
203 vCardLine.setValue( QString::fromUtf8( output ) );
205 }
else if ( wasBase64Encoded ) {
206 vCardLine.setValue( output );
208 vCardLine.setValue( QString::fromUtf8( output ) );
211 currentVCard.addLine( vCardLine );
215 if ( ( *it ).toLower().startsWith(
"begin:vcard" ) ) {
218 currentVCard.clear();
222 if ( ( *it ).toLower().startsWith(
"end:vcard" ) ) {
224 vCardList.append( currentVCard );
226 currentVCard.clear();
230 currentLine = ( *it );
237QByteArray VCardParser::createVCards(
const VCard::List &list )
241 QString encodingType;
245 QStringList::ConstIterator identIt;
246 QStringList::Iterator paramIt;
247 QStringList::ConstIterator valueIt;
249 VCardLine::List lines;
250 VCardLine::List::ConstIterator lineIt;
251 VCard::List::ConstIterator cardIt;
255 text.reserve( list.size() * 300 );
258 VCard::List::ConstIterator listEnd( list.end() );
259 for ( cardIt = list.begin(); cardIt != listEnd; ++cardIt ) {
260 text.append(
"BEGIN:VCARD\r\n" );
262 idents = ( *cardIt ).identifiers();
264 if (idents.contains(QLatin1String(
"VERSION"))) {
265 const QString str = idents.takeAt(idents.indexOf(QLatin1String(
"VERSION")));
269 for ( identIt = idents.constBegin(); identIt != idents.constEnd(); ++identIt ) {
270 lines = ( *cardIt ).lines( ( *identIt ) );
273 for ( lineIt = lines.constBegin(); lineIt != lines.constEnd(); ++lineIt ) {
274 QVariant val = ( *lineIt ).value();
275 if ( val.isValid() ) {
276 if ( ( *lineIt ).hasGroup() ) {
277 textLine = ( *lineIt ).group().toLatin1() +
'.' + ( *lineIt ).identifier().toLatin1();
279 textLine = ( *lineIt ).identifier().toLatin1();
282 params = ( *lineIt ).parameterList();
284 if ( !params.isEmpty() ) {
285 for ( paramIt = params.begin(); paramIt != params.end(); ++paramIt ) {
286 if ( ( *paramIt ) == QLatin1String(
"encoding" ) ) {
288 encodingType = ( *lineIt ).parameter( QLatin1String(
"encoding" ) ).toLower();
291 values = ( *lineIt ).parameters( *paramIt );
292 for ( valueIt = values.constBegin(); valueIt != values.constEnd(); ++valueIt ) {
293 textLine.append(
';' + ( *paramIt ).toLatin1().toUpper() );
294 if ( !( *valueIt ).isEmpty() ) {
295 textLine.append(
'=' + ( *valueIt ).toLatin1() );
300 QByteArray input, output;
301 bool checkMultibyte =
false;
304 if ( ( *lineIt ).parameterList().contains( QLatin1String(
"charset" ) ) ) {
306 const QString value = ( *lineIt ).value().toString();
307 QTextCodec *codec = QTextCodec::codecForName(
308 ( *lineIt ).parameter( QLatin1String(
"charset" ) ).toLatin1() );
310 input = codec->fromUnicode( value );
312 checkMultibyte =
true;
313 input = value.toUtf8();
315 }
else if ( ( *lineIt ).value().type() == QVariant::ByteArray ) {
316 input = ( *lineIt ).value().toByteArray();
318 checkMultibyte =
true;
319 input = ( *lineIt ).value().toString().toUtf8();
324 if ( encodingType == QLatin1String(
"b" ) ) {
325 checkMultibyte =
false;
326 output = input.toBase64();
327 }
else if ( encodingType == QLatin1String(
"quoted-printable" ) ) {
328 checkMultibyte =
false;
329 KCodecs::quotedPrintableEncode( input, output,
false );
334 addEscapes( output, (( *lineIt ).identifier() == QLatin1String(
"CATEGORIES" )|| ( *lineIt ).identifier() == QLatin1String(
"GEO" )) );
336 if ( !output.isEmpty() ) {
337 textLine.append(
':' + output );
339 if ( textLine.length() > FOLD_WIDTH ) {
340 if ( checkMultibyte ) {
344 for (
int i = 0; i < textLine.length(); ++i ) {
345 if ( (textLine[i] & 0xC0) == 0xC0 ) {
346 int sequenceLength = 2;
347 if ( (textLine[i] & 0xE0) == 0xE0 ) {
349 }
else if ( (textLine[i] & 0xF0) == 0xF0 ) {
352 if ( (lineLength + sequenceLength) > FOLD_WIDTH ) {
354 text +=
"\r\n " + textLine.mid(i, sequenceLength);
355 lineLength = 1 + sequenceLength;
357 text += textLine.mid(i, sequenceLength);
358 lineLength += sequenceLength;
360 i += sequenceLength - 1;
365 if ( (lineLength == FOLD_WIDTH) && (i < (textLine.length() - 1)) ) {
372 for (
int i = 0; i <= ( textLine.length() / FOLD_WIDTH ); ++i ) {
374 ( i == 0 ?
"" :
" " ) + textLine.mid( i * FOLD_WIDTH, FOLD_WIDTH ) +
"\r\n" );
378 text.append( textLine +
"\r\n" );
385 text.append(
"END:VCARD\r\n" );
386 text.append(
"\r\n" );
Class that holds a Calendar Url (FBURL/CALADRURI/CALURI)