• Skip to content
  • Skip to link menu
KDE API Reference
  • KDE API Reference
  • kdeutils API Reference
  • KDE Home
  • Contact Us
 

kgpg

  • sources
  • kde-4.14
  • kdeutils
  • kgpg
  • model
kgpgsearchresultmodel.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2009,2010,2013 Rolf Eike Beer <kde@opensource.sf-tec.de>
3  */
4 
5 /***************************************************************************
6  * *
7  * This program is free software; you can redistribute it and/or modify *
8  * it under the terms of the GNU General Public License as published by *
9  * the Free Software Foundation; either version 2 of the License, or *
10  * (at your option) any later version. *
11  * *
12  ***************************************************************************/
13 
14 #include "kgpgsearchresultmodel.h"
15 
16 #include <KDateTime>
17 #include <KDebug>
18 #include <KLocale>
19 #include <QString>
20 #include <QStringList>
21 #include <QTextCodec>
22 
23 #include "core/convert.h"
24 #include "core/kgpgkey.h"
25 
26 class SearchResult {
27 private:
28  QStringList m_emails;
29  QStringList m_names;
30 
31 public:
32  SearchResult(const QString &line);
33 
34  bool m_validPub; // true when the "pub" line passed to constructor was valid
35 
36  void addUid(const QString &id);
37  const QString &getName(const int index) const;
38  const QString &getEmail(const int index) const;
39  int getUidCount() const;
40 
41  QString m_fingerprint;
42  unsigned int m_uatCount;
43 
44  QVariant summary() const;
45 private:
46  KDateTime m_expiry;
47  KDateTime m_creation;
48  bool m_revoked;
49  unsigned int m_bits;
50  KgpgCore::KgpgKeyAlgo m_algo;
51 };
52 
53 class KGpgSearchResultModelPrivate {
54 public:
55  explicit KGpgSearchResultModelPrivate();
56  ~KGpgSearchResultModelPrivate();
57 
58  QList<SearchResult *> m_items;
59 
60  QString urlDecode(const QString &line);
61 };
62 
63 SearchResult::SearchResult(const QString &line)
64  : m_validPub(false),
65  m_uatCount(0),
66  m_revoked(false),
67  m_bits(0)
68 {
69  const QStringList parts(line.split(QLatin1Char( ':' )));
70 
71  if (parts.count() < 6)
72  return;
73 
74  if (parts.at(1).isEmpty())
75  return;
76 
77  m_fingerprint = parts.at(1);
78  m_algo = KgpgCore::Convert::toAlgo(parts.at(2));
79  m_bits = parts.at(3).toUInt();
80  m_creation.setTime_t(parts.at(4).toULongLong());
81  m_revoked = (parts.at(6) == QLatin1String( "r" ));
82 
83  m_validPub = true;
84 }
85 
86 void
87 SearchResult::addUid(const QString &id)
88 {
89  Q_ASSERT(m_emails.count() == m_names.count());
90  QRegExp hasmail( QLatin1String( "(.*) <(.*)>" ));
91 
92  if (hasmail.exactMatch(id)) {
93  m_names.append(hasmail.capturedTexts().at(1));
94  m_emails.append(hasmail.capturedTexts().at(2));
95  } else {
96  m_names.append(id);
97  m_emails.append(QString());
98  }
99 }
100 
101 const QString &
102 SearchResult::getName(const int index) const
103 {
104  return m_names.at(index);
105 }
106 
107 const QString &
108 SearchResult::getEmail(const int index) const
109 {
110  return m_emails.at(index);
111 }
112 
113 int
114 SearchResult::getUidCount() const
115 {
116  Q_ASSERT(m_emails.count() == m_names.count());
117 
118  return m_emails.count();
119 }
120 
121 QVariant
122 SearchResult::summary() const
123 {
124  if (m_revoked) {
125  return i18nc("example: ID abc123xy, 1024-bit RSA key, created Jan 12 2009, revoked",
126  "ID %1, %2-bit %3 key, created %4, revoked", m_fingerprint,
127  m_bits, KgpgCore::Convert::toString(m_algo),
128  m_creation.toString(KDateTime::LocalDate));
129  } else {
130  return i18nc("example: ID abc123xy, 1024-bit RSA key, created Jan 12 2009",
131  "ID %1, %2-bit %3 key, created %4", m_fingerprint,
132  m_bits, KgpgCore::Convert::toString(m_algo),
133  m_creation.toString(KDateTime::LocalDate));
134  }
135 }
136 
137 KGpgSearchResultModelPrivate::KGpgSearchResultModelPrivate()
138 {
139 }
140 
141 KGpgSearchResultModelPrivate::~KGpgSearchResultModelPrivate()
142 {
143  foreach (SearchResult *item, m_items)
144  delete item;
145 }
146 
147 QString
148 KGpgSearchResultModelPrivate::urlDecode(const QString &line)
149 {
150  if (!line.contains(QLatin1Char( '%' )))
151  return line;
152 
153  QByteArray tmp(line.toAscii());
154  const QRegExp hex( QLatin1String( "[A-F0-9]{2}" )); // URL-encoding uses only uppercase
155 
156  int pos = -1; // avoid error if '%' is URL-encoded
157  while ((pos = tmp.indexOf("%", pos + 1)) >= 0) {
158  const QByteArray hexnum(tmp.mid(pos + 1, 2));
159 
160  // the input is not properly URL-encoded, so assume it does not need to be decoded at all
161  if (!hex.exactMatch(QLatin1String( hexnum )))
162  return line;
163 
164  char n[2];
165  // this must work as we checked the regexp before
166  n[0] = hexnum.toUShort(NULL, 16);
167  n[1] = '\0'; // to use n as a 0-terminated string
168 
169  tmp.replace(pos, 3, n);
170  }
171 
172  return QTextCodec::codecForName("utf8")->toUnicode(tmp);
173 }
174 
175 KGpgSearchResultModel::KGpgSearchResultModel(QObject *parent)
176  : QAbstractItemModel(parent), d(new KGpgSearchResultModelPrivate())
177 {
178 }
179 
180 KGpgSearchResultModel::~KGpgSearchResultModel()
181 {
182  delete d;
183 }
184 
185 QVariant
186 KGpgSearchResultModel::data(const QModelIndex &index, int role) const
187 {
188  if (!index.isValid())
189  return QVariant();
190 
191  if (role != Qt::DisplayRole)
192  return QVariant();
193 
194  if (index.row() < 0)
195  return QVariant();
196 
197  SearchResult *tmp = static_cast<SearchResult *>(index.internalPointer());
198  int row;
199 
200  if (tmp == NULL) {
201  // this is a "top" item, show the first uid
202  if (index.row() >= d->m_items.count())
203  return QVariant();
204 
205  tmp = d->m_items.at(index.row());
206  row = 0;
207  } else {
208  row = index.row() + 1;
209  int summaryRow = tmp->getUidCount();
210  int uatRow;
211  if (tmp->m_uatCount != 0) {
212  uatRow = summaryRow;
213  summaryRow++;
214  } else {
215  uatRow = -1;
216  }
217 
218  if (row == uatRow) {
219  if (index.column() == 0)
220  return i18np("One Photo ID", "%1 Photo IDs", tmp->m_uatCount);
221  else
222  return QVariant();
223  } else if (row == summaryRow) {
224  if (index.column() == 0)
225  return tmp->summary();
226  else
227  return QVariant();
228  }
229  Q_ASSERT(row < tmp->getUidCount());
230  }
231 
232  switch (index.column()) {
233  case 0:
234  return tmp->getName(row);
235  case 1:
236  return tmp->getEmail(row);
237  default:
238  return QVariant();
239  }
240 }
241 
242 int
243 KGpgSearchResultModel::columnCount(const QModelIndex &parent) const
244 {
245  if (parent.isValid()) {
246  if (parent.column() != 0)
247  return 0;
248 
249  SearchResult *tmp = static_cast<SearchResult *>(parent.internalPointer());
250 
251  if (tmp == NULL)
252  return 2;
253  else
254  return 0;
255  } else {
256  return 2;
257  }
258 }
259 
260 QModelIndex
261 KGpgSearchResultModel::index(int row, int column, const QModelIndex &parent) const
262 {
263  // there are three hierarchy levels:
264  // root: this is simply QModelIndex()
265  // key items: parent is invalid, internalPointer is NULL
266  // uid entries: parent is key item, internalPointer is set to SearchResult*
267 
268  if (parent.isValid()) {
269  if (parent.internalPointer() != NULL) {
270  return QModelIndex();
271  } else {
272  if (parent.row() >= d->m_items.count())
273  return QModelIndex();
274  SearchResult *tmp = d->m_items.at(parent.row());
275  int maxRow = tmp->getUidCount();
276  if (tmp->m_uatCount != 0)
277  maxRow++;
278  if ((row >= maxRow) || (column > 1))
279  return QModelIndex();
280  return createIndex(row, column, tmp);
281  }
282  } else {
283  if ((row >= d->m_items.count()) || (column > 1) || (row < 0) || (column < 0))
284  return QModelIndex();
285  return createIndex(row, column);
286  }
287 }
288 
289 QModelIndex
290 KGpgSearchResultModel::parent(const QModelIndex &index) const
291 {
292  if (!index.isValid())
293  return QModelIndex();
294 
295  SearchResult *tmp = static_cast<SearchResult *>(index.internalPointer());
296 
297  if (tmp == NULL)
298  return QModelIndex();
299 
300  return createIndex(d->m_items.indexOf(tmp), 0);
301 }
302 
303 int
304 KGpgSearchResultModel::rowCount(const QModelIndex &parent) const
305 {
306  if (!parent.isValid()) {
307  return d->m_items.count();
308  } else if (parent.column() == 0) {
309  if (parent.internalPointer() != NULL)
310  return 0;
311 
312  SearchResult *item = d->m_items.at(parent.row());
313  int cnt = item->getUidCount();
314  if (item->m_uatCount != 0)
315  cnt++;
316 
317  return cnt;
318  } else {
319  return 0;
320  }
321 }
322 
323 QVariant
324 KGpgSearchResultModel::headerData(int section, Qt::Orientation orientation, int role) const
325 {
326  if (role != Qt::DisplayRole)
327  return QVariant();
328 
329  if (orientation != Qt::Horizontal)
330  return QVariant();
331 
332  switch (section) {
333  case 0:
334  return i18n("Name");
335  case 1:
336  return QString(i18nc("@title:column Title of a column of emails", "Email"));
337  default:
338  return QVariant();
339  }
340 }
341 
342 const QString &
343 KGpgSearchResultModel::idForIndex(const QModelIndex &index) const
344 {
345  Q_ASSERT(index.isValid());
346 
347  SearchResult *tmp = static_cast<SearchResult *>(index.internalPointer());
348  if (tmp == NULL)
349  tmp = d->m_items.at(index.row());
350 
351  return tmp->m_fingerprint;
352 }
353 
354 void
355 KGpgSearchResultModel::slotAddKey(QStringList lines)
356 {
357  Q_ASSERT(!lines.isEmpty());
358  Q_ASSERT(lines.first().startsWith(QLatin1String("pub:")));
359 
360  if (lines.count() == 1)
361  return;
362 
363  SearchResult *nkey = new SearchResult(lines.takeFirst());
364  if (!nkey->m_validPub) {
365  delete nkey;
366  return;
367  }
368 
369  foreach (const QString &line, lines) {
370  if (line.startsWith(QLatin1String("uid:"))) {
371  QString kid = d->urlDecode(line.section(QLatin1Char( ':' ), 1, 1));
372 
373  nkey->addUid(kid);
374  } else if (line.startsWith(QLatin1String("uat:"))) {
375  nkey->m_uatCount++;
376  } else {
377  kDebug(2100) << "ignored search result line" << line;
378  }
379  }
380 
381  if (nkey->getUidCount() > 0) {
382  beginInsertRows(QModelIndex(), d->m_items.count(), d->m_items.count());
383  d->m_items.append(nkey);
384  endInsertRows();
385  } else {
386  // key server sent back a crappy key
387  delete nkey;
388  }
389 }
390 
391 #include "kgpgsearchresultmodel.moc"
QModelIndex
QByteArray
QString::split
QStringList split(const QString &sep, SplitBehavior behavior, Qt::CaseSensitivity cs) const
QList::at
const T & at(int i) const
kgpgkey.h
KGpgSearchResultModel::rowCount
virtual int rowCount(const QModelIndex &parent=QModelIndex()) const
Definition: kgpgsearchresultmodel.cpp:304
KGpgSearchResultModel::slotAddKey
void slotAddKey(QStringList lines)
Definition: kgpgsearchresultmodel.cpp:355
QRegExp
QModelIndex::isValid
bool isValid() const
QList::count
int count(const T &value) const
QAbstractItemModel::endInsertRows
void endInsertRows()
KGpgSearchResultModel::~KGpgSearchResultModel
~KGpgSearchResultModel()
Definition: kgpgsearchresultmodel.cpp:180
QObject
QList::isEmpty
bool isEmpty() const
QModelIndex::row
int row() const
QString::startsWith
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const
KgpgCore::Convert::toString
QString toString(const KgpgKeyAlgo algorithm)
Definition: convert.cpp:35
QModelIndex::internalPointer
void * internalPointer() const
QList::first
T & first()
QString
QList< SearchResult * >
QStringList
QAbstractItemModel::createIndex
QModelIndex createIndex(int row, int column, void *ptr) const
kgpgsearchresultmodel.h
QString::contains
bool contains(QChar ch, Qt::CaseSensitivity cs) const
QLatin1Char
KGpgSearchResultModel::KGpgSearchResultModel
KGpgSearchResultModel(QObject *parent=NULL)
Definition: kgpgsearchresultmodel.cpp:175
QAbstractItemModel::beginInsertRows
void beginInsertRows(const QModelIndex &parent, int first, int last)
KGpgSearchResultModel::index
virtual QModelIndex index(int row, int column, const QModelIndex &parent=QModelIndex()) const
Definition: kgpgsearchresultmodel.cpp:261
KGpgSearchResultModel::columnCount
virtual int columnCount(const QModelIndex &parent=QModelIndex()) const
Definition: kgpgsearchresultmodel.cpp:243
QList::takeFirst
T takeFirst()
QLatin1String
KGpgSearchResultModel::headerData
QVariant headerData(int section, Qt::Orientation orientation, int role=Qt::DisplayRole) const
Definition: kgpgsearchresultmodel.cpp:324
KGpgSearchResultModel::idForIndex
const QString & idForIndex(const QModelIndex &index) const
get the key fingerprint for the given index
Definition: kgpgsearchresultmodel.cpp:343
QString::at
const QChar at(int position) const
QTextCodec::codecForName
QTextCodec * codecForName(const QByteArray &name)
QModelIndex::column
int column() const
KGpgSearchResultModel::data
virtual QVariant data(const QModelIndex &index, int role=Qt::DisplayRole) const
Definition: kgpgsearchresultmodel.cpp:186
QAbstractItemModel
QString::section
QString section(QChar sep, int start, int end, QFlags< QString::SectionFlag > flags) const
QObject::parent
QObject * parent() const
convert.h
KgpgCore::Convert::toAlgo
KgpgKeyAlgo toAlgo(const uint v)
Definition: convert.cpp:116
QTextCodec::toUnicode
QString toUnicode(const QByteArray &a) const
QString::toAscii
QByteArray toAscii() const
QVariant
QString::toUShort
ushort toUShort(bool *ok, int base) const
This file is part of the KDE documentation.
Documentation copyright © 1996-2020 The KDE developers.
Generated on Mon Jun 22 2020 13:42:08 by doxygen 1.8.7 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.

kgpg

Skip menu "kgpg"
  • Main Page
  • Namespace List
  • Namespace Members
  • Alphabetical List
  • Class List
  • Class Hierarchy
  • Class Members
  • File List
  • File Members
  • Related Pages

kdeutils API Reference

Skip menu "kdeutils API Reference"
  • ark
  • filelight
  • kcalc
  • kcharselect
  • kdf
  • kfloppy
  • kgpg
  • ktimer
  • kwallet
  • sweeper

Search



Report problems with this website to our bug tracking system.
Contact the specific authors with questions and comments about the page contents.

KDE® and the K Desktop Environment® logo are registered trademarks of KDE e.V. | Legal