KCalendarCore

person.cpp
Go to the documentation of this file.
1 /*
2  This file is part of the kcalcore library.
3 
4  SPDX-FileCopyrightText: 2001 Cornelius Schumacher <[email protected]>
5  SPDX-FileCopyrightText: 2003-2004 Reinhold Kainhofer <[email protected]>
6  SPDX-FileCopyrightText: 2010 Casey Link <[email protected]>
7  SPDX-FileCopyrightText: 2009-2010 Klaralvdalens Datakonsult AB, a KDAB Group company <[email protected]>
8 
9  SPDX-License-Identifier: LGPL-2.0-or-later
10 */
23 #include "person.h"
24 #include "person_p.h"
25 
26 #include <QDataStream>
27 #include <QRegularExpression>
28 
29 using namespace KCalendarCore;
30 
35 //@cond PRIVATE
36 class Q_DECL_HIDDEN KCalendarCore::Person::Private : public QSharedData
37 {
38 public:
39  QString mName; // person name
40  QString mEmail; // person email address
41 };
42 //@endcond
43 
44 Person::Person() : d(new KCalendarCore::Person::Private)
45 {
46 }
47 
49  : d(new KCalendarCore::Person::Private)
50 {
51  d->mName = name;
52  d->mEmail = email;
53 }
54 
55 Person::Person(const Person &person)
56  : d(person.d)
57 {
58 }
59 
60 Person::~Person() = default;
61 
62 bool KCalendarCore::Person::operator==(const Person &person) const
63 {
64  return
65  d->mName == person.d->mName &&
66  d->mEmail == person.d->mEmail;
67 }
68 
69 bool KCalendarCore::Person::operator!=(const Person &person) const
70 {
71  return !(*this == person);
72 }
73 
75 {
76  // check for self assignment
77  if (&person == this) {
78  return *this;
79  }
80 
81  d = person.d;
82  return *this;
83 }
84 
85 QString KCalendarCore::fullNameHelper(const QString &name, const QString &email)
86 {
87  if (name.isEmpty()) {
88  return email;
89  }
90  if (email.isEmpty()) {
91  return name;
92  }
93  // Taken from KContacts::Addressee::fullEmail
95  const QRegularExpression needQuotes(QStringLiteral("[^ 0-9A-Za-z\\x{0080}-\\x{FFFF}]"));
96  bool weNeedToQuote = name.indexOf(needQuotes) != -1;
97  if (weNeedToQuote) {
98  if (fullName[0] != QLatin1Char('"')) {
99  fullName.prepend(QLatin1Char('"'));
100  }
101  if (fullName[ fullName.length() - 1 ] != QLatin1Char('"')) {
102  fullName.append(QLatin1Char('"'));
103  }
104  }
105  return fullName + QStringLiteral(" <") + email + QLatin1Char('>');
106 }
107 
109 {
110  return fullNameHelper(d->mName, d->mEmail);
111 }
112 
113 QString Person::name() const
114 {
115  return d->mName;
116 }
117 
118 QString Person::email() const
119 {
120  return d->mEmail;
121 }
122 
123 bool Person::isEmpty() const
124 {
125  return d->mEmail.isEmpty() && d->mName.isEmpty();
126 }
127 
128 void Person::setName(const QString &name)
129 {
130  d->mName = name;
131 }
132 
133 void Person::setEmail(const QString &email)
134 {
135  if (email.startsWith(QLatin1String("mailto:"), Qt::CaseInsensitive)) {
136  d->mEmail = email.mid(7);
137  } else {
138  d->mEmail = email;
139  }
140 }
141 
142 bool Person::isValidEmail(const QString &email)
143 {
144  const int pos = email.lastIndexOf(QLatin1Char('@'));
145  return (pos > 0) && (email.lastIndexOf(QLatin1Char('.')) > pos) && ((email.length() - pos) > 4);
146 }
147 
149 {
150  return qHash(key.fullName());
151 }
152 
154 {
155  return stream
156  << person.d->mName
157  << person.d->mEmail
158  << (int)(0);
159 }
160 
162 {
163  int count;
164  stream >> person.d->mName >> person.d->mEmail >> count;
165  return stream;
166 }
167 
168 // The following function was lifted directly from KPIMUtils
169 // in order to eliminate the dependency on that library.
170 // Any changes made here should be ported there, and vice versa.
171 static bool extractEmailAddressAndName(const QString &aStr, QString &mail, QString &name)
172 {
173  name.clear();
174  mail.clear();
175 
176  const int len = aStr.length();
177  const char cQuotes = '"';
178 
179  bool bInComment = false;
180  bool bInQuotesOutsideOfEmail = false;
181  int i = 0, iAd = 0, iMailStart = 0, iMailEnd = 0;
182  QChar c;
183  unsigned int commentstack = 0;
184 
185  // Find the '@' of the email address
186  // skipping all '@' inside "(...)" comments:
187  while (i < len) {
188  c = aStr[i];
189  if (QLatin1Char('(') == c) {
190  commentstack++;
191  }
192  if (QLatin1Char(')') == c) {
193  commentstack--;
194  }
195  bInComment = commentstack != 0;
196  if (QLatin1Char('"') == c && !bInComment) {
197  bInQuotesOutsideOfEmail = !bInQuotesOutsideOfEmail;
198  }
199 
200  if (!bInComment && !bInQuotesOutsideOfEmail) {
201  if (QLatin1Char('@') == c) {
202  iAd = i;
203  break; // found it
204  }
205  }
206  ++i;
207  }
208 
209  if (!iAd) {
210  // We suppose the user is typing the string manually and just
211  // has not finished typing the mail address part.
212  // So we take everything that's left of the '<' as name and the rest as mail
213  for (i = 0; len > i; ++i) {
214  c = aStr[i];
215  if (QLatin1Char('<') != c) {
216  name.append(c);
217  } else {
218  break;
219  }
220  }
221  mail = aStr.mid(i + 1);
222  if (mail.endsWith(QLatin1Char('>'))) {
223  mail.chop(1);
224  }
225 
226  } else {
227  // Loop backwards until we find the start of the string
228  // or a ',' that is outside of a comment
229  // and outside of quoted text before the leading '<'.
230  bInComment = false;
231  bInQuotesOutsideOfEmail = false;
232  for (i = iAd - 1; 0 <= i; --i) {
233  c = aStr[i];
234  if (bInComment) {
235  if (QLatin1Char('(') == c) {
236  if (!name.isEmpty()) {
237  name.prepend(QLatin1Char(' '));
238  }
239  bInComment = false;
240  } else {
241  name.prepend(c); // all comment stuff is part of the name
242  }
243  } else if (bInQuotesOutsideOfEmail) {
244  if (QLatin1Char(cQuotes) == c) {
245  bInQuotesOutsideOfEmail = false;
246  } else if (c != QLatin1Char('\\')) {
247  name.prepend(c);
248  }
249  } else {
250  // found the start of this addressee ?
251  if (QLatin1Char(',') == c) {
252  break;
253  }
254  // stuff is before the leading '<' ?
255  if (iMailStart) {
256  if (QLatin1Char(cQuotes) == c) {
257  bInQuotesOutsideOfEmail = true; // end of quoted text found
258  } else {
259  name.prepend(c);
260  }
261  } else {
262  switch (c.toLatin1()) {
263  case '<':
264  iMailStart = i;
265  break;
266  case ')':
267  if (!name.isEmpty()) {
268  name.prepend(QLatin1Char(' '));
269  }
270  bInComment = true;
271  break;
272  default:
273  if (QLatin1Char(' ') != c) {
274  mail.prepend(c);
275  }
276  }
277  }
278  }
279  }
280 
281  name = name.simplified();
282  mail = mail.simplified();
283 
284  if (mail.isEmpty()) {
285  return false;
286  }
287 
288  mail.append(QLatin1Char('@'));
289 
290  // Loop forward until we find the end of the string
291  // or a ',' that is outside of a comment
292  // and outside of quoted text behind the trailing '>'.
293  bInComment = false;
294  bInQuotesOutsideOfEmail = false;
295  int parenthesesNesting = 0;
296  for (i = iAd + 1; len > i; ++i) {
297  c = aStr[i];
298  if (bInComment) {
299  if (QLatin1Char(')') == c) {
300  if (--parenthesesNesting == 0) {
301  bInComment = false;
302  if (!name.isEmpty()) {
303  name.append(QLatin1Char(' '));
304  }
305  } else {
306  // nested ")", add it
307  name.append(QLatin1Char(')')); // name can't be empty here
308  }
309  } else {
310  if (QLatin1Char('(') == c) {
311  // nested "("
312  ++parenthesesNesting;
313  }
314  name.append(c); // all comment stuff is part of the name
315  }
316  } else if (bInQuotesOutsideOfEmail) {
317  if (QLatin1Char(cQuotes) == c) {
318  bInQuotesOutsideOfEmail = false;
319  } else if (c != QLatin1Char('\\')) {
320  name.append(c);
321  }
322  } else {
323  // found the end of this addressee ?
324  if (QLatin1Char(',') == c) {
325  break;
326  }
327  // stuff is behind the trailing '>' ?
328  if (iMailEnd) {
329  if (QLatin1Char(cQuotes) == c) {
330  bInQuotesOutsideOfEmail = true; // start of quoted text found
331  } else {
332  name.append(c);
333  }
334  } else {
335  switch (c.toLatin1()) {
336  case '>':
337  iMailEnd = i;
338  break;
339  case '(':
340  if (!name.isEmpty()) {
341  name.append(QLatin1Char(' '));
342  }
343  if (++parenthesesNesting > 0) {
344  bInComment = true;
345  }
346  break;
347  default:
348  if (QLatin1Char(' ') != c) {
349  mail.append(c);
350  }
351  }
352  }
353  }
354  }
355  }
356 
357  name = name.simplified();
358  mail = mail.simplified();
359 
360  return !(name.isEmpty() || mail.isEmpty());
361 }
362 
364 {
365  QString email, name;
366  extractEmailAddressAndName(fullName, email, name);
367  return Person(name, email);
368 }
KCALENDARCORE_EXPORT QDataStream & operator<<(QDataStream &out, const KCalendarCore::Alarm::Ptr &)
Alarm serializer.
Definition: alarm.cpp:825
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const const
bool operator==(const Person &person) const
Compares this with person for equality.
Definition: person.cpp:62
QString & append(QChar ch)
static bool isValidEmail(const QString &email)
Returns true if person&#39;s email address is valid.
Definition: person.cpp:142
Represents a person, by name and email address.
Definition: person.h:38
QString & prepend(QChar ch)
KCALENDARCORE_EXPORT QDataStream & operator>>(QDataStream &in, const KCalendarCore::Alarm::Ptr &)
Alarm deserializer.
Definition: alarm.cpp:849
QString simplified() const const
bool isEmpty() const
Returns true if the person name and email address are empty.
static Person fromFullName(const QString &fullName)
Constructs a person with name and email address taken from fullName.
Definition: person.cpp:363
void setEmail(const QString &email)
Sets the email address for this person to email.
Definition: person.cpp:133
void chop(int n)
int lastIndexOf(QChar ch, int from, Qt::CaseSensitivity cs) const const
QString name() const
Returns the person name string.
void clear()
Person & operator=(const Person &person)
Sets this person equal to person.
Definition: person.cpp:74
This file is part of the API for handling calendar data and defines the Person class.
KCODECS_EXPORT bool extractEmailAddressAndName(const QString &aStr, QString &mail, QString &name)
CaseInsensitive
bool isEmpty() const const
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const const
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const const
QString email() const
Returns the email address for this person.
char toLatin1() const const
QString mid(int position, int n) const const
int length() const const
virtual ~Person()
Destroys a person.
Person()
Constructs a blank person.
Definition: person.cpp:44
bool operator!=(const Person &person) const
Compares this with person for non-equality.
Definition: person.cpp:69
void setName(const QString &name)
Sets the name of the person to name.
Definition: person.cpp:128
KCALENDARCORE_EXPORT uint qHash(const KCalendarCore::Person &key)
Return a hash value for a Person argument.
Definition: person.cpp:148
Namespace for all KCalendarCore types.
Definition: alarm.h:36
QString fullName() const
Returns the full name of this person.
This file is part of the KDE documentation.
Documentation copyright © 1996-2021 The KDE developers.
Generated on Tue Jan 26 2021 22:51:02 by doxygen 1.8.11 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.