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 dn_escape( const QString & s ) {
00272 QString result;
00273 for ( unsigned int i = 0, end = s.length() ; i != end ; ++i ) {
00274 const QChar ch = s[i];
00275 switch ( ch.unicode() ) {
00276 case ',':
00277 case '+':
00278 case '"':
00279 case '\\':
00280 case '<':
00281 case '>':
00282 case ';':
00283 result += '\\';
00284
00285 default:
00286 result += ch;
00287 }
00288 }
00289 return result;
00290 }
00291
00292 static QString
00293 serialise( const QValueVector<Kleo::DN::Attribute> & dn ) {
00294 QStringList result;
00295 for ( QValueVector<Kleo::DN::Attribute>::const_iterator it = dn.begin() ; it != dn.end() ; ++it )
00296 if ( !(*it).name().isEmpty() && !(*it).value().isEmpty() )
00297 result.push_back( (*it).name().stripWhiteSpace() + '=' + dn_escape( (*it).value().stripWhiteSpace() ) );
00298 return result.join( "," );
00299 }
00300
00301 static Kleo::DN::Attribute::List
00302 reorder_dn( const Kleo::DN::Attribute::List & dn ) {
00303 const QStringList & attrOrder = Kleo::DNAttributeMapper::instance()->attributeOrder();
00304
00305 Kleo::DN::Attribute::List unknownEntries;
00306 Kleo::DN::Attribute::List result;
00307 unknownEntries.reserve( dn.size() );
00308 result.reserve( dn.size() );
00309
00310
00311 for ( Kleo::DN::const_iterator it = dn.begin(); it != dn.end(); ++it )
00312 if ( attrOrder.find( (*it).name() ) == attrOrder.end() )
00313 unknownEntries.push_back( *it );
00314
00315
00316 for ( QStringList::const_iterator oit = attrOrder.begin() ; oit != attrOrder.end() ; ++oit )
00317 if ( *oit == "_X_" ) {
00318
00319 std::copy( unknownEntries.begin(), unknownEntries.end(),
00320 std::back_inserter( result ) );
00321 unknownEntries.clear();
00322 } else {
00323 for ( Kleo::DN::const_iterator dnit = dn.begin() ; dnit != dn.end() ; ++dnit )
00324 if ( (*dnit).name() == *oit )
00325 result.push_back( *dnit );
00326 }
00327
00328 return result;
00329 }
00330
00331
00332
00333
00334
00335
00336
00337 Kleo::DN::DN() {
00338 d = new Private();
00339 d->ref();
00340 }
00341
00342 Kleo::DN::DN( const QString & dn ) {
00343 d = new Private();
00344 d->ref();
00345 d->attributes = parse_dn( dn );
00346 }
00347
00348 Kleo::DN::DN( const char * utf8DN ) {
00349 d = new Private();
00350 d->ref();
00351 if ( utf8DN )
00352 d->attributes = parse_dn( (const unsigned char*)utf8DN );
00353 }
00354
00355 Kleo::DN::DN( const DN & other )
00356 : d( other.d )
00357 {
00358 if ( d ) d->ref();
00359 }
00360
00361 Kleo::DN::~DN() {
00362 if ( d ) d->unref();
00363 }
00364
00365 const Kleo::DN & Kleo::DN::operator=( const DN & that ) {
00366 if ( this->d == that.d )
00367 return *this;
00368
00369 if ( that.d )
00370 that.d->ref();
00371 if ( this->d )
00372 this->d->unref();
00373
00374 this->d = that.d;
00375
00376 return *this;
00377 }
00378
00379 QString Kleo::DN::prettyDN() const {
00380 if ( !d )
00381 return QString::null;
00382 if ( d->reorderedAttributes.empty() )
00383 d->reorderedAttributes = reorder_dn( d->attributes );
00384 return serialise( d->reorderedAttributes );
00385 }
00386
00387 QString Kleo::DN::dn() const {
00388 return d ? serialise( d->attributes ) : QString::null ;
00389 }
00390
00391
00392 QString Kleo::DN::escape( const QString & value ) {
00393 return dn_escape( value );
00394 }
00395
00396 void Kleo::DN::detach() {
00397 if ( !d ) {
00398 d = new Kleo::DN::Private();
00399 d->ref();
00400 } else if ( d->refCount() > 1 ) {
00401 Kleo::DN::Private * d_save = d;
00402 d = new Kleo::DN::Private( *d );
00403 d->ref();
00404 d_save->unref();
00405 }
00406 }
00407
00408 void Kleo::DN::append( const Attribute & attr ) {
00409 detach();
00410 d->attributes.push_back( attr );
00411 d->reorderedAttributes.clear();
00412 }
00413
00414 QString Kleo::DN::operator[]( const QString & attr ) const {
00415 if ( !d )
00416 return QString::null;
00417 const QString attrUpper = attr.upper();
00418 for ( QValueVector<Attribute>::const_iterator it = d->attributes.begin() ;
00419 it != d->attributes.end() ; ++it )
00420 if ( (*it).name() == attrUpper )
00421 return (*it).value();
00422 return QString::null;
00423 }
00424
00425 static QValueVector<Kleo::DN::Attribute> empty;
00426
00427 Kleo::DN::const_iterator Kleo::DN::begin() const {
00428 return d ? d->attributes.begin() : empty.begin() ;
00429 }
00430
00431 Kleo::DN::const_iterator Kleo::DN::end() const {
00432 return d ? d->attributes.end() : empty.end() ;
00433 }
00434
00435
00437
00438 namespace {
00439 struct ltstr {
00440 bool operator()( const char * s1, const char * s2 ) const {
00441 return qstrcmp( s1, s2 ) < 0 ;
00442 }
00443 };
00444 }
00445
00446 static const char * defaultOrder[] = {
00447 "CN", "L", "_X_", "OU", "O", "C"
00448 };
00449
00450 std::pair<const char*,const char*> attributeLabels[] = {
00451 #define MAKE_PAIR(x,y) std::pair<const char*,const char*>( x, y )
00452 MAKE_PAIR( "CN", I18N_NOOP("Common name") ),
00453 MAKE_PAIR( "SN", I18N_NOOP("Surname") ),
00454 MAKE_PAIR( "GN", I18N_NOOP("Given name") ),
00455 MAKE_PAIR( "L", I18N_NOOP("Location") ),
00456 MAKE_PAIR( "T", I18N_NOOP("Title") ),
00457 MAKE_PAIR( "OU", I18N_NOOP("Organizational unit") ),
00458 MAKE_PAIR( "O", I18N_NOOP("Organization") ),
00459 MAKE_PAIR( "PC", I18N_NOOP("Postal code") ),
00460 MAKE_PAIR( "C", I18N_NOOP("Country code") ),
00461 MAKE_PAIR( "SP", I18N_NOOP("State or province") ),
00462 MAKE_PAIR( "DC", I18N_NOOP("Domain component") ),
00463 MAKE_PAIR( "BC", I18N_NOOP("Business category") ),
00464 MAKE_PAIR( "EMAIL", I18N_NOOP("Email address") ),
00465 MAKE_PAIR( "MAIL", I18N_NOOP("Mail address") ),
00466 MAKE_PAIR( "MOBILE", I18N_NOOP("Mobile phone number") ),
00467 MAKE_PAIR( "TEL", I18N_NOOP("Telephone number") ),
00468 MAKE_PAIR( "FAX", I18N_NOOP("Fax number") ),
00469 MAKE_PAIR( "STREET", I18N_NOOP("Street address") ),
00470 MAKE_PAIR( "UID", I18N_NOOP("Unique ID") )
00471 #undef MAKE_PAIR
00472 };
00473 static const unsigned int numAttributeLabels = sizeof attributeLabels / sizeof *attributeLabels ;
00474
00475 class Kleo::DNAttributeMapper::Private {
00476 public:
00477 Private();
00478 std::map<const char*,const char*,ltstr> map;
00479 QStringList attributeOrder;
00480 };
00481
00482 Kleo::DNAttributeMapper::Private::Private()
00483 : map( attributeLabels, attributeLabels + numAttributeLabels ) {}
00484
00485 Kleo::DNAttributeMapper::DNAttributeMapper() {
00486 d = new Private();
00487 const KConfigGroup config( kapp->config(), "DN" );
00488 d->attributeOrder = config.readListEntry( "AttributeOrder" );
00489 if ( d->attributeOrder.empty() )
00490 std::copy( defaultOrder, defaultOrder + sizeof defaultOrder / sizeof *defaultOrder,
00491 std::back_inserter( d->attributeOrder ) );
00492 mSelf = this;
00493 }
00494
00495 Kleo::DNAttributeMapper::~DNAttributeMapper() {
00496 mSelf = 0;
00497 delete d; d = 0;
00498 }
00499
00500 Kleo::DNAttributeMapper * Kleo::DNAttributeMapper::mSelf = 0;
00501
00502 const Kleo::DNAttributeMapper * Kleo::DNAttributeMapper::instance() {
00503 if ( !mSelf )
00504 (void)new DNAttributeMapper();
00505 return mSelf;
00506 }
00507
00508 QString Kleo::DNAttributeMapper::name2label( const QString & s ) const {
00509 const std::map<const char*,const char*,ltstr>::const_iterator it
00510 = d->map.find( s.stripWhiteSpace().upper().latin1() );
00511 if ( it == d->map.end() )
00512 return QString::null;
00513 return i18n( it->second );
00514 }
00515
00516 QStringList Kleo::DNAttributeMapper::names() const {
00517 QStringList result;
00518 for ( std::map<const char*,const char*,ltstr>::const_iterator it = d->map.begin() ; it != d->map.end() ; ++it )
00519 result.push_back( it->first );
00520 return result;
00521 }
00522
00523 const QStringList & Kleo::DNAttributeMapper::attributeOrder() const {
00524 return d->attributeOrder;
00525 }
00526
00527 void Kleo::DNAttributeMapper::setAttributeOrder( const QStringList & order ) {
00528 d->attributeOrder = order;
00529 if ( order.empty() )
00530 std::copy( defaultOrder, defaultOrder + sizeof defaultOrder / sizeof *defaultOrder,
00531 std::back_inserter( d->attributeOrder ) );
00532 KConfigGroup config( kapp->config(), "DN" );
00533 config.writeEntry( "AttributeOrder", order );
00534 }
00535
00536 Kleo::DNAttributeOrderConfigWidget * Kleo::DNAttributeMapper::configWidget( QWidget * parent, const char * name ) const {
00537 return new DNAttributeOrderConfigWidget( mSelf, parent, name );
00538 }