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;
53 static 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" );
63 static 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 *)
"\\\\",
"\\" );
72 VCardParser::VCardParser()
77 VCardParser::~VCardParser()
81 VCard::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 );
237 QByteArray 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();
263 for ( identIt = idents.constBegin(); identIt != idents.constEnd(); ++identIt ) {
264 lines = ( *cardIt ).lines( ( *identIt ) );
267 for ( lineIt = lines.constBegin(); lineIt != lines.constEnd(); ++lineIt ) {
268 QVariant val = ( *lineIt ).value();
269 if ( val.isValid() ) {
270 if ( ( *lineIt ).hasGroup() ) {
271 textLine = ( *lineIt ).group().toLatin1() +
'.' + ( *lineIt ).identifier().toLatin1();
273 textLine = ( *lineIt ).identifier().toLatin1();
276 params = ( *lineIt ).parameterList();
278 if ( !params.isEmpty() ) {
279 for ( paramIt = params.begin(); paramIt != params.end(); ++paramIt ) {
280 if ( ( *paramIt ) == QLatin1String(
"encoding" ) ) {
282 encodingType = ( *lineIt ).parameter( QLatin1String(
"encoding" ) ).toLower();
285 values = ( *lineIt ).parameters( *paramIt );
286 for ( valueIt = values.constBegin(); valueIt != values.constEnd(); ++valueIt ) {
287 textLine.append(
';' + ( *paramIt ).toLatin1().toUpper() );
288 if ( !( *valueIt ).isEmpty() ) {
289 textLine.append(
'=' + ( *valueIt ).toLatin1() );
295 QByteArray input, output;
296 bool checkMultibyte =
false;
299 if ( ( *lineIt ).parameterList().contains( QLatin1String(
"charset" ) ) ) {
301 const QString value = ( *lineIt ).value().toString();
302 QTextCodec *codec = QTextCodec::codecForName(
303 ( *lineIt ).parameter( QLatin1String(
"charset" ) ).toLatin1() );
305 input = codec->fromUnicode( value );
307 checkMultibyte =
true;
308 input = value.toUtf8();
310 }
else if ( ( *lineIt ).value().type() == QVariant::ByteArray ) {
311 input = ( *lineIt ).value().toByteArray();
313 checkMultibyte =
true;
314 input = ( *lineIt ).value().toString().toUtf8();
319 if ( encodingType == QLatin1String(
"b" ) ) {
320 checkMultibyte =
false;
321 output = input.toBase64();
322 }
else if ( encodingType == QLatin1String(
"quoted-printable" ) ) {
323 checkMultibyte =
false;
324 KCodecs::quotedPrintableEncode( input, output,
false );
329 addEscapes( output, ( *lineIt ).identifier() == QLatin1String(
"CATEGORIES" ) );
331 if ( !output.isEmpty() ) {
332 textLine.append(
':' + output );
334 if ( textLine.length() > FOLD_WIDTH ) {
335 if ( checkMultibyte ) {
339 for (
int i = 0; i < textLine.length(); ++i ) {
340 if ( (textLine[i] & 0xC0) == 0xC0 ) {
341 int sequenceLength = 2;
342 if ( (textLine[i] & 0xE0) == 0xE0 ) {
344 }
else if ( (textLine[i] & 0xF0) == 0xF0 ) {
347 if ( (lineLength + sequenceLength) > FOLD_WIDTH ) {
349 text +=
"\r\n " + textLine.mid(i, sequenceLength);
350 lineLength = 1 + sequenceLength;
352 text += textLine.mid(i, sequenceLength);
353 lineLength += sequenceLength;
355 i += sequenceLength - 1;
360 if ( (lineLength == FOLD_WIDTH) && (i < (textLine.length() - 1)) ) {
367 for (
int i = 0; i <= ( textLine.length() / FOLD_WIDTH ); ++i ) {
369 ( i == 0 ?
"" :
" " ) + textLine.mid( i * FOLD_WIDTH, FOLD_WIDTH ) +
"\r\n" );
373 text.append( textLine +
"\r\n" );
380 text.append(
"END:VCARD\r\n" );
381 text.append(
"\r\n" );