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 <[email protected]>
6 
7  SPDX-License-Identifier: LGPL-2.0-or-later
8 */
9 
10 #include "ldif_p.h"
11 
12 #include "kcontacts_debug.h"
13 
14 class Q_DECL_HIDDEN Ldif::LdifPrivate
15 {
16 public:
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 
30 Ldif::Ldif()
31  : d(new LdifPrivate)
32 {
33  startParsing();
34 }
35 
36 Ldif::Ldif(const Ldif &that)
37  : d(new LdifPrivate)
38 {
39  *d = *that.d;
40 
41  startParsing();
42 }
43 
44 Ldif &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 
55 Ldif::~Ldif()
56 {
57  delete d;
58 }
59 
60 QByteArray 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 
109 QByteArray Ldif::assembleLine(const QString &fieldname, const QString &value, uint linelen, bool url)
110 {
111  return assembleLine(fieldname, value.toUtf8(), linelen, url);
112 }
113 
114 bool 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 
161 bool 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 
183 Ldif::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 
309 Ldif::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 
349 void Ldif::endLdif()
350 {
351  QByteArray tmp(3, '\n');
352  d->mLdif = tmp;
353  d->mPos = 0;
354 }
355 
356 void 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 
370 void Ldif::setLdif(const QByteArray &ldif)
371 {
372  d->mLdif = ldif;
373  d->mPos = 0;
374 }
375 
376 Ldif::EntryType Ldif::entryType() const
377 {
378  return d->mEntryType;
379 }
380 
381 int Ldif::modType() const
382 {
383  return d->mModType;
384 }
385 
386 QString Ldif::newRdn() const
387 {
388  return d->mNewRdn;
389 }
390 
391 QString Ldif::newSuperior() const
392 {
393  return d->mNewSuperior;
394 }
395 
396 bool Ldif::delOldRdn() const
397 {
398  return d->mDelOldRdn;
399 }
400 
401 QString Ldif::attr() const
402 {
403  return d->mAttr;
404 }
405 
406 QByteArray Ldif::value() const
407 {
408  return d->mValue;
409 }
410 
411 bool Ldif::isUrl() const
412 {
413  return d->mUrl;
414 }
415 
416 bool Ldif::isCritical() const
417 {
418  return d->mCritical;
419 }
420 
421 QString Ldif::oid() const
422 {
423  return d->mOid;
424 }
425 
426 uint Ldif::lineNumber() const
427 {
428  return d->mLineNumber;
429 }
QByteArray trimmed() const const
bool isEmpty() const const
QByteArray & insert(int i, char ch)
int length() const const
void chop(int n)
void resize(int size)
int indexOf(char ch, int from) const const
QString fromUtf8(const char *str, int size)
bool isEmpty() const const
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const const
QByteArray mid(int pos, int len) const const
QString toLower() const const
QByteArray left(int len) const const
QByteArray fromBase64(const QByteArray &base64, QByteArray::Base64Options options)
int length() const const
int size() const const
QByteArray toBase64(QByteArray::Base64Options options) const const
QByteArray toUtf8() const const
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Mon Sep 20 2021 22:56:07 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.