File indexing completed on 2025-01-19 03:39:52
0001 /* 0002 A temporary copy to break dependency to KLDAP 0003 0004 This file is part of libkldap. 0005 SPDX-FileCopyrightText: 2004-2006 Szombathelyi György <gyurco@freemail.hu> 0006 0007 SPDX-License-Identifier: LGPL-2.0-or-later 0008 */ 0009 0010 #include "ldif_p.h" 0011 0012 #include "kcontacts_debug.h" 0013 0014 class Q_DECL_HIDDEN Ldif::LdifPrivate 0015 { 0016 public: 0017 int mModType; 0018 bool mDelOldRdn, mUrl; 0019 QByteArray mDn; 0020 QString mAttr, mNewRdn, mNewSuperior, mOid; 0021 QByteArray mLdif, mValue; 0022 EntryType mEntryType; 0023 0024 bool mIsNewLine, mIsComment, mCritical; 0025 ParseValue mLastParseValue; 0026 uint mPos, mLineNumber; 0027 QByteArray mLine; 0028 }; 0029 0030 Ldif::Ldif() 0031 : d(new LdifPrivate) 0032 { 0033 startParsing(); 0034 } 0035 0036 Ldif::Ldif(const Ldif &that) 0037 : d(new LdifPrivate) 0038 { 0039 *d = *that.d; 0040 0041 startParsing(); 0042 } 0043 0044 Ldif &Ldif::operator=(const Ldif &that) 0045 { 0046 if (this == &that) { 0047 return *this; 0048 } 0049 0050 *d = *that.d; 0051 0052 return *this; 0053 } 0054 0055 Ldif::~Ldif() 0056 { 0057 delete d; 0058 } 0059 0060 QByteArray Ldif::assembleLine(const QString &fieldname, const QByteArray &value, uint linelen, bool url) 0061 { 0062 QByteArray result; 0063 0064 if (url) { 0065 result = fieldname.toUtf8() + ":< " + value; 0066 } else { 0067 bool safe = false; 0068 bool isDn = fieldname.toLower() == QLatin1String("dn"); 0069 // SAFE-INIT-CHAR 0070 if (value.size() > 0 && value[0] > 0 && value[0] != '\n' // 0071 && value[0] != '\r' && value[0] != ':' && value[0] != '<') { 0072 safe = true; 0073 } 0074 0075 // SAFE-CHAR 0076 if (safe) { 0077 for (int i = 1; i < value.size(); ++i) { 0078 // allow utf-8 in Distinguished Names 0079 if ((isDn && value[i] == 0) // 0080 || (!isDn && value[i] <= 0) // 0081 || value[i] == '\r' || value[i] == '\n') { 0082 safe = false; 0083 break; 0084 } 0085 } 0086 } 0087 0088 if (value.isEmpty()) { 0089 safe = true; 0090 } 0091 0092 if (safe) { 0093 result = fieldname.toUtf8() + ": " + value; 0094 } else { 0095 result = fieldname.toUtf8() + ":: " + value.toBase64(); 0096 } 0097 0098 if (linelen > 0) { 0099 int i = (uint)(fieldname.length() + 2) > linelen ? fieldname.length() + 2 : linelen; 0100 while (i < result.length()) { 0101 result.insert(i, "\n "); 0102 i += linelen + 2; 0103 } 0104 } 0105 } 0106 return result; 0107 } 0108 0109 QByteArray Ldif::assembleLine(const QString &fieldname, const QString &value, uint linelen, bool url) 0110 { 0111 return assembleLine(fieldname, value.toUtf8(), linelen, url); 0112 } 0113 0114 bool Ldif::splitLine(const QByteArray &line, QString &fieldname, QByteArray &value) 0115 { 0116 int position; 0117 int linelen; 0118 0119 // qCDebug(KCONTACTS_LOG) << "line:" << QString::fromUtf8(line); 0120 0121 position = line.indexOf(":"); 0122 if (position == -1) { 0123 // strange: we did not find a fieldname 0124 fieldname = QLatin1String(""); 0125 value = line.trimmed(); 0126 // qCDebug(KCONTACTS_LOG) << "value :" << value[0]; 0127 return false; 0128 } 0129 0130 linelen = line.size(); 0131 fieldname = QString::fromUtf8(line.left(position).trimmed()); 0132 0133 if (linelen > (position + 1) && line[position + 1] == ':') { 0134 // String is BASE64 encoded -> decode it now. 0135 if (linelen <= (position + 3)) { 0136 value.resize(0); 0137 return false; 0138 } 0139 value = QByteArray::fromBase64(line.mid(position + 3)); 0140 return false; 0141 } 0142 0143 if (linelen > (position + 1) && line[position + 1] == '<') { 0144 // String is an URL. 0145 if (linelen <= (position + 3)) { 0146 value.resize(0); 0147 return false; 0148 } 0149 value = QByteArray::fromBase64(line.mid(position + 3)); 0150 return true; 0151 } 0152 0153 if (linelen <= (position + 2)) { 0154 value.resize(0); 0155 return false; 0156 } 0157 value = line.mid(position + 2); 0158 return false; 0159 } 0160 0161 bool Ldif::splitControl(const QByteArray &line, QString &oid, bool &critical, QByteArray &value) 0162 { 0163 QString tmp; 0164 critical = false; 0165 bool url = splitLine(line, tmp, value); 0166 0167 qCDebug(KCONTACTS_LOG) << "value:" << QString::fromUtf8(value); 0168 if (tmp.isEmpty()) { 0169 tmp = QString::fromUtf8(value); 0170 value.resize(0); 0171 } 0172 if (tmp.endsWith(QLatin1String("true"))) { 0173 critical = true; 0174 tmp.chop(5); 0175 } else if (tmp.endsWith(QLatin1String("false"))) { 0176 critical = false; 0177 tmp.chop(6); 0178 } 0179 oid = tmp; 0180 return url; 0181 } 0182 0183 Ldif::ParseValue Ldif::processLine() 0184 { 0185 if (d->mIsComment) { 0186 return None; 0187 } 0188 0189 ParseValue retval = None; 0190 if (d->mLastParseValue == EndEntry) { 0191 d->mEntryType = Entry_None; 0192 } 0193 0194 d->mUrl = splitLine(d->mLine, d->mAttr, d->mValue); 0195 0196 QString attrLower = d->mAttr.toLower(); 0197 0198 switch (d->mEntryType) { 0199 case Entry_None: 0200 if (attrLower == QLatin1String("version")) { 0201 if (!d->mDn.isEmpty()) { 0202 retval = Err; 0203 } 0204 } else if (attrLower == QLatin1String("dn")) { 0205 qCDebug(KCONTACTS_LOG) << "ldapentry dn:" << QString::fromUtf8(d->mValue); 0206 d->mDn = d->mValue; 0207 d->mModType = Mod_None; 0208 retval = NewEntry; 0209 } else if (attrLower == QLatin1String("changetype")) { 0210 if (d->mDn.isEmpty()) { 0211 retval = Err; 0212 } else { 0213 QString tmpval = QString::fromUtf8(d->mValue); 0214 qCDebug(KCONTACTS_LOG) << "changetype:" << tmpval; 0215 if (tmpval == QLatin1String("add")) { 0216 d->mEntryType = Entry_Add; 0217 } else if (tmpval == QLatin1String("delete")) { 0218 d->mEntryType = Entry_Del; 0219 } else if (tmpval == QLatin1String("modrdn") || tmpval == QLatin1String("moddn")) { 0220 d->mNewRdn = QLatin1String(""); 0221 d->mNewSuperior = QLatin1String(""); 0222 d->mDelOldRdn = true; 0223 d->mEntryType = Entry_Modrdn; 0224 } else if (tmpval == QLatin1String("modify")) { 0225 d->mEntryType = Entry_Mod; 0226 } else { 0227 retval = Err; 0228 } 0229 } 0230 } else if (attrLower == QLatin1String("control")) { 0231 d->mUrl = splitControl(d->mValue, d->mOid, d->mCritical, d->mValue); 0232 retval = Control; 0233 } else if (!d->mAttr.isEmpty() && !d->mValue.isEmpty()) { 0234 d->mEntryType = Entry_Add; 0235 retval = Item; 0236 } 0237 break; 0238 case Entry_Add: 0239 if (d->mAttr.isEmpty() && d->mValue.isEmpty()) { 0240 retval = EndEntry; 0241 } else { 0242 retval = Item; 0243 } 0244 break; 0245 case Entry_Del: 0246 if (d->mAttr.isEmpty() && d->mValue.isEmpty()) { 0247 retval = EndEntry; 0248 } else { 0249 retval = Err; 0250 } 0251 break; 0252 case Entry_Mod: 0253 if (d->mModType == Mod_None) { 0254 qCDebug(KCONTACTS_LOG) << "new modtype" << d->mAttr; 0255 if (d->mAttr.isEmpty() && d->mValue.isEmpty()) { 0256 retval = EndEntry; 0257 } else if (attrLower == QLatin1String("add")) { 0258 d->mModType = Mod_Add; 0259 } else if (attrLower == QLatin1String("replace")) { 0260 d->mModType = Mod_Replace; 0261 d->mAttr = QString::fromUtf8(d->mValue); 0262 d->mValue = QByteArray(); 0263 retval = Item; 0264 } else if (attrLower == QLatin1String("delete")) { 0265 d->mModType = Mod_Del; 0266 d->mAttr = QString::fromUtf8(d->mValue); 0267 d->mValue = QByteArray(); 0268 retval = Item; 0269 } else { 0270 retval = Err; 0271 } 0272 } else { 0273 if (d->mAttr.isEmpty()) { 0274 if (QString::fromUtf8(d->mValue) == QLatin1String("-")) { 0275 d->mModType = Mod_None; 0276 } else if (d->mValue.isEmpty()) { 0277 retval = EndEntry; 0278 } else { 0279 retval = Err; 0280 } 0281 } else { 0282 retval = Item; 0283 } 0284 } 0285 break; 0286 case Entry_Modrdn: 0287 if (d->mAttr.isEmpty() && d->mValue.isEmpty()) { 0288 retval = EndEntry; 0289 } else if (attrLower == QLatin1String("newrdn")) { 0290 d->mNewRdn = QString::fromUtf8(d->mValue); 0291 } else if (attrLower == QLatin1String("newsuperior")) { 0292 d->mNewSuperior = QString::fromUtf8(d->mValue); 0293 } else if (attrLower == QLatin1String("deleteoldrdn")) { 0294 if (d->mValue.size() > 0 && d->mValue[0] == '0') { 0295 d->mDelOldRdn = false; 0296 } else if (d->mValue.size() > 0 && d->mValue[0] == '1') { 0297 d->mDelOldRdn = true; 0298 } else { 0299 retval = Err; 0300 } 0301 } else { 0302 retval = Err; 0303 } 0304 break; 0305 } 0306 return retval; 0307 } 0308 0309 Ldif::ParseValue Ldif::nextItem() 0310 { 0311 ParseValue retval = None; 0312 char c = 0; 0313 0314 while (retval == None) { 0315 if (d->mPos < (uint)d->mLdif.size()) { 0316 c = d->mLdif[d->mPos]; 0317 d->mPos++; 0318 if (d->mIsNewLine && c == '\r') { 0319 continue; // handle \n\r line end 0320 } 0321 if (d->mIsNewLine && (c == ' ' || c == '\t')) { // line folding 0322 d->mIsNewLine = false; 0323 continue; 0324 } 0325 if (d->mIsNewLine) { 0326 d->mIsNewLine = false; 0327 retval = processLine(); 0328 d->mLastParseValue = retval; 0329 d->mLine.resize(0); 0330 d->mIsComment = (c == '#'); 0331 } 0332 if (c == '\n' || c == '\r') { 0333 d->mLineNumber++; 0334 d->mIsNewLine = true; 0335 continue; 0336 } 0337 } else { 0338 retval = MoreData; 0339 break; 0340 } 0341 0342 if (!d->mIsComment) { 0343 d->mLine += c; 0344 } 0345 } 0346 return retval; 0347 } 0348 0349 void Ldif::endLdif() 0350 { 0351 QByteArray tmp(3, '\n'); 0352 d->mLdif = tmp; 0353 d->mPos = 0; 0354 } 0355 0356 void Ldif::startParsing() 0357 { 0358 d->mPos = d->mLineNumber = 0; 0359 d->mDelOldRdn = false; 0360 d->mEntryType = Entry_None; 0361 d->mModType = Mod_None; 0362 d->mNewRdn.clear(); 0363 d->mNewSuperior.clear(); 0364 d->mLine = QByteArray(); 0365 d->mIsNewLine = false; 0366 d->mIsComment = false; 0367 d->mLastParseValue = None; 0368 } 0369 0370 void Ldif::setLdif(const QByteArray &ldif) 0371 { 0372 d->mLdif = ldif; 0373 d->mPos = 0; 0374 } 0375 0376 Ldif::EntryType Ldif::entryType() const 0377 { 0378 return d->mEntryType; 0379 } 0380 0381 int Ldif::modType() const 0382 { 0383 return d->mModType; 0384 } 0385 0386 QString Ldif::newRdn() const 0387 { 0388 return d->mNewRdn; 0389 } 0390 0391 QString Ldif::newSuperior() const 0392 { 0393 return d->mNewSuperior; 0394 } 0395 0396 bool Ldif::delOldRdn() const 0397 { 0398 return d->mDelOldRdn; 0399 } 0400 0401 QString Ldif::attr() const 0402 { 0403 return d->mAttr; 0404 } 0405 0406 QByteArray Ldif::value() const 0407 { 0408 return d->mValue; 0409 } 0410 0411 bool Ldif::isUrl() const 0412 { 0413 return d->mUrl; 0414 } 0415 0416 bool Ldif::isCritical() const 0417 { 0418 return d->mCritical; 0419 } 0420 0421 QString Ldif::oid() const 0422 { 0423 return d->mOid; 0424 } 0425 0426 uint Ldif::lineNumber() const 0427 { 0428 return d->mLineNumber; 0429 }