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

KDE's Doxygen guidelines are available online.