formatter.cpp 20.4 KB
Newer Older
1
/*
2
3
4
5
6
    SPDX-FileCopyrightText: 2001 Cornelius Schumacher <schumacher@kde.org>
    SPDX-FileCopyrightText: 2004 Reinhold Kainhofer <reinhold@kainhofer.com>
    SPDX-FileCopyrightText: 2005 Rafal Rzepecki <divide@users.sourceforge.net>

    SPDX-License-Identifier: LGPL-2.0-or-later
7
*/
8
9
/**
  @file
Allen Winter's avatar
Allen Winter committed
10
11
12
13
14
15
  This file is part of the API for handling TNEF data and provides
  static Formatter helpers.

  @brief
  Provides helpers too format @acronym TNEF attachments into different
  formats like eg. a HTML representation.
16
17
18
19
20

  @author Cornelius Schumacher
  @author Reinhold Kainhofer
  @author Rafal Rzepecki
*/
21

Allen Winter's avatar
Allen Winter committed
22
23
#include "formatter.h"
#include "ktnefdefs.h"
Laurent Montel's avatar
Laurent Montel committed
24
25
#include "ktnefmessage.h"
#include "ktnefparser.h"
Allen Winter's avatar
Allen Winter committed
26

Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
27
28
#include <kcontacts/phonenumber.h>
#include <kcontacts/vcardconverter.h>
29

Laurent Montel's avatar
Laurent Montel committed
30
#include <KCalUtils/IncidenceFormatter>
31
32
#include <KCalendarCore/Calendar>
#include <KCalendarCore/ICalFormat>
33

34
#include <KLocalizedString>
35

Laurent Montel's avatar
Laurent Montel committed
36
#include <QBuffer>
37
#include <QTimeZone>
38

Allen Winter's avatar
Allen Winter committed
39
#include <time.h>
40

41
using namespace KCalendarCore;
42
43
44
45
46
47
48
using namespace KTnef;

/*******************************************************************
 *  Helper functions for the msTNEF -> VPart converter
 *******************************************************************/

//-----------------------------------------------------------------------------
49
//@cond IGNORE
Laurent Montel's avatar
Laurent Montel committed
50
static QString stringProp(KTNEFMessage *tnefMsg, quint32 key, const QString &fallback = QString())
51
{
Laurent Montel's avatar
Laurent Montel committed
52
    return tnefMsg->findProp(key < 0x10000 ? key & 0xFFFF : key >> 16, fallback);
53
54
}

Laurent Montel's avatar
Laurent Montel committed
55
static QString sNamedProp(KTNEFMessage *tnefMsg, const QString &name, const QString &fallback = QString())
56
{
Laurent Montel's avatar
Laurent Montel committed
57
    return tnefMsg->findNamedProp(name, fallback);
58
59
}

60
static QDateTime pureISOToLocalQDateTime(const QString &dtStr)
61
{
Laurent Montel's avatar
Laurent Montel committed
62
63
64
65
66
67
68
    const QStringView dtView{dtStr};
    const int year = dtView.left(4).toInt();
    const int month = dtView.mid(4, 2).toInt();
    const int day = dtView.mid(6, 2).toInt();
    const int hour = dtView.mid(9, 2).toInt();
    const int minute = dtView.mid(11, 2).toInt();
    const int second = dtView.mid(13, 2).toInt();
Laurent Montel's avatar
Indent    
Laurent Montel committed
69
    QDate tmpDate;
70
    tmpDate.setDate(year, month, day);
Laurent Montel's avatar
Laurent Montel committed
71
    QTime tmpTime;
Laurent Montel's avatar
Laurent Montel committed
72
    tmpTime.setHMS(hour, minute, second);
Laurent Montel's avatar
Indent    
Laurent Montel committed
73

Laurent Montel's avatar
Laurent Montel committed
74
    if (tmpDate.isValid() && tmpTime.isValid()) {
75
        QDateTime dT = QDateTime(tmpDate, tmpTime);
Laurent Montel's avatar
Indent    
Laurent Montel committed
76

77
78
        // correct for GMT ( == Zulu time == UTC )
        if (dtStr.at(dtStr.length() - 1) == QLatin1Char('Z')) {
Laurent Montel's avatar
Laurent Montel committed
79
80
            // dT = dT.addSecs( 60 * KRFCDate::localUTCOffset() );
            // localUTCOffset( dT ) );
81
            dT = dT.toLocalTime();
Laurent Montel's avatar
Indent    
Laurent Montel committed
82
83
84
        }
        return dT;
    } else {
85
        return QDateTime();
86
87
    }
}
88
//@endcond
89

Laurent Montel's avatar
Laurent Montel committed
90
QString KTnef::msTNEFToVPart(const QByteArray &tnef)
91
{
Laurent Montel's avatar
Indent    
Laurent Montel committed
92
    KTNEFParser parser;
Laurent Montel's avatar
Laurent Montel committed
93
94
    QByteArray b(tnef);
    QBuffer buf(&b);
95
    MemoryCalendar::Ptr cal(new MemoryCalendar(QTimeZone::utc()));
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
96
    KContacts::Addressee addressee;
Laurent Montel's avatar
Indent    
Laurent Montel committed
97
    ICalFormat calFormat;
Laurent Montel's avatar
Laurent Montel committed
98
    Event::Ptr event(new Event());
Laurent Montel's avatar
Indent    
Laurent Montel committed
99

Laurent Montel's avatar
Laurent Montel committed
100
    if (parser.openDevice(&buf)) {
Laurent Montel's avatar
Indent    
Laurent Montel committed
101
        KTNEFMessage *tnefMsg = parser.message();
Laurent Montel's avatar
Laurent Montel committed
102
        // QMap<int,KTNEFProperty*> props = parser.message()->properties();
Laurent Montel's avatar
Indent    
Laurent Montel committed
103
104
105

        // Everything depends from property PR_MESSAGE_CLASS
        // (this is added by KTNEFParser):
Laurent Montel's avatar
Laurent Montel committed
106
107
        QString msgClass = tnefMsg->findProp(0x001A, QString(), true).toUpper();
        if (!msgClass.isEmpty()) {
Laurent Montel's avatar
Indent    
Laurent Montel committed
108
109
110
111
112
113
114
115
            // Match the old class names that might be used by Outlook for
            // compatibility with Microsoft Mail for Windows for Workgroups 3.1.
            bool bCompatClassAppointment = false;
            bool bCompatMethodRequest = false;
            bool bCompatMethodCancled = false;
            bool bCompatMethodAccepted = false;
            bool bCompatMethodAcceptedCond = false;
            bool bCompatMethodDeclined = false;
Laurent Montel's avatar
Laurent Montel committed
116
            if (msgClass.startsWith(QLatin1String("IPM.MICROSOFT SCHEDULE."))) {
Laurent Montel's avatar
Indent    
Laurent Montel committed
117
                bCompatClassAppointment = true;
Laurent Montel's avatar
Laurent Montel committed
118
                if (msgClass.endsWith(QLatin1String(".MTGREQ"))) {
Laurent Montel's avatar
Indent    
Laurent Montel committed
119
                    bCompatMethodRequest = true;
Laurent Montel's avatar
Laurent Montel committed
120
                } else if (msgClass.endsWith(QLatin1String(".MTGCNCL"))) {
Laurent Montel's avatar
Indent    
Laurent Montel committed
121
                    bCompatMethodCancled = true;
Laurent Montel's avatar
Laurent Montel committed
122
                } else if (msgClass.endsWith(QLatin1String(".MTGRESPP"))) {
Laurent Montel's avatar
Indent    
Laurent Montel committed
123
                    bCompatMethodAccepted = true;
Laurent Montel's avatar
Laurent Montel committed
124
                } else if (msgClass.endsWith(QLatin1String(".MTGRESPA"))) {
Laurent Montel's avatar
Indent    
Laurent Montel committed
125
                    bCompatMethodAcceptedCond = true;
Laurent Montel's avatar
Laurent Montel committed
126
                } else if (msgClass.endsWith(QLatin1String(".MTGRESPN"))) {
Laurent Montel's avatar
Indent    
Laurent Montel committed
127
128
129
                    bCompatMethodDeclined = true;
                }
            }
Laurent Montel's avatar
Laurent Montel committed
130
            bool bCompatClassNote = (msgClass == QLatin1String("IPM.MICROSOFT MAIL.NOTE"));
Laurent Montel's avatar
Indent    
Laurent Montel committed
131

Laurent Montel's avatar
Laurent Montel committed
132
            if (bCompatClassAppointment || QLatin1String("IPM.APPOINTMENT") == msgClass) {
Laurent Montel's avatar
Indent    
Laurent Montel committed
133
134
                // Compose a vCal
                bool bIsReply = false;
135
136
                QString prodID = QStringLiteral("-//Microsoft Corporation//Outlook ");
                prodID += tnefMsg->findNamedProp(QStringLiteral("0x8554"), QStringLiteral("9.0"));
Laurent Montel's avatar
Indent    
Laurent Montel committed
137
138
                prodID += QLatin1String("MIMEDIR/EN\n");
                prodID += QLatin1String("VERSION:2.0\n");
139
                calFormat.setApplication(QStringLiteral("Outlook"), prodID);
Laurent Montel's avatar
Indent    
Laurent Montel committed
140

Laurent Montel's avatar
Laurent Montel committed
141
                // iTIPMethod method;
Laurent Montel's avatar
Laurent Montel committed
142
                if (bCompatMethodRequest) {
Laurent Montel's avatar
Laurent Montel committed
143
                    // method = iTIPRequest;
Laurent Montel's avatar
Laurent Montel committed
144
                } else if (bCompatMethodCancled) {
Laurent Montel's avatar
Laurent Montel committed
145
146
147
                    // method = iTIPCancel;
                } else if (bCompatMethodAccepted || bCompatMethodAcceptedCond || bCompatMethodDeclined) {
                    // method = iTIPReply;
Laurent Montel's avatar
Indent    
Laurent Montel committed
148
149
150
151
152
153
154
155
156
157
                    bIsReply = true;
                } else {
                    // pending(khz): verify whether "0x0c17" is the right tag ???
                    //
                    // at the moment we think there are REQUESTS and UPDATES
                    //
                    // but WHAT ABOUT REPLIES ???
                    //
                    //

158
                    if (tnefMsg->findProp(0x0c17) == QLatin1Char('1')) {
Laurent Montel's avatar
Indent    
Laurent Montel committed
159
160
                        bIsReply = true;
                    }
Laurent Montel's avatar
Laurent Montel committed
161
                    // method = iTIPRequest;
Laurent Montel's avatar
Indent    
Laurent Montel committed
162
                }
163

Laurent Montel's avatar
Indent    
Laurent Montel committed
164
                /// ###  FIXME Need to get this attribute written
Laurent Montel's avatar
Laurent Montel committed
165
                // ScheduleMessage schedMsg( event, method, ScheduleMessage::Unknown );
166

Laurent Montel's avatar
Laurent Montel committed
167
                QString sSenderSearchKeyEmail(tnefMsg->findProp(0x0C1D));
168
169
170
                if (sSenderSearchKeyEmail.isEmpty()) {
                    sSenderSearchKeyEmail = tnefMsg->findProp(0x0C1f);
                }
171

Laurent Montel's avatar
Laurent Montel committed
172
                if (!sSenderSearchKeyEmail.isEmpty()) {
Laurent Montel's avatar
Laurent Montel committed
173
                    const int colon = sSenderSearchKeyEmail.indexOf(QLatin1Char(':'));
Laurent Montel's avatar
Indent    
Laurent Montel committed
174
                    // May be e.g. "SMTP:KHZ@KDE.ORG"
Laurent Montel's avatar
Laurent Montel committed
175
                    if (colon == -1) {
Laurent Montel's avatar
Laurent Montel committed
176
                        sSenderSearchKeyEmail.remove(0, colon + 1);
Laurent Montel's avatar
Indent    
Laurent Montel committed
177
178
                    }
                }
179

Laurent Montel's avatar
Laurent Montel committed
180
181
                QString s(tnefMsg->findProp(0x8189));
                const QStringList attendees = s.split(QLatin1Char(';'));
Sergio Martins's avatar
Sergio Martins committed
182
183
                if (!attendees.isEmpty()) {
                    for (auto it = attendees.cbegin(), end = attendees.cend(); it != end; ++it) {
Laurent Montel's avatar
Indent    
Laurent Montel committed
184
185
                        // Skip all entries that have no '@' since these are
                        // no mail addresses
Laurent Montel's avatar
Laurent Montel committed
186
                        if (!(*it).contains(QLatin1Char('@'))) {
Laurent Montel's avatar
Indent    
Laurent Montel committed
187
188
                            s = (*it).trimmed();

189
                            Attendee attendee(s, s, true);
Laurent Montel's avatar
Laurent Montel committed
190
191
                            if (bIsReply) {
                                if (bCompatMethodAccepted) {
192
                                    attendee.setStatus(Attendee::Accepted);
Laurent Montel's avatar
Indent    
Laurent Montel committed
193
                                }
Laurent Montel's avatar
Laurent Montel committed
194
                                if (bCompatMethodDeclined) {
195
                                    attendee.setStatus(Attendee::Declined);
Laurent Montel's avatar
Indent    
Laurent Montel committed
196
                                }
Laurent Montel's avatar
Laurent Montel committed
197
                                if (bCompatMethodAcceptedCond) {
198
                                    attendee.setStatus(Attendee::Tentative);
Laurent Montel's avatar
Indent    
Laurent Montel committed
199
200
                                }
                            } else {
201
202
                                attendee.setStatus(Attendee::NeedsAction);
                                attendee.setRole(Attendee::ReqParticipant);
Laurent Montel's avatar
Indent    
Laurent Montel committed
203
                            }
Laurent Montel's avatar
Laurent Montel committed
204
                            event->addAttendee(attendee);
Laurent Montel's avatar
Indent    
Laurent Montel committed
205
206
207
208
209
210
                        }
                    }
                } else {
                    // Oops, no attendees?
                    // This must be old style, let us use the PR_SENDER_SEARCH_KEY.
                    s = sSenderSearchKeyEmail;
Laurent Montel's avatar
Laurent Montel committed
211
                    if (!s.isEmpty()) {
212
                        Attendee attendee(QString(), QString(), true);
Laurent Montel's avatar
Laurent Montel committed
213
214
                        if (bIsReply) {
                            if (bCompatMethodAccepted) {
215
                                attendee.setStatus(Attendee::Accepted);
Laurent Montel's avatar
Indent    
Laurent Montel committed
216
                            }
Laurent Montel's avatar
Laurent Montel committed
217
                            if (bCompatMethodAcceptedCond) {
218
                                attendee.setStatus(Attendee::Declined);
Laurent Montel's avatar
Indent    
Laurent Montel committed
219
                            }
Laurent Montel's avatar
Laurent Montel committed
220
                            if (bCompatMethodDeclined) {
221
                                attendee.setStatus(Attendee::Tentative);
Laurent Montel's avatar
Indent    
Laurent Montel committed
222
223
                            }
                        } else {
224
225
                            attendee.setStatus(Attendee::NeedsAction);
                            attendee.setRole(Attendee::ReqParticipant);
Laurent Montel's avatar
Indent    
Laurent Montel committed
226
                        }
Laurent Montel's avatar
Laurent Montel committed
227
                        event->addAttendee(attendee);
Laurent Montel's avatar
Indent    
Laurent Montel committed
228
                    }
Allen Winter's avatar
Allen Winter committed
229
                }
Laurent Montel's avatar
Laurent Montel committed
230
                s = tnefMsg->findProp(0x3ff8); // look for organizer property
Laurent Montel's avatar
Laurent Montel committed
231
                if (s.isEmpty() && !bIsReply) {
Laurent Montel's avatar
Indent    
Laurent Montel committed
232
                    s = sSenderSearchKeyEmail;
Allen Winter's avatar
Allen Winter committed
233
                }
Laurent Montel's avatar
Indent    
Laurent Montel committed
234
                // TODO: Use the common name?
Laurent Montel's avatar
Laurent Montel committed
235
236
                if (!s.isEmpty()) {
                    event->setOrganizer(s);
Allen Winter's avatar
Allen Winter committed
237
                }
238

239
240
241
242
                QDateTime dt = tnefMsg->property(0x819b).toDateTime();
                if (!dt.isValid()) {
                    dt = tnefMsg->property(0x0060).toDateTime();
                }
Laurent Montel's avatar
Laurent Montel committed
243
                event->setDtStart(dt); // ## Format??
Laurent Montel's avatar
Indent    
Laurent Montel committed
244

245
                dt = tnefMsg->property(0x819c).toDateTime();
Laurent Montel's avatar
Laurent Montel committed
246
                if (!dt.isValid()) {
247
248
249
                    dt = tnefMsg->property(0x0061).toDateTime();
                }
                event->setDtEnd(dt);
Laurent Montel's avatar
Indent    
Laurent Montel committed
250

Laurent Montel's avatar
Laurent Montel committed
251
252
                s = tnefMsg->findProp(0x810d);
                event->setLocation(s);
Laurent Montel's avatar
Indent    
Laurent Montel committed
253
                // is it OK to set this to OPAQUE always ??
Laurent Montel's avatar
Laurent Montel committed
254
255
                // vPart += "TRANSP:OPAQUE\n"; ###FIXME, portme!
                // vPart += "SEQUENCE:0\n";
Laurent Montel's avatar
Indent    
Laurent Montel committed
256
257

                // is "0x0023" OK  -  or should we look for "0x0003" ??
258
                s = tnefMsg->findProp(0x0062);
Laurent Montel's avatar
Laurent Montel committed
259
                event->setUid(s);
Laurent Montel's avatar
Indent    
Laurent Montel committed
260
261
262
263

                // PENDING(khz): is this value in local timezone? Must it be
                // adjusted? Most likely this is a bug in the server or in
                // Outlook - we ignore it for now.
Laurent Montel's avatar
Laurent Montel committed
264
                s = tnefMsg->findProp(0x8202).remove(QLatin1Char('-')).remove(QLatin1Char(':'));
Laurent Montel's avatar
Indent    
Laurent Montel committed
265
266
267
                // ### kcal always uses currentDateTime()
                // event->setDtStamp( QDateTime::fromString( s ) );

268
                s = tnefMsg->findNamedProp(QStringLiteral("Keywords"));
Laurent Montel's avatar
Laurent Montel committed
269
                event->setCategories(s);
Laurent Montel's avatar
Indent    
Laurent Montel committed
270

Laurent Montel's avatar
Laurent Montel committed
271
                s = tnefMsg->findProp(0x1000);
272
273
274
                if (s.isEmpty()) {
                    s = tnefMsg->findProp(0x3fd9);
                }
Laurent Montel's avatar
Laurent Montel committed
275
                event->setDescription(s);
Laurent Montel's avatar
Indent    
Laurent Montel committed
276

Laurent Montel's avatar
Laurent Montel committed
277
                s = tnefMsg->findProp(0x0070);
278
279
280
                if (s.isEmpty()) {
                    s = tnefMsg->findProp(0x0037);
                }
Laurent Montel's avatar
Laurent Montel committed
281
                event->setSummary(s);
Laurent Montel's avatar
Indent    
Laurent Montel committed
282

Laurent Montel's avatar
Laurent Montel committed
283
284
                s = tnefMsg->findProp(0x0026);
                event->setPriority(s.toInt());
Laurent Montel's avatar
Indent    
Laurent Montel committed
285
                // is reminder flag set ?
Laurent Montel's avatar
Laurent Montel committed
286
                if (!tnefMsg->findProp(0x8503).isEmpty()) {
Laurent Montel's avatar
Laurent Montel committed
287
288
289
                    Alarm::Ptr alarm(new Alarm(event.data())); // TODO: fix when KCalendarCore::Alarm is fixed
                    QDateTime highNoonTime = pureISOToLocalQDateTime(tnefMsg->findProp(0x8502).remove(QLatin1Char('-')).remove(QLatin1Char(':')));
                    QDateTime wakeMeUpTime = pureISOToLocalQDateTime(tnefMsg->findProp(0x8560, QString()).remove(QLatin1Char('-')).remove(QLatin1Char(':')));
Laurent Montel's avatar
Laurent Montel committed
290
                    alarm->setTime(wakeMeUpTime);
Laurent Montel's avatar
Indent    
Laurent Montel committed
291

Laurent Montel's avatar
Laurent Montel committed
292
293
                    if (highNoonTime.isValid() && wakeMeUpTime.isValid()) {
                        alarm->setStartOffset(Duration(highNoonTime, wakeMeUpTime));
Laurent Montel's avatar
Indent    
Laurent Montel committed
294
295
                    } else {
                        // default: wake them up 15 minutes before the appointment
Laurent Montel's avatar
Laurent Montel committed
296
                        alarm->setStartOffset(Duration(15 * 60));
Laurent Montel's avatar
Indent    
Laurent Montel committed
297
                    }
Laurent Montel's avatar
Laurent Montel committed
298
                    alarm->setDisplayAlarm(i18n("Reminder"));
Laurent Montel's avatar
Indent    
Laurent Montel committed
299
300
301

                    // Sorry: the different action types are not known (yet)
                    //        so we always set 'DISPLAY' (no sounds, no images...)
Laurent Montel's avatar
Laurent Montel committed
302
                    event->addAlarm(alarm);
Laurent Montel's avatar
Indent    
Laurent Montel committed
303
                }
Laurent Montel's avatar
Laurent Montel committed
304
                // ensure we have a uid for this event
Laurent Montel's avatar
Laurent Montel committed
305
306
                if (event->uid().isEmpty()) {
                    event->setUid(CalFormat::createUniqueId());
Laurent Montel's avatar
Indent    
Laurent Montel committed
307
                }
Laurent Montel's avatar
Laurent Montel committed
308
                cal->addEvent(event);
Laurent Montel's avatar
Laurent Montel committed
309
                // bOk = true;
Laurent Montel's avatar
Indent    
Laurent Montel committed
310
                // we finished composing a vCal
Laurent Montel's avatar
Laurent Montel committed
311
312
313
            } else if (bCompatClassNote || QLatin1String("IPM.CONTACT") == msgClass) {
                addressee.setUid(stringProp(tnefMsg, attMSGID));
                addressee.setFormattedName(stringProp(tnefMsg, MAPI_TAG_PR_DISPLAY_NAME));
314
315
316
                addressee.insertEmail(sNamedProp(tnefMsg, QStringLiteral(MAPI_TAG_CONTACT_EMAIL1EMAILADDRESS)), true);
                addressee.insertEmail(sNamedProp(tnefMsg, QStringLiteral(MAPI_TAG_CONTACT_EMAIL2EMAILADDRESS)), false);
                addressee.insertEmail(sNamedProp(tnefMsg, QStringLiteral(MAPI_TAG_CONTACT_EMAIL3EMAILADDRESS)), false);
Laurent Montel's avatar
Laurent Montel committed
317
318
                addressee.insertCustom(QStringLiteral("KADDRESSBOOK"),
                                       QStringLiteral("X-IMAddress"),
319
                                       sNamedProp(tnefMsg, QStringLiteral(MAPI_TAG_CONTACT_IMADDRESS)));
Laurent Montel's avatar
Laurent Montel committed
320
321
322
323
324
325
326
327
                addressee.insertCustom(QStringLiteral("KADDRESSBOOK"), QStringLiteral("X-SpousesName"), stringProp(tnefMsg, MAPI_TAG_PR_SPOUSE_NAME));
                addressee.insertCustom(QStringLiteral("KADDRESSBOOK"), QStringLiteral("X-ManagersName"), stringProp(tnefMsg, MAPI_TAG_PR_MANAGER_NAME));
                addressee.insertCustom(QStringLiteral("KADDRESSBOOK"), QStringLiteral("X-AssistantsName"), stringProp(tnefMsg, MAPI_TAG_PR_ASSISTANT));
                addressee.insertCustom(QStringLiteral("KADDRESSBOOK"), QStringLiteral("X-Department"), stringProp(tnefMsg, MAPI_TAG_PR_DEPARTMENT_NAME));
                addressee.insertCustom(QStringLiteral("KADDRESSBOOK"), QStringLiteral("X-Office"), stringProp(tnefMsg, MAPI_TAG_PR_OFFICE_LOCATION));
                addressee.insertCustom(QStringLiteral("KADDRESSBOOK"), QStringLiteral("X-Profession"), stringProp(tnefMsg, MAPI_TAG_PR_PROFESSION));

                QString s = tnefMsg->findProp(MAPI_TAG_PR_WEDDING_ANNIVERSARY).remove(QLatin1Char('-')).remove(QLatin1Char(':'));
Laurent Montel's avatar
Laurent Montel committed
328
                if (!s.isEmpty()) {
329
                    addressee.insertCustom(QStringLiteral("KADDRESSBOOK"), QStringLiteral("X-Anniversary"), s);
Laurent Montel's avatar
Indent    
Laurent Montel committed
330
                }
331

332
                KContacts::ResourceLocatorUrl url;
333
                url.setUrl(QUrl(sNamedProp(tnefMsg, QStringLiteral(MAPI_TAG_CONTACT_WEBPAGE))));
334
335

                addressee.setUrl(url);
336

Laurent Montel's avatar
Indent    
Laurent Montel committed
337
                // collect parts of Name entry
Laurent Montel's avatar
Laurent Montel committed
338
339
340
341
342
343
344
345
346
                addressee.setFamilyName(stringProp(tnefMsg, MAPI_TAG_PR_SURNAME));
                addressee.setGivenName(stringProp(tnefMsg, MAPI_TAG_PR_GIVEN_NAME));
                addressee.setAdditionalName(stringProp(tnefMsg, MAPI_TAG_PR_MIDDLE_NAME));
                addressee.setPrefix(stringProp(tnefMsg, MAPI_TAG_PR_DISPLAY_NAME_PREFIX));
                addressee.setSuffix(stringProp(tnefMsg, MAPI_TAG_PR_GENERATION));

                addressee.setNickName(stringProp(tnefMsg, MAPI_TAG_PR_NICKNAME));
                addressee.setRole(stringProp(tnefMsg, MAPI_TAG_PR_TITLE));
                addressee.setOrganization(stringProp(tnefMsg, MAPI_TAG_PR_COMPANY_NAME));
Laurent Montel's avatar
Indent    
Laurent Montel committed
347
                /*
Laurent Montel's avatar
Laurent Montel committed
348
349
350
                the MAPI property ID of this (multiline) )field is unknown:
                vPart += stringProp(tnefMsg, "\n","NOTE", ... , "" );
                */
351

Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
352
                KContacts::Address adr;
Laurent Montel's avatar
Laurent Montel committed
353
354
355
356
357
358
                adr.setPostOfficeBox(stringProp(tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_PO_BOX));
                adr.setStreet(stringProp(tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_STREET));
                adr.setLocality(stringProp(tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_CITY));
                adr.setRegion(stringProp(tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_STATE_OR_PROVINCE));
                adr.setPostalCode(stringProp(tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_POSTAL_CODE));
                adr.setCountry(stringProp(tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_COUNTRY));
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
359
                adr.setType(KContacts::Address::Home);
Laurent Montel's avatar
Laurent Montel committed
360
361
                addressee.insertAddress(adr);

362
363
364
365
366
367
                adr.setPostOfficeBox(sNamedProp(tnefMsg, QStringLiteral(MAPI_TAG_CONTACT_BUSINESSADDRESSPOBOX)));
                adr.setStreet(sNamedProp(tnefMsg, QStringLiteral(MAPI_TAG_CONTACT_BUSINESSADDRESSSTREET)));
                adr.setLocality(sNamedProp(tnefMsg, QStringLiteral(MAPI_TAG_CONTACT_BUSINESSADDRESSCITY)));
                adr.setRegion(sNamedProp(tnefMsg, QStringLiteral(MAPI_TAG_CONTACT_BUSINESSADDRESSSTATE)));
                adr.setPostalCode(sNamedProp(tnefMsg, QStringLiteral(MAPI_TAG_CONTACT_BUSINESSADDRESSPOSTALCODE)));
                adr.setCountry(sNamedProp(tnefMsg, QStringLiteral(MAPI_TAG_CONTACT_BUSINESSADDRESSCOUNTRY)));
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
368
                adr.setType(KContacts::Address::Work);
Laurent Montel's avatar
Laurent Montel committed
369
370
371
372
373
374
375
376
                addressee.insertAddress(adr);

                adr.setPostOfficeBox(stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_PO_BOX));
                adr.setStreet(stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_STREET));
                adr.setLocality(stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_CITY));
                adr.setRegion(stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_STATE_OR_PROVINCE));
                adr.setPostalCode(stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_POSTAL_CODE));
                adr.setCountry(stringProp(tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_COUNTRY));
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
377
                adr.setType(KContacts::Address::Dom);
Laurent Montel's avatar
Laurent Montel committed
378
                addressee.insertAddress(adr);
Laurent Montel's avatar
Indent    
Laurent Montel committed
379
380
381
382
383
384
385
386

                // problem: the 'other' address was stored by KOrganizer in
                //          a line looking like the following one:
                // vPart += "\nADR;TYPE=dom;TYPE=intl;TYPE=parcel;TYPE=postal;TYPE=work;"
                //          "TYPE=home:other_pobox;;other_str1\nother_str2;other_loc;other_region;"
                //          "other_pocode;other_country"

                QString nr;
Laurent Montel's avatar
Laurent Montel committed
387
                nr = stringProp(tnefMsg, MAPI_TAG_PR_HOME_TELEPHONE_NUMBER);
Laurent Montel's avatar
Laurent Montel committed
388
                addressee.insertPhoneNumber(KContacts::PhoneNumber(nr, KContacts::PhoneNumber::Home));
Laurent Montel's avatar
Laurent Montel committed
389
                nr = stringProp(tnefMsg, MAPI_TAG_PR_BUSINESS_TELEPHONE_NUMBER);
Laurent Montel's avatar
Laurent Montel committed
390
                addressee.insertPhoneNumber(KContacts::PhoneNumber(nr, KContacts::PhoneNumber::Work));
Laurent Montel's avatar
Laurent Montel committed
391
                nr = stringProp(tnefMsg, MAPI_TAG_PR_MOBILE_TELEPHONE_NUMBER);
Laurent Montel's avatar
Laurent Montel committed
392
                addressee.insertPhoneNumber(KContacts::PhoneNumber(nr, KContacts::PhoneNumber::Cell));
Laurent Montel's avatar
Laurent Montel committed
393
                nr = stringProp(tnefMsg, MAPI_TAG_PR_HOME_FAX_NUMBER);
Laurent Montel's avatar
Laurent Montel committed
394
                addressee.insertPhoneNumber(KContacts::PhoneNumber(nr, KContacts::PhoneNumber::Fax | KContacts::PhoneNumber::Home));
Laurent Montel's avatar
Laurent Montel committed
395
                nr = stringProp(tnefMsg, MAPI_TAG_PR_BUSINESS_FAX_NUMBER);
Laurent Montel's avatar
Laurent Montel committed
396
                addressee.insertPhoneNumber(KContacts::PhoneNumber(nr, KContacts::PhoneNumber::Fax | KContacts::PhoneNumber::Work));
Laurent Montel's avatar
Indent    
Laurent Montel committed
397

Laurent Montel's avatar
Laurent Montel committed
398
                s = tnefMsg->findProp(MAPI_TAG_PR_BIRTHDAY).remove(QLatin1Char('-')).remove(QLatin1Char(':'));
Laurent Montel's avatar
Laurent Montel committed
399
400
                if (!s.isEmpty()) {
                    addressee.setBirthday(QDateTime::fromString(s));
Laurent Montel's avatar
Indent    
Laurent Montel committed
401
                }
402

Laurent Montel's avatar
Laurent Montel committed
403
                // bOk = (!addressee.isEmpty());
Laurent Montel's avatar
Laurent Montel committed
404
            } else if (QLatin1String("IPM.NOTE") == msgClass) {
Laurent Montel's avatar
Indent    
Laurent Montel committed
405
406
407
408
409
            } // else if ... and so on ...
        }
    }

    // Compose return string
Laurent Montel's avatar
Laurent Montel committed
410
411
    const QString iCal = calFormat.toString(cal, QString());
    if (!iCal.isEmpty()) {
Laurent Montel's avatar
Indent    
Laurent Montel committed
412
413
        // This was an iCal
        return iCal;
414
    }
Laurent Montel's avatar
Indent    
Laurent Montel committed
415
416

    // Not an iCal - try a vCard
Aleix Pol Gonzalez's avatar
Aleix Pol Gonzalez committed
417
    KContacts::VCardConverter converter;
Laurent Montel's avatar
Laurent Montel committed
418
    return QString::fromUtf8(converter.createVCard(addressee));
419
420
}

Laurent Montel's avatar
Laurent Montel committed
421
QString KTnef::formatTNEFInvitation(const QByteArray &tnef, const MemoryCalendar::Ptr &cal, KCalUtils::InvitationFormatterHelper *h)
422
{
Laurent Montel's avatar
Laurent Montel committed
423
    const QString vPart = msTNEFToVPart(tnef);
424
    QString iCal = KCalUtils::IncidenceFormatter::formatICalInvitation(vPart, cal, h);
Laurent Montel's avatar
Laurent Montel committed
425
    if (!iCal.isEmpty()) {
Laurent Montel's avatar
Indent    
Laurent Montel committed
426
427
428
429
        return iCal;
    } else {
        return vPart;
    }
430
}