• Skip to content
  • Skip to link menu
KDE 4.2 API Reference
  • KDE API Reference
  • kdepim
  • Sitemap
  • Contact Us
 

libkleo

dn.cpp

Go to the documentation of this file.
00001 /*
00002     dn.cpp
00003 
00004     This file is part of libkleopatra, the KDE keymanagement library
00005     Copyright (c) 2004 Klarälvdalens Datakonsult AB
00006 
00007     DN parsing:
00008     Copyright (c) 2002 g10 Code GmbH
00009     Copyright (c) 2004 Klarälvdalens Datakonsult AB
00010 
00011     Libkleopatra is free software; you can redistribute it and/or
00012     modify it under the terms of the GNU General Public License as
00013     published by the Free Software Foundation; either version 2 of the
00014     License, or (at your option) any later version.
00015 
00016     Libkleopatra is distributed in the hope that it will be useful,
00017     but WITHOUT ANY WARRANTY; without even the implied warranty of
00018     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019     General Public License for more details.
00020 
00021     You should have received a copy of the GNU General Public License along
00022     with this program; if not, write to the Free Software Foundation, Inc.,
00023     51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
00024 
00025     In addition, as a special exception, the copyright holders give
00026     permission to link the code of this program with any edition of
00027     the Qt library by Trolltech AS, Norway (or with modified versions
00028     of Qt that use the same license as Qt), and distribute linked
00029     combinations including the two.  You must obey the GNU General
00030     Public License in all respects for all of the code used other than
00031     Qt.  If you modify this file, you may extend this exception to
00032     your version of the file, but you are not obligated to do so.  If
00033     you do not wish to do so, delete this exception statement from
00034     your version.
00035 */
00036 
00037 #include "dn.h"
00038 
00039 #include "oidmap.h"
00040 
00041 #include "libkleo/ui/dnattributeorderconfigwidget.h"
00042 
00043 #include <kconfig.h>
00044 #include <klocale.h>
00045 
00046 #include <QStringList>
00047 
00048 #include <iostream>
00049 #include <iterator>
00050 #include <algorithm>
00051 #include <map>
00052 
00053 #include <string.h>
00054 #include <ctype.h>
00055 #include <stdlib.h>
00056 #include <kglobal.h>
00057 #include <kconfiggroup.h>
00058 
00059 class Kleo::DN::Private {
00060 public:
00061   Private() : mRefCount( 0 ) {}
00062   Private( const Private & other )
00063     : attributes( other.attributes ),
00064       reorderedAttributes( other.reorderedAttributes ),
00065       mRefCount( 0 )
00066   {
00067 
00068   }
00069 
00070   int ref() {
00071     return ++mRefCount;
00072   }
00073 
00074   int unref() {
00075     if ( --mRefCount <= 0 ) {
00076       delete this;
00077       return 0;
00078     } else
00079       return mRefCount;
00080   }
00081 
00082   int refCount() const { return mRefCount; }
00083 
00084   DN::Attribute::List attributes;
00085   DN::Attribute::List reorderedAttributes;
00086 private:
00087   int mRefCount;
00088 };
00089 
00090 namespace {
00091   struct DnPair {
00092     char * key;
00093     char * value;
00094   };
00095 }
00096 
00097 // copied from CryptPlug and adapted to work on DN::Attribute::List:
00098 
00099 #define digitp(p)   (*(p) >= '0' && *(p) <= '9')
00100 #define hexdigitp(a) (digitp (a)                     \
00101                       || (*(a) >= 'A' && *(a) <= 'F')  \
00102                       || (*(a) >= 'a' && *(a) <= 'f'))
00103 #define xtoi_1(p)   (*(p) <= '9'? (*(p)- '0'): \
00104                      *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
00105 #define xtoi_2(p)   ((xtoi_1(p) * 16) + xtoi_1((p)+1))
00106 
00107 static char *
00108 trim_trailing_spaces( char *string )
00109 {
00110     char *p, *mark;
00111 
00112     for( mark = NULL, p = string; *p; p++ ) {
00113     if( isspace( *p ) ) {
00114         if( !mark )
00115         mark = p;
00116     }
00117     else
00118         mark = NULL;
00119     }
00120     if( mark )
00121     *mark = '\0' ;
00122 
00123     return string ;
00124 }
00125 
00126 /* Parse a DN and return an array-ized one.  This is not a validating
00127    parser and it does not support any old-stylish syntax; gpgme is
00128    expected to return only rfc2253 compatible strings. */
00129 static const unsigned char *
00130 parse_dn_part (DnPair *array, const unsigned char *string)
00131 {
00132   const unsigned char *s, *s1;
00133   size_t n;
00134   char *p;
00135 
00136   /* parse attributeType */
00137   for (s = string+1; *s && *s != '='; s++)
00138     ;
00139   if (!*s)
00140     return NULL; /* error */
00141   n = s - string;
00142   if (!n)
00143     return NULL; /* empty key */
00144   p = (char*)malloc (n+1);
00145 
00146 
00147   memcpy (p, string, n);
00148   p[n] = 0;
00149   trim_trailing_spaces ((char*)p);
00150   // map OIDs to their names:
00151   for ( unsigned int i = 0 ; i < numOidMaps ; ++i )
00152     if ( !strcasecmp ((char*)p, oidmap[i].oid) ) {
00153       free( p );
00154       p = strdup( oidmap[i].name );
00155       break;
00156     }
00157   array->key = p;
00158   string = s + 1;
00159 
00160   if (*string == '#')
00161     { /* hexstring */
00162       string++;
00163       for (s=string; hexdigitp (s); s++)
00164         s++;
00165       n = s - string;
00166       if (!n || (n & 1))
00167         return NULL; /* empty or odd number of digits */
00168       n /= 2;
00169       array->value = p = (char*)malloc (n+1);
00170 
00171 
00172       for (s1=string; n; s1 += 2, n--)
00173         *p++ = xtoi_2 (s1);
00174       *p = 0;
00175    }
00176   else
00177     { /* regular v3 quoted string */
00178       for (n=0, s=string; *s; s++)
00179         {
00180           if (*s == '\\')
00181             { /* pair */
00182               s++;
00183               if (*s == ',' || *s == '=' || *s == '+'
00184                   || *s == '<' || *s == '>' || *s == '#' || *s == ';'
00185                   || *s == '\\' || *s == '\"' || *s == ' ')
00186                 n++;
00187               else if (hexdigitp (s) && hexdigitp (s+1))
00188                 {
00189                   s++;
00190                   n++;
00191                 }
00192               else
00193                 return NULL; /* invalid escape sequence */
00194             }
00195           else if (*s == '\"')
00196             return NULL; /* invalid encoding */
00197           else if (*s == ',' || *s == '=' || *s == '+'
00198                    || *s == '<' || *s == '>' || *s == '#' || *s == ';' )
00199             break;
00200           else
00201             n++;
00202         }
00203 
00204       array->value = p = (char*)malloc (n+1);
00205 
00206 
00207       for (s=string; n; s++, n--)
00208         {
00209           if (*s == '\\')
00210             {
00211               s++;
00212               if (hexdigitp (s))
00213                 {
00214                   *p++ = xtoi_2 (s);
00215                   s++;
00216                 }
00217               else
00218                 *p++ = *s;
00219             }
00220           else
00221             *p++ = *s;
00222         }
00223       *p = 0;
00224     }
00225   return s;
00226 }
00227 
00228 
00229 /* Parse a DN and return an array-ized one.  This is not a validating
00230    parser and it does not support any old-stylish syntax; gpgme is
00231    expected to return only rfc2253 compatible strings. */
00232 static Kleo::DN::Attribute::List
00233 parse_dn( const unsigned char * string ) {
00234   if ( !string )
00235     return QVector<Kleo::DN::Attribute>();
00236 
00237   QVector<Kleo::DN::Attribute> result;
00238   while (*string)
00239     {
00240       while (*string == ' ')
00241         string++;
00242       if (!*string)
00243         break; /* ready */
00244 
00245       DnPair pair = { 0, 0 };
00246       string = parse_dn_part (&pair, string);
00247       if (!string)
00248     goto failure;
00249       if ( pair.key && pair.value )
00250     result.push_back( Kleo::DN::Attribute( QString::fromUtf8( pair.key ),
00251                            QString::fromUtf8( pair.value ) ) );
00252       free( pair.key );
00253       free( pair.value );
00254 
00255       while (*string == ' ')
00256         string++;
00257       if (*string && *string != ',' && *string != ';' && *string != '+')
00258         goto failure; /* invalid delimiter */
00259       if (*string)
00260         string++;
00261     }
00262   return result;
00263 
00264 failure:
00265   return QVector<Kleo::DN::Attribute>();
00266 }
00267 
00268 static QVector<Kleo::DN::Attribute>
00269 parse_dn( const QString & dn ) {
00270   return parse_dn( (const unsigned char*)dn.toUtf8().data() );
00271 }
00272 
00273 static QString dn_escape( const QString & s ) {
00274     QString result;
00275     for ( unsigned int i = 0, end = s.length() ; i != end ; ++i ) {
00276         const QChar ch = s[i];
00277         switch ( ch.unicode() ) {
00278         case ',':
00279         case '+':
00280         case '"':
00281         case '\\':
00282         case '<':
00283         case '>':
00284         case ';':
00285             result += '\\';
00286             // fall through
00287         default:
00288             result += ch;
00289         }
00290     }
00291     return result;
00292 }
00293 
00294 static QString
00295 serialise( const QVector<Kleo::DN::Attribute> & dn ) {
00296   QStringList result;
00297   for ( QVector<Kleo::DN::Attribute>::const_iterator it = dn.begin() ; it != dn.end() ; ++it )
00298     if ( !(*it).name().isEmpty() && !(*it).value().isEmpty() )
00299       result.push_back( (*it).name().trimmed() + '=' + dn_escape( (*it).value().trimmed() ) );
00300   return result.join( "," );
00301 }
00302 
00303 static Kleo::DN::Attribute::List
00304 reorder_dn( const Kleo::DN::Attribute::List & dn ) {
00305   const QStringList & attrOrder = Kleo::DNAttributeMapper::instance()->attributeOrder();
00306 
00307   Kleo::DN::Attribute::List unknownEntries;
00308   Kleo::DN::Attribute::List result;
00309   unknownEntries.reserve( dn.size() );
00310   result.reserve( dn.size() );
00311 
00312   // find all unknown entries in their order of appearance
00313   for ( Kleo::DN::const_iterator it = dn.begin(); it != dn.end(); ++it )
00314     if ( !attrOrder.contains( (*it).name() )  )
00315       unknownEntries.push_back( *it );
00316 
00317   // process the known attrs in the desired order
00318   for ( QStringList::const_iterator oit = attrOrder.begin() ; oit != attrOrder.end() ; ++oit )
00319     if ( *oit == "_X_" ) {
00320       // insert the unknown attrs
00321       std::copy( unknownEntries.begin(), unknownEntries.end(),
00322          std::back_inserter( result ) );
00323       unknownEntries.clear(); // don't produce dup's
00324     } else {
00325       for ( Kleo::DN::const_iterator dnit = dn.begin() ; dnit != dn.end() ; ++dnit )
00326     if ( (*dnit).name() == *oit )
00327       result.push_back( *dnit );
00328     }
00329 
00330   return result;
00331 }
00332 
00333 //
00334 //
00335 // class DN
00336 //
00337 //
00338 
00339 Kleo::DN::DN() {
00340   d = new Private();
00341   d->ref();
00342 }
00343 
00344 Kleo::DN::DN( const QString & dn ) {
00345   d = new Private();
00346   d->ref();
00347   d->attributes = parse_dn( dn );
00348 }
00349 
00350 Kleo::DN::DN( const char * utf8DN ) {
00351   d = new Private();
00352   d->ref();
00353   if ( utf8DN )
00354     d->attributes = parse_dn( (const unsigned char*)utf8DN );
00355 }
00356 
00357 Kleo::DN::DN( const DN & other )
00358   : d( other.d )
00359 {
00360   if ( d ) d->ref();
00361 }
00362 
00363 Kleo::DN::~DN() {
00364   if ( d ) d->unref();
00365 }
00366 
00367 const Kleo::DN & Kleo::DN::operator=( const DN & that ) {
00368   if ( this->d == that.d )
00369     return *this;
00370 
00371   if ( that.d )
00372     that.d->ref();
00373   if ( this->d )
00374     this->d->unref();
00375 
00376   this->d = that.d;
00377 
00378   return *this;
00379 }
00380 
00381 QString Kleo::DN::prettyDN() const {
00382   if ( !d )
00383     return QString();
00384   if ( d->reorderedAttributes.empty() )
00385     d->reorderedAttributes = reorder_dn( d->attributes );
00386   return serialise( d->reorderedAttributes );
00387 }
00388 
00389 QString Kleo::DN::dn() const {
00390   return d ? serialise( d->attributes ) : QString() ;
00391 }
00392 
00393 // static
00394 QString Kleo::DN::escape( const QString & value ) {
00395     return dn_escape( value );
00396 }
00397 
00398 void Kleo::DN::detach() {
00399   if ( !d ) {
00400     d = new Kleo::DN::Private();
00401     d->ref();
00402   } else if ( d->refCount() > 1 ) {
00403     Kleo::DN::Private * d_save = d;
00404     d = new Kleo::DN::Private( *d );
00405     d->ref();
00406     d_save->unref();
00407   }
00408 }
00409 
00410 void Kleo::DN::append( const Attribute & attr ) {
00411   detach();
00412   d->attributes.push_back( attr );
00413   d->reorderedAttributes.clear();
00414 }
00415 
00416 QString Kleo::DN::operator[]( const QString & attr ) const {
00417   if ( !d )
00418     return QString();
00419   const QString attrUpper = attr.toUpper();
00420   for ( QVector<Attribute>::const_iterator it = d->attributes.begin() ;
00421     it != d->attributes.end() ; ++it )
00422     if ( (*it).name() == attrUpper )
00423       return (*it).value();
00424   return QString();
00425 }
00426 
00427 static QVector<Kleo::DN::Attribute> empty;
00428 
00429 Kleo::DN::const_iterator Kleo::DN::begin() const {
00430   return d ? d->attributes.begin() : empty.begin() ;
00431 }
00432 
00433 Kleo::DN::const_iterator Kleo::DN::end() const {
00434   return d ? d->attributes.end() : empty.end() ;
00435 }
00436 
00437 
00439 
00440 namespace {
00441   struct ltstr {
00442     bool operator()( const char * s1, const char * s2 ) const {
00443       return qstrcmp( s1, s2 ) < 0 ;
00444     }
00445   };
00446 }
00447 
00448 static const char * defaultOrder[] = {
00449   "CN", "L", "_X_", "OU", "O", "C"
00450 };
00451 
00452 std::pair<const char*,const char*> attributeLabels[] = {
00453 #define MAKE_PAIR(x,y) std::pair<const char*,const char*>( x, y )
00454   MAKE_PAIR( "CN", I18N_NOOP("Common name") ),
00455   MAKE_PAIR( "SN", I18N_NOOP("Surname") ),
00456   MAKE_PAIR( "GN", I18N_NOOP("Given name") ),
00457   MAKE_PAIR( "L",  I18N_NOOP("Location") ),
00458   MAKE_PAIR( "T",  I18N_NOOP("Title") ),
00459   MAKE_PAIR( "OU", I18N_NOOP("Organizational unit") ),
00460   MAKE_PAIR( "O",  I18N_NOOP("Organization") ),
00461   MAKE_PAIR( "PC", I18N_NOOP("Postal code") ),
00462   MAKE_PAIR( "C",  I18N_NOOP("Country code") ),
00463   MAKE_PAIR( "SP", I18N_NOOP("State or province") ),
00464   MAKE_PAIR( "DC", I18N_NOOP("Domain component") ),
00465   MAKE_PAIR( "BC", I18N_NOOP("Business category") ),
00466   MAKE_PAIR( "EMAIL", I18N_NOOP("Email address") ),
00467   MAKE_PAIR( "MAIL", I18N_NOOP("Mail address") ),
00468   MAKE_PAIR( "MOBILE", I18N_NOOP("Mobile phone number") ),
00469   MAKE_PAIR( "TEL", I18N_NOOP("Telephone number") ),
00470   MAKE_PAIR( "FAX", I18N_NOOP("Fax number") ),
00471   MAKE_PAIR( "STREET", I18N_NOOP("Street address") ),
00472   MAKE_PAIR( "UID", I18N_NOOP("Unique ID") )
00473 #undef MAKE_PAIR
00474 };
00475 static const unsigned int numAttributeLabels = sizeof attributeLabels / sizeof *attributeLabels ;
00476 
00477 class Kleo::DNAttributeMapper::Private {
00478 public:
00479   Private();
00480   std::map<const char*,const char*,ltstr> map;
00481   QStringList attributeOrder;
00482 };
00483 
00484 Kleo::DNAttributeMapper::Private::Private()
00485   : map( attributeLabels, attributeLabels + numAttributeLabels ) {}
00486 
00487 Kleo::DNAttributeMapper::DNAttributeMapper() {
00488   d = new Private();
00489   const KConfigGroup config( KGlobal::config(), "DN" );
00490   d->attributeOrder = config.readEntry( "AttributeOrder" , QStringList() );
00491   if ( d->attributeOrder.empty() )
00492     std::copy( defaultOrder, defaultOrder + sizeof defaultOrder / sizeof *defaultOrder,
00493            std::back_inserter( d->attributeOrder ) );
00494   mSelf = this;
00495 }
00496 
00497 Kleo::DNAttributeMapper::~DNAttributeMapper() {
00498   mSelf = 0;
00499   delete d; d = 0;
00500 }
00501 
00502 Kleo::DNAttributeMapper * Kleo::DNAttributeMapper::mSelf = 0;
00503 
00504 const Kleo::DNAttributeMapper * Kleo::DNAttributeMapper::instance() {
00505   if ( !mSelf )
00506     (void)new DNAttributeMapper();
00507   return mSelf;
00508 }
00509 
00510 QString Kleo::DNAttributeMapper::name2label( const QString & s ) const {
00511   const std::map<const char*,const char*,ltstr>::const_iterator it
00512     = d->map.find( s.trimmed().toUpper().toLatin1() );
00513   if ( it == d->map.end() )
00514     return QString();
00515   return i18n( it->second );
00516 }
00517 
00518 QStringList Kleo::DNAttributeMapper::names() const {
00519   QStringList result;
00520   for ( std::map<const char*,const char*,ltstr>::const_iterator it = d->map.begin() ; it != d->map.end() ; ++it )
00521     result.push_back( it->first );
00522   return result;
00523 }
00524 
00525 const QStringList & Kleo::DNAttributeMapper::attributeOrder() const {
00526   return d->attributeOrder;
00527 }
00528 
00529 void Kleo::DNAttributeMapper::setAttributeOrder( const QStringList & order ) {
00530   d->attributeOrder = order;
00531   if ( order.empty() )
00532     std::copy( defaultOrder, defaultOrder + sizeof defaultOrder / sizeof *defaultOrder,
00533            std::back_inserter( d->attributeOrder ) );
00534   KConfigGroup config( KGlobal::config(), "DN" );
00535   config.writeEntry( "AttributeOrder", order );
00536 }
00537 
00538 Kleo::DNAttributeOrderConfigWidget * Kleo::DNAttributeMapper::configWidget( QWidget * parent ) const {
00539   return new DNAttributeOrderConfigWidget( mSelf, parent );
00540 }

libkleo

Skip menu "libkleo"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members

kdepim

Skip menu "kdepim"
  • akonadi
  •   clients
  •   kabc
  •   kcal
  •   kcm
  • akregator
  • console
  •   kabcclient
  •   konsolekalendar
  • kaddressbook
  • kalarm
  •   lib
  • kdgantt
  • kdgantt1
  • kjots
  • kleopatra
  • kmail
  • kmobiletools
  • knode
  • knotes
  • kontact
  • kontactinterfaces
  • korganizer
  •   korgac
  • kpilot
  • ktimetracker
  •   doc
  • libkdepim
  • libkholidays
  • libkleo
  • libkpgp
  • maildir
Generated for kdepim by doxygen 1.5.4
This website is maintained by Adriaan de Groot and Allen Winter.
KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal