Example #1
0
VCard::List VCardParser::parseVCards( const QByteArray &text )
{
  VCard currentVCard;
  VCard::List vCardList;
  QByteArray currentLine;

  QList<QByteArray> lines = text.split( '\n' );

  bool inVCard = false;
  QList<QByteArray>::Iterator it( lines.begin() );
  QList<QByteArray>::Iterator linesEnd( lines.end() );
  for ( ; it != linesEnd; ++it ) {
    // remove the trailing \r, left from \r\n
    if ( ( *it ).endsWith( '\r' ) ) {
        ( *it ).chop( 1 );
    }

    if ( ( *it ).startsWith( ' ' ) ||
         ( *it ).startsWith( '\t' ) ) { //folded line => append to previous
      currentLine.append( ( *it ).mid( 1 ) );
      continue;
    } else {
      if ( ( *it ).trimmed().isEmpty() ) { // empty line
        continue;
      }
      if ( inVCard && !currentLine.isEmpty() ) { // now parse the line
        int colon = currentLine.indexOf( ':' );
        if ( colon == -1 ) { // invalid line
          currentLine = ( *it );
          continue;
        }

        VCardLine vCardLine;
        const QByteArray key = currentLine.left( colon ).trimmed();
        QByteArray value = currentLine.mid( colon + 1 );

        QList<QByteArray> params = key.split( ';' );

        // check for group
        int groupPos = params[ 0 ].indexOf( '.' );
        if ( groupPos != -1 ) {
          vCardLine.setGroup( QString::fromLatin1( params[ 0 ].left( groupPos ) ) );
          vCardLine.setIdentifier( QString::fromLatin1( params[ 0 ].mid( groupPos + 1 ) ) );
        } else {
          vCardLine.setIdentifier( QString::fromLatin1( params[ 0 ] ) );
        }

        if ( params.count() > 1 ) { // find all parameters
          QList<QByteArray>::ConstIterator paramIt( params.constBegin() );
          for ( ++paramIt; paramIt != params.constEnd(); ++paramIt ) {
            QList<QByteArray> pair = ( *paramIt ).split( '=' );
            if ( pair.count() == 1 ) {
              // correct the f*****g 2.1 'standard'
              if ( pair[ 0 ].toLower() == "quoted-printable" ) {
                pair[ 0 ] = "encoding";
                pair.append( "quoted-printable" );
              } else if ( pair[ 0 ].toLower() == "base64" ) {
                pair[ 0 ] = "encoding";
                pair.append( "base64" );
              } else {
                pair.prepend( "type" );
              }
            }
            if ( pair[ 1 ].indexOf( ',' ) != -1 ) { // parameter in type=x,y,z format
              const QList<QByteArray> args = pair[ 1 ].split( ',' );
              QList<QByteArray>::ConstIterator argIt;
              QList<QByteArray>::ConstIterator argEnd( args.constEnd() );
              for ( argIt = args.constBegin(); argIt != argEnd; ++argIt ) {
                vCardLine.addParameter( QString::fromLatin1( pair[ 0 ].toLower() ),
                                        QString::fromLatin1( *argIt ) );
              }
            } else {
              vCardLine.addParameter( QString::fromLatin1( pair[ 0 ].toLower() ),
                                      QString::fromLatin1( pair[ 1 ] ) );
            }
          }
        }

        removeEscapes( value );

        QByteArray output;
        bool wasBase64Encoded = false;

        if ( vCardLine.parameterList().contains( QLatin1String( "encoding" ) ) ) {
          const QString encoding = vCardLine.parameter( QLatin1String( "encoding" ) ).toLower();

          // have to decode the data
          if ( encoding == QLatin1String( "b" ) || encoding == QLatin1String( "base64" ) ) {
            output = QByteArray::fromBase64( value );
            wasBase64Encoded = true;
          }
          else if ( encoding == QLatin1String( "quoted-printable" ) ) {
            // join any qp-folded lines
            while ( value.endsWith( '=' ) && it != linesEnd ) {
              value.chop( 1 ); // remove the '='
              value.append( *it );
              ++it;
            }
            KCodecs::quotedPrintableDecode( value, output );
          } else if ( encoding == QLatin1String( "8bit" ) ) {
            output = value;
          } else {
            qDebug( "Unknown vcard encoding type!" );
          }
        } else {
          output = value;
        }

        if ( vCardLine.parameterList().contains( QLatin1String( "charset" ) ) ) {
          // have to convert the data
          QTextCodec *codec = QTextCodec::codecForName(
            vCardLine.parameter( QLatin1String( "charset" ) ).toLatin1() );
          if ( codec ) {
            vCardLine.setValue( codec->toUnicode( output ) );
          } else {
            vCardLine.setValue( QString::fromUtf8( output ) );
          }
        } else if ( wasBase64Encoded ) {
            vCardLine.setValue( output );
        } else {
            vCardLine.setValue( QString::fromUtf8( output ) );
        }

        currentVCard.addLine( vCardLine );
      }

      // we do not save the start and end tag as vcardline
      if ( ( *it ).toLower().startsWith( "begin:vcard" ) ) { //krazy:exclude=strings
        inVCard = true;
        currentLine.clear();
        currentVCard.clear(); // flush vcard
        continue;
      }

      if ( ( *it ).toLower().startsWith( "end:vcard" ) ) { //krazy:exclude=strings
        inVCard = false;
        vCardList.append( currentVCard );
        currentLine.clear();
        currentVCard.clear(); // flush vcard
        continue;
      }

      currentLine = ( *it );
    }
  }

  return vCardList;
}
Example #2
0
// TODO: make list a const&
QString VCardTool::createVCards(Addressee::List list, VCard::Version version)
{
    VCard::List vCardList;

    Addressee::List::ConstIterator addrIt;
    Addressee::List::ConstIterator listEnd(list.constEnd());
    for(addrIt = list.constBegin(); addrIt != listEnd; ++addrIt)
    {
        VCard card;
        QStringList::ConstIterator strIt;

        // ADR + LABEL
        const Address::List addresses = (*addrIt).addresses();
        for(Address::List::ConstIterator it = addresses.begin(); it != addresses.end(); ++it)
        {
            QStringList address;

            bool isEmpty = ((*it).postOfficeBox().isEmpty() && (*it).extended().isEmpty() && (*it).street().isEmpty() && (*it).locality().isEmpty()
                            && (*it).region().isEmpty() && (*it).postalCode().isEmpty() && (*it).country().isEmpty());

            address.append((*it).postOfficeBox().replace(';', "\\;"));
            address.append((*it).extended().replace(';', "\\;"));
            address.append((*it).street().replace(';', "\\;"));
            address.append((*it).locality().replace(';', "\\;"));
            address.append((*it).region().replace(';', "\\;"));
            address.append((*it).postalCode().replace(';', "\\;"));
            address.append((*it).country().replace(';', "\\;"));

            VCardLine adrLine("ADR", address.join(";"));
            if(version == VCard::v2_1 && needsEncoding(address.join(";")))
            {
                adrLine.addParameter("charset", "UTF-8");
                adrLine.addParameter("encoding", "QUOTED-PRINTABLE");
            }

            VCardLine labelLine("LABEL", (*it).label());
            if(version == VCard::v2_1 && needsEncoding((*it).label()))
            {
                labelLine.addParameter("charset", "UTF-8");
                labelLine.addParameter("encoding", "QUOTED-PRINTABLE");
            }

            bool hasLabel = !(*it).label().isEmpty();
            QMap< QString, int >::ConstIterator typeIt;
            for(typeIt = mAddressTypeMap.constBegin(); typeIt != mAddressTypeMap.constEnd(); ++typeIt)
            {
                if(typeIt.data() & (*it).type())
                {
                    adrLine.addParameter("TYPE", typeIt.key());
                    if(hasLabel)
                        labelLine.addParameter("TYPE", typeIt.key());
                }
            }

            if(!isEmpty)
                card.addLine(adrLine);
            if(hasLabel)
                card.addLine(labelLine);
        }

        // AGENT
        card.addLine(createAgent(version, (*addrIt).agent()));

        // BDAY
        card.addLine(VCardLine("BDAY", createDateTime((*addrIt).birthday())));

        // CATEGORIES
        if(version == VCard::v3_0)
        {
            QStringList categories = (*addrIt).categories();
            QStringList::Iterator catIt;
            for(catIt = categories.begin(); catIt != categories.end(); ++catIt)
                (*catIt).replace(',', "\\,");

            VCardLine catLine("CATEGORIES", categories.join(","));
            if(version == VCard::v2_1 && needsEncoding(categories.join(",")))
            {
                catLine.addParameter("charset", "UTF-8");
                catLine.addParameter("encoding", "QUOTED-PRINTABLE");
            }

            card.addLine(catLine);
        }

        // CLASS
        if(version == VCard::v3_0)
        {
            card.addLine(createSecrecy((*addrIt).secrecy()));
        }

        // EMAIL
        const QStringList emails = (*addrIt).emails();
        bool pref = true;
        for(strIt = emails.begin(); strIt != emails.end(); ++strIt)
        {
            VCardLine line("EMAIL", *strIt);
            if(pref == true && emails.count() > 1)
            {
                line.addParameter("TYPE", "PREF");
                pref = false;
            }
            card.addLine(line);
        }

        // FN
        VCardLine fnLine("FN", (*addrIt).formattedName());
        if(version == VCard::v2_1 && needsEncoding((*addrIt).formattedName()))
        {
            fnLine.addParameter("charset", "UTF-8");
            fnLine.addParameter("encoding", "QUOTED-PRINTABLE");
        }
        card.addLine(fnLine);

        // GEO
        Geo geo = (*addrIt).geo();
        if(geo.isValid())
        {
            QString str;
            str.sprintf("%.6f;%.6f", geo.latitude(), geo.longitude());
            card.addLine(VCardLine("GEO", str));
        }

        // KEY
        const Key::List keys = (*addrIt).keys();
        Key::List::ConstIterator keyIt;
        for(keyIt = keys.begin(); keyIt != keys.end(); ++keyIt)
            card.addLine(createKey(*keyIt));

        // LOGO
        card.addLine(createPicture("LOGO", (*addrIt).logo()));

        // MAILER
        VCardLine mailerLine("MAILER", (*addrIt).mailer());
        if(version == VCard::v2_1 && needsEncoding((*addrIt).mailer()))
        {
            mailerLine.addParameter("charset", "UTF-8");
            mailerLine.addParameter("encoding", "QUOTED-PRINTABLE");
        }
        card.addLine(mailerLine);

        // N
        QStringList name;
        name.append((*addrIt).familyName().replace(';', "\\;"));
        name.append((*addrIt).givenName().replace(';', "\\;"));
        name.append((*addrIt).additionalName().replace(';', "\\;"));
        name.append((*addrIt).prefix().replace(';', "\\;"));
        name.append((*addrIt).suffix().replace(';', "\\;"));

        VCardLine nLine("N", name.join(";"));
        if(version == VCard::v2_1 && needsEncoding(name.join(";")))
        {
            nLine.addParameter("charset", "UTF-8");
            nLine.addParameter("encoding", "QUOTED-PRINTABLE");
        }
        card.addLine(nLine);

        // NAME
        VCardLine nameLine("NAME", (*addrIt).name());
        if(version == VCard::v2_1 && needsEncoding((*addrIt).name()))
        {
            nameLine.addParameter("charset", "UTF-8");
            nameLine.addParameter("encoding", "QUOTED-PRINTABLE");
        }
        card.addLine(nameLine);

        // NICKNAME
        if(version == VCard::v3_0)
            card.addLine(VCardLine("NICKNAME", (*addrIt).nickName()));

        // NOTE
        VCardLine noteLine("NOTE", (*addrIt).note());
        if(version == VCard::v2_1 && needsEncoding((*addrIt).note()))
        {
            noteLine.addParameter("charset", "UTF-8");
            noteLine.addParameter("encoding", "QUOTED-PRINTABLE");
        }
        card.addLine(noteLine);

        // ORG
        QStringList organization;
        organization.append((*addrIt).organization().replace(';', "\\;"));
        if(!(*addrIt).department().isEmpty())
            organization.append((*addrIt).department().replace(';', "\\;"));
        VCardLine orgLine("ORG", organization.join(";"));
        if(version == VCard::v2_1 && needsEncoding(organization.join(";")))
        {
            orgLine.addParameter("charset", "UTF-8");
            orgLine.addParameter("encoding", "QUOTED-PRINTABLE");
        }
        card.addLine(orgLine);

        // PHOTO
        card.addLine(createPicture("PHOTO", (*addrIt).photo()));

        // PROID
        if(version == VCard::v3_0)
            card.addLine(VCardLine("PRODID", (*addrIt).productId()));

        // REV
        card.addLine(VCardLine("REV", createDateTime((*addrIt).revision())));

        // ROLE
        VCardLine roleLine("ROLE", (*addrIt).role());
        if(version == VCard::v2_1 && needsEncoding((*addrIt).role()))
        {
            roleLine.addParameter("charset", "UTF-8");
            roleLine.addParameter("encoding", "QUOTED-PRINTABLE");
        }
        card.addLine(roleLine);

        // SORT-STRING
        if(version == VCard::v3_0)
            card.addLine(VCardLine("SORT-STRING", (*addrIt).sortString()));

        // SOUND
        card.addLine(createSound((*addrIt).sound()));

        // TEL
        const PhoneNumber::List phoneNumbers = (*addrIt).phoneNumbers();
        PhoneNumber::List::ConstIterator phoneIt;
        for(phoneIt = phoneNumbers.begin(); phoneIt != phoneNumbers.end(); ++phoneIt)
        {
            VCardLine line("TEL", (*phoneIt).number());

            QMap< QString, int >::ConstIterator typeIt;
            for(typeIt = mPhoneTypeMap.constBegin(); typeIt != mPhoneTypeMap.constEnd(); ++typeIt)
            {
                if(typeIt.data() & (*phoneIt).type())
                    line.addParameter("TYPE", typeIt.key());
            }

            card.addLine(line);
        }

        // TITLE
        VCardLine titleLine("TITLE", (*addrIt).title());
        if(version == VCard::v2_1 && needsEncoding((*addrIt).title()))
        {
            titleLine.addParameter("charset", "UTF-8");
            titleLine.addParameter("encoding", "QUOTED-PRINTABLE");
        }
        card.addLine(titleLine);

        // TZ
        TimeZone timeZone = (*addrIt).timeZone();
        if(timeZone.isValid())
        {
            QString str;

            int neg = 1;
            if(timeZone.offset() < 0)
                neg = -1;

            str.sprintf("%c%02d:%02d", (timeZone.offset() >= 0 ? '+' : '-'), (timeZone.offset() / 60) * neg, (timeZone.offset() % 60) * neg);

            card.addLine(VCardLine("TZ", str));
        }

        // UID
        card.addLine(VCardLine("UID", (*addrIt).uid()));

        // URL
        card.addLine(VCardLine("URL", (*addrIt).url().url()));

        // VERSION
        if(version == VCard::v2_1)
            card.addLine(VCardLine("VERSION", "2.1"));
        if(version == VCard::v3_0)
            card.addLine(VCardLine("VERSION", "3.0"));

        // X-
        const QStringList customs = (*addrIt).customs();
        for(strIt = customs.begin(); strIt != customs.end(); ++strIt)
        {
            QString identifier = "X-" + (*strIt).left((*strIt).find(":"));
            QString value = (*strIt).mid((*strIt).find(":") + 1);
            if(value.isEmpty())
                continue;

            VCardLine line(identifier, value);
            if(version == VCard::v2_1 && needsEncoding(value))
            {
                line.addParameter("charset", "UTF-8");
                line.addParameter("encoding", "QUOTED-PRINTABLE");
            }
            card.addLine(line);
        }

        vCardList.append(card);
    }

    return VCardParser::createVCards(vCardList);
}
Example #3
0
VCard::List VCardParser::parseVCards( const QString& text )
{
  static QRegExp sep( "[\x0d\x0a]" );

  VCard currentVCard;
  VCard::List vCardList;
  QString currentLine;

  const QStringList lines = QStringList::split( sep, text );
  QStringList::ConstIterator it;

  bool inVCard = false;
  QStringList::ConstIterator linesEnd( lines.end() );
  for ( it = lines.begin(); it != linesEnd; ++it ) {

    if ( (*it).isEmpty() ) // empty line
      continue;

    if ( (*it)[ 0 ] == ' ' || (*it)[ 0 ] == '\t' ) { // folded line => append to previous
      currentLine += QString( *it ).remove( 0, 1 );
      continue;
    } else {
      if ( inVCard && !currentLine.isEmpty() ) { // now parse the line
        int colon = currentLine.find( ':' );
        if ( colon == -1 ) { // invalid line
          currentLine = (*it);
          continue;
        }

        VCardLine vCardLine;
        const QString key = currentLine.left( colon ).stripWhiteSpace();
        QString value = currentLine.mid( colon + 1 );

        QStringList params = QStringList::split( ';', key );

        // check for group
        if ( params[0].find( '.' ) != -1 ) {
          const QStringList groupList = QStringList::split( '.', params[0] );
          vCardLine.setGroup( groupList[0] );
          vCardLine.setIdentifier( groupList[1] );
        } else
          vCardLine.setIdentifier( params[0] );

        if ( params.count() > 1 ) { // find all parameters
          QStringList::ConstIterator paramIt = params.begin();
          for ( ++paramIt; paramIt != params.end(); ++paramIt ) {
            QStringList pair = QStringList::split( '=', *paramIt );
            if ( pair.size() == 1 ) {
              // correct the f*****g 2.1 'standard'
              if ( pair[0].lower() == "quoted-printable" ) {
                pair[0] = "encoding";
                pair[1] = "quoted-printable";
              } else if ( pair[0].lower() == "base64" ) {
                pair[0] = "encoding";
                pair[1] = "base64";
              } else {
                pair.prepend( "type" );
              }
            }
            // This is pretty much a faster pair[1].contains( ',' )...
            if ( pair[1].find( ',' ) != -1 ) { // parameter in type=x,y,z format
              const QStringList args = QStringList::split( ',', pair[ 1 ] );
              QStringList::ConstIterator argIt;
              for ( argIt = args.begin(); argIt != args.end(); ++argIt )
                vCardLine.addParameter( pair[0].lower(), *argIt );
            } else
              vCardLine.addParameter( pair[0].lower(), pair[1] );
          }
        }

        removeEscapes( value );

        QByteArray output;
        bool wasBase64Encoded = false;

        params = vCardLine.parameterList();
        if ( params.findIndex( "encoding" ) != -1 ) { // have to decode the data
          QByteArray input;
          input = QCString(value.latin1());
          if ( vCardLine.parameter( "encoding" ).lower() == "b" ||
               vCardLine.parameter( "encoding" ).lower() == "base64" ) {
            KCodecs::base64Decode( input, output );
            wasBase64Encoded = true;
          }
          else if ( vCardLine.parameter( "encoding" ).lower() == "quoted-printable" ) {
            // join any qp-folded lines
            while ( value.at( value.length() - 1 ) == '=' && it != linesEnd ) {
              value = value.remove( value.length() - 1, 1 ) + (*it);
              ++it;
            }
            input = QCString(value.latin1());
            KCodecs::quotedPrintableDecode( input, output );
          }
        } else {
          output = QCString(value.latin1());
        }

        if ( params.findIndex( "charset" ) != -1 ) { // have to convert the data
          QTextCodec *codec =
            QTextCodec::codecForName( vCardLine.parameter( "charset" ).latin1() );
          if ( codec ) {
            vCardLine.setValue( codec->toUnicode( output ) );
          } else {
            vCardLine.setValue( QString::fromUtf8( output ) );
          }
        } else if ( wasBase64Encoded ) {
            vCardLine.setValue( output );
        } else {  // if charset not given, assume it's in UTF-8 (as used in previous KDE versions)
            vCardLine.setValue( QString::fromUtf8( output ) );
        }

        currentVCard.addLine( vCardLine );
      }

      // we do not save the start and end tag as vcardline
      if ( (*it).lower().startsWith( "begin:vcard" ) ) {
        inVCard = true;
        currentLine.setLength( 0 );
        currentVCard.clear(); // flush vcard
        continue;
      }

      if ( (*it).lower().startsWith( "end:vcard" ) ) {
        inVCard = false;
        vCardList.append( currentVCard );
        currentLine.setLength( 0 );
        currentVCard.clear(); // flush vcard
        continue;
      }

      currentLine = (*it);
    }
  }

  return vCardList;
}