~ubuntu-branches/ubuntu/quantal/kdepimlibs/quantal-proposed

« back to all changes in this revision

Viewing changes to ktnef/ktnefwriter.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Jonathan Riddell
  • Date: 2006-09-06 22:45:39 UTC
  • Revision ID: james.westby@ubuntu.com-20060906224539-fiq8t03qdbqu7z3i
Tags: upstream-3.80.1
ImportĀ upstreamĀ versionĀ 3.80.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
    ktnefwriter.cpp
 
3
 
 
4
    Copyright (C) 2002 Bo Thorsen  <bo@sonofthor.dk>
 
5
 
 
6
    This file is part of KTNEF, the KDE TNEF support library/program.
 
7
 
 
8
    This library is free software; you can redistribute it and/or
 
9
    modify it under the terms of the GNU Library General Public
 
10
    License as published by the Free Software Foundation; either
 
11
    version 2 of the License, or (at your option) any later version.
 
12
 
 
13
    This library is distributed in the hope that it will be useful,
 
14
    but WITHOUT ANY WARRANTY; without even the implied warranty of
 
15
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 
16
    Library General Public License for more details.
 
17
 
 
18
    You should have received a copy of the GNU Library General Public License
 
19
    along with this library; see the file COPYING.LIB.  If not, write to
 
20
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
 
21
    Boston, MA 02110-1301, USA.
 
22
 */
 
23
 
 
24
#ifdef HAVE_CONFIG_H
 
25
#include <config.h>
 
26
#endif /* HAVE_CONFIG_H */
 
27
 
 
28
#include <assert.h>
 
29
 
 
30
#include <QFile>
 
31
#include <QDateTime>
 
32
#include <QDataStream>
 
33
#include <QList>
 
34
#include <QByteArray>
 
35
 
 
36
#include <kdebug.h>
 
37
 
 
38
#include "ktnef/ktnefwriter.h"
 
39
#include "ktnef/ktnefproperty.h"
 
40
#include "ktnef/ktnefpropertyset.h"
 
41
#include "ktnef/ktnefdefs.h"
 
42
 
 
43
using namespace KTnef;
 
44
 
 
45
class KTNEFWriter::PrivateData {
 
46
public:
 
47
  PrivateData() { mFirstAttachNum = QDateTime::currentDateTime().toTime_t(); }
 
48
 
 
49
  KTNEFPropertySet properties;
 
50
  quint16 mFirstAttachNum;
 
51
};
 
52
 
 
53
 
 
54
KTNEFWriter::KTNEFWriter() {
 
55
  mData = new PrivateData;
 
56
 
 
57
  // This is not something the user should fiddle with
 
58
  // First set the TNEF version
 
59
  QVariant v(0x00010000);
 
60
  addProperty( attTNEFVERSION, atpDWORD, v );
 
61
 
 
62
  // Now set the code page to something reasonable. TODO: Use the right one
 
63
  QVariant v1( (quint32)0x4e4 );
 
64
  QVariant v2( (quint32)0x0 );
 
65
  QList<QVariant> list;
 
66
  list << v1;
 
67
  list << v2;
 
68
  v = QVariant( list );
 
69
  addProperty( attOEMCODEPAGE, atpBYTE, list );
 
70
}
 
71
 
 
72
KTNEFWriter::~KTNEFWriter() {
 
73
  delete mData;
 
74
}
 
75
 
 
76
 
 
77
void KTNEFWriter::addProperty( int tag, int type, const QVariant& value ) {
 
78
  mData->properties.addProperty( tag, type, value );
 
79
}
 
80
 
 
81
 
 
82
void addToChecksum( quint32 i, quint16 &checksum ) {
 
83
  checksum += i & 0xff;
 
84
  checksum += (i >> 8) & 0xff;
 
85
  checksum += (i >> 16) & 0xff;
 
86
  checksum += (i >> 24) & 0xff;
 
87
}
 
88
 
 
89
void addToChecksum( QByteArray &cs, quint16 &checksum ) {
 
90
  int len = cs.length();
 
91
  for (int i=0; i<len; i++)
 
92
    checksum += (quint8)cs[i];
 
93
}
 
94
 
 
95
void writeCString( QDataStream &stream, QByteArray &str ) {
 
96
  stream.writeRawData( str.data(), str.length() );
 
97
  stream << (quint8)0;
 
98
}
 
99
 
 
100
quint32 mergeTagAndType( quint32 tag, quint32 type ) {
 
101
  return ( ( type & 0xffff ) << 16 ) | ( tag & 0xffff );
 
102
}
 
103
 
 
104
/* This writes a TNEF property to the file.
 
105
 *
 
106
 * A TNEF property has a 1 byte type (LVL_MESSAGE or LVL_ATTACHMENT),
 
107
 * a 4 byte type/tag, a 4 byte length, the data and finally the checksum.
 
108
 *
 
109
 * The checksum is a 16 byte int with all bytes in the data added.
 
110
 */
 
111
bool KTNEFWriter::writeProperty( QDataStream &stream, int &bytes, int tag) {
 
112
  QMap<int,KTNEFProperty*>& properties = mData->properties.properties();
 
113
  QMap<int,KTNEFProperty*>::Iterator it = properties.find( tag );
 
114
 
 
115
  if ( it == properties.end() )
 
116
    return false;
 
117
 
 
118
  KTNEFProperty *property = *it;
 
119
 
 
120
  quint32 i;
 
121
  quint16 checksum = 0;
 
122
  QList<QVariant> list;
 
123
  QString s;
 
124
  QByteArray cs, cs2;
 
125
  QDateTime dt;
 
126
  QDate date;
 
127
  QTime time;
 
128
  switch( tag ) {
 
129
  case attMSGSTATUS:
 
130
    // quint8
 
131
    i = property->value().toUInt() & 0xff;
 
132
    checksum = i;
 
133
 
 
134
    stream << (quint8)LVL_MESSAGE;
 
135
    stream << mergeTagAndType( tag, property->type() );
 
136
    stream << (quint32)1;
 
137
    stream << (quint8)i;
 
138
 
 
139
    bytes += 10;
 
140
    break;
 
141
 
 
142
  case attMSGPRIORITY:
 
143
  case attREQUESTRES:
 
144
    // quint16
 
145
    i = property->value().toUInt() & 0xffff;
 
146
    addToChecksum( i, checksum );
 
147
 
 
148
    stream << (quint8)LVL_MESSAGE;
 
149
    stream << mergeTagAndType( tag, property->type() );
 
150
    stream << (quint32)2;
 
151
    stream << (quint16)i;
 
152
 
 
153
    bytes += 11;
 
154
    break;
 
155
 
 
156
  case attTNEFVERSION:
 
157
    // quint32
 
158
    i = property->value().toUInt();
 
159
    addToChecksum( i, checksum );
 
160
 
 
161
    stream << (quint8)LVL_MESSAGE;
 
162
    stream << mergeTagAndType( tag, property->type() );
 
163
    stream << (quint32)4;
 
164
    stream << (quint32)i;
 
165
 
 
166
    bytes += 13;
 
167
    break;
 
168
 
 
169
  case attOEMCODEPAGE:
 
170
    // 2 quint32
 
171
    list = property->value().toList();
 
172
    assert( list.count() == 2 );
 
173
 
 
174
    stream << (quint8)LVL_MESSAGE;
 
175
    stream << mergeTagAndType( tag, property->type() );
 
176
    stream << (quint32)8;
 
177
 
 
178
    i = list[0].toInt();
 
179
    addToChecksum( i, checksum );
 
180
    stream << (quint32)i;
 
181
    i = list[1].toInt();
 
182
    addToChecksum( i, checksum );
 
183
    stream << (quint32)i;
 
184
 
 
185
    bytes += 17;
 
186
    break;
 
187
 
 
188
  case attMSGCLASS:
 
189
  case attSUBJECT:
 
190
  case attBODY:
 
191
  case attMSGID:
 
192
    // QCString
 
193
    cs = property->value().toString().toLocal8Bit();
 
194
    addToChecksum( cs, checksum );
 
195
 
 
196
    stream << (quint8)LVL_MESSAGE;
 
197
    stream << mergeTagAndType( tag, property->type() );
 
198
    stream << (quint32)cs.length()+1;
 
199
    writeCString( stream, cs );
 
200
 
 
201
    bytes += 9 + cs.length()+1;
 
202
    break;
 
203
 
 
204
  case attFROM:
 
205
    // 2 QString encoded to a TRP structure
 
206
    list = property->value().toList();
 
207
    assert( list.count() == 2 );
 
208
 
 
209
    cs = list[0].toString().toLocal8Bit();                       // Name
 
210
    cs2 = (QString("smtp:") + list[1].toString()).toLocal8Bit(); // Email address
 
211
    i = 18 + cs.length() + cs2.length(); // 2 * sizof(TRP) + strings + 2x'\0'
 
212
 
 
213
    stream << (quint8)LVL_MESSAGE;
 
214
    stream << mergeTagAndType( tag, property->type() );
 
215
    stream << (quint32)i;
 
216
 
 
217
    // The stream has to be aligned to 4 bytes for the strings
 
218
    // TODO: Or does it? Looks like Outlook doesn't do this
 
219
    // bytes += 17;
 
220
    // Write the first TRP structure
 
221
    stream << (quint16)4;                 // trpidOneOff
 
222
    stream << (quint16)i;                 // totalsize
 
223
    stream << (quint16)(cs.length()+1);   // sizeof name
 
224
    stream << (quint16)(cs2.length()+1);  // sizeof address
 
225
 
 
226
    // if ( bytes % 4 != 0 )
 
227
      // Align the buffer
 
228
 
 
229
    // Write the strings
 
230
    writeCString( stream, cs );
 
231
    writeCString( stream, cs2 );
 
232
 
 
233
    // Write the empty padding TRP structure (just zeroes)
 
234
    stream << (quint32)0 << (quint32)0;
 
235
 
 
236
    addToChecksum( 4, checksum );
 
237
    addToChecksum( i, checksum );
 
238
    addToChecksum( cs.length()+1, checksum );
 
239
    addToChecksum( cs2.length()+1, checksum );
 
240
    addToChecksum( cs, checksum );
 
241
    addToChecksum( cs2, checksum );
 
242
 
 
243
    bytes += 10;
 
244
    break;
 
245
 
 
246
  case attDATESENT:
 
247
  case attDATERECD:
 
248
  case attDATEMODIFIED:
 
249
    // QDateTime
 
250
    dt = property->value().toDateTime();
 
251
    time = dt.time();
 
252
    date = dt.date();
 
253
 
 
254
    stream << (quint8)LVL_MESSAGE;
 
255
    stream << mergeTagAndType( tag, property->type() );
 
256
    stream << (quint32)14;
 
257
 
 
258
    i = (quint16)date.year();
 
259
    addToChecksum( i, checksum );
 
260
    stream << (quint16)i;
 
261
    i = (quint16)date.month();
 
262
    addToChecksum( i, checksum );
 
263
    stream << (quint16)i;
 
264
    i = (quint16)date.day();
 
265
    addToChecksum( i, checksum );
 
266
    stream << (quint16)i;
 
267
    i = (quint16)time.hour();
 
268
    addToChecksum( i, checksum );
 
269
    stream << (quint16)i;
 
270
    i = (quint16)time.minute();
 
271
    addToChecksum( i, checksum );
 
272
    stream << (quint16)i;
 
273
    i = (quint16)time.second();
 
274
    addToChecksum( i, checksum );
 
275
    stream << (quint16)i;
 
276
    i = (quint16)date.dayOfWeek();
 
277
    addToChecksum( i, checksum );
 
278
    stream << (quint16)i;
 
279
    break;
 
280
/*
 
281
  case attMSGSTATUS:
 
282
    {
 
283
      quint8 c;
 
284
      quint32 flag = 0;
 
285
      if ( c & fmsRead ) flag |= MSGFLAG_READ;
 
286
      if ( !( c & fmsModified ) ) flag |= MSGFLAG_UNMODIFIED;
 
287
      if ( c & fmsSubmitted ) flag |= MSGFLAG_SUBMIT;
 
288
      if ( c & fmsHasAttach ) flag |= MSGFLAG_HASATTACH;
 
289
      if ( c & fmsLocal ) flag |= MSGFLAG_UNSENT;
 
290
      d->stream_ >> c;
 
291
 
 
292
      i = property->value().toUInt();
 
293
      stream << (quint8)LVL_MESSAGE;
 
294
      stream << (quint32)type;
 
295
      stream << (quint32)2;
 
296
      stream << (quint8)i;
 
297
      addToChecksum( i, checksum );
 
298
      // from reader: d->message_->addProperty( 0x0E07, MAPI_TYPE_ULONG, flag );
 
299
    }
 
300
    kDebug() << "Message Status" << " (length=" << i2 << ")" << endl;
 
301
    break;
 
302
*/
 
303
 
 
304
  default:
 
305
    kDebug() << "Unknown TNEF tag: " << tag << endl;
 
306
    return false;
 
307
  }
 
308
 
 
309
  stream << (quint16)checksum;
 
310
  return true;
 
311
}
 
312
 
 
313
 
 
314
bool KTNEFWriter::writeFile( QIODevice &file ) {
 
315
  if ( !file.open( QIODevice::WriteOnly ) )
 
316
    return false;
 
317
 
 
318
  QDataStream stream( &file );
 
319
  return writeFile( stream );
 
320
}
 
321
 
 
322
 
 
323
bool KTNEFWriter::writeFile( QDataStream &stream ) {
 
324
  stream.setByteOrder( QDataStream::LittleEndian );
 
325
 
 
326
  // Start by writing the opening TNEF stuff
 
327
  stream << TNEF_SIGNATURE;
 
328
 
 
329
  // Store the PR_ATTACH_NUM value for the first attachment
 
330
  // ( must be stored even if *no* attachments are stored )
 
331
  stream << mData->mFirstAttachNum;
 
332
 
 
333
  // Now do some writing
 
334
  bool ok = true;
 
335
  int bytesWritten = 0;
 
336
  ok &= writeProperty( stream, bytesWritten, attTNEFVERSION );
 
337
  ok &= writeProperty( stream, bytesWritten, attOEMCODEPAGE );
 
338
  ok &= writeProperty( stream, bytesWritten, attMSGCLASS );
 
339
  ok &= writeProperty( stream, bytesWritten, attMSGPRIORITY );
 
340
  ok &= writeProperty( stream, bytesWritten, attSUBJECT );
 
341
  ok &= writeProperty( stream, bytesWritten, attDATESENT );
 
342
  ok &= writeProperty( stream, bytesWritten, attDATESTART );
 
343
  ok &= writeProperty( stream, bytesWritten, attDATEEND );
 
344
  // ok &= writeProperty( stream, bytesWritten, attAIDOWNER );
 
345
  ok &= writeProperty( stream, bytesWritten, attREQUESTRES );
 
346
  ok &= writeProperty( stream, bytesWritten, attFROM );
 
347
  ok &= writeProperty( stream, bytesWritten, attDATERECD );
 
348
  ok &= writeProperty( stream, bytesWritten, attMSGSTATUS );
 
349
  ok &= writeProperty( stream, bytesWritten, attBODY );
 
350
  return ok;
 
351
}
 
352
 
 
353
 
 
354
void KTNEFWriter::setSender(const QString &name, const QString &email) {
 
355
  assert( !name.isEmpty() );
 
356
  assert( !email.isEmpty() );
 
357
 
 
358
  QVariant v1( name );
 
359
  QVariant v2( email );
 
360
 
 
361
  QList<QVariant> list;
 
362
  list << v1;
 
363
  list << v2;
 
364
 
 
365
  QVariant v( list );
 
366
  addProperty( attFROM, 0, list ); // What's up with the 0 here ??
 
367
}
 
368
 
 
369
void KTNEFWriter::setMessageType(MessageType m) {
 
370
  // Note that the MessageType list here is probably not long enough,
 
371
  // more entries are most likely needed later
 
372
 
 
373
  QVariant v;
 
374
  switch( m ) {
 
375
  case Appointment:
 
376
    v = QVariant( QString( "IPM.Appointment" ) );
 
377
    break;
 
378
 
 
379
  case MeetingCancelled:
 
380
    v = QVariant( QString( "IPM.Schedule.Meeting.Cancelled" ) );
 
381
    break;
 
382
 
 
383
  case MeetingRequest:
 
384
    v = QVariant( QString( "IPM.Schedule.Meeting.Request" ) );
 
385
    break;
 
386
 
 
387
  case MeetingNo:
 
388
    v = QVariant( QString( "IPM.Schedule.Meeting.Resp.Neg" ) );
 
389
    break;
 
390
 
 
391
  case MeetingYes:
 
392
    v = QVariant( QString( "IPM.Schedule.Meeting.Resp.Pos" ) );
 
393
    break;
 
394
 
 
395
  case MeetingTent:
 
396
    // Tent?
 
397
    v = QVariant( QString( "IPM.Schedule.Meeting.Resp.Tent" ) );
 
398
    break;
 
399
 
 
400
  default:
 
401
    return;
 
402
  }
 
403
 
 
404
  addProperty( attMSGCLASS, atpWORD, v );
 
405
}
 
406
 
 
407
 
 
408
void KTNEFWriter::setMethod( Method )
 
409
{
 
410
 
 
411
}
 
412
 
 
413
 
 
414
void KTNEFWriter::clearAttendees()
 
415
{
 
416
 
 
417
}
 
418
 
 
419
 
 
420
void KTNEFWriter::addAttendee( const QString& /*cn*/, Role /*r*/, PartStat /*p*/,
 
421
                               bool /*rsvp*/, const QString& /*mailto*/ )
 
422
{
 
423
 
 
424
}
 
425
 
 
426
 
 
427
// I assume this is the same as the sender?
 
428
// U also assume that this is like "Name <address>"
 
429
void KTNEFWriter::setOrganizer( const QString& organizer ) {
 
430
  int i = organizer.indexOf( '<' );
 
431
 
 
432
  if ( i == -1 )
 
433
    return;
 
434
 
 
435
  QString name = organizer.left( i );
 
436
  name.trimmed();
 
437
 
 
438
  QString email = organizer.right( i+1 );
 
439
  email = email.left( email.length()-1 );
 
440
  email.trimmed();
 
441
 
 
442
  setSender( name, email );
 
443
}
 
444
 
 
445
 
 
446
void KTNEFWriter::setDtStart( const QDateTime& dtStart ) {
 
447
  QVariant v( dtStart );
 
448
  addProperty( attDATESTART, atpDATE, v );
 
449
}
 
450
 
 
451
 
 
452
void KTNEFWriter::setDtEnd( const QDateTime& dtEnd ) {
 
453
  QVariant v( dtEnd );
 
454
  addProperty( attDATEEND, atpDATE, v );
 
455
}
 
456
 
 
457
 
 
458
void KTNEFWriter::setLocation( const QString& /*location*/ )
 
459
{
 
460
 
 
461
}
 
462
 
 
463
 
 
464
void KTNEFWriter::setUID( const QString& uid ) {
 
465
  QVariant v( uid );
 
466
  addProperty( attMSGID, atpSTRING, v );
 
467
}
 
468
 
 
469
 
 
470
// Date sent
 
471
void KTNEFWriter::setDtStamp( const QDateTime& dtStamp ) {
 
472
  QVariant v( dtStamp );
 
473
  addProperty( attDATESENT, atpDATE, v );
 
474
}
 
475
 
 
476
 
 
477
void KTNEFWriter::setCategories( const QStringList& )
 
478
{
 
479
 
 
480
}
 
481
 
 
482
 
 
483
// I hope this is the body
 
484
void KTNEFWriter::setDescription( const QString &body ) {
 
485
  QVariant v( body );
 
486
  addProperty( attBODY, atpTEXT, v );
 
487
}
 
488
 
 
489
 
 
490
void KTNEFWriter::setSummary( const QString &s ) {
 
491
  QVariant v( s );
 
492
  addProperty( attSUBJECT, atpSTRING, v );
 
493
}
 
494
 
 
495
// TNEF encoding: Normal =  3, high = 2, low = 1
 
496
// MAPI encoding: Normal = -1, high = 0, low = 1
 
497
void KTNEFWriter::setPriority( Priority p ) {
 
498
  QVariant v( (quint32)p );
 
499
  addProperty( attMSGPRIORITY, atpSHORT, v );
 
500
}
 
501
 
 
502
 
 
503
void KTNEFWriter::setAlarm( const QString& /*description*/, AlarmAction /*action*/,
 
504
                            const QDateTime& /*wakeBefore*/ )
 
505
{
 
506
 
 
507
}