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