1/*
2 This file is part of the KContacts framework.
3 SPDX-FileCopyrightText: 2008 Tobias Koenig <tokoe@kde.org>
4 SPDX-FileCopyrightText: 2008 Kevin Krammer <kevin.krammer@gmx.at>
5
6 SPDX-License-Identifier: LGPL-2.0-or-later
7*/
8
9#include "contactgrouptool.h"
10#include "contactgroup.h"
11
12#include <QIODevice>
13
14#include <QXmlStreamReader>
15#include <QXmlStreamWriter>
16
17using namespace KContacts;
18
19class XmlContactGroupWriter : public QXmlStreamWriter
20{
21public:
22 XmlContactGroupWriter();
23
24 void write(const ContactGroup &group, QIODevice *device);
25 void write(const QList<ContactGroup> &groupLis, QIODevice *device);
26
27private:
28 void writeGroup(const ContactGroup &group);
29 void writeContactReference(const ContactGroup::ContactReference &reference);
30 void writeContactGroupReference(const ContactGroup::ContactGroupReference &reference);
31 void writeData(const ContactGroup::Data &data);
32};
33
34XmlContactGroupWriter::XmlContactGroupWriter()
35{
36 setAutoFormatting(true);
37}
38
39void XmlContactGroupWriter::write(const ContactGroup &group, QIODevice *device)
40{
41 setDevice(device);
42
43 writeStartDocument();
44
45 writeGroup(group);
46
47 writeEndDocument();
48}
49
50void XmlContactGroupWriter::write(const QList<ContactGroup> &groupList, QIODevice *device)
51{
52 setDevice(device);
53
54 writeStartDocument();
55
56 writeStartElement(QStringLiteral("contactGroupList"));
57
58 for (const ContactGroup &group : groupList) {
59 writeGroup(group);
60 }
61
62 writeEndElement();
63
64 writeEndDocument();
65}
66
67void XmlContactGroupWriter::writeGroup(const ContactGroup &group)
68{
69 writeStartElement(QStringLiteral("contactGroup"));
70 writeAttribute(QStringLiteral("uid"), value: group.id());
71 writeAttribute(QStringLiteral("name"), value: group.name());
72
73 const uint contactCount(group.contactReferenceCount());
74 for (uint i = 0; i < contactCount; ++i) {
75 writeContactReference(reference: group.contactReference(index: i));
76 }
77
78 const uint contactGroupReference(group.contactGroupReferenceCount());
79 for (uint i = 0; i < contactGroupReference; ++i) {
80 writeContactGroupReference(reference: group.contactGroupReference(index: i));
81 }
82
83 const uint dataCount(group.dataCount());
84 for (uint i = 0; i < dataCount; ++i) {
85 writeData(data: group.data(index: i));
86 }
87
88 writeEndElement();
89}
90
91void XmlContactGroupWriter::writeContactReference(const ContactGroup::ContactReference &reference)
92{
93 writeStartElement(QStringLiteral("contactReference"));
94 writeAttribute(QStringLiteral("uid"), value: reference.uid());
95 writeAttribute(QStringLiteral("gid"), value: reference.gid());
96 if (!reference.preferredEmail().isEmpty()) {
97 writeAttribute(QStringLiteral("preferredEmail"), value: reference.preferredEmail());
98 }
99
100 // TODO: customs
101
102 writeEndElement();
103}
104
105void XmlContactGroupWriter::writeContactGroupReference(const ContactGroup::ContactGroupReference &reference)
106{
107 writeStartElement(QStringLiteral("contactGroupReference"));
108 writeAttribute(QStringLiteral("uid"), value: reference.uid());
109
110 // TODO: customs
111
112 writeEndElement();
113}
114
115void XmlContactGroupWriter::writeData(const ContactGroup::Data &data)
116{
117 writeStartElement(QStringLiteral("contactData"));
118 writeAttribute(QStringLiteral("name"), value: data.name());
119 writeAttribute(QStringLiteral("email"), value: data.email());
120
121 // TODO: customs
122
123 writeEndElement();
124}
125
126class XmlContactGroupReader : public QXmlStreamReader
127{
128public:
129 XmlContactGroupReader();
130
131 bool read(QIODevice *device, ContactGroup &group);
132 bool read(QIODevice *device, QList<ContactGroup> &groupList);
133
134private:
135 bool readGroup(ContactGroup &group);
136 bool readContactReference(ContactGroup::ContactReference &reference);
137 bool readContactGroupReference(ContactGroup::ContactGroupReference &reference);
138 bool readData(ContactGroup::Data &data);
139};
140
141XmlContactGroupReader::XmlContactGroupReader()
142{
143}
144
145bool XmlContactGroupReader::read(QIODevice *device, ContactGroup &group)
146{
147 setDevice(device);
148
149 while (!atEnd()) {
150 readNext();
151 if (isStartElement()) {
152 if (name() == QLatin1String("contactGroup")) {
153 return readGroup(group);
154 } else {
155 raiseError(QStringLiteral("The document does not describe a ContactGroup"));
156 }
157 }
158 }
159
160 return error() == NoError;
161}
162
163bool XmlContactGroupReader::read(QIODevice *device, QList<ContactGroup> &groupList)
164{
165 setDevice(device);
166
167 int depth = 0;
168
169 while (!atEnd()) {
170 readNext();
171 if (isStartElement()) {
172 ++depth;
173 if (depth == 1) {
174 if (name() == QLatin1String("contactGroupList")) {
175 continue;
176 } else {
177 raiseError(QStringLiteral("The document does not describe a list of ContactGroup"));
178 }
179 } else if (depth == 2) {
180 if (name() == QLatin1String("contactGroup")) {
181 ContactGroup group;
182 if (!readGroup(group)) {
183 return false;
184 }
185
186 groupList.append(t: group);
187 } else {
188 raiseError(QStringLiteral("The document does not describe a list of ContactGroup"));
189 }
190 }
191 }
192
193 if (isEndElement()) {
194 --depth;
195 }
196 }
197
198 return error() == NoError;
199}
200
201bool XmlContactGroupReader::readGroup(ContactGroup &group)
202{
203 const QXmlStreamAttributes elementAttributes = attributes();
204 const auto uid = elementAttributes.value(qualifiedName: QLatin1String("uid"));
205 if (uid.isEmpty()) {
206 raiseError(QStringLiteral("ContactGroup is missing a uid"));
207 return false;
208 }
209
210 const auto groupName = elementAttributes.value(qualifiedName: QLatin1String("name"));
211 if (groupName.isEmpty()) {
212 raiseError(QStringLiteral("ContactGroup is missing a name"));
213 return false;
214 }
215
216 group.setId(uid.toString());
217 group.setName(groupName.toString());
218
219 while (!atEnd()) {
220 readNext();
221 if (isStartElement()) {
222 if (name() == QLatin1String("contactData")) {
223 ContactGroup::Data data;
224 if (!readData(data)) {
225 return false;
226 }
227 group.append(data);
228 } else if (name() == QLatin1String("contactReference")) {
229 ContactGroup::ContactReference reference;
230 if (!readContactReference(reference)) {
231 return false;
232 }
233 group.append(reference);
234 } else if (name() == QLatin1String("contactGroupReference")) {
235 ContactGroup::ContactGroupReference reference;
236 if (!readContactGroupReference(reference)) {
237 return false;
238 }
239 group.append(reference);
240 } else {
241 raiseError(QStringLiteral("The document does not describe a ContactGroup"));
242 }
243 }
244
245 if (isEndElement()) {
246 if (name() == QLatin1String("contactGroup")) {
247 return true;
248 }
249 }
250 }
251
252 return false;
253}
254
255bool XmlContactGroupReader::readData(ContactGroup::Data &data)
256{
257 const QXmlStreamAttributes elementAttributes = attributes();
258 const auto email = elementAttributes.value(qualifiedName: QLatin1String("email"));
259 if (email.isEmpty()) {
260 raiseError(QStringLiteral("ContactData is missing an email address"));
261 return false;
262 }
263
264 const auto name = elementAttributes.value(qualifiedName: QLatin1String("name"));
265
266 data.setName(name.toString());
267 data.setEmail(email.toString());
268
269 return true;
270}
271
272bool XmlContactGroupReader::readContactReference(ContactGroup::ContactReference &reference)
273{
274 const QXmlStreamAttributes elementAttributes = attributes();
275 const auto uid = elementAttributes.value(qualifiedName: QLatin1String("uid"));
276 const auto gid = elementAttributes.value(qualifiedName: QLatin1String("gid"));
277 if (uid.isEmpty() && gid.isEmpty()) {
278 raiseError(QStringLiteral("ContactReference is missing both uid and gid"));
279 return false;
280 }
281 const auto preferredEmail = elementAttributes.value(qualifiedName: QLatin1String("preferredEmail"));
282
283 reference.setUid(uid.toString());
284 reference.setGid(gid.toString());
285 reference.setPreferredEmail(preferredEmail.toString());
286
287 return true;
288}
289
290bool XmlContactGroupReader::readContactGroupReference(ContactGroup::ContactGroupReference &reference)
291{
292 const QXmlStreamAttributes elementAttributes = attributes();
293 const auto uid = elementAttributes.value(qualifiedName: QLatin1String("uid"));
294 if (uid.isEmpty()) {
295 raiseError(QStringLiteral("ContactGroupReference is missing a uid"));
296 return false;
297 }
298
299 reference.setUid(uid.toString());
300
301 return true;
302}
303
304bool ContactGroupTool::convertFromXml(QIODevice *device, ContactGroup &group, QString *errorMessage)
305{
306 Q_UNUSED(errorMessage);
307
308 XmlContactGroupReader reader;
309
310 bool ok = reader.read(device, group);
311
312 if (!ok && errorMessage != nullptr) {
313 *errorMessage = reader.errorString();
314 }
315
316 return ok;
317}
318
319bool ContactGroupTool::convertToXml(const ContactGroup &group, QIODevice *device, QString *errorMessage)
320{
321 Q_UNUSED(errorMessage);
322
323 XmlContactGroupWriter writer;
324 writer.write(group, device);
325
326 return true;
327}
328
329bool ContactGroupTool::convertFromXml(QIODevice *device, QList<ContactGroup> &groupList, QString *errorMessage)
330{
331 Q_UNUSED(errorMessage);
332
333 XmlContactGroupReader reader;
334
335 bool ok = reader.read(device, groupList);
336
337 if (!ok && errorMessage != nullptr) {
338 *errorMessage = reader.errorString();
339 }
340
341 return ok;
342}
343
344bool ContactGroupTool::convertToXml(const QList<ContactGroup> &groupList, QIODevice *device, QString *errorMessage)
345{
346 Q_UNUSED(errorMessage);
347
348 XmlContactGroupWriter writer;
349 writer.write(groupList, device);
350
351 return true;
352}
353

source code of kcontacts/src/contactgrouptool.cpp