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 <schumacher@kde.org>
5 SPDX-FileCopyrightText: 2003-2004 Reinhold Kainhofer <reinhold@kainhofer.com>
6 SPDX-FileCopyrightText: 2010 Casey Link <unnamedrambler@gmail.com>
7 SPDX-FileCopyrightText: 2009-2010 Klaralvdalens Datakonsult AB, a KDAB Group company <info@kdab.net>
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 <schumacher@kde.org>
20 @author Reinhold Kainhofer <reinhold@kainhofer.com>
21*/
22
23#include "person.h"
24#include "person_p.h"
25
26#include <QDataStream>
27#include <QRegularExpression>
28
29using namespace KCalendarCore;
30
31/**
32 Private class that helps to provide binary compatibility between releases.
33 @internal
34*/
35//@cond PRIVATE
36class Q_DECL_HIDDEN KCalendarCore::Person::Private : public QSharedData
37{
38public:
39 QString mName; // person name
40 QString mEmail; // person email address
41};
42//@endcond
43
45 : d(new KCalendarCore::Person::Private)
46{
47}
48
49Person::Person(const QString &name, const QString &email)
50 : d(new KCalendarCore::Person::Private)
51{
52 d->mName = name;
53 d->mEmail = email;
54}
55
56Person::Person(const Person &person)
57 : d(person.d)
58{
59}
60
61Person::~Person() = default;
62
64{
65 return d->mName == person.d->mName && d->mEmail == person.d->mEmail;
66}
67
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
84QString 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('"')) {
99 }
100 if (fullName[fullName.length() - 1] != QLatin1Char('"')) {
102 }
103 }
104 return fullName + QStringLiteral(" <") + email + QLatin1Char('>');
105}
106
107QString Person::fullName() const
108{
109 return fullNameHelper(d->mName, d->mEmail);
110}
111
112QString Person::name() const
113{
114 return d->mName;
115}
116
117QString Person::email() const
118{
119 return d->mEmail;
120}
121
122bool Person::isEmpty() const
123{
124 return d->mEmail.isEmpty() && d->mName.isEmpty();
125}
126
127void Person::setName(const QString &name)
128{
129 d->mName = name;
130}
131
132void 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
142{
143 const int pos = email.lastIndexOf(QLatin1Char('@'));
144 return (pos > 0) && (email.lastIndexOf(QLatin1Char('.')) > pos) && ((email.length() - pos) > 4);
145}
146
147size_t KCalendarCore::qHash(const KCalendarCore::Person &key, size_t seed)
148{
149 return qHash(key.fullName(), seed);
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.
167static 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;
178 int iAd = 0;
179 int iMailStart = 0;
180 int iMailEnd = 0;
181 QChar c;
182 unsigned int commentstack = 0;
183
184 // Find the '@' of the email address
185 // skipping all '@' inside "(...)" comments:
186 while (i < len) {
187 c = aStr[i];
188 if (QLatin1Char('(') == c) {
189 commentstack++;
190 }
191 if (QLatin1Char(')') == c) {
192 commentstack--;
193 }
194 bInComment = commentstack != 0;
195 if (QLatin1Char('"') == c && !bInComment) {
196 bInQuotesOutsideOfEmail = !bInQuotesOutsideOfEmail;
197 }
198
199 if (!bInComment && !bInQuotesOutsideOfEmail) {
200 if (QLatin1Char('@') == c) {
201 iAd = i;
202 break; // found it
203 }
204 }
205 ++i;
206 }
207
208 if (!iAd) {
209 // We suppose the user is typing the string manually and just
210 // has not finished typing the mail address part.
211 // So we take everything that's left of the '<' as name and the rest as mail
212 for (i = 0; len > i; ++i) {
213 c = aStr[i];
214 if (QLatin1Char('<') != c) {
215 name.append(c);
216 } else {
217 break;
218 }
219 }
220 mail = aStr.mid(i + 1);
221 if (mail.endsWith(QLatin1Char('>'))) {
222 mail.chop(1);
223 }
224
225 } else {
226 // Loop backwards until we find the start of the string
227 // or a ',' that is outside of a comment
228 // and outside of quoted text before the leading '<'.
229 bInComment = false;
230 bInQuotesOutsideOfEmail = false;
231 for (i = iAd - 1; 0 <= i; --i) {
232 c = aStr[i];
233 if (bInComment) {
234 if (QLatin1Char('(') == c) {
235 if (!name.isEmpty()) {
237 }
238 bInComment = false;
239 } else {
240 name.prepend(c); // all comment stuff is part of the name
241 }
242 } else if (bInQuotesOutsideOfEmail) {
243 if (QLatin1Char(cQuotes) == c) {
244 bInQuotesOutsideOfEmail = false;
245 } else if (c != QLatin1Char('\\')) {
246 name.prepend(c);
247 }
248 } else {
249 // found the start of this addressee ?
250 if (QLatin1Char(',') == c) {
251 break;
252 }
253 // stuff is before the leading '<' ?
254 if (iMailStart) {
255 if (QLatin1Char(cQuotes) == c) {
256 bInQuotesOutsideOfEmail = true; // end of quoted text found
257 } else {
258 name.prepend(c);
259 }
260 } else {
261 switch (c.toLatin1()) {
262 case '<':
263 iMailStart = i;
264 break;
265 case ')':
266 if (!name.isEmpty()) {
268 }
269 bInComment = true;
270 break;
271 default:
272 if (QLatin1Char(' ') != c) {
273 mail.prepend(c);
274 }
275 }
276 }
277 }
278 }
279
280 name = name.simplified();
281 mail = mail.simplified();
282
283 if (mail.isEmpty()) {
284 return false;
285 }
286
287 mail.append(QLatin1Char('@'));
288
289 // Loop forward until we find the end of the string
290 // or a ',' that is outside of a comment
291 // and outside of quoted text behind the trailing '>'.
292 bInComment = false;
293 bInQuotesOutsideOfEmail = false;
294 int parenthesesNesting = 0;
295 for (i = iAd + 1; len > i; ++i) {
296 c = aStr[i];
297 if (bInComment) {
298 if (QLatin1Char(')') == c) {
299 if (--parenthesesNesting == 0) {
300 bInComment = false;
301 if (!name.isEmpty()) {
302 name.append(QLatin1Char(' '));
303 }
304 } else {
305 // nested ")", add it
306 name.append(QLatin1Char(')')); // name can't be empty here
307 }
308 } else {
309 if (QLatin1Char('(') == c) {
310 // nested "("
311 ++parenthesesNesting;
312 }
313 name.append(c); // all comment stuff is part of the name
314 }
315 } else if (bInQuotesOutsideOfEmail) {
316 if (QLatin1Char(cQuotes) == c) {
317 bInQuotesOutsideOfEmail = false;
318 } else if (c != QLatin1Char('\\')) {
319 name.append(c);
320 }
321 } else {
322 // found the end of this addressee ?
323 if (QLatin1Char(',') == c) {
324 break;
325 }
326 // stuff is behind the trailing '>' ?
327 if (iMailEnd) {
328 if (QLatin1Char(cQuotes) == c) {
329 bInQuotesOutsideOfEmail = true; // start of quoted text found
330 } else {
331 name.append(c);
332 }
333 } else {
334 switch (c.toLatin1()) {
335 case '>':
336 iMailEnd = i;
337 break;
338 case '(':
339 if (!name.isEmpty()) {
340 name.append(QLatin1Char(' '));
341 }
342 if (++parenthesesNesting > 0) {
343 bInComment = true;
344 }
345 break;
346 default:
347 if (QLatin1Char(' ') != c) {
348 mail.append(c);
349 }
350 }
351 }
352 }
353 }
354 }
355
356 name = name.simplified();
357 mail = mail.simplified();
358
359 return !(name.isEmpty() || mail.isEmpty());
360}
361
363{
364 QString email;
365 QString name;
366 extractEmailAddressAndName(fullName, email, name);
367 return Person(name, email);
368}
369
370#include "moc_person.cpp"
Represents a person, by name and email address.
Definition person.h:38
Person()
Constructs a blank person.
Definition person.cpp:44
static bool isValidEmail(const QString &email)
Returns true if person's email address is valid.
Definition person.cpp:141
bool operator==(const Person &person) const
Compares this with person for equality.
Definition person.cpp:63
Person & operator=(const Person &person)
Sets this person equal to person.
Definition person.cpp:73
virtual ~Person()
Destroys a person.
void setEmail(const QString &email)
Sets the email address for this person to email.
Definition person.cpp:132
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
static Person fromFullName(const QString &fullName)
Constructs a person with name and email address taken from fullName.
Definition person.cpp:362
QString fullName(const PartType &type)
Namespace for all KCalendarCore types.
Definition alarm.h:37
KCALENDARCORE_EXPORT QDataStream & operator>>(QDataStream &in, const KCalendarCore::Alarm::Ptr &)
Alarm deserializer.
Definition alarm.cpp:833
KCALENDARCORE_EXPORT QDataStream & operator<<(QDataStream &out, const KCalendarCore::Alarm::Ptr &)
Alarm serializer.
Definition alarm.cpp:820
QAction * mail(const QObject *recvr, const char *slot, QObject *parent)
QString name(StandardShortcut id)
This file is part of the API for handling calendar data and defines the Person class.
char toLatin1() const const
QString & append(QChar ch)
void clear()
int indexOf(QChar ch, int from, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
int lastIndexOf(QChar ch, int from, Qt::CaseSensitivity cs) const const
int length() const const
QString mid(int position, int n) const const
QString & prepend(QChar ch)
QString simplified() const const
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const const
CaseInsensitive
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Sun Feb 25 2024 18:39:07 by doxygen 1.10.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.