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 }