1 | /* |
2 | Copyright (c) 2001 Cornelius Schumacher <schumacher@kde.org> |
3 | Copyright (c) 2004 Reinhold Kainhofer <reinhold@kainhofer.com> |
4 | Copyright (c) 2005 Rafal Rzepecki <divide@users.sourceforge.net> |
5 | |
6 | This library is free software; you can redistribute it and/or |
7 | modify it under the terms of the GNU Library General Public |
8 | License as published by the Free Software Foundation; either |
9 | version 2 of the License, or (at your option) any later version. |
10 | |
11 | This library is distributed in the hope that it will be useful, |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
14 | Library General Public License for more details. |
15 | |
16 | You should have received a copy of the GNU Library General Public License |
17 | along with this library; see the file COPYING.LIB. If not, write to |
18 | the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, |
19 | Boston, MA 02110-1301, USA. |
20 | */ |
21 | /** |
22 | @file |
23 | This file is part of the API for handling TNEF data and provides |
24 | static Formatter helpers. |
25 | |
26 | @brief |
27 | Provides helpers too format @acronym TNEF attachments into different |
28 | formats like eg. a HTML representation. |
29 | |
30 | @author Cornelius Schumacher |
31 | @author Reinhold Kainhofer |
32 | @author Rafal Rzepecki |
33 | */ |
34 | |
35 | #include "formatter.h" |
36 | #include "ktnefparser.h" |
37 | #include "ktnefmessage.h" |
38 | #include "ktnefdefs.h" |
39 | |
40 | #include <kpimutils/email.h> |
41 | #include <kabc/phonenumber.h> |
42 | #include <kabc/vcardconverter.h> |
43 | |
44 | #ifndef KDEPIM_NO_KCAL |
45 | #include <kcal/incidenceformatter.h> |
46 | #include <kcal/calendar.h> |
47 | #endif |
48 | |
49 | #include <kcalcore/calendar.h> |
50 | #include <kcalcore/icalformat.h> |
51 | #include <kcalutils/incidenceformatter.h> |
52 | |
53 | #include <klocalizedstring.h> |
54 | #include <kdatetime.h> |
55 | |
56 | #include <QtCore/QBuffer> |
57 | |
58 | #include <time.h> |
59 | |
60 | using namespace KCalCore; |
61 | using namespace KTnef; |
62 | |
63 | /******************************************************************* |
64 | * Helper functions for the msTNEF -> VPart converter |
65 | *******************************************************************/ |
66 | |
67 | //----------------------------------------------------------------------------- |
68 | //@cond IGNORE |
69 | static QString stringProp( KTNEFMessage *tnefMsg, const quint32 &key, |
70 | const QString &fallback = QString() ) |
71 | { |
72 | return tnefMsg->findProp( key < 0x10000 ? key & 0xFFFF : key >> 16, fallback ); |
73 | } |
74 | |
75 | static QString sNamedProp( KTNEFMessage *tnefMsg, const QString &name, |
76 | const QString &fallback = QString() ) |
77 | { |
78 | return tnefMsg->findNamedProp( name, fallback ); |
79 | } |
80 | |
81 | struct save_tz { |
82 | char *old_tz; |
83 | char *tz_env_str; |
84 | }; |
85 | |
86 | /* temporarily go to a different timezone */ |
87 | static struct save_tz set_tz( const char *_tc ) |
88 | { |
89 | const char *tc = _tc?_tc:"UTC" ; |
90 | |
91 | struct save_tz rv; |
92 | |
93 | rv.old_tz = 0; |
94 | rv.tz_env_str = 0; |
95 | |
96 | //kDebug() << "set_tz(), timezone before =" << timezone; |
97 | |
98 | char *tz_env = 0; |
99 | if ( !qgetenv( "TZ" ).isEmpty() ) { |
100 | tz_env = qstrdup( qgetenv( "TZ" ) ); |
101 | rv.old_tz = tz_env; |
102 | } |
103 | char *tmp_env = (char*)malloc( strlen( tc ) + 4 ); |
104 | strcpy( tmp_env, "TZ=" ); |
105 | strcpy( tmp_env+3, tc ); |
106 | putenv( tmp_env ); |
107 | |
108 | rv.tz_env_str = tmp_env; |
109 | |
110 | /* tmp_env is not free'ed -- it is part of the environment */ |
111 | |
112 | tzset(); |
113 | //kDebug() << "set_tz(), timezone after =" << timezone; |
114 | |
115 | return rv; |
116 | } |
117 | |
118 | /* restore previous timezone */ |
119 | static void unset_tz( struct save_tz old_tz ) |
120 | { |
121 | if ( old_tz.old_tz ) { |
122 | char *tmp_env = (char*)malloc( strlen( old_tz.old_tz ) + 4 ); |
123 | strcpy( tmp_env, "TZ=" ); |
124 | strcpy( tmp_env+3, old_tz.old_tz ); |
125 | putenv( tmp_env ); |
126 | /* tmp_env is not free'ed -- it is part of the environment */ |
127 | free( old_tz.old_tz ); |
128 | } else { |
129 | /* clear TZ from env */ |
130 | putenv( strdup( "TZ" ) ); |
131 | } |
132 | tzset(); |
133 | |
134 | /* is this OK? */ |
135 | if ( old_tz.tz_env_str ) { |
136 | free( old_tz.tz_env_str ); |
137 | } |
138 | } |
139 | |
140 | static KDateTime utc2Local( const KDateTime &utcdt ) |
141 | { |
142 | struct tm tmL; |
143 | |
144 | save_tz tmp_tz = set_tz( "UTC" ); |
145 | time_t utc = utcdt.toTime_t(); |
146 | unset_tz( tmp_tz ); |
147 | |
148 | localtime_r( &utc, &tmL ); |
149 | return KDateTime( QDate( tmL.tm_year + 1900, tmL.tm_mon + 1, tmL.tm_mday ), |
150 | QTime( tmL.tm_hour, tmL.tm_min, tmL.tm_sec ) ); |
151 | } |
152 | |
153 | static KDateTime pureISOToLocalQDateTime( const QString &dtStr, |
154 | bool bDateOnly = false ) |
155 | { |
156 | QDate tmpDate; |
157 | QTime tmpTime; |
158 | int year, month, day, hour, minute, second; |
159 | |
160 | if ( bDateOnly ) { |
161 | year = dtStr.left( 4 ).toInt(); |
162 | month = dtStr.mid( 4, 2 ).toInt(); |
163 | day = dtStr.mid( 6, 2 ).toInt(); |
164 | hour = 0; |
165 | minute = 0; |
166 | second = 0; |
167 | } else { |
168 | year = dtStr.left( 4 ).toInt(); |
169 | month = dtStr.mid( 4, 2 ).toInt(); |
170 | day = dtStr.mid( 6, 2 ).toInt(); |
171 | hour = dtStr.mid( 9, 2 ).toInt(); |
172 | minute = dtStr.mid( 11, 2 ).toInt(); |
173 | second = dtStr.mid( 13, 2 ).toInt(); |
174 | } |
175 | tmpDate.setYMD( year, month, day ); |
176 | tmpTime.setHMS( hour, minute, second ); |
177 | |
178 | if ( tmpDate.isValid() && tmpTime.isValid() ) { |
179 | KDateTime dT = KDateTime( tmpDate, tmpTime ); |
180 | |
181 | if ( !bDateOnly ) { |
182 | // correct for GMT ( == Zulu time == UTC ) |
183 | if ( dtStr.at( dtStr.length() - 1 ) == 'Z' ) { |
184 | //dT = dT.addSecs( 60 * KRFCDate::localUTCOffset() ); |
185 | //localUTCOffset( dT ) ); |
186 | dT = utc2Local( dT ); |
187 | } |
188 | } |
189 | return dT; |
190 | } else { |
191 | return KDateTime(); |
192 | } |
193 | } |
194 | //@endcond |
195 | |
196 | QString KTnef::msTNEFToVPart( const QByteArray &tnef ) |
197 | { |
198 | bool bOk = false; |
199 | |
200 | KTNEFParser parser; |
201 | QByteArray b( tnef ); |
202 | QBuffer buf( &b ); |
203 | MemoryCalendar::Ptr cal( new MemoryCalendar( KDateTime::UTC ) ); |
204 | KABC::Addressee addressee; |
205 | ICalFormat calFormat; |
206 | Event::Ptr event( new Event() ); |
207 | |
208 | if ( parser.openDevice( &buf ) ) { |
209 | KTNEFMessage *tnefMsg = parser.message(); |
210 | //QMap<int,KTNEFProperty*> props = parser.message()->properties(); |
211 | |
212 | // Everything depends from property PR_MESSAGE_CLASS |
213 | // (this is added by KTNEFParser): |
214 | QString msgClass = tnefMsg->findProp( 0x001A, QString(), true ).toUpper(); |
215 | if ( !msgClass.isEmpty() ) { |
216 | // Match the old class names that might be used by Outlook for |
217 | // compatibility with Microsoft Mail for Windows for Workgroups 3.1. |
218 | bool bCompatClassAppointment = false; |
219 | bool bCompatMethodRequest = false; |
220 | bool bCompatMethodCancled = false; |
221 | bool bCompatMethodAccepted = false; |
222 | bool bCompatMethodAcceptedCond = false; |
223 | bool bCompatMethodDeclined = false; |
224 | if ( msgClass.startsWith( QLatin1String( "IPM.MICROSOFT SCHEDULE." ) ) ) { |
225 | bCompatClassAppointment = true; |
226 | if ( msgClass.endsWith( QLatin1String( ".MTGREQ" ) ) ) { |
227 | bCompatMethodRequest = true; |
228 | } |
229 | if ( msgClass.endsWith( QLatin1String( ".MTGCNCL" ) ) ) { |
230 | bCompatMethodCancled = true; |
231 | } |
232 | if ( msgClass.endsWith( QLatin1String( ".MTGRESPP" ) ) ) { |
233 | bCompatMethodAccepted = true; |
234 | } |
235 | if ( msgClass.endsWith( QLatin1String( ".MTGRESPA" ) ) ) { |
236 | bCompatMethodAcceptedCond = true; |
237 | } |
238 | if ( msgClass.endsWith( QLatin1String( ".MTGRESPN" ) ) ) { |
239 | bCompatMethodDeclined = true; |
240 | } |
241 | } |
242 | bool bCompatClassNote = ( msgClass == "IPM.MICROSOFT MAIL.NOTE" ); |
243 | |
244 | if ( bCompatClassAppointment || "IPM.APPOINTMENT" == msgClass ) { |
245 | // Compose a vCal |
246 | bool bIsReply = false; |
247 | QString prodID = "-//Microsoft Corporation//Outlook " ; |
248 | prodID += tnefMsg->findNamedProp( "0x8554" , "9.0" ); |
249 | prodID += "MIMEDIR/EN\n" ; |
250 | prodID += "VERSION:2.0\n" ; |
251 | calFormat.setApplication( "Outlook" , prodID ); |
252 | |
253 | iTIPMethod method; |
254 | if ( bCompatMethodRequest ) { |
255 | method = iTIPRequest; |
256 | } else if ( bCompatMethodCancled ) { |
257 | method = iTIPCancel; |
258 | } else if ( bCompatMethodAccepted || bCompatMethodAcceptedCond || |
259 | bCompatMethodDeclined ) { |
260 | method = iTIPReply; |
261 | bIsReply = true; |
262 | } else { |
263 | // pending(khz): verify whether "0x0c17" is the right tag ??? |
264 | // |
265 | // at the moment we think there are REQUESTS and UPDATES |
266 | // |
267 | // but WHAT ABOUT REPLIES ??? |
268 | // |
269 | // |
270 | |
271 | if ( tnefMsg->findProp(0x0c17) == "1" ) { |
272 | bIsReply = true; |
273 | } |
274 | method = iTIPRequest; |
275 | } |
276 | |
277 | /// ### FIXME Need to get this attribute written |
278 | ScheduleMessage schedMsg( event, method, ScheduleMessage::Unknown ); |
279 | |
280 | QString sSenderSearchKeyEmail( tnefMsg->findProp( 0x0C1D ) ); |
281 | |
282 | if ( !sSenderSearchKeyEmail.isEmpty() ) { |
283 | int colon = sSenderSearchKeyEmail.indexOf( ':' ); |
284 | // May be e.g. "SMTP:KHZ@KDE.ORG" |
285 | if ( sSenderSearchKeyEmail.indexOf( ':' ) == -1 ) { |
286 | sSenderSearchKeyEmail.remove( 0, colon+1 ); |
287 | } |
288 | } |
289 | |
290 | QString s( tnefMsg->findProp( 0x8189 ) ); |
291 | const QStringList attendees = s.split( ';' ); |
292 | if ( attendees.count() ) { |
293 | for ( QStringList::const_iterator it = attendees.begin(); |
294 | it != attendees.end(); ++it ) { |
295 | // Skip all entries that have no '@' since these are |
296 | // no mail addresses |
297 | if ( (*it).indexOf( '@' ) == -1 ) { |
298 | s = (*it).trimmed(); |
299 | |
300 | Attendee::Ptr attendee( new Attendee( s, s, true ) ); |
301 | if ( bIsReply ) { |
302 | if ( bCompatMethodAccepted ) { |
303 | attendee->setStatus( Attendee::Accepted ); |
304 | } |
305 | if ( bCompatMethodDeclined ) { |
306 | attendee->setStatus( Attendee::Declined ); |
307 | } |
308 | if ( bCompatMethodAcceptedCond ) { |
309 | attendee->setStatus( Attendee::Tentative ); |
310 | } |
311 | } else { |
312 | attendee->setStatus( Attendee::NeedsAction ); |
313 | attendee->setRole( Attendee::ReqParticipant ); |
314 | } |
315 | event->addAttendee( attendee ); |
316 | } |
317 | } |
318 | } else { |
319 | // Oops, no attendees? |
320 | // This must be old style, let us use the PR_SENDER_SEARCH_KEY. |
321 | s = sSenderSearchKeyEmail; |
322 | if ( !s.isEmpty() ) { |
323 | Attendee::Ptr attendee( new Attendee( QString(), QString(), true ) ); |
324 | if ( bIsReply ) { |
325 | if ( bCompatMethodAccepted ) { |
326 | attendee->setStatus( Attendee::Accepted ); |
327 | } |
328 | if ( bCompatMethodAcceptedCond ) { |
329 | attendee->setStatus( Attendee::Declined ); |
330 | } |
331 | if ( bCompatMethodDeclined ) { |
332 | attendee->setStatus( Attendee::Tentative ); |
333 | } |
334 | } else { |
335 | attendee->setStatus( Attendee::NeedsAction ); |
336 | attendee->setRole( Attendee::ReqParticipant ); |
337 | } |
338 | event->addAttendee( attendee ); |
339 | } |
340 | } |
341 | s = tnefMsg->findProp( 0x3ff8 ); // look for organizer property |
342 | if ( s.isEmpty() && !bIsReply ) { |
343 | s = sSenderSearchKeyEmail; |
344 | } |
345 | // TODO: Use the common name? |
346 | if ( !s.isEmpty() ) { |
347 | event->setOrganizer( s ); |
348 | } |
349 | |
350 | s = tnefMsg->findProp( 0x819b ).remove( QChar( '-' ) ).remove( QChar( ':' ) ); |
351 | event->setDtStart( KDateTime::fromString( s ) ); // ## Format?? |
352 | |
353 | s = tnefMsg->findProp( 0x819c ).remove( QChar( '-' ) ).remove( QChar( ':' ) ); |
354 | event->setDtEnd( KDateTime::fromString( s ) ); |
355 | |
356 | s = tnefMsg->findProp( 0x810d ); |
357 | event->setLocation( s ); |
358 | // is it OK to set this to OPAQUE always ?? |
359 | //vPart += "TRANSP:OPAQUE\n"; ###FIXME, portme! |
360 | //vPart += "SEQUENCE:0\n"; |
361 | |
362 | // is "0x0023" OK - or should we look for "0x0003" ?? |
363 | s = tnefMsg->findProp( 0x0023 ); |
364 | event->setUid( s ); |
365 | |
366 | // PENDING(khz): is this value in local timezone? Must it be |
367 | // adjusted? Most likely this is a bug in the server or in |
368 | // Outlook - we ignore it for now. |
369 | s = tnefMsg->findProp( 0x8202 ).remove( QChar( '-' ) ).remove( QChar( ':' ) ); |
370 | // ### kcal always uses currentDateTime() |
371 | // event->setDtStamp( QDateTime::fromString( s ) ); |
372 | |
373 | s = tnefMsg->findNamedProp( "Keywords" ); |
374 | event->setCategories( s ); |
375 | |
376 | s = tnefMsg->findProp( 0x1000 ); |
377 | event->setDescription( s ); |
378 | |
379 | s = tnefMsg->findProp( 0x0070 ); |
380 | event->setSummary( s ); |
381 | |
382 | s = tnefMsg->findProp( 0x0026 ); |
383 | event->setPriority( s.toInt() ); |
384 | // is reminder flag set ? |
385 | if ( !tnefMsg->findProp( 0x8503 ).isEmpty() ) { |
386 | Alarm::Ptr alarm( new Alarm( event.data() ) ); // TODO: fix when KCalCore::Alarm is fixed |
387 | KDateTime highNoonTime = |
388 | pureISOToLocalQDateTime( tnefMsg->findProp( 0x8502 ). |
389 | remove( QChar( '-' ) ).remove( QChar( ':' ) ) ); |
390 | KDateTime wakeMeUpTime = |
391 | pureISOToLocalQDateTime( tnefMsg->findProp( 0x8560, "" ). |
392 | remove( QChar( '-' ) ).remove( QChar( ':' ) ) ); |
393 | alarm->setTime( wakeMeUpTime ); |
394 | |
395 | if ( highNoonTime.isValid() && wakeMeUpTime.isValid() ) { |
396 | alarm->setStartOffset( Duration( highNoonTime, wakeMeUpTime ) ); |
397 | } else { |
398 | // default: wake them up 15 minutes before the appointment |
399 | alarm->setStartOffset( Duration( 15 * 60 ) ); |
400 | } |
401 | alarm->setDisplayAlarm( i18n( "Reminder" ) ); |
402 | |
403 | // Sorry: the different action types are not known (yet) |
404 | // so we always set 'DISPLAY' (no sounds, no images...) |
405 | event->addAlarm( alarm ); |
406 | } |
407 | //ensure we have a uid for this event |
408 | if ( event->uid().isEmpty() ) { |
409 | event->setUid( CalFormat::createUniqueId() ); |
410 | } |
411 | cal->addEvent( event ); |
412 | bOk = true; |
413 | // we finished composing a vCal |
414 | } else if ( bCompatClassNote || "IPM.CONTACT" == msgClass ) { |
415 | addressee.setUid( stringProp( tnefMsg, attMSGID ) ); |
416 | addressee.setFormattedName( stringProp( tnefMsg, MAPI_TAG_PR_DISPLAY_NAME ) ); |
417 | addressee.insertEmail( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_EMAIL1EMAILADDRESS ), true ); |
418 | addressee.insertEmail( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_EMAIL2EMAILADDRESS ), false ); |
419 | addressee.insertEmail( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_EMAIL3EMAILADDRESS ), false ); |
420 | addressee.insertCustom( "KADDRESSBOOK" , "X-IMAddress" , |
421 | sNamedProp( tnefMsg, MAPI_TAG_CONTACT_IMADDRESS ) ); |
422 | addressee.insertCustom( "KADDRESSBOOK" , "X-SpousesName" , |
423 | stringProp( tnefMsg, MAPI_TAG_PR_SPOUSE_NAME ) ); |
424 | addressee.insertCustom( "KADDRESSBOOK" , "X-ManagersName" , |
425 | stringProp( tnefMsg, MAPI_TAG_PR_MANAGER_NAME ) ); |
426 | addressee.insertCustom( "KADDRESSBOOK" , "X-AssistantsName" , |
427 | stringProp( tnefMsg, MAPI_TAG_PR_ASSISTANT ) ); |
428 | addressee.insertCustom( "KADDRESSBOOK" , "X-Department" , |
429 | stringProp( tnefMsg, MAPI_TAG_PR_DEPARTMENT_NAME ) ); |
430 | addressee.insertCustom( "KADDRESSBOOK" , "X-Office" , |
431 | stringProp( tnefMsg, MAPI_TAG_PR_OFFICE_LOCATION ) ); |
432 | addressee.insertCustom( "KADDRESSBOOK" , "X-Profession" , |
433 | stringProp( tnefMsg, MAPI_TAG_PR_PROFESSION ) ); |
434 | |
435 | QString s = tnefMsg->findProp( MAPI_TAG_PR_WEDDING_ANNIVERSARY ). |
436 | remove( QChar( '-' ) ).remove( QChar( ':' ) ); |
437 | if ( !s.isEmpty() ) { |
438 | addressee.insertCustom( "KADDRESSBOOK" , "X-Anniversary" , s ); |
439 | } |
440 | |
441 | addressee.setUrl( KUrl( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_WEBPAGE ) ) ); |
442 | |
443 | // collect parts of Name entry |
444 | addressee.setFamilyName( stringProp( tnefMsg, MAPI_TAG_PR_SURNAME ) ); |
445 | addressee.setGivenName( stringProp( tnefMsg, MAPI_TAG_PR_GIVEN_NAME ) ); |
446 | addressee.setAdditionalName( stringProp( tnefMsg, MAPI_TAG_PR_MIDDLE_NAME ) ); |
447 | addressee.setPrefix( stringProp( tnefMsg, MAPI_TAG_PR_DISPLAY_NAME_PREFIX ) ); |
448 | addressee.setSuffix( stringProp( tnefMsg, MAPI_TAG_PR_GENERATION ) ); |
449 | |
450 | addressee.setNickName( stringProp( tnefMsg, MAPI_TAG_PR_NICKNAME ) ); |
451 | addressee.setRole( stringProp( tnefMsg, MAPI_TAG_PR_TITLE ) ); |
452 | addressee.setOrganization( stringProp( tnefMsg, MAPI_TAG_PR_COMPANY_NAME ) ); |
453 | /* |
454 | the MAPI property ID of this (multiline) )field is unknown: |
455 | vPart += stringProp(tnefMsg, "\n","NOTE", ... , "" ); |
456 | */ |
457 | |
458 | KABC::Address adr; |
459 | adr.setPostOfficeBox( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_PO_BOX ) ); |
460 | adr.setStreet( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_STREET ) ); |
461 | adr.setLocality( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_CITY ) ); |
462 | adr.setRegion( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_STATE_OR_PROVINCE ) ); |
463 | adr.setPostalCode( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_POSTAL_CODE ) ); |
464 | adr.setCountry( stringProp( tnefMsg, MAPI_TAG_PR_HOME_ADDRESS_COUNTRY ) ); |
465 | adr.setType( KABC::Address::Home ); |
466 | addressee.insertAddress( adr ); |
467 | |
468 | adr.setPostOfficeBox( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSPOBOX ) ); |
469 | adr.setStreet( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSSTREET ) ); |
470 | adr.setLocality( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSCITY ) ); |
471 | adr.setRegion( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSSTATE ) ); |
472 | adr.setPostalCode( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSPOSTALCODE ) ); |
473 | adr.setCountry( sNamedProp( tnefMsg, MAPI_TAG_CONTACT_BUSINESSADDRESSCOUNTRY ) ); |
474 | adr.setType( KABC::Address::Work ); |
475 | addressee.insertAddress( adr ); |
476 | |
477 | adr.setPostOfficeBox( stringProp( tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_PO_BOX ) ); |
478 | adr.setStreet( stringProp( tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_STREET ) ); |
479 | adr.setLocality( stringProp( tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_CITY ) ); |
480 | adr.setRegion( stringProp( tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_STATE_OR_PROVINCE ) ); |
481 | adr.setPostalCode( stringProp( tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_POSTAL_CODE ) ); |
482 | adr.setCountry( stringProp( tnefMsg, MAPI_TAG_PR_OTHER_ADDRESS_COUNTRY ) ); |
483 | adr.setType( KABC::Address::Dom ); |
484 | addressee.insertAddress( adr ); |
485 | |
486 | // problem: the 'other' address was stored by KOrganizer in |
487 | // a line looking like the following one: |
488 | // vPart += "\nADR;TYPE=dom;TYPE=intl;TYPE=parcel;TYPE=postal;TYPE=work;" |
489 | // "TYPE=home:other_pobox;;other_str1\nother_str2;other_loc;other_region;" |
490 | // "other_pocode;other_country" |
491 | |
492 | QString nr; |
493 | nr = stringProp( tnefMsg, MAPI_TAG_PR_HOME_TELEPHONE_NUMBER ); |
494 | addressee.insertPhoneNumber( |
495 | KABC::PhoneNumber( nr, KABC::PhoneNumber::Home ) ); |
496 | nr = stringProp( tnefMsg, MAPI_TAG_PR_BUSINESS_TELEPHONE_NUMBER ); |
497 | addressee.insertPhoneNumber( |
498 | KABC::PhoneNumber( nr, KABC::PhoneNumber::Work ) ); |
499 | nr = stringProp( tnefMsg, MAPI_TAG_PR_MOBILE_TELEPHONE_NUMBER ); |
500 | addressee.insertPhoneNumber( |
501 | KABC::PhoneNumber( nr, KABC::PhoneNumber::Cell ) ); |
502 | nr = stringProp( tnefMsg, MAPI_TAG_PR_HOME_FAX_NUMBER ); |
503 | addressee.insertPhoneNumber( |
504 | KABC::PhoneNumber( nr, KABC::PhoneNumber::Fax | KABC::PhoneNumber::Home ) ); |
505 | nr = stringProp( tnefMsg, MAPI_TAG_PR_BUSINESS_FAX_NUMBER ); |
506 | addressee.insertPhoneNumber( |
507 | KABC::PhoneNumber( nr, KABC::PhoneNumber::Fax | KABC::PhoneNumber::Work ) ); |
508 | |
509 | s = tnefMsg->findProp( MAPI_TAG_PR_BIRTHDAY ). |
510 | remove( QChar( '-' ) ).remove( QChar( ':' ) ); |
511 | if ( !s.isEmpty() ) { |
512 | addressee.setBirthday( QDateTime::fromString( s ) ); |
513 | } |
514 | |
515 | bOk = ( !addressee.isEmpty() ); |
516 | } else if ( "IPM.NOTE" == msgClass ) { |
517 | |
518 | } // else if ... and so on ... |
519 | } |
520 | } |
521 | |
522 | // Compose return string |
523 | // KDAB_TODO: Interesting, without the explicit QString the toString call is |
524 | // reported to be ambigious with toString( const Incidence::Ptr & ). |
525 | const QString iCal = calFormat.toString( cal, QString() ); |
526 | if ( !iCal.isEmpty() ) { |
527 | // This was an iCal |
528 | return iCal; |
529 | } |
530 | |
531 | // Not an iCal - try a vCard |
532 | KABC::VCardConverter converter; |
533 | return QString::fromUtf8( converter.createVCard( addressee ) ); |
534 | } |
535 | |
536 | #ifndef KDEPIM_NO_KCAL |
537 | QString KTnef::formatTNEFInvitation( const QByteArray &tnef, |
538 | KCal::Calendar *cal, |
539 | KCal::InvitationFormatterHelper *h ) |
540 | { |
541 | QString vPart = msTNEFToVPart( tnef ); |
542 | QString iCal = KCal::IncidenceFormatter::formatICalInvitation( vPart, cal, h ); |
543 | if ( !iCal.isEmpty() ) { |
544 | return iCal; |
545 | } else { |
546 | return vPart; |
547 | } |
548 | } |
549 | #endif |
550 | |
551 | QString KTnef::formatTNEFInvitation( const QByteArray &tnef, |
552 | const MemoryCalendar::Ptr &cal, |
553 | KCalUtils::InvitationFormatterHelper *h ) |
554 | { |
555 | const QString vPart = msTNEFToVPart( tnef ); |
556 | QString iCal = KCalUtils::IncidenceFormatter::formatICalInvitation( vPart, cal, h, true ); |
557 | if ( !iCal.isEmpty() ) { |
558 | return iCal; |
559 | } else { |
560 | return vPart; |
561 | } |
562 | } |
563 | |
564 | |