00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
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
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
00127
00128
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
00137 for (s = string+1; *s && *s != '='; s++)
00138 ;
00139 if (!*s)
00140 return NULL;
00141 n = s - string;
00142 if (!n)
00143 return NULL;
00144 p = (char*)malloc (n+1);
00145
00146
00147 memcpy (p, string, n);
00148 p[n] = 0;
00149 trim_trailing_spaces ((char*)p);
00150
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 {
00162 string++;
00163 for (s=string; hexdigitp (s); s++)
00164 s++;
00165 n = s - string;
00166 if (!n || (n & 1))
00167 return NULL;
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 {
00178 for (n=0, s=string; *s; s++)
00179 {
00180 if (*s == '\\')
00181 {
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;
00194 }
00195 else if (*s == '\"')
00196 return NULL;
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
00230
00231
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;
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;
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
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
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
00318 for ( QStringList::const_iterator oit = attrOrder.begin() ; oit != attrOrder.end() ; ++oit )
00319 if ( *oit == "_X_" ) {
00320
00321 std::copy( unknownEntries.begin(), unknownEntries.end(),
00322 std::back_inserter( result ) );
00323 unknownEntries.clear();
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
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
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 }