00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "ldif_p.h"
00024
00025 #include <kdebug.h>
00026
00027 class Ldif::LdifPrivate
00028 {
00029 public:
00030 int mModType;
00031 bool mDelOldRdn, mUrl;
00032 LdapDN mDn;
00033 QString mAttr, mNewRdn, mNewSuperior, mOid;
00034 QByteArray mLdif, mValue;
00035 EntryType mEntryType;
00036
00037 bool mIsNewLine, mIsComment, mCritical;
00038 ParseValue mLastParseValue;
00039 uint mPos, mLineNumber;
00040 QByteArray mLine;
00041 };
00042
00043 Ldif::Ldif() : d( new LdifPrivate )
00044 {
00045 startParsing();
00046 }
00047
00048 Ldif::Ldif( const Ldif &that ) : d( new LdifPrivate )
00049 {
00050 *d = *that.d;
00051
00052 startParsing();
00053 }
00054
00055 Ldif &Ldif::operator=( const Ldif &that )
00056 {
00057 if ( this == &that ) {
00058 return *this;
00059 }
00060
00061 *d = *that.d;
00062
00063 return *this;
00064 }
00065
00066 Ldif::~Ldif()
00067 {
00068 delete d;
00069 }
00070
00071 QByteArray Ldif::assembleLine( const QString &fieldname,
00072 const QByteArray &value,
00073 uint linelen, bool url )
00074 {
00075 bool safe = false;
00076 bool isDn;
00077 QByteArray result;
00078
00079 if ( url ) {
00080 result = fieldname.toUtf8() + ":< " + value;
00081 } else {
00082 isDn = fieldname.toLower() == QLatin1String( "dn" );
00083
00084 if ( value.size() > 0 && value[0] > 0 && value[0] != '\n' &&
00085 value[0] != '\r' && value[0] != ':' && value[0] != '<' ) safe = true;
00086
00087
00088 if ( safe ) {
00089 for ( int i=1; i < value.size(); i++ ) {
00090
00091 if ( ( isDn && value[i] == 0 ) ||
00092 ( !isDn && value[i] <= 0 ) ||
00093 value[i] == '\r' || value[i] == '\n' ) {
00094 safe = false;
00095 break;
00096 }
00097 }
00098 }
00099
00100 if ( value.size() == 0 ) {
00101 safe = true;
00102 }
00103
00104 if ( safe ) {
00105 result = fieldname.toUtf8() + ": " + value;
00106 } else {
00107 result = fieldname.toUtf8() + ":: " + value.toBase64();
00108 }
00109
00110 if ( linelen > 0 ) {
00111 int i = (uint)( fieldname.length() + 2 ) > linelen ? fieldname.length() + 2 : linelen;
00112 while ( i < result.length() ) {
00113 result.insert( i, "\n " );
00114 i += linelen+2;
00115 }
00116 }
00117 }
00118 return result;
00119 }
00120
00121 QByteArray Ldif::assembleLine( const QString &fieldname, const QString &value,
00122 uint linelen, bool url )
00123 {
00124 return assembleLine( fieldname, value.toUtf8(), linelen, url );
00125 }
00126
00127 bool Ldif::splitLine( const QByteArray &line, QString &fieldname, QByteArray &value )
00128 {
00129 int position;
00130 QByteArray tmp;
00131 int linelen;
00132
00133
00134
00135 position = line.indexOf( ":" );
00136 if ( position == -1 ) {
00137
00138 fieldname = QLatin1String( "" );
00139 value = line.trimmed();
00140
00141 return false;
00142 }
00143
00144 linelen = line.size();
00145 fieldname = QString::fromUtf8( line.left( position ).trimmed() );
00146
00147 if ( linelen > ( position + 1 ) && line[ position + 1 ] == ':' ) {
00148
00149 if ( linelen <= ( position + 3 ) ) {
00150 value.resize( 0 );
00151 return false;
00152 }
00153 value = QByteArray::fromBase64( line.mid( position + 3 ) );
00154 return false;
00155 }
00156
00157 if ( linelen > ( position + 1 ) && line[ position + 1 ] == '<' ) {
00158
00159 if ( linelen <= ( position + 3 ) ) {
00160 value.resize( 0 );
00161 return false;
00162 }
00163 value = QByteArray::fromBase64( line.mid( position + 3 ) );
00164 return true;
00165 }
00166
00167 if ( linelen <= ( position + 2 ) ) {
00168 value.resize( 0 );
00169 return false;
00170 }
00171 value = line.mid( position + 2 );
00172 return false;
00173 }
00174
00175 bool Ldif::splitControl( const QByteArray &line, QString &oid, bool &critical,
00176 QByteArray &value )
00177 {
00178 QString tmp;
00179 critical = false;
00180 bool url = splitLine( line, tmp, value );
00181
00182 kDebug() << "value:" << QString::fromUtf8( value, value.size() );
00183 if ( tmp.isEmpty() ) {
00184 tmp = QString::fromUtf8( value, value.size() );
00185 value.resize( 0 );
00186 }
00187 if ( tmp.endsWith( QLatin1String( "true" ) ) ) {
00188 critical = true;
00189 tmp.truncate( tmp.length() - 5 );
00190 } else if ( tmp.endsWith( QLatin1String( "false" ) ) ) {
00191 critical = false;
00192 tmp.truncate( tmp.length() - 6 );
00193 }
00194 oid = tmp;
00195 return url;
00196 }
00197
00198 Ldif::ParseValue Ldif::processLine()
00199 {
00200
00201 if ( d->mIsComment ) {
00202 return None;
00203 }
00204
00205 ParseValue retval = None;
00206 if ( d->mLastParseValue == EndEntry ) {
00207 d->mEntryType = Entry_None;
00208 }
00209
00210 d->mUrl = splitLine( d->mLine, d->mAttr, d->mValue );
00211
00212 QString attrLower = d->mAttr.toLower();
00213
00214 switch ( d->mEntryType ) {
00215 case Entry_None:
00216 if ( attrLower == QLatin1String( "version" ) ) {
00217 if ( !d->mDn.isEmpty() ) {
00218 retval = Err;
00219 }
00220 } else if ( attrLower == QLatin1String( "dn" ) ) {
00221 kDebug() << "ldapentry dn:" << QString::fromUtf8( d->mValue, d->mValue.size() );
00222 d->mDn = LdapDN( QString::fromUtf8( d->mValue, d->mValue.size() ) );
00223 d->mModType = Mod_None;
00224 retval = NewEntry;
00225 } else if ( attrLower == QLatin1String( "changetype" ) ) {
00226 if ( d->mDn.isEmpty() ) {
00227 retval = Err;
00228 } else {
00229 QString tmpval = QString::fromUtf8( d->mValue, d->mValue.size() );
00230 kDebug() << "changetype:" << tmpval;
00231 if ( tmpval == QLatin1String( "add" ) ) {
00232 d->mEntryType = Entry_Add;
00233 } else if ( tmpval == QLatin1String( "delete" ) ) {
00234 d->mEntryType = Entry_Del;
00235 } else if ( tmpval == QLatin1String( "modrdn" ) || tmpval == QLatin1String( "moddn" ) ) {
00236 d->mNewRdn = QLatin1String( "" );
00237 d->mNewSuperior = QLatin1String( "" );
00238 d->mDelOldRdn = true;
00239 d->mEntryType = Entry_Modrdn;
00240 } else if ( tmpval == QLatin1String( "modify" ) ) {
00241 d->mEntryType = Entry_Mod;
00242 } else {
00243 retval = Err;
00244 }
00245 }
00246 } else if ( attrLower == QLatin1String( "control" ) ) {
00247 d->mUrl = splitControl( d->mValue, d->mOid, d->mCritical, d->mValue );
00248 retval = Control;
00249 } else if ( !d->mAttr.isEmpty() && d->mValue.size() > 0 ) {
00250 d->mEntryType = Entry_Add;
00251 retval = Item;
00252 }
00253 break;
00254 case Entry_Add:
00255 if ( d->mAttr.isEmpty() && d->mValue.size() == 0 ) {
00256 retval = EndEntry;
00257 } else {
00258 retval = Item;
00259 }
00260 break;
00261 case Entry_Del:
00262 if ( d->mAttr.isEmpty() && d->mValue.size() == 0 ) {
00263 retval = EndEntry;
00264 } else {
00265 retval = Err;
00266 }
00267 break;
00268 case Entry_Mod:
00269 if ( d->mModType == Mod_None ) {
00270 kDebug() << "new modtype" << d->mAttr;
00271 if ( d->mAttr.isEmpty() && d->mValue.size() == 0 ) {
00272 retval = EndEntry;
00273 } else if ( attrLower == QLatin1String( "add" ) ) {
00274 d->mModType = Mod_Add;
00275 } else if ( attrLower == QLatin1String( "replace" ) ) {
00276 d->mModType = Mod_Replace;
00277 d->mAttr = QString::fromUtf8( d->mValue, d->mValue.size() );
00278 d->mValue = QByteArray();
00279 retval = Item;
00280 } else if ( attrLower == QLatin1String( "delete" ) ) {
00281 d->mModType = Mod_Del;
00282 d->mAttr = QString::fromUtf8( d->mValue, d->mValue.size() );
00283 d->mValue = QByteArray();
00284 retval = Item;
00285 } else {
00286 retval = Err;
00287 }
00288 } else {
00289 if ( d->mAttr.isEmpty() ) {
00290 if ( QString::fromUtf8( d->mValue, d->mValue.size() ) == QLatin1String( "-" ) ) {
00291 d->mModType = Mod_None;
00292 } else if ( d->mValue.size() == 0 ) {
00293 retval = EndEntry;
00294 } else {
00295 retval = Err;
00296 }
00297 } else {
00298 retval = Item;
00299 }
00300 }
00301 break;
00302 case Entry_Modrdn:
00303 if ( d->mAttr.isEmpty() && d->mValue.size() == 0 ) {
00304 retval = EndEntry;
00305 } else if ( attrLower == QLatin1String( "newrdn" ) ) {
00306 d->mNewRdn = QString::fromUtf8( d->mValue, d->mValue.size() );
00307 } else if ( attrLower == QLatin1String( "newsuperior" ) ) {
00308 d->mNewSuperior = QString::fromUtf8( d->mValue, d->mValue.size() );
00309 } else if ( attrLower == QLatin1String( "deleteoldrdn" ) ) {
00310 if ( d->mValue.size() > 0 && d->mValue[0] == '0' ) {
00311 d->mDelOldRdn = false;
00312 } else if ( d->mValue.size() > 0 && d->mValue[0] == '1' ) {
00313 d->mDelOldRdn = true;
00314 } else {
00315 retval = Err;
00316 }
00317 } else {
00318 retval = Err;
00319 }
00320 break;
00321 }
00322 return retval;
00323 }
00324
00325 Ldif::ParseValue Ldif::nextItem()
00326 {
00327 ParseValue retval = None;
00328 char c=0;
00329
00330 while ( retval == None ) {
00331 if ( d->mPos < (uint)d->mLdif.size() ) {
00332 c = d->mLdif[d->mPos];
00333 d->mPos++;
00334 if ( d->mIsNewLine && c == '\r' ) {
00335 continue;
00336 }
00337 if ( d->mIsNewLine && ( c == ' ' || c == '\t' ) ) {
00338 d->mIsNewLine = false;
00339 continue;
00340 }
00341 if ( d->mIsNewLine ) {
00342 d->mIsNewLine = false;
00343 retval = processLine();
00344 d->mLastParseValue = retval;
00345 d->mLine.resize( 0 );
00346 d->mIsComment = ( c == '#' );
00347 }
00348 if ( c == '\n' || c == '\r' ) {
00349 d->mLineNumber++;
00350 d->mIsNewLine = true;
00351 continue;
00352 }
00353 } else {
00354 retval = MoreData;
00355 break;
00356 }
00357
00358 if ( !d->mIsComment ) {
00359 d->mLine += c;
00360 }
00361 }
00362 return retval;
00363 }
00364
00365 void Ldif::endLdif()
00366 {
00367 QByteArray tmp( 3, '\n' );
00368 d->mLdif = tmp;
00369 d->mPos = 0;
00370 }
00371
00372 void Ldif::startParsing()
00373 {
00374 d->mPos = d->mLineNumber = 0;
00375 d->mDelOldRdn = false;
00376 d->mEntryType = Entry_None;
00377 d->mModType = Mod_None;
00378 d->mDn = LdapDN();
00379 d->mNewRdn.clear();
00380 d->mNewSuperior.clear();
00381 d->mLine = QByteArray();
00382 d->mIsNewLine = false;
00383 d->mIsComment = false;
00384 d->mLastParseValue = None;
00385 }
00386
00387 void Ldif::setLdif( const QByteArray &ldif )
00388 {
00389 d->mLdif = ldif;
00390 d->mPos = 0;
00391 }
00392
00393 Ldif::EntryType Ldif::entryType() const
00394 {
00395 return d->mEntryType;
00396 }
00397
00398 int Ldif::modType() const
00399 {
00400 return d->mModType;
00401 }
00402
00403 LdapDN Ldif::dn() const
00404 {
00405 return d->mDn;
00406 }
00407
00408 QString Ldif::newRdn() const
00409 {
00410 return d->mNewRdn;
00411 }
00412
00413 QString Ldif::newSuperior() const
00414 {
00415 return d->mNewSuperior;
00416 }
00417
00418 bool Ldif::delOldRdn() const
00419 {
00420 return d->mDelOldRdn;
00421 }
00422
00423 QString Ldif::attr() const
00424 {
00425 return d->mAttr;
00426 }
00427
00428 QByteArray Ldif::value() const
00429 {
00430 return d->mValue;
00431 }
00432
00433 bool Ldif::isUrl() const
00434 {
00435 return d->mUrl;
00436 }
00437
00438 bool Ldif::isCritical() const
00439 {
00440 return d->mCritical;
00441 }
00442
00443 QString Ldif::oid() const
00444 {
00445 return d->mOid;
00446 }
00447
00448 uint Ldif::lineNumber() const
00449 {
00450 return d->mLineNumber;
00451 }