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 #include "ui/dnattributeorderconfigwidget.h"
00041
00042 #include <kapplication.h>
00043 #include <kconfig.h>
00044 #include <klocale.h>
00045
00046 #include <qstringlist.h>
00047 #include <qvaluevector.h>
00048
00049 #include <iostream>
00050 #include <iterator>
00051 #include <algorithm>
00052 #include <map>
00053
00054 #include <string.h>
00055 #include <ctype.h>
00056 #include <stdlib.h>
00057
00058 struct Kleo::DN::Private {
00059 Private() : mRefCount( 0 ) {}
00060 Private( const Private & other )
00061 : attributes( other.attributes ),
00062 reorderedAttributes( other.reorderedAttributes ),
00063 mRefCount( 0 )
00064 {
00065
00066 }
00067
00068 int ref() {
00069 return ++mRefCount;
00070 }
00071
00072 int unref() {
00073 if ( --mRefCount <= 0 ) {
00074 delete this;
00075 return 0;
00076 } else
00077 return mRefCount;
00078 }
00079
00080 int refCount() const { return mRefCount; }
00081
00082 DN::Attribute::List attributes;
00083 DN::Attribute::List reorderedAttributes;
00084 private:
00085 int mRefCount;
00086 };
00087
00088 namespace {
00089 struct DnPair {
00090 char * key;
00091 char * value;
00092 };
00093 }
00094
00095
00096
00097 #define digitp(p) (*(p) >= '0' && *(p) <= '9')
00098 #define hexdigitp(a) (digitp (a) \
00099 || (*(a) >= 'A' && *(a) <= 'F') \
00100 || (*(a) >= 'a' && *(a) <= 'f'))
00101 #define xtoi_1(p) (*(p) <= '9'? (*(p)- '0'): \
00102 *(p) <= 'F'? (*(p)-'A'+10):(*(p)-'a'+10))
00103 #define xtoi_2(p) ((xtoi_1(p) * 16) + xtoi_1((p)+1))
00104
00105 static char *
00106 trim_trailing_spaces( char *string )
00107 {
00108 char *p, *mark;
00109
00110 for( mark = NULL, p = string; *p; p++ ) {
00111 if( isspace( *p ) ) {
00112 if( !mark )
00113 mark = p;
00114 }
00115 else
00116 mark = NULL;
00117 }
00118 if( mark )
00119 *mark = '\0' ;
00120
00121 return string ;
00122 }
00123
00124
00125
00126
00127 static const unsigned char *
00128 parse_dn_part (DnPair *array, const unsigned char *string)
00129 {
00130 const unsigned char *s, *s1;
00131 size_t n;
00132 char *p;
00133
00134
00135 for (s = string+1; *s && *s != '='; s++)
00136 ;
00137 if (!*s)
00138 return NULL;
00139 n = s - string;
00140 if (!n)
00141 return NULL;
00142 p = (char*)malloc (n+1);
00143
00144
00145 memcpy (p, string, n);
00146 p[n] = 0;
00147 trim_trailing_spaces ((char*)p);
00148
00149 for ( unsigned int i = 0 ; i < numOidMaps ; ++i )
00150 if ( !strcasecmp ((char*)p, oidmap[i].oid) ) {
00151 free( p );
00152 p = strdup( oidmap[i].name );
00153 break;
00154 }
00155 array->key = p;
00156 string = s + 1;
00157
00158 if (*string == '#')
00159 {
00160 string++;
00161 for (s=string; hexdigitp (s); s++)
00162 s++;
00163 n = s - string;
00164 if (!n || (n & 1))
00165 return NULL;
00166 n /= 2;
00167 array->value = p = (char*)malloc (n+1);
00168
00169
00170 for (s1=string; n; s1 += 2, n--)
00171 *p++ = xtoi_2 (s1);
00172 *p = 0;
00173 }
00174 else
00175 {
00176 for (n=0, s=string; *s; s++)
00177 {
00178 if (*s == '\\')
00179 {
00180 s++;
00181 if (*s == ',' || *s == '=' || *s == '+'
00182 || *s == '<' || *s == '>' || *s == '#' || *s == ';'
00183 || *s == '\\' || *s == '\"' || *s == ' ')
00184 n++;
00185 else if (hexdigitp (s) && hexdigitp (s+1))
00186 {
00187 s++;
00188 n++;
00189 }
00190 else
00191 return NULL;
00192 }
00193 else if (*s == '\"')
00194 return NULL;
00195 else if (*s == ',' || *s == '=' || *s == '+'
00196 || *s == '<' || *s == '>' || *s == '#' || *s == ';' )
00197 break;
00198 else
00199 n++;
00200 }
00201
00202 array->value = p = (char*)malloc (n+1);
00203
00204
00205 for (s=string; n; s++, n--)
00206 {
00207 if (*s == '\\')
00208 {
00209 s++;
00210 if (hexdigitp (s))
00211 {
00212 *p++ = xtoi_2 (s);
00213 s++;
00214 }
00215 else
00216 *p++ = *s;
00217 }
00218 else
00219 *p++ = *s;
00220 }
00221 *p = 0;
00222 }
00223 return s;
00224 }
00225
00226
00227
00228
00229
00230 static Kleo::DN::Attribute::List
00231 parse_dn( const unsigned char * string ) {
00232 if ( !string )
00233 return QValueVector<Kleo::DN::Attribute>();
00234
00235 QValueVector<Kleo::DN::Attribute> result;
00236 while (*string)
00237 {
00238 while (*string == ' ')
00239 string++;
00240 if (!*string)
00241 break;
00242
00243 DnPair pair = { 0, 0 };
00244 string = parse_dn_part (&pair, string);
00245 if (!string)
00246 goto failure;
00247 if ( pair.key && pair.value )
00248 result.push_back( Kleo::DN::Attribute( QString::fromUtf8( pair.key ),
00249 QString::fromUtf8( pair.value ) ) );
00250 free( pair.key );
00251 free( pair.value );
00252
00253 while (*string == ' ')
00254 string++;
00255 if (*string && *string != ',' && *string != ';' && *string != '+')
00256 goto failure;
00257 if (*string)
00258 string++;
00259 }
00260 return result;
00261
00262 failure:
00263 return QValueVector<Kleo::DN::Attribute>();
00264 }
00265
00266 static QValueVector<Kleo::DN::Attribute>
00267 parse_dn( const QString & dn ) {
00268 return parse_dn( (const unsigned char*)dn.utf8().data() );
00269 }
00270
00271 static QString
00272 serialise( const QValueVector<Kleo::DN::Attribute> & dn ) {
00273 QStringList result;
00274 for ( QValueVector<Kleo::DN::Attribute>::const_iterator it = dn.begin() ; it != dn.end() ; ++it )
00275 if ( !(*it).name().isEmpty() && !(*it).value().isEmpty() )
00276 result.push_back( (*it).name().stripWhiteSpace() + '=' + (*it).value().stripWhiteSpace() );
00277 return result.join( "," );
00278 }
00279
00280 static Kleo::DN::Attribute::List
00281 reorder_dn( const Kleo::DN::Attribute::List & dn ) {
00282 const QStringList & attrOrder = Kleo::DNAttributeMapper::instance()->attributeOrder();
00283
00284 Kleo::DN::Attribute::List unknownEntries;
00285 Kleo::DN::Attribute::List result;
00286 unknownEntries.reserve( dn.size() );
00287 result.reserve( dn.size() );
00288
00289
00290 for ( Kleo::DN::const_iterator it = dn.begin(); it != dn.end(); ++it )
00291 if ( attrOrder.find( (*it).name() ) == attrOrder.end() )
00292 unknownEntries.push_back( *it );
00293
00294
00295 for ( QStringList::const_iterator oit = attrOrder.begin() ; oit != attrOrder.end() ; ++oit )
00296 if ( *oit == "_X_" ) {
00297
00298 std::copy( unknownEntries.begin(), unknownEntries.end(),
00299 std::back_inserter( result ) );
00300 unknownEntries.clear();
00301 } else {
00302 for ( Kleo::DN::const_iterator dnit = dn.begin() ; dnit != dn.end() ; ++dnit )
00303 if ( (*dnit).name() == *oit )
00304 result.push_back( *dnit );
00305 }
00306
00307 return result;
00308 }
00309
00310
00311
00312
00313
00314
00315
00316 Kleo::DN::DN() {
00317 d = new Private();
00318 d->ref();
00319 }
00320
00321 Kleo::DN::DN( const QString & dn ) {
00322 d = new Private();
00323 d->ref();
00324 d->attributes = parse_dn( dn );
00325 }
00326
00327 Kleo::DN::DN( const char * utf8DN ) {
00328 d = new Private();
00329 d->ref();
00330 if ( utf8DN )
00331 d->attributes = parse_dn( (const unsigned char*)utf8DN );
00332 }
00333
00334 Kleo::DN::DN( const DN & other )
00335 : d( other.d )
00336 {
00337 if ( d ) d->ref();
00338 }
00339
00340 Kleo::DN::~DN() {
00341 if ( d ) d->unref();
00342 }
00343
00344 const Kleo::DN & Kleo::DN::operator=( const DN & that ) {
00345 if ( this->d == that.d )
00346 return *this;
00347
00348 if ( that.d )
00349 that.d->ref();
00350 if ( this->d )
00351 this->d->unref();
00352
00353 this->d = that.d;
00354
00355 return *this;
00356 }
00357
00358 QString Kleo::DN::prettyDN() const {
00359 if ( !d )
00360 return QString::null;
00361 if ( d->reorderedAttributes.empty() )
00362 d->reorderedAttributes = reorder_dn( d->attributes );
00363 return serialise( d->reorderedAttributes );
00364 }
00365
00366 QString Kleo::DN::dn() const {
00367 return d ? serialise( d->attributes ) : QString::null ;
00368 }
00369
00370 void Kleo::DN::detach() {
00371 if ( !d ) {
00372 d = new Kleo::DN::Private();
00373 d->ref();
00374 } else if ( d->refCount() > 1 ) {
00375 Kleo::DN::Private * d_save = d;
00376 d = new Kleo::DN::Private( *d );
00377 d->ref();
00378 d_save->unref();
00379 }
00380 }
00381
00382 void Kleo::DN::append( const Attribute & attr ) {
00383 detach();
00384 d->attributes.push_back( attr );
00385 d->reorderedAttributes.clear();
00386 }
00387
00388 QString Kleo::DN::operator[]( const QString & attr ) const {
00389 if ( !d )
00390 return QString::null;
00391 const QString attrUpper = attr.upper();
00392 for ( QValueVector<Attribute>::const_iterator it = d->attributes.begin() ;
00393 it != d->attributes.end() ; ++it )
00394 if ( (*it).name() == attrUpper )
00395 return (*it).value();
00396 return QString::null;
00397 }
00398
00399 static QValueVector<Kleo::DN::Attribute> empty;
00400
00401 Kleo::DN::const_iterator Kleo::DN::begin() const {
00402 return d ? d->attributes.begin() : empty.begin() ;
00403 }
00404
00405 Kleo::DN::const_iterator Kleo::DN::end() const {
00406 return d ? d->attributes.end() : empty.end() ;
00407 }
00408
00409
00411
00412 namespace {
00413 struct ltstr {
00414 bool operator()( const char * s1, const char * s2 ) const {
00415 return qstrcmp( s1, s2 ) < 0 ;
00416 }
00417 };
00418 }
00419
00420 static const char * defaultOrder[] = {
00421 "CN", "L", "_X_", "OU", "O", "C"
00422 };
00423
00424 std::pair<const char*,const char*> attributeLabels[] = {
00425 #define MAKE_PAIR(x,y) std::pair<const char*,const char*>( x, y )
00426 MAKE_PAIR( "CN", I18N_NOOP("Common name") ),
00427 MAKE_PAIR( "SN", I18N_NOOP("Surname") ),
00428 MAKE_PAIR( "GN", I18N_NOOP("Given name") ),
00429 MAKE_PAIR( "L", I18N_NOOP("Location") ),
00430 MAKE_PAIR( "T", I18N_NOOP("Title") ),
00431 MAKE_PAIR( "OU", I18N_NOOP("Organizational unit") ),
00432 MAKE_PAIR( "O", I18N_NOOP("Organization") ),
00433 MAKE_PAIR( "PC", I18N_NOOP("Postal code") ),
00434 MAKE_PAIR( "C", I18N_NOOP("Country code") ),
00435 MAKE_PAIR( "SP", I18N_NOOP("State or province") ),
00436 MAKE_PAIR( "DC", I18N_NOOP("Domain component") ),
00437 MAKE_PAIR( "BC", I18N_NOOP("Business category") ),
00438 MAKE_PAIR( "EMAIL", I18N_NOOP("Email address") ),
00439 MAKE_PAIR( "MAIL", I18N_NOOP("Mail address") ),
00440 MAKE_PAIR( "MOBILE", I18N_NOOP("Mobile phone number") ),
00441 MAKE_PAIR( "TEL", I18N_NOOP("Telephone number") ),
00442 MAKE_PAIR( "FAX", I18N_NOOP("Fax number") ),
00443 MAKE_PAIR( "STREET", I18N_NOOP("Street address") ),
00444 MAKE_PAIR( "UID", I18N_NOOP("Unique ID") )
00445 #undef MAKE_PAIR
00446 };
00447 static const unsigned int numAttributeLabels = sizeof attributeLabels / sizeof *attributeLabels ;
00448
00449 class Kleo::DNAttributeMapper::Private {
00450 public:
00451 Private();
00452 std::map<const char*,const char*,ltstr> map;
00453 QStringList attributeOrder;
00454 };
00455
00456 Kleo::DNAttributeMapper::Private::Private()
00457 : map( attributeLabels, attributeLabels + numAttributeLabels ) {}
00458
00459 Kleo::DNAttributeMapper::DNAttributeMapper() {
00460 d = new Private();
00461 const KConfigGroup config( kapp->config(), "DN" );
00462 d->attributeOrder = config.readListEntry( "AttributeOrder" );
00463 if ( d->attributeOrder.empty() )
00464 std::copy( defaultOrder, defaultOrder + sizeof defaultOrder / sizeof *defaultOrder,
00465 std::back_inserter( d->attributeOrder ) );
00466 mSelf = this;
00467 }
00468
00469 Kleo::DNAttributeMapper::~DNAttributeMapper() {
00470 mSelf = 0;
00471 delete d; d = 0;
00472 }
00473
00474 Kleo::DNAttributeMapper * Kleo::DNAttributeMapper::mSelf = 0;
00475
00476 const Kleo::DNAttributeMapper * Kleo::DNAttributeMapper::instance() {
00477 if ( !mSelf )
00478 (void)new DNAttributeMapper();
00479 return mSelf;
00480 }
00481
00482 QString Kleo::DNAttributeMapper::name2label( const QString & s ) const {
00483 const std::map<const char*,const char*,ltstr>::const_iterator it
00484 = d->map.find( s.stripWhiteSpace().upper().latin1() );
00485 if ( it == d->map.end() )
00486 return QString::null;
00487 return i18n( it->second );
00488 }
00489
00490 QStringList Kleo::DNAttributeMapper::names() const {
00491 QStringList result;
00492 for ( std::map<const char*,const char*,ltstr>::const_iterator it = d->map.begin() ; it != d->map.end() ; ++it )
00493 result.push_back( it->first );
00494 return result;
00495 }
00496
00497 const QStringList & Kleo::DNAttributeMapper::attributeOrder() const {
00498 return d->attributeOrder;
00499 }
00500
00501 void Kleo::DNAttributeMapper::setAttributeOrder( const QStringList & order ) {
00502 d->attributeOrder = order;
00503 if ( order.empty() )
00504 std::copy( defaultOrder, defaultOrder + sizeof defaultOrder / sizeof *defaultOrder,
00505 std::back_inserter( d->attributeOrder ) );
00506 KConfigGroup config( kapp->config(), "DN" );
00507 config.writeEntry( "AttributeOrder", order );
00508 }
00509
00510 Kleo::DNAttributeOrderConfigWidget * Kleo::DNAttributeMapper::configWidget( QWidget * parent, const char * name ) const {
00511 return new DNAttributeOrderConfigWidget( mSelf, parent, name );
00512 }