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 KCodecs::quotedPrintableDecode( value, output );
183 }
else if ( encoding == QLatin1String(
"8bit" ) ) {
186 qDebug(
"Unknown vcard encoding type!" );
192 if ( vCardLine.parameterList().contains( QLatin1String(
"charset" ) ) ) {
194 QTextCodec *codec = QTextCodec::codecForName(
195 vCardLine.parameter( QLatin1String(
"charset" ) ).toLatin1() );
197 vCardLine.setValue( codec->toUnicode( output ) );
199 vCardLine.setValue( QString::fromUtf8( output ) );
201 }
else if ( wasBase64Encoded ) {
202 vCardLine.setValue( output );
204 vCardLine.setValue( QString::fromUtf8( output ) );
207 currentVCard.addLine( vCardLine );
211 if ( ( *it ).toLower().startsWith(
"begin:vcard" ) ) {
214 currentVCard.clear();
218 if ( ( *it ).toLower().startsWith(
"end:vcard" ) ) {
220 vCardList.append( currentVCard );
222 currentVCard.clear();
226 currentLine = ( *it );
233 QByteArray VCardParser::createVCards(
const VCard::List &list )
237 QString encodingType;
241 QStringList::ConstIterator identIt;
242 QStringList::Iterator paramIt;
243 QStringList::ConstIterator valueIt;
245 VCardLine::List lines;
246 VCardLine::List::ConstIterator lineIt;
247 VCard::List::ConstIterator cardIt;
251 text.reserve( list.size() * 300 );
254 VCard::List::ConstIterator listEnd( list.end() );
255 for ( cardIt = list.begin(); cardIt != listEnd; ++cardIt ) {
256 text.append(
"BEGIN:VCARD\r\n" );
258 idents = ( *cardIt ).identifiers();
259 for ( identIt = idents.constBegin(); identIt != idents.constEnd(); ++identIt ) {
260 lines = ( *cardIt ).lines( ( *identIt ) );
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();
269 textLine = ( *lineIt ).identifier().toLatin1();
272 params = ( *lineIt ).parameterList();
274 if ( !params.isEmpty() ) {
275 for ( paramIt = params.begin(); paramIt != params.end(); ++paramIt ) {
276 if ( ( *paramIt ) == QLatin1String(
"encoding" ) ) {
278 encodingType = ( *lineIt ).parameter( QLatin1String(
"encoding" ) ).toLower();
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() );
291 QByteArray input, output;
294 if ( ( *lineIt ).parameterList().contains( QLatin1String(
"charset" ) ) ) {
296 const QString value = ( *lineIt ).value().toString();
297 QTextCodec *codec = QTextCodec::codecForName(
298 ( *lineIt ).parameter( QLatin1String(
"charset" ) ).toLatin1() );
300 input = codec->fromUnicode( value );
302 input = value.toUtf8();
304 }
else if ( ( *lineIt ).value().type() == QVariant::ByteArray ) {
305 input = ( *lineIt ).value().toByteArray();
307 input = ( *lineIt ).value().toString().toUtf8();
312 if ( encodingType == QLatin1String(
"b" ) ) {
313 output = input.toBase64();
314 }
else if ( encodingType == QLatin1String(
"quoted-printable" ) ) {
315 KCodecs::quotedPrintableEncode( input, output,
false );
320 addEscapes( output, ( *lineIt ).identifier() == QLatin1String(
"CATEGORIES" ) );
322 if ( !output.isEmpty() ) {
323 textLine.append(
':' + output );
325 if ( textLine.length() > FOLD_WIDTH ) {
326 for (
int i = 0; i <= ( textLine.length() / FOLD_WIDTH ); ++i ) {
328 ( i == 0 ?
"" :
" " ) + textLine.mid( i * FOLD_WIDTH, FOLD_WIDTH ) +
"\r\n" );
331 text.append( textLine +
"\r\n" );
338 text.append(
"END:VCARD\r\n" );
339 text.append(
"\r\n" );