KContacts

ldif.cpp
1/*
2 A temporary copy to break dependency to KLDAP
3
4 This file is part of libkldap.
5 SPDX-FileCopyrightText: 2004-2006 Szombathelyi György <gyurco@freemail.hu>
6
7 SPDX-License-Identifier: LGPL-2.0-or-later
8*/
9
10#include "ldif_p.h"
11
12#include "kcontacts_debug.h"
13
14class Q_DECL_HIDDEN Ldif::LdifPrivate
15{
16public:
17 int mModType;
18 bool mDelOldRdn, mUrl;
19 QByteArray mDn;
20 QString mAttr, mNewRdn, mNewSuperior, mOid;
21 QByteArray mLdif, mValue;
22 EntryType mEntryType;
23
24 bool mIsNewLine, mIsComment, mCritical;
25 ParseValue mLastParseValue;
26 uint mPos, mLineNumber;
27 QByteArray mLine;
28};
29
30Ldif::Ldif()
31 : d(new LdifPrivate)
32{
33 startParsing();
34}
35
36Ldif::Ldif(const Ldif &that)
37 : d(new LdifPrivate)
38{
39 *d = *that.d;
40
41 startParsing();
42}
43
44Ldif &Ldif::operator=(const Ldif &that)
45{
46 if (this == &that) {
47 return *this;
48 }
49
50 *d = *that.d;
51
52 return *this;
53}
54
55Ldif::~Ldif()
56{
57 delete d;
58}
59
60QByteArray Ldif::assembleLine(const QString &fieldname, const QByteArray &value, uint linelen, bool url)
61{
62 QByteArray result;
63
64 if (url) {
65 result = fieldname.toUtf8() + ":< " + value;
66 } else {
67 bool safe = false;
68 bool isDn = fieldname.toLower() == QLatin1String("dn");
69 // SAFE-INIT-CHAR
70 if (value.size() > 0 && value[0] > 0 && value[0] != '\n' //
71 && value[0] != '\r' && value[0] != ':' && value[0] != '<') {
72 safe = true;
73 }
74
75 // SAFE-CHAR
76 if (safe) {
77 for (int i = 1; i < value.size(); ++i) {
78 // allow utf-8 in Distinguished Names
79 if ((isDn && value[i] == 0) //
80 || (!isDn && value[i] <= 0) //
81 || value[i] == '\r' || value[i] == '\n') {
82 safe = false;
83 break;
84 }
85 }
86 }
87
88 if (value.isEmpty()) {
89 safe = true;
90 }
91
92 if (safe) {
93 result = fieldname.toUtf8() + ": " + value;
94 } else {
95 result = fieldname.toUtf8() + ":: " + value.toBase64();
96 }
97
98 if (linelen > 0) {
99 int i = (uint)(fieldname.length() + 2) > linelen ? fieldname.length() + 2 : linelen;
100 while (i < result.length()) {
101 result.insert(i, "\n ");
102 i += linelen + 2;
103 }
104 }
105 }
106 return result;
107}
108
109QByteArray Ldif::assembleLine(const QString &fieldname, const QString &value, uint linelen, bool url)
110{
111 return assembleLine(fieldname, value.toUtf8(), linelen, url);
112}
113
114bool Ldif::splitLine(const QByteArray &line, QString &fieldname, QByteArray &value)
115{
116 int position;
117 int linelen;
118
119 // qCDebug(KCONTACTS_LOG) << "line:" << QString::fromUtf8(line);
120
121 position = line.indexOf(":");
122 if (position == -1) {
123 // strange: we did not find a fieldname
124 fieldname = QLatin1String("");
125 value = line.trimmed();
126 // qCDebug(KCONTACTS_LOG) << "value :" << value[0];
127 return false;
128 }
129
130 linelen = line.size();
131 fieldname = QString::fromUtf8(line.left(position).trimmed());
132
133 if (linelen > (position + 1) && line[position + 1] == ':') {
134 // String is BASE64 encoded -> decode it now.
135 if (linelen <= (position + 3)) {
136 value.resize(0);
137 return false;
138 }
139 value = QByteArray::fromBase64(line.mid(position + 3));
140 return false;
141 }
142
143 if (linelen > (position + 1) && line[position + 1] == '<') {
144 // String is an URL.
145 if (linelen <= (position + 3)) {
146 value.resize(0);
147 return false;
148 }
149 value = QByteArray::fromBase64(line.mid(position + 3));
150 return true;
151 }
152
153 if (linelen <= (position + 2)) {
154 value.resize(0);
155 return false;
156 }
157 value = line.mid(position + 2);
158 return false;
159}
160
161bool Ldif::splitControl(const QByteArray &line, QString &oid, bool &critical, QByteArray &value)
162{
163 QString tmp;
164 critical = false;
165 bool url = splitLine(line, tmp, value);
166
167 qCDebug(KCONTACTS_LOG) << "value:" << QString::fromUtf8(value);
168 if (tmp.isEmpty()) {
169 tmp = QString::fromUtf8(value);
170 value.resize(0);
171 }
172 if (tmp.endsWith(QLatin1String("true"))) {
173 critical = true;
174 tmp.chop(5);
175 } else if (tmp.endsWith(QLatin1String("false"))) {
176 critical = false;
177 tmp.chop(6);
178 }
179 oid = tmp;
180 return url;
181}
182
183Ldif::ParseValue Ldif::processLine()
184{
185 if (d->mIsComment) {
186 return None;
187 }
188
189 ParseValue retval = None;
190 if (d->mLastParseValue == EndEntry) {
191 d->mEntryType = Entry_None;
192 }
193
194 d->mUrl = splitLine(d->mLine, d->mAttr, d->mValue);
195
196 QString attrLower = d->mAttr.toLower();
197
198 switch (d->mEntryType) {
199 case Entry_None:
200 if (attrLower == QLatin1String("version")) {
201 if (!d->mDn.isEmpty()) {
202 retval = Err;
203 }
204 } else if (attrLower == QLatin1String("dn")) {
205 qCDebug(KCONTACTS_LOG) << "ldapentry dn:" << QString::fromUtf8(d->mValue);
206 d->mDn = d->mValue;
207 d->mModType = Mod_None;
208 retval = NewEntry;
209 } else if (attrLower == QLatin1String("changetype")) {
210 if (d->mDn.isEmpty()) {
211 retval = Err;
212 } else {
213 QString tmpval = QString::fromUtf8(d->mValue);
214 qCDebug(KCONTACTS_LOG) << "changetype:" << tmpval;
215 if (tmpval == QLatin1String("add")) {
216 d->mEntryType = Entry_Add;
217 } else if (tmpval == QLatin1String("delete")) {
218 d->mEntryType = Entry_Del;
219 } else if (tmpval == QLatin1String("modrdn") || tmpval == QLatin1String("moddn")) {
220 d->mNewRdn = QLatin1String("");
221 d->mNewSuperior = QLatin1String("");
222 d->mDelOldRdn = true;
223 d->mEntryType = Entry_Modrdn;
224 } else if (tmpval == QLatin1String("modify")) {
225 d->mEntryType = Entry_Mod;
226 } else {
227 retval = Err;
228 }
229 }
230 } else if (attrLower == QLatin1String("control")) {
231 d->mUrl = splitControl(d->mValue, d->mOid, d->mCritical, d->mValue);
232 retval = Control;
233 } else if (!d->mAttr.isEmpty() && !d->mValue.isEmpty()) {
234 d->mEntryType = Entry_Add;
235 retval = Item;
236 }
237 break;
238 case Entry_Add:
239 if (d->mAttr.isEmpty() && d->mValue.isEmpty()) {
240 retval = EndEntry;
241 } else {
242 retval = Item;
243 }
244 break;
245 case Entry_Del:
246 if (d->mAttr.isEmpty() && d->mValue.isEmpty()) {
247 retval = EndEntry;
248 } else {
249 retval = Err;
250 }
251 break;
252 case Entry_Mod:
253 if (d->mModType == Mod_None) {
254 qCDebug(KCONTACTS_LOG) << "new modtype" << d->mAttr;
255 if (d->mAttr.isEmpty() && d->mValue.isEmpty()) {
256 retval = EndEntry;
257 } else if (attrLower == QLatin1String("add")) {
258 d->mModType = Mod_Add;
259 } else if (attrLower == QLatin1String("replace")) {
260 d->mModType = Mod_Replace;
261 d->mAttr = QString::fromUtf8(d->mValue);
262 d->mValue = QByteArray();
263 retval = Item;
264 } else if (attrLower == QLatin1String("delete")) {
265 d->mModType = Mod_Del;
266 d->mAttr = QString::fromUtf8(d->mValue);
267 d->mValue = QByteArray();
268 retval = Item;
269 } else {
270 retval = Err;
271 }
272 } else {
273 if (d->mAttr.isEmpty()) {
274 if (QString::fromUtf8(d->mValue) == QLatin1String("-")) {
275 d->mModType = Mod_None;
276 } else if (d->mValue.isEmpty()) {
277 retval = EndEntry;
278 } else {
279 retval = Err;
280 }
281 } else {
282 retval = Item;
283 }
284 }
285 break;
286 case Entry_Modrdn:
287 if (d->mAttr.isEmpty() && d->mValue.isEmpty()) {
288 retval = EndEntry;
289 } else if (attrLower == QLatin1String("newrdn")) {
290 d->mNewRdn = QString::fromUtf8(d->mValue);
291 } else if (attrLower == QLatin1String("newsuperior")) {
292 d->mNewSuperior = QString::fromUtf8(d->mValue);
293 } else if (attrLower == QLatin1String("deleteoldrdn")) {
294 if (d->mValue.size() > 0 && d->mValue[0] == '0') {
295 d->mDelOldRdn = false;
296 } else if (d->mValue.size() > 0 && d->mValue[0] == '1') {
297 d->mDelOldRdn = true;
298 } else {
299 retval = Err;
300 }
301 } else {
302 retval = Err;
303 }
304 break;
305 }
306 return retval;
307}
308
309Ldif::ParseValue Ldif::nextItem()
310{
311 ParseValue retval = None;
312 char c = 0;
313
314 while (retval == None) {
315 if (d->mPos < (uint)d->mLdif.size()) {
316 c = d->mLdif[d->mPos];
317 d->mPos++;
318 if (d->mIsNewLine && c == '\r') {
319 continue; // handle \n\r line end
320 }
321 if (d->mIsNewLine && (c == ' ' || c == '\t')) { // line folding
322 d->mIsNewLine = false;
323 continue;
324 }
325 if (d->mIsNewLine) {
326 d->mIsNewLine = false;
327 retval = processLine();
328 d->mLastParseValue = retval;
329 d->mLine.resize(0);
330 d->mIsComment = (c == '#');
331 }
332 if (c == '\n' || c == '\r') {
333 d->mLineNumber++;
334 d->mIsNewLine = true;
335 continue;
336 }
337 } else {
338 retval = MoreData;
339 break;
340 }
341
342 if (!d->mIsComment) {
343 d->mLine += c;
344 }
345 }
346 return retval;
347}
348
349void Ldif::endLdif()
350{
351 QByteArray tmp(3, '\n');
352 d->mLdif = tmp;
353 d->mPos = 0;
354}
355
356void Ldif::startParsing()
357{
358 d->mPos = d->mLineNumber = 0;
359 d->mDelOldRdn = false;
360 d->mEntryType = Entry_None;
361 d->mModType = Mod_None;
362 d->mNewRdn.clear();
363 d->mNewSuperior.clear();
364 d->mLine = QByteArray();
365 d->mIsNewLine = false;
366 d->mIsComment = false;
367 d->mLastParseValue = None;
368}
369
370void Ldif::setLdif(const QByteArray &ldif)
371{
372 d->mLdif = ldif;
373 d->mPos = 0;
374}
375
376Ldif::EntryType Ldif::entryType() const
377{
378 return d->mEntryType;
379}
380
381int Ldif::modType() const
382{
383 return d->mModType;
384}
385
386QString Ldif::newRdn() const
387{
388 return d->mNewRdn;
389}
390
391QString Ldif::newSuperior() const
392{
393 return d->mNewSuperior;
394}
395
396bool Ldif::delOldRdn() const
397{
398 return d->mDelOldRdn;
399}
400
401QString Ldif::attr() const
402{
403 return d->mAttr;
404}
405
406QByteArray Ldif::value() const
407{
408 return d->mValue;
409}
410
411bool Ldif::isUrl() const
412{
413 return d->mUrl;
414}
415
416bool Ldif::isCritical() const
417{
418 return d->mCritical;
419}
420
421QString Ldif::oid() const
422{
423 return d->mOid;
424}
425
426uint Ldif::lineNumber() const
427{
428 return d->mLineNumber;
429}
QByteArray fromBase64(const QByteArray &base64, Base64Options options)
qsizetype indexOf(QByteArrayView bv, qsizetype from) const const
QByteArray & insert(qsizetype i, QByteArrayView data)
bool isEmpty() const const
QByteArray left(qsizetype len) const const
qsizetype length() const const
QByteArray mid(qsizetype pos, qsizetype len) const const
void resize(qsizetype newSize, char c)
qsizetype size() const const
QByteArray toBase64(Base64Options options) const const
QByteArray trimmed() const const
void chop(qsizetype n)
void clear()
bool endsWith(QChar c, Qt::CaseSensitivity cs) const const
QString fromUtf8(QByteArrayView str)
bool isEmpty() const const
qsizetype length() const const
QString toLower() const const
QByteArray toUtf8() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Tue Mar 26 2024 11:14:08 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.