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

KDE's Doxygen guidelines are available online.