summaryrefslogtreecommitdiffstats
path: root/ktnef
diff options
context:
space:
mode:
Diffstat (limited to 'ktnef')
-rw-r--r--ktnef/AUTHORS2
-rw-r--r--ktnef/Makefile.am5
-rw-r--r--ktnef/configure.in.in3
-rw-r--r--ktnef/gui/Makefile.am26
-rw-r--r--ktnef/gui/attachpropertydialog.cpp187
-rw-r--r--ktnef/gui/attachpropertydialog.h51
-rw-r--r--ktnef/gui/attachpropertydialogbase.ui281
-rw-r--r--ktnef/gui/ktnef.desktop109
-rw-r--r--ktnef/gui/ktnefmain.cpp409
-rw-r--r--ktnef/gui/ktnefmain.h81
-rw-r--r--ktnef/gui/ktnefui.rc36
-rw-r--r--ktnef/gui/ktnefview.cpp136
-rw-r--r--ktnef/gui/ktnefview.h52
-rw-r--r--ktnef/gui/main.cpp57
-rw-r--r--ktnef/gui/messagepropertydialog.cpp46
-rw-r--r--ktnef/gui/messagepropertydialog.h40
-rw-r--r--ktnef/gui/metafuncs.h90
-rw-r--r--ktnef/gui/ms-tnef.desktop62
-rw-r--r--ktnef/gui/pics/Makefile.am4
-rw-r--r--ktnef/gui/pics/hi22-action-ktnef_extract_all_to.pngbin0 -> 1110 bytes
-rw-r--r--ktnef/gui/pics/hi22-action-ktnef_extract_to.pngbin0 -> 1207 bytes
-rw-r--r--ktnef/gui/pics/hi48-app-ktnef.pngbin0 -> 4799 bytes
-rw-r--r--ktnef/gui/pics/lo16-action-ktnef_extract_all_to.pngbin0 -> 361 bytes
-rw-r--r--ktnef/gui/pics/lo16-action-ktnef_extract_to.pngbin0 -> 419 bytes
-rw-r--r--ktnef/gui/pics/lo16-app-ktnef.pngbin0 -> 465 bytes
-rw-r--r--ktnef/gui/pics/lo32-app-ktnef.pngbin0 -> 737 bytes
-rw-r--r--ktnef/gui/qwmf.cpp1258
-rw-r--r--ktnef/gui/qwmf.h228
-rw-r--r--ktnef/gui/wmfstruct.h107
-rw-r--r--ktnef/ktnef/Makefile.am4
-rw-r--r--ktnef/ktnef/ktnefattach.h70
-rw-r--r--ktnef/ktnef/ktnefdefs.h256
-rw-r--r--ktnef/ktnef/ktnefmessage.h44
-rw-r--r--ktnef/ktnef/ktnefparser.h58
-rw-r--r--ktnef/ktnef/ktnefproperty.h63
-rw-r--r--ktnef/ktnef/ktnefpropertyset.h54
-rw-r--r--ktnef/ktnef/ktnefwriter.h92
-rw-r--r--ktnef/lib/Makefile.am11
-rw-r--r--ktnef/lib/ktnefattach.cpp127
-rw-r--r--ktnef/lib/ktnefmessage.cpp82
-rw-r--r--ktnef/lib/ktnefparser.cpp883
-rw-r--r--ktnef/lib/ktnefproperty.cpp99
-rw-r--r--ktnef/lib/ktnefpropertyset.cpp155
-rw-r--r--ktnef/lib/ktnefwriter.cpp497
-rw-r--r--ktnef/lib/lzfu.cpp178
-rw-r--r--ktnef/lib/lzfu.h25
-rw-r--r--ktnef/lib/mapi.cpp222
-rw-r--r--ktnef/lib/mapi.h26
-rw-r--r--ktnef/tests/Makefile.am10
-rw-r--r--ktnef/tests/README1
-rw-r--r--ktnef/tests/mapi_attach_data_obj.tnefbin0 -> 348479 bytes
-rw-r--r--ktnef/tests/one-file.tnefbin0 -> 2272 bytes
-rw-r--r--ktnef/tests/parsertest.cpp104
-rw-r--r--ktnef/tests/parsertest.h32
-rw-r--r--ktnef/tests/two-files.tnefbin0 -> 3481 bytes
55 files changed, 6363 insertions, 0 deletions
diff --git a/ktnef/AUTHORS b/ktnef/AUTHORS
new file mode 100644
index 000000000..dfb1b0df6
--- /dev/null
+++ b/ktnef/AUTHORS
@@ -0,0 +1,2 @@
+Michael Goffioul <kdeprint@swing.be>
+ - Main developer
diff --git a/ktnef/Makefile.am b/ktnef/Makefile.am
new file mode 100644
index 000000000..e181c0636
--- /dev/null
+++ b/ktnef/Makefile.am
@@ -0,0 +1,5 @@
+SUBDIRS = ktnef lib gui tests
+
+messages: rc.cpp
+ $(EXTRACTRC) gui/*.rc gui/*.ui >> rc.cpp
+ $(XGETTEXT) rc.cpp gui/*.cpp lib/*.cpp -o $(podir)/ktnef.pot
diff --git a/ktnef/configure.in.in b/ktnef/configure.in.in
new file mode 100644
index 000000000..1f4b03854
--- /dev/null
+++ b/ktnef/configure.in.in
@@ -0,0 +1,3 @@
+AC_CHECK_SIZEOF(unsigned long long)
+AC_CHECK_SIZEOF(unsigned long)
+AC_CHECK_SIZEOF(uint64_t)
diff --git a/ktnef/gui/Makefile.am b/ktnef/gui/Makefile.am
new file mode 100644
index 000000000..1a9674610
--- /dev/null
+++ b/ktnef/gui/Makefile.am
@@ -0,0 +1,26 @@
+INCLUDES = -I$(top_srcdir)/ktnef $(all_includes)
+
+SUBDIRS = pics
+
+bin_PROGRAMS = ktnef
+
+ktnef_LDFLAGS = $(KDE_RPATH) $(all_libraries)
+ktnef_LDADD = $(LIB_KFILE) $(top_builddir)/ktnef/lib/libktnef.la
+ktnef_SOURCES = ktnefmain.cpp ktnefview.cpp attachpropertydialogbase.ui \
+ attachpropertydialog.cpp messagepropertydialog.cpp \
+ qwmf.cpp main.cpp
+ktnef_METASOURCES = AUTO
+
+noinst_HEADERS = ktnefmain.h ktnefview.h attachpropertydialog.h \
+ qwmf.h wmfstruct.h metafuncs.h
+
+rcdir = $(kde_datadir)/ktnef
+rc_DATA = ktnefui.rc
+
+#messages: rc.cpp
+# $(XGETTEXT) -C -ki18n -x $(includedir)/kde.pot $(ktnef_SOURCES) && mv messages.po ../po/ktnef.pot
+
+xdg_apps_DATA = ktnef.desktop
+
+mime_DATA = ms-tnef.desktop
+mimedir = $(kde_mimedir)/application
diff --git a/ktnef/gui/attachpropertydialog.cpp b/ktnef/gui/attachpropertydialog.cpp
new file mode 100644
index 000000000..8675b6baa
--- /dev/null
+++ b/ktnef/gui/attachpropertydialog.cpp
@@ -0,0 +1,187 @@
+/*
+ attachpropertydialog.cpp
+
+ Copyright (C) 2002 Michael Goffioul <kdeprint@swing.be>
+
+ This file is part of KTNEF, the KDE TNEF support library/program.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "attachpropertydialog.h"
+#include <ktnef/ktnefattach.h>
+#include <ktnef/ktnefproperty.h>
+#include <ktnef/ktnefpropertyset.h>
+#include <ktnef/ktnefdefs.h>
+#include "qwmf.h"
+
+#include <qlabel.h>
+#include <klistview.h>
+#include <kmimetype.h>
+#include <kdebug.h>
+#include <klocale.h>
+#include <kmessagebox.h>
+#include <kfiledialog.h>
+#include <qbuffer.h>
+#include <qdatastream.h>
+#include <qpicture.h>
+
+AttachPropertyDialog::AttachPropertyDialog(QWidget *parent, const char *name)
+ : AttachPropertyDialogBase(parent, name, true)
+{
+}
+
+AttachPropertyDialog::~AttachPropertyDialog()
+{
+}
+
+void AttachPropertyDialog::setAttachment(KTNEFAttach *attach)
+{
+ QString s = (attach->fileName().isEmpty() ? attach->name() : attach->fileName());
+ filename_->setText("<b>"+s+"</b>");
+ setCaption(s);
+ display_->setText(attach->displayName());
+ mime_->setText(attach->mimeTag());
+ s.setNum(attach->size());
+ s.append(" bytes");
+ size_->setText(s);
+ KMimeType::Ptr mimetype = KMimeType::mimeType(attach->mimeTag());
+ QPixmap pix = loadRenderingPixmap( attach, colorGroup().background() );
+ if ( !pix.isNull() )
+ icon_->setPixmap( pix );
+ else
+ icon_->setPixmap(mimetype->pixmap(KIcon::Small));
+ description_->setText(mimetype->comment());
+ s.setNum(attach->index());
+ index_->setText(s);
+
+ formatPropertySet( attach, properties_ );
+ m_attach = attach;
+}
+
+void AttachPropertyDialog::saveClicked()
+{
+ saveProperty( properties_, m_attach, this );
+}
+
+void formatProperties( const QMap<int,KTNEFProperty*>& props, QListView *lv, QListViewItem *item, const QString& prefix )
+{
+ for ( QMap<int,KTNEFProperty*>::ConstIterator it=props.begin(); it!=props.end(); ++it )
+ {
+ QListViewItem *newItem = 0;
+ if ( lv )
+ newItem = new QListViewItem( lv, ( *it )->keyString() );
+ else if ( item )
+ newItem = new QListViewItem( item, ( *it )->keyString() );
+ else
+ {
+ kdWarning() << "formatProperties() called with no listview and no item" << endl;
+ return;
+ }
+
+ QVariant value = ( *it )->value();
+ if ( value.type() == QVariant::List )
+ {
+ newItem->setOpen( true );
+ newItem->setText( 0, newItem->text( 0 ) + " [" + QString::number( value.asList().count() ) + "]" );
+ int i = 0;
+ for ( QValueList<QVariant>::ConstIterator lit=value.listBegin(); lit!=value.listEnd(); ++lit, i++ )
+ new QListViewItem( newItem, "[" + QString::number( i ) + "]", KTNEFProperty::formatValue( *lit ) );
+ }
+ else if ( value.type() == QVariant::DateTime )
+ newItem->setText( 1, value.asDateTime().toString() );
+ else
+ {
+ newItem->setText( 1, ( *it )->valueString() );
+ newItem->setText( 2, prefix + "_" + QString::number( it.key() ) );
+ }
+ }
+}
+
+void formatPropertySet( KTNEFPropertySet *pSet, QListView *lv )
+{
+ formatProperties( pSet->properties(), lv, 0, "prop" );
+ QListViewItem *item = new QListViewItem( lv, i18n( "TNEF Attributes" ) );
+ item->setOpen( true );
+ formatProperties( pSet->attributes(), 0, item, "attr" );
+}
+
+void saveProperty( QListView *lv, KTNEFPropertySet *pSet, QWidget *parent )
+{
+ QListViewItem *item = lv->selectedItem();
+ if ( !item )
+ KMessageBox::error( parent, i18n( "Select an item." ) );
+ else if ( item->text( 2 ).isEmpty() )
+ KMessageBox::error( parent, i18n( "The selected item cannot be saved." ) );
+ else
+ {
+ QString tag = item->text( 2 );
+ int key = tag.mid( 5 ).toInt();
+ QVariant prop = ( tag.startsWith( "attr_" ) ? pSet->attribute( key ) : pSet->property( key ) );
+ QString filename = KFileDialog::getSaveFileName( tag, QString::null, parent );
+ if ( !filename.isEmpty() )
+ {
+ QFile f( filename );
+ if ( f.open( IO_WriteOnly ) )
+ {
+ switch ( prop.type() )
+ {
+ case QVariant::ByteArray:
+ f.writeBlock( prop.asByteArray().data(), prop.asByteArray().size() );
+ break;
+ default:
+ {
+ QTextStream t( &f );
+ t << prop.toString();
+ break;
+ }
+ }
+ f.close();
+ }
+ else
+ KMessageBox::error( parent, i18n( "Unable to open file for writing, check file permissions." ) );
+ }
+ }
+}
+
+QPixmap loadRenderingPixmap( KTNEFPropertySet *pSet, const QColor& bgColor )
+{
+ QPixmap pix;
+ QVariant rendData = pSet->attribute( attATTACHRENDDATA ), wmf = pSet->attribute( attATTACHMETAFILE );
+ if ( !rendData.isNull() && !wmf.isNull() )
+ {
+ // Get rendering size
+ QBuffer rendBuffer( rendData.asByteArray() );
+ rendBuffer.open( IO_ReadOnly );
+ QDataStream rendStream( &rendBuffer );
+ rendStream.setByteOrder( QDataStream::LittleEndian );
+ Q_UINT16 type, w, h;
+ rendStream >> type >> w >> w; // read type and skip 4 bytes
+ rendStream >> w >> h;
+ rendBuffer.close();
+
+ if ( type == 1 && w > 0 && h > 0 )
+ {
+ // Load WMF data
+ QWinMetaFile wmfLoader;
+ QBuffer wmfBuffer( wmf.asByteArray() );
+ wmfBuffer.open( IO_ReadOnly );
+ wmfLoader.setBbox( QRect( 0, 0, w, h ) );
+ if ( wmfLoader.load( wmfBuffer ) )
+ {
+ pix.resize( w, h );
+ pix.fill( bgColor );
+ wmfLoader.paint( &pix );
+ }
+ wmfBuffer.close();
+ }
+ }
+ return pix;
+}
diff --git a/ktnef/gui/attachpropertydialog.h b/ktnef/gui/attachpropertydialog.h
new file mode 100644
index 000000000..a731572eb
--- /dev/null
+++ b/ktnef/gui/attachpropertydialog.h
@@ -0,0 +1,51 @@
+/*
+ attachpropertydialog.h
+
+ Copyright (C) 2002 Michael Goffioul <kdeprint@swing.be>
+
+ This file is part of KTNEF, the KDE TNEF support library/program.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef ATTACHPROPERTYDLG_H
+#define ATTACHPROPERTYDLG_H
+
+#include "attachpropertydialogbase.h"
+#include <qmap.h>
+#include <qpixmap.h>
+
+class KTNEFAttach;
+class KTNEFProperty;
+class KTNEFPropertySet;
+class QListView;
+class QListViewItem;
+
+class AttachPropertyDialog : public AttachPropertyDialogBase
+{
+public:
+ AttachPropertyDialog(QWidget *parent = 0, const char *name = 0);
+ ~AttachPropertyDialog();
+
+ void setAttachment(KTNEFAttach *attach);
+
+protected slots:
+ void saveClicked();
+
+private:
+ KTNEFAttach *m_attach;
+};
+
+void formatProperties( const QMap<int,KTNEFProperty*>&, QListView*, QListViewItem*, const QString& = "prop" );
+void formatPropertySet( KTNEFPropertySet*, QListView* );
+void saveProperty( QListView*, KTNEFPropertySet*, QWidget* );
+QPixmap loadRenderingPixmap( KTNEFPropertySet*, const QColor& );
+
+#endif
diff --git a/ktnef/gui/attachpropertydialogbase.ui b/ktnef/gui/attachpropertydialogbase.ui
new file mode 100644
index 000000000..0d68c3ac4
--- /dev/null
+++ b/ktnef/gui/attachpropertydialogbase.ui
@@ -0,0 +1,281 @@
+<!DOCTYPE UI><UI version="3.1" stdsetdef="1">
+<class>AttachPropertyDialogBase</class>
+<widget class="QDialog">
+ <property name="name">
+ <cstring>AttachPropertyDialogBase</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>376</width>
+ <height>426</height>
+ </rect>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>11</number>
+ </property>
+ <property name="spacing">
+ <number>6</number>
+ </property>
+ <widget class="QLabel" row="1" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>display_</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>description_</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>mime_</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>size_</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="QLabel" row="5" column="1" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>index_</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ </widget>
+ <widget class="Line" row="6" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>Line2</cstring>
+ </property>
+ <property name="frameShape">
+ <enum>HLine</enum>
+ </property>
+ <property name="frameShadow">
+ <enum>Sunken</enum>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>displayLabel_</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>1</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="text">
+ <string>Comment:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>descriptionLabel_</cstring>
+ </property>
+ <property name="text">
+ <string>Description:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>mimeLabel_</cstring>
+ </property>
+ <property name="text">
+ <string>Mime type:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="4" column="0">
+ <property name="name">
+ <cstring>sizeLabel_</cstring>
+ </property>
+ <property name="text">
+ <string>File size:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="5" column="0">
+ <property name="name">
+ <cstring>indexLabel_</cstring>
+ </property>
+ <property name="text">
+ <string>Index:</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>filename_</cstring>
+ </property>
+ <property name="sizePolicy">
+ <sizepolicy>
+ <hsizetype>3</hsizetype>
+ <vsizetype>1</vsizetype>
+ <horstretch>0</horstretch>
+ <verstretch>0</verstretch>
+ </sizepolicy>
+ </property>
+ <property name="textFormat">
+ <enum>RichText</enum>
+ </property>
+ </widget>
+ <widget class="QLabel" row="0" column="2">
+ <property name="name">
+ <cstring>icon_</cstring>
+ </property>
+ <property name="minimumSize">
+ <size>
+ <width>16</width>
+ <height>16</height>
+ </size>
+ </property>
+ </widget>
+ <widget class="KListView" row="7" column="0" rowspan="1" colspan="3">
+ <column>
+ <property name="text">
+ <string>Name</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string>Value</string>
+ </property>
+ <property name="clickable">
+ <bool>true</bool>
+ </property>
+ <property name="resizable">
+ <bool>true</bool>
+ </property>
+ </column>
+ <property name="name">
+ <cstring>properties_</cstring>
+ </property>
+ <property name="allColumnsShowFocus">
+ <bool>true</bool>
+ </property>
+ <property name="resizeMode">
+ <enum>AllColumns</enum>
+ </property>
+ </widget>
+ <widget class="QLayoutWidget" row="8" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>layout2</cstring>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <spacer>
+ <property name="name">
+ <cstring>Spacer1</cstring>
+ </property>
+ <property name="orientation">
+ <enum>Horizontal</enum>
+ </property>
+ <property name="sizeType">
+ <enum>Expanding</enum>
+ </property>
+ <property name="sizeHint">
+ <size>
+ <width>150</width>
+ <height>20</height>
+ </size>
+ </property>
+ </spacer>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>save_</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Save</string>
+ </property>
+ </widget>
+ <widget class="QPushButton">
+ <property name="name">
+ <cstring>close_</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Close</string>
+ </property>
+ <property name="default">
+ <bool>true</bool>
+ </property>
+ </widget>
+ </hbox>
+ </widget>
+ </grid>
+</widget>
+<connections>
+ <connection>
+ <sender>close_</sender>
+ <signal>clicked()</signal>
+ <receiver>AttachPropertyDialogBase</receiver>
+ <slot>accept()</slot>
+ </connection>
+ <connection>
+ <sender>save_</sender>
+ <signal>clicked()</signal>
+ <receiver>AttachPropertyDialogBase</receiver>
+ <slot>saveClicked()</slot>
+ </connection>
+</connections>
+<slots>
+ <slot access="protected">saveClicked()</slot>
+</slots>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>klistview.h</includehint>
+</includehints>
+</UI>
diff --git a/ktnef/gui/ktnef.desktop b/ktnef/gui/ktnef.desktop
new file mode 100644
index 000000000..b2d75f8de
--- /dev/null
+++ b/ktnef/gui/ktnef.desktop
@@ -0,0 +1,109 @@
+[Desktop Entry]
+Name=KTnef
+Name[sv]=Ktnef
+GenericName=TNEF File Viewer
+GenericName[af]=TNEF lêer leser
+GenericName[bg]=Преглед на файлове TNEF
+GenericName[br]=Gweler restr TNEF
+GenericName[ca]=Visor de fitxers TNEF
+GenericName[cs]=ProhlížeÄ TNEF souborů
+GenericName[cy]=Syllwr Ffeil TNEF
+GenericName[da]=TNEF Fil-fremviser
+GenericName[de]=TNEF-Dateibetrachter
+GenericName[el]=ΠÏοβολέας αÏχείων TNEF
+GenericName[eo]=TNEF-dosierorigardilo
+GenericName[es]=Visor de archivos TNEF
+GenericName[et]=TNEF-failide näitaja
+GenericName[eu]=TNEF fitxategi ikustailea
+GenericName[fa]=مشاهده‌گر پروندۀ TNEF
+GenericName[fi]=TNEF-tiedostonäytin
+GenericName[fr]=Afficheur de fichiers TNEF
+GenericName[fy]=TNEF-triemwerjefte
+GenericName[ga]=Amharcán Comhad TNEF
+GenericName[gl]=Visor de Ficheiros TNEF
+GenericName[hu]=TNEF-fájlnézegető
+GenericName[is]=TNEF skráarskoðari
+GenericName[it]=Visualizzatore file TNEF
+GenericName[ja]=TNEF ファイルビュー
+GenericName[ka]=TNEF ფáƒáƒ˜áƒšáƒ”ბის დáƒáƒ›áƒ—ვáƒáƒšáƒ˜áƒ”რებელი
+GenericName[kk]=TNEF файлды қарау құралы
+GenericName[km]=កម្មវិធី​មើល​ឯកសារ TNEF
+GenericName[lt]=TNEF bylų žiūryklė
+GenericName[mk]=Прегледувач на TNEF-датотеки
+GenericName[ms]=Pemapar Fail TNEF
+GenericName[nb]=TNEF-filvisning
+GenericName[nds]=TNEF-Dateikieker
+GenericName[ne]=TNEF फाइल दरà¥à¤¶à¤•
+GenericName[nl]=TNEF-bestandsweergave
+GenericName[nn]=TNEF filvisar
+GenericName[pl]=Przeglądarka plików TNEF
+GenericName[pt]=Visualizador de Ficheiros TNEF
+GenericName[pt_BR]=Visualizador de Arquivos TNEF
+GenericName[ru]=ПроÑмотр файлов TNEF
+GenericName[sk]=PrehliadaÄ súborov TNEF
+GenericName[sl]=Pregledovalnik datotek TNEF
+GenericName[sr]=Приказивач TNEF фајлова
+GenericName[sr@Latn]=PrikazivaÄ TNEF fajlova
+GenericName[sv]=TNEF-filvisning
+GenericName[ta]=TNEF கோபà¯à®ªà¯ காடà¯à®šà®¿à®¯à®¾à®³à®©à¯
+GenericName[tr]=TNEF Dosya Göstericisi
+GenericName[uk]=ПереглÑдач файлів TNEF
+GenericName[zh_CN]=TNEF 文件查看器
+GenericName[zh_TW]=TNEF 檔案檢視器
+Exec=ktnef %i %m -caption "%c"
+Icon=ktnef
+Type=Application
+DocPath=ktnef/index.html
+Comment=A viewer/extractor for TNEF files
+Comment[af]='n Leeser en data onttrekker vir TNEF lêers
+Comment[bg]=Програма за преглед и извличане на файлове TNEF
+Comment[bs]=Preglednik/ekstraktor za TNEF datoteke
+Comment[ca]=Un visor/extractor per a fitxers TNEF
+Comment[cs]=ProhlížeÄ TNEF souborů
+Comment[cy]=Gwelydd/echdynnydd i ffeiliau TNEF
+Comment[da]=En fremviser/udpakker for TNEF-filer
+Comment[de]=Betrachten und Extrahieren von TNEF-Dateien
+Comment[el]=Ένας Ï€Ïοβολέας/εξαγωγέας για αÏχεία TNEF
+Comment[es]=A visor/extractor para archivos TNEF
+Comment[et]=TNEF-failide näitaja/ekstraktija
+Comment[eu]=TNEF fitxategien ikustaile/erauzlea
+Comment[fa]=یک مشاهده‌گر/استخراج‌گر برای پرونده‌های TNEF
+Comment[fi]=Näytin/purkaja TNEF-tiedostoille
+Comment[fr]=Pour afficher / extraire des fichiers TNEF
+Comment[fy]=In werjefteprogramma/útpakker foar TNEF-triemmen
+Comment[gl]=Un visor/extractor para ficheiros TNEF
+Comment[hi]=टीà¤à¤¨à¤ˆà¤à¤« फ़ाइलों के लिठà¤à¤• पà¥à¤°à¤¦à¤°à¥à¤¶à¤•/à¤à¤•à¥à¤¸à¤Ÿà¥à¤°à¥‡à¤•à¥à¤Ÿà¤°
+Comment[hr]=PrikazivaÄ/izdvajaÄ za TNEF datoteke
+Comment[hu]=Nézegetőprogram TNEF-fájlokhoz
+Comment[is]=Sýnir/lesari fyrir TNEF skrár
+Comment[it]=Un visualizzatore/estrattore di file TNEF
+Comment[ja]=TNEF ファイルã®ãŸã‚ã®ãƒ“ューア/展開ツール
+Comment[ka]= TNEF ფáƒáƒ˜áƒšáƒ”ბის ექსტრáƒáƒ¥áƒ¢áƒáƒ áƒ˜/დáƒáƒ›áƒ—ვáƒáƒšáƒ˜áƒ”რებელი
+Comment[kk]=TNEF файдарды қарау/тарқату
+Comment[km]=កម្មវិធី​មើល និង​ស្រង់​ឯកសារ TNEF
+Comment[lt]=TNEF bylų žiūryklė - išpakuotojas
+Comment[ms]=Pemapar/pengekstrak untuk fail TNEF
+Comment[nb]=En utpakker/fremviser for TNEF-filer
+Comment[nds]=TNEF-Dateien ankieken un Delen ruttrecken
+Comment[ne]=TNEF फाइलका लागि दरà¥à¤¶à¤•/निषà¥à¤•à¤¾à¤¸à¤•
+Comment[nl]=Een weergaveprogramma/uitpakker voor TNEF-bestanden
+Comment[nn]=Ein framvisar/utpakkar for TNEF-filer
+Comment[pl]=Przeglądarka/program wyciągający zawartość plików TNEF
+Comment[pt]=Um visualizador/extractor de ficheiros TNEF
+Comment[pt_BR]=Um visualizador/extrator para arquivos TNEF
+Comment[ro]=Un vizualizor/extractor pentru fiÅŸiere TNEF
+Comment[ru]=ПроÑмотр и раÑпаковка файлов TNEF
+Comment[sk]=PrehliadaÄ/extraktor pre TNEF súbory
+Comment[sl]=Pregledovalnik/izvleÄevalnik za datoteke TNEF
+Comment[sr]=Приказивач/издвајач за TNEF фајлове
+Comment[sr@Latn]=PrikazivaÄ/izdvajaÄ za TNEF fajlove
+Comment[sv]=Visning och uppackning av TNEF-filer
+Comment[ta]=TNEF கோபà¯à®ªà¯à®•à®³à¯à®•à¯à®•à®¾à®© காடà¯à®šà®¿à®¯à®•à®®à¯/பிரிதà¯à®¤à¯†à®Ÿà¯à®ªà¯à®ªà®¾à®³à®°à¯
+Comment[tg]=Ðамоиш ва боз кардани файлҳои TNEF
+Comment[tr]=TNEF dosyaları için gösterici/çıkarıcı
+Comment[uk]=ПереглÑдач/розпаковувач файлів TNEF
+Comment[zh_CN]=TNEF 文件的查看/æå–器
+Comment[zh_TW]=TNEF 檔案檢視器
+Terminal=false
+MimeType=application/ms-tnef;
+Categories=Qt;KDE;X-KDE-Utilities-PIM;Office;Network;Email;
diff --git a/ktnef/gui/ktnefmain.cpp b/ktnef/gui/ktnefmain.cpp
new file mode 100644
index 000000000..a31d40161
--- /dev/null
+++ b/ktnef/gui/ktnefmain.cpp
@@ -0,0 +1,409 @@
+/*
+ ktnefmain.cpp
+
+ Copyright (C) 2002 Michael Goffioul <kdeprint@swing.be>
+
+ This file is part of KTNEF, the KDE TNEF support library/program.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <kdebug.h>
+#include "ktnefmain.h"
+#include <ktnef/ktnefparser.h>
+#include "ktnefview.h"
+#include <ktnef/ktnefattach.h>
+#include <ktnef/ktnefproperty.h>
+#include <ktnef/ktnefmessage.h>
+#include "attachpropertydialog.h"
+#include "messagepropertydialog.h"
+
+#include <qpopupmenu.h>
+#include <klistview.h>
+#include <klocale.h>
+#include <kapplication.h>
+#include <kiconloader.h>
+#include <qpixmap.h>
+#include <kstdaccel.h>
+#include <qmessagebox.h>
+#include <kfiledialog.h>
+#include <qdir.h>
+#include <kprocess.h>
+#include <kglobal.h>
+#include <kstandarddirs.h>
+#include <kaction.h>
+#include <kstdaction.h>
+#include <kdialogbase.h>
+#include <ktempfile.h>
+#include <kkeydialog.h>
+
+#ifdef KDE_NO_COMPAT
+#undef KDE_NO_COMPAT
+#endif
+
+#include <krun.h>
+#include <kopenwith.h>
+#include <kedittoolbar.h>
+#include <kstatusbar.h>
+#include <kurldrag.h>
+
+
+#define NOT_IMPLEMENTED QMessageBox::information(this, "ktnef", "Not implemented yet", QMessageBox::Ok|QMessageBox::Default, 0)
+
+KTNEFMain::KTNEFMain(QWidget *parent, const char *name)
+ : KMainWindow(parent, name)
+{
+ setupActions();
+ setupStatusbar();
+
+ setupTNEF();
+
+ KGlobal::config()->setGroup("Settings");
+ defaultdir_ = KGlobal::config()->readPathEntry("defaultdir", "/tmp/");
+ lastdir_ = defaultdir_;
+
+ // create personale temo extract dir
+ KStandardDirs::makeDir(KGlobal::dirs()->localkdedir() + "/share/apps/ktnef/tmp");
+
+ resize(430,350);
+ setAutoSaveSettings( "MainWindow" );
+}
+
+KTNEFMain::~KTNEFMain()
+{
+ delete parser_;
+ cleanup();
+}
+
+void KTNEFMain::setupActions()
+{
+ // File menu
+ KStdAction::open(this, SLOT(openFile()), actionCollection());
+ KStdAction::quit(kapp, SLOT(quit()), actionCollection());
+
+ // Action menu
+ new KAction(i18n("View"), QString("viewmag"), 0, this, SLOT(viewFile()), actionCollection(), "view_file");
+ new KAction(i18n("View With..."), QString("package_applications"), 0, this, SLOT(viewFileAs()), actionCollection(), "view_file_as");
+ new KAction(i18n("Extract"), 0, this, SLOT(extractFile()), actionCollection(), "extract_file");
+ new KAction(i18n("Extract To..."), QString("ktnef_extract_to"), 0, this, SLOT(extractFileTo()), actionCollection(), "extract_file_to");
+ new KAction(i18n("Extract All To..."), QString("ktnef_extract_all_to"), 0, this, SLOT(extractAllFiles()), actionCollection(), "extract_all_files");
+ new KAction( i18n( "Message Properties" ), "help", 0, this, SLOT( slotShowMessageProperties() ), actionCollection(), "msg_properties" );
+ new KAction(i18n("Properties"), QString("contents"), 0, this, SLOT(propertiesFile()), actionCollection(), "properties_file");
+ new KAction( i18n( "Show Message Text" ), "mail_generic", 0, this, SLOT( slotShowMessageText() ), actionCollection(), "msg_text" );
+ new KAction( i18n( "Save Message Text As..." ), "filesave", 0, this, SLOT( slotSaveMessageText() ), actionCollection(), "msg_save" );
+ actionCollection()->action("view_file")->setEnabled(false);
+ actionCollection()->action("view_file_as")->setEnabled(false);
+ actionCollection()->action("extract_file")->setEnabled(false);
+ actionCollection()->action("extract_file_to")->setEnabled(false);
+ actionCollection()->action("extract_all_files")->setEnabled(false);
+ actionCollection()->action("properties_file")->setEnabled(false);
+
+ // Option menu
+ new KAction(i18n("Default Folder..."), QString("folder_open"), 0, this, SLOT(optionDefaultDir()), actionCollection(), "options_default_dir");
+
+ createStandardStatusBarAction();
+ setStandardToolBarMenuEnabled(true);
+ KStdAction::configureToolbars(this, SLOT(slotEditToolbars()), actionCollection());
+ KStdAction::keyBindings( this, SLOT( slotConfigureKeys() ), actionCollection() );
+
+ createGUI();
+}
+
+void KTNEFMain::slotConfigureKeys()
+{
+ KKeyDialog::configure( actionCollection(), this );
+}
+
+
+void KTNEFMain::setupStatusbar()
+{
+ statusBar()->insertItem(i18n("100 attachments found"), 0);
+ statusBar()->changeItem(i18n("No file loaded"), 0);
+}
+
+void KTNEFMain::setupTNEF()
+{
+ view_ = new KTNEFView(this);
+ view_->setAllColumnsShowFocus( true );
+ parser_ = new KTNEFParser;
+
+ setCentralWidget(view_);
+ connect(view_, SIGNAL(selectionChanged()), SLOT(viewSelectionChanged()));
+ connect(view_, SIGNAL(rightButtonPressed(QListViewItem*,const QPoint&,int)), SLOT(viewRightButtonPressed(QListViewItem*,const QPoint&,int)));
+ connect(view_, SIGNAL(doubleClicked(QListViewItem*)), SLOT(viewDoubleClicked(QListViewItem*)));
+ connect(view_, SIGNAL(dragRequested(const QValueList<KTNEFAttach*>&)), SLOT(viewDragRequested(const QValueList<KTNEFAttach*>&)));
+}
+
+void KTNEFMain::loadFile(const QString& filename)
+{
+ filename_ = filename;
+ setCaption(filename_);
+ if (!parser_->openFile(filename))
+ {
+ QMessageBox::critical(this, i18n("Error"), i18n("Unable to open file."), QMessageBox::Ok|QMessageBox::Default, 0);
+ view_->setAttachments(0);
+ enableExtractAll(false);
+ }
+ else
+ {
+ QPtrList<KTNEFAttach> list = parser_->message()->attachmentList();
+ QString msg;
+ msg = i18n( "%n attachment found", "%n attachments found", list.count() );
+ statusBar()->changeItem(msg, 0);
+ view_->setAttachments(&list);
+ enableExtractAll((list.count() > 0));
+ enableSingleAction(false);
+ }
+}
+
+void KTNEFMain::openFile()
+{
+ QString filename = KFileDialog::getOpenFileName(0,0,this,0);
+ if (!filename.isEmpty()) loadFile(filename);
+}
+
+void KTNEFMain::viewFile()
+{
+ KTNEFAttach *attach = view_->getSelection()->first();
+ KURL url("file:"+extractTemp(attach));
+ QString mimename(attach->mimeTag());
+
+ if (mimename.isEmpty() || mimename == "application/octet-stream")
+ {
+ kdDebug() << "No mime type found in attachment object, trying to guess..." << endl;
+ mimename = KMimeType::findByURL(url, 0, true)->name();
+ kdDebug() << "Detected mime type: " << mimename << endl;
+ }
+ else
+ kdDebug() << "Mime type from attachment object: " << mimename << endl;
+
+ KRun::runURL(url, mimename);
+}
+
+QString KTNEFMain::extractTemp(KTNEFAttach *att)
+{
+ QString dir = KGlobal::dirs()->localkdedir() + "/share/apps/ktnef/tmp/";
+ parser_->extractFileTo(att->name(), dir);
+ dir.append(att->name());
+ return dir;
+}
+
+void KTNEFMain::viewFileAs()
+{
+ KURL::List list;
+ list.append(KURL::fromPathOrURL( extractTemp(view_->getSelection()->first()) ));
+
+ KRun::displayOpenWithDialog(list);
+}
+
+void KTNEFMain::extractFile()
+{
+ extractTo(defaultdir_);
+}
+
+void KTNEFMain::extractFileTo()
+{
+ QString dir = KFileDialog::getExistingDirectory(lastdir_, this);
+ if (!dir.isEmpty())
+ {
+ extractTo(dir);
+ lastdir_ = dir;
+ }
+}
+
+void KTNEFMain::extractAllFiles()
+{
+ QString dir = KFileDialog::getExistingDirectory(lastdir_, this);
+ if (!dir.isEmpty())
+ {
+ lastdir_ = dir;
+ dir.append("/");
+ QPtrList<KTNEFAttach> list = parser_->message()->attachmentList();
+ QPtrListIterator<KTNEFAttach> it(list);
+ for (;it.current();++it)
+ if (!parser_->extractFileTo(it.current()->name(), dir))
+ {
+ QString msg = i18n( "Unable to extract file \"%1\"" ).arg( it.current()->name() );
+ QMessageBox::critical(this,i18n("Error"),msg,QMessageBox::Ok|QMessageBox::Default,0);
+ return;
+ }
+ }
+}
+
+void KTNEFMain::propertiesFile()
+{
+ KTNEFAttach *attach = view_->getSelection()->first();
+ AttachPropertyDialog dlg(this);
+ dlg.setAttachment(attach);
+ dlg.exec();
+}
+
+void KTNEFMain::optionDefaultDir()
+{
+ QString dirname = KFileDialog::getExistingDirectory(defaultdir_, this);
+ if (!dirname.isEmpty())
+ {
+ defaultdir_ = dirname;
+ KGlobal::config()->setGroup("Settings");
+ KGlobal::config()->writePathEntry("defaultdir",defaultdir_);
+ }
+}
+
+void KTNEFMain::viewSelectionChanged()
+{
+ QPtrList<KTNEFAttach> *list = view_->getSelection();
+ bool on1 = (list->count() == 1u), on2 = (list->count() > 0u);
+ actionCollection()->action("view_file")->setEnabled(on1);
+ actionCollection()->action("view_file_as")->setEnabled(on1);
+ actionCollection()->action("properties_file")->setEnabled(on1);
+
+ actionCollection()->action("extract_file")->setEnabled(on2);
+ actionCollection()->action("extract_file_to")->setEnabled(on2);
+}
+
+void KTNEFMain::enableExtractAll(bool on)
+{
+ if (!on) enableSingleAction(false);
+ actionCollection()->action("extract_all_files")->setEnabled(on);
+}
+
+void KTNEFMain::enableSingleAction(bool on)
+{
+ actionCollection()->action("extract_file")->setEnabled(on);
+ actionCollection()->action("extract_file_to")->setEnabled(on);
+ actionCollection()->action("view_file")->setEnabled(on);
+ actionCollection()->action("view_file_as")->setEnabled(on);
+ actionCollection()->action("properties_file")->setEnabled(on);
+}
+
+void KTNEFMain::cleanup()
+{
+ QDir d(KGlobal::dirs()->localkdedir() + "/share/apps/ktnef/tmp/");
+ const QFileInfoList *list = d.entryInfoList(QDir::Files|QDir::Hidden,QDir::Unsorted);
+ QFileInfoListIterator it(*list);
+ for (;it.current();++it)
+ d.remove(it.current()->absFilePath());
+}
+
+void KTNEFMain::extractTo(const QString& dirname)
+{
+ QString dir = dirname;
+ if (dir.right(1) != "/") dir.append("/");
+ QPtrList<KTNEFAttach> *list = view_->getSelection();
+ QPtrListIterator<KTNEFAttach> it(*list);
+ for (;it.current();++it)
+ if (!parser_->extractFileTo(it.current()->name(), dir))
+ {
+ QString msg = i18n("Unable to extract file \"%1\"").arg( it.current()->name() );
+ QMessageBox::critical(this,i18n("Error"),msg,QMessageBox::Ok|QMessageBox::Default,0);
+ return;
+ }
+}
+
+/* This breaks the saveMainWindowSettings stuff....
+ void KTNEFMain::closeEvent(QCloseEvent *e)
+{
+ e->accept();
+}*/
+
+void KTNEFMain::viewRightButtonPressed(QListViewItem*, const QPoint& p, int)
+{
+ QPtrList<KTNEFAttach> *list = view_->getSelection();
+ QPopupMenu m;
+ if (list->count() > 0u)
+ {
+ if (list->count() == 1u)
+ {
+ m.insertItem(SmallIcon("viewmag"), i18n("View"), this, SLOT(viewFile()));
+ m.insertItem(SmallIcon("package_applications"), i18n("View With..."), this, SLOT(viewFileAs()));
+ m.insertSeparator();
+ }
+ m.insertItem(i18n("Extract"), this, SLOT(extractFile()));
+ m.insertItem(SmallIcon("ktnef_extract_to"), i18n("Extract To..."), this, SLOT(extractFileTo()));
+ if (list->count() == 1u)
+ {
+ m.insertSeparator();
+ m.insertItem(SmallIcon("contents"), i18n("Properties"), this, SLOT(propertiesFile()));
+ }
+ }
+ else if ( list->count() == 0 )
+ actionCollection()->action( "msg_properties" )->plug( &m );
+ m.exec( p );
+}
+
+void KTNEFMain::viewDoubleClicked(QListViewItem *item)
+{
+ if (item && item->isSelected())
+ viewFile();
+}
+
+void KTNEFMain::viewDragRequested( const QValueList<KTNEFAttach*>& list )
+{
+ KURL::List urlList;
+ for ( QValueList<KTNEFAttach*>::ConstIterator it=list.constBegin(); it!=list.constEnd(); ++it )
+ urlList << KURL( extractTemp( *it ) );
+ if ( !list.isEmpty() )
+ {
+ KURLDrag *urlDrag = new KURLDrag( urlList, this );
+ urlDrag->dragCopy();
+ }
+}
+
+void KTNEFMain::slotEditToolbars()
+{
+ saveMainWindowSettings( KGlobal::config(), QString::fromLatin1("MainWindow") );
+ KEditToolbar dlg(actionCollection());
+ connect(&dlg, SIGNAL( newToolbarConfig() ), this, SLOT( slotNewToolbarConfig() ));
+ dlg.exec();
+}
+
+void KTNEFMain::slotNewToolbarConfig()
+{
+ createGUI();
+ applyMainWindowSettings( KGlobal::config(), QString::fromLatin1("MainWindow") );
+}
+
+void KTNEFMain::slotShowMessageProperties()
+{
+ MessagePropertyDialog dlg( this, parser_->message() );
+ dlg.exec();
+}
+
+void KTNEFMain::slotShowMessageText()
+{
+ QString rtf = parser_->message()->rtfString();
+ qDebug( "%s", rtf.latin1() );
+ KTempFile tmpFile( KGlobal::dirs()->localkdedir() + "/share/apps/ktnef/tmp/", "rtf");
+ *( tmpFile.textStream() ) << rtf;
+ tmpFile.close();
+
+ KRun::runURL( KURL::fromPathOrURL( tmpFile.name() ), "text/rtf", true );
+}
+
+void KTNEFMain::slotSaveMessageText()
+{
+ QString rtf = parser_->message()->rtfString();
+ QString filename = KFileDialog::getSaveFileName( QString::null, QString::null, this );
+ if ( !filename.isEmpty() )
+ {
+ QFile f( filename );
+ if ( f.open( IO_WriteOnly ) )
+ {
+ QTextStream t( &f );
+ t << rtf;
+ }
+ else
+ QMessageBox::critical( this, i18n( "Error" ),
+ i18n( "Unable to open file for writing, check file permissions." ),
+ QMessageBox::Ok|QMessageBox::Default, 0);
+ }
+}
+
+#include "ktnefmain.moc"
diff --git a/ktnef/gui/ktnefmain.h b/ktnef/gui/ktnefmain.h
new file mode 100644
index 000000000..30f5a171f
--- /dev/null
+++ b/ktnef/gui/ktnefmain.h
@@ -0,0 +1,81 @@
+/*
+ ktnefmain.h
+
+ Copyright (C) 2002 Michael Goffioul <kdeprint@swing.be>
+
+ This file is part of KTNEF, the KDE TNEF support library/program.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef KTNEFMAIN_H
+#define KTNEFMAIN_H
+
+#include <kmainwindow.h>
+#include <qstring.h>
+#include <qlistview.h>
+
+class KTNEFView;
+class KTNEFParser;
+class KTNEFAttach;
+
+class KTNEFMain : public KMainWindow
+{
+ Q_OBJECT
+
+public:
+ KTNEFMain(QWidget *parent = 0, const char *name = 0);
+ ~KTNEFMain();
+
+ void loadFile(const QString& filename);
+
+protected slots:
+ void openFile();
+ void viewFile();
+ void viewFileAs();
+ void extractFile();
+ void extractFileTo();
+ void propertiesFile();
+ void optionDefaultDir();
+ void extractAllFiles();
+ void slotEditToolbars();
+ void slotNewToolbarConfig();
+ void slotShowMessageProperties();
+ void slotShowMessageText();
+ void slotSaveMessageText();
+
+ void viewSelectionChanged();
+ void viewRightButtonPressed(QListViewItem *item, const QPoint& p, int c);
+ void viewDoubleClicked(QListViewItem*);
+ void viewDragRequested( const QValueList<KTNEFAttach*>& list );
+ void slotConfigureKeys();
+//protected:
+// void closeEvent(QCloseEvent *e);
+
+private:
+ void setupStatusbar();
+ void setupActions();
+ void setupTNEF();
+ void enableExtractAll(bool on = true);
+ void enableSingleAction(bool on = true);
+ void cleanup();
+
+ void extractTo(const QString& dirname);
+ QString extractTemp(KTNEFAttach *att);
+
+private:
+ KTNEFView *view_;
+ KTNEFParser *parser_;
+ QString filename_;
+ QString defaultdir_;
+ QString lastdir_;
+};
+
+#endif
diff --git a/ktnef/gui/ktnefui.rc b/ktnef/gui/ktnefui.rc
new file mode 100644
index 000000000..c08cf1366
--- /dev/null
+++ b/ktnef/gui/ktnefui.rc
@@ -0,0 +1,36 @@
+<!DOCTYPE kpartgui>
+<kpartgui name="kups" version="2">
+<MenuBar>
+ <Menu name="action"><text>&amp;Action</text>
+ <Action name="view_file" />
+ <Action name="view_file_as" />
+ <Separator/>
+ <Action name="extract_file" />
+ <Action name="extract_file_to" />
+ <Separator/>
+ <Action name="extract_all_files" />
+ <Separator/>
+ <Action name="properties_file" />
+ <Separator/>
+ <Action name="msg_properties" />
+ <Action name="msg_text" />
+ <Action name="msg_save" />
+ </Menu>
+ <Menu name="settings"><text>&amp;Settings</text>
+ <Action name="options_default_dir" append="save_merge"/>
+ </Menu>
+</MenuBar>
+<ToolBar name="mainToolBar" noMerge="1">
+ <text>Main Toolbar</text>
+ <Action name="file_open" />
+ <Separator/>
+ <Action name="view_file" />
+ <Action name="properties_file" />
+ <Separator/>
+ <Action name="extract_file_to" />
+ <Action name="extract_all_files" />
+ <Separator/>
+ <Action name="msg_properties" />
+ <Action name="msg_text" />
+</ToolBar>
+</kpartgui>
diff --git a/ktnef/gui/ktnefview.cpp b/ktnef/gui/ktnefview.cpp
new file mode 100644
index 000000000..abee5a73b
--- /dev/null
+++ b/ktnef/gui/ktnefview.cpp
@@ -0,0 +1,136 @@
+/*
+ ktnefview.cpp
+
+ Copyright (C) 2002 Michael Goffioul <kdeprint@swing.be>
+
+ This file is part of KTNEF, the KDE TNEF support library/program.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "ktnefview.h"
+#include <ktnef/ktnefattach.h>
+#include "attachpropertydialog.h"
+
+#include <qheader.h>
+#include <qpixmap.h>
+#include <qtimer.h>
+
+#include <kapplication.h>
+#include <kiconloader.h>
+#include <klocale.h>
+#include <kdebug.h>
+
+#include <kmimetype.h>
+
+class Attachment : public QListViewItem
+{
+public:
+ Attachment(QListView *parent, KTNEFAttach *attach);
+ ~Attachment();
+
+ KTNEFAttach* getAttachment() const { return attach_; }
+
+private:
+ KTNEFAttach *attach_;
+};
+
+Attachment::Attachment(QListView *parent, KTNEFAttach *attach)
+ : QListViewItem(parent, attach->name()), attach_(attach)
+{
+ setText(2, QString::number( attach_->size() ));
+ if (!attach_->fileName().isEmpty()) setText(0, attach_->fileName());
+ KMimeType::Ptr mimeType = KMimeType::mimeType( attach_->mimeTag() );
+ setText(1, mimeType->comment());
+ QPixmap pix = loadRenderingPixmap( attach, parent->colorGroup().base() );
+ if ( !pix.isNull() )
+ setPixmap( 0, pix );
+ else
+ setPixmap(0, mimeType->pixmap(KIcon::Small));
+ setDragEnabled( true );
+}
+
+Attachment::~Attachment()
+{
+}
+
+//------------------------------------------------------------------------------------------------------
+
+KTNEFView::KTNEFView(QWidget *parent, const char *name)
+ : KListView(parent,name)
+{
+ attachments_.setAutoDelete(false);
+ addColumn(i18n("File Name"));
+ addColumn(i18n("File Type"));
+ addColumn(i18n("Size"));
+ setFrameStyle(QFrame::WinPanel|QFrame::Sunken);
+ setLineWidth(1);
+ setSelectionMode(QListView::Extended);
+ setHScrollBarMode(QScrollView::AlwaysOff);
+ setVScrollBarMode(QScrollView::AlwaysOn);
+ QTimer::singleShot( 0, this, SLOT(adjustColumnWidth()) );
+}
+
+KTNEFView::~KTNEFView()
+{
+}
+
+void KTNEFView::setAttachments(QPtrList<KTNEFAttach> *list)
+{
+ clear();
+ if (list)
+ {
+ QPtrListIterator<KTNEFAttach> it(*list);
+ for (;it.current();++it)
+ new Attachment(this, it.current());
+ }
+}
+
+void KTNEFView::resizeEvent(QResizeEvent *e)
+{
+ adjustColumnWidth();
+ resizeContents(visibleWidth(),visibleHeight());
+ if (e) QListView::resizeEvent(e);
+}
+
+QPtrList<KTNEFAttach>* KTNEFView::getSelection()
+{
+ attachments_.clear();
+ QListViewItem *item = firstChild();
+ while (item)
+ {
+ if (item->isSelected()) attachments_.append(((Attachment*)item)->getAttachment());
+ item = item->nextSibling();
+ }
+ return &attachments_;
+}
+
+void KTNEFView::startDrag()
+{
+ QListViewItemIterator it( this, QListViewItemIterator::Selected );
+ QValueList<KTNEFAttach*> list;
+ while ( it.current() )
+ {
+ list << static_cast<Attachment*>( it.current() )->getAttachment();
+ ++it;
+ }
+ if ( !list.isEmpty() )
+ emit dragRequested( list );
+}
+
+void KTNEFView::adjustColumnWidth()
+{
+ int w = visibleWidth()/2;
+ setColumnWidth(0,w);
+ setColumnWidth(1,w/2);
+ setColumnWidth(2,w/2);
+}
+
+#include "ktnefview.moc"
diff --git a/ktnef/gui/ktnefview.h b/ktnef/gui/ktnefview.h
new file mode 100644
index 000000000..00c49b7c7
--- /dev/null
+++ b/ktnef/gui/ktnefview.h
@@ -0,0 +1,52 @@
+/*
+ ktnefview.h
+
+ Copyright (C) 2002 Michael Goffioul <kdeprint@swing.be>
+
+ This file is part of KTNEF, the KDE TNEF support library/program.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef KTNEFWIDGET_H
+#define KTNEFWIDGET_H
+
+#include <klistview.h>
+#include <qptrlist.h>
+#include <kdepimmacros.h>
+
+class KTNEFAttach;
+
+class KDE_EXPORT KTNEFView : public KListView
+{
+ Q_OBJECT
+
+public:
+ KTNEFView(QWidget *parent = 0, const char *name = 0);
+ ~KTNEFView();
+
+ void setAttachments(QPtrList<KTNEFAttach> *list);
+ QPtrList<KTNEFAttach>* getSelection();
+
+signals:
+ void dragRequested( const QValueList<KTNEFAttach*>& list );
+
+protected:
+ void resizeEvent(QResizeEvent *e);
+ void startDrag();
+
+private slots:
+ void adjustColumnWidth();
+
+private:
+ QPtrList<KTNEFAttach> attachments_;
+};
+
+#endif
diff --git a/ktnef/gui/main.cpp b/ktnef/gui/main.cpp
new file mode 100644
index 000000000..e975630df
--- /dev/null
+++ b/ktnef/gui/main.cpp
@@ -0,0 +1,57 @@
+/*
+ main.cpp
+
+ Copyright (C) 2002 Michael Goffioul <kdeprint@swing.be>
+
+ This file is part of KTNEF, the KDE TNEF support library/program.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include <kcmdlineargs.h>
+#include <kaboutdata.h>
+#include <klocale.h>
+#include <kapplication.h>
+
+#include "ktnefmain.h"
+
+static const char description[] =
+ I18N_NOOP("Viewer for mail attachments using TNEF format");
+
+
+static KCmdLineOptions options[] =
+{
+ { "+[file]", I18N_NOOP("An optional argument 'file'"), 0 },
+ KCmdLineLastOption
+ // INSERT YOUR COMMANDLINE OPTIONS HERE
+};
+
+int main(int argc, char *argv[])
+{
+
+ KAboutData aboutData( "ktnef", I18N_NOOP("KTnef"),
+ "1.0", description, KAboutData::License_GPL,
+ "(c) 2000, Michael Goffioul");
+ aboutData.addAuthor("Michael Goffioul",0, "kdeprint@swing.be");
+ KCmdLineArgs::init( argc, argv, &aboutData );
+ KCmdLineArgs::addCmdLineOptions( options ); // Add our own options.
+ KApplication::addCmdLineOptions();
+
+ KApplication a;
+ KTNEFMain *tnef = new KTNEFMain();
+ a.setMainWidget(tnef);
+ tnef->show();
+
+ KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
+ if (args->count() > 0)
+ tnef->loadFile(args->arg(0));
+
+ return a.exec();
+}
diff --git a/ktnef/gui/messagepropertydialog.cpp b/ktnef/gui/messagepropertydialog.cpp
new file mode 100644
index 000000000..0e098c35c
--- /dev/null
+++ b/ktnef/gui/messagepropertydialog.cpp
@@ -0,0 +1,46 @@
+/*
+ messagepropertydialog.cpp
+
+ Copyright (C) 2003 Michael Goffioul <kdeprint@swing.be>
+
+ This file is part of KTNEF, the KDE TNEF support library/program.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "messagepropertydialog.h"
+#include "attachpropertydialog.h"
+#include "ktnef/ktnefmessage.h"
+
+#include <klistview.h>
+#include <klocale.h>
+
+MessagePropertyDialog::MessagePropertyDialog( QWidget *parent, KTNEFMessage *msg )
+ : KDialogBase( parent, "MessagePropertyDialog", true, i18n( "Message Properties" ),
+ KDialogBase::Close|KDialogBase::User1, KDialogBase::Close, false,
+ KStdGuiItem::save() )
+{
+ m_message = msg;
+
+ m_listview = new KListView( this );
+ m_listview->addColumn( i18n( "Name" ) );
+ m_listview->addColumn( i18n( "Value" ) );
+ m_listview->setAllColumnsShowFocus( true );
+ setMainWidget( m_listview );
+
+ formatPropertySet( m_message, m_listview );
+}
+
+void MessagePropertyDialog::slotUser1()
+{
+ saveProperty( m_listview, m_message, this );
+}
+
+#include "messagepropertydialog.moc"
diff --git a/ktnef/gui/messagepropertydialog.h b/ktnef/gui/messagepropertydialog.h
new file mode 100644
index 000000000..7b357b716
--- /dev/null
+++ b/ktnef/gui/messagepropertydialog.h
@@ -0,0 +1,40 @@
+/*
+ messagepropertydialog.h
+
+ Copyright (C) 2003 Michael Goffioul <kdeprint@swing.be>
+
+ This file is part of KTNEF, the KDE TNEF support library/program.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef MESSAGEPROPERTYDIALOG_H
+#define MESSAGEPROPERTYDIALOG_H
+
+#include <kdialogbase.h>
+
+class KListView;
+class KTNEFMessage;
+
+class MessagePropertyDialog : public KDialogBase
+{
+ Q_OBJECT
+public:
+ MessagePropertyDialog( QWidget *parent, KTNEFMessage *msg );
+
+protected slots:
+ void slotUser1();
+
+private:
+ KTNEFMessage *m_message;
+ KListView *m_listview;
+};
+
+#endif /* MESSAGEPROPERTYDIALOG_H */
diff --git a/ktnef/gui/metafuncs.h b/ktnef/gui/metafuncs.h
new file mode 100644
index 000000000..8675851e0
--- /dev/null
+++ b/ktnef/gui/metafuncs.h
@@ -0,0 +1,90 @@
+/* WMF Metafile Function Description Table
+ * Author: Stefan Taferner <taferner@kde.org>
+ */
+#ifndef metafunc_h
+#define metafunc_h
+
+class QWinMetaFile;
+
+static const struct MetaFuncRec
+{
+ const char* name;
+ unsigned short func;
+ void ( QWinMetaFile::*method )( long, short* );
+} metaFuncTab[] =
+ {
+ { "SETBKCOLOR", 0x0201, &QWinMetaFile::setBkColor },
+ { "SETBKMODE", 0x0102, &QWinMetaFile::setBkMode },
+ { "SETMAPMODE", 0x0103, &QWinMetaFile::noop },
+ { "SETROP2", 0x0104, &QWinMetaFile::setRop },
+ { "SETRELABS", 0x0105, &QWinMetaFile::noop },
+ { "SETPOLYFILLMODE", 0x0106, &QWinMetaFile::setPolyFillMode },
+ { "SETSTRETCHBLTMODE", 0x0107, &QWinMetaFile::noop },
+ { "SETTEXTCHAREXTRA", 0x0108, &QWinMetaFile::noop },
+ { "SETTEXTCOLOR", 0x0209, &QWinMetaFile::setTextColor },
+ { "SETTEXTJUSTIFICATION", 0x020A, &QWinMetaFile::noop },
+ { "SETWINDOWORG", 0x020B, &QWinMetaFile::setWindowOrg },
+ { "SETWINDOWEXT", 0x020C, &QWinMetaFile::setWindowExt },
+ { "SETVIEWPORTORG", 0x020D, &QWinMetaFile::noop },
+ { "SETVIEWPORTEXT", 0x020E, &QWinMetaFile::noop },
+ { "OFFSETWINDOWORG", 0x020F, &QWinMetaFile::noop },
+ { "SCALEWINDOWEXT", 0x0410, &QWinMetaFile::noop },
+ { "OFFSETVIEWPORTORG", 0x0211, &QWinMetaFile::noop },
+ { "SCALEVIEWPORTEXT", 0x0412, &QWinMetaFile::noop },
+ { "LINETO", 0x0213, &QWinMetaFile::lineTo },
+ { "MOVETO", 0x0214, &QWinMetaFile::moveTo },
+ { "EXCLUDECLIPRECT", 0x0415, &QWinMetaFile::excludeClipRect },
+ { "INTERSECTCLIPRECT", 0x0416, &QWinMetaFile::intersectClipRect },
+ { "ARC", 0x0817, &QWinMetaFile::arc },
+ { "ELLIPSE", 0x0418, &QWinMetaFile::ellipse },
+ { "FLOODFILL", 0x0419, &QWinMetaFile::noop },
+ { "PIE", 0x081A, &QWinMetaFile::pie },
+ { "RECTANGLE", 0x041B, &QWinMetaFile::rectangle },
+ { "ROUNDRECT", 0x061C, &QWinMetaFile::roundRect },
+ { "PATBLT", 0x061D, &QWinMetaFile::noop },
+ { "SAVEDC", 0x001E, &QWinMetaFile::saveDC },
+ { "SETPIXEL", 0x041F, &QWinMetaFile::setPixel },
+ { "OFFSETCLIPRGN", 0x0220, &QWinMetaFile::noop },
+ { "TEXTOUT", 0x0521, &QWinMetaFile::textOut },
+ { "BITBLT", 0x0922, &QWinMetaFile::noop },
+ { "STRETCHBLT", 0x0B23, &QWinMetaFile::noop },
+ { "POLYGON", 0x0324, &QWinMetaFile::polygon },
+ { "POLYLINE", 0x0325, &QWinMetaFile::polyline },
+ { "ESCAPE", 0x0626, &QWinMetaFile::noop },
+ { "RESTOREDC", 0x0127, &QWinMetaFile::restoreDC },
+ { "FILLREGION", 0x0228, &QWinMetaFile::noop },
+ { "FRAMEREGION", 0x0429, &QWinMetaFile::noop },
+ { "INVERTREGION", 0x012A, &QWinMetaFile::noop },
+ { "PAINTREGION", 0x012B, &QWinMetaFile::noop },
+ { "SELECTCLIPREGION", 0x012C, &QWinMetaFile::noop },
+ { "SELECTOBJECT", 0x012D, &QWinMetaFile::selectObject },
+ { "SETTEXTALIGN", 0x012E, &QWinMetaFile::setTextAlign },
+ { "CHORD", 0x0830, &QWinMetaFile::chord },
+ { "SETMAPPERFLAGS", 0x0231, &QWinMetaFile::noop },
+ { "EXTTEXTOUT", 0x0a32, &QWinMetaFile::extTextOut },
+ { "SETDIBTODEV", 0x0d33, &QWinMetaFile::noop },
+ { "SELECTPALETTE", 0x0234, &QWinMetaFile::noop },
+ { "REALIZEPALETTE", 0x0035, &QWinMetaFile::noop },
+ { "ANIMATEPALETTE", 0x0436, &QWinMetaFile::noop },
+ { "SETPALENTRIES", 0x0037, &QWinMetaFile::noop },
+ { "POLYPOLYGON", 0x0538, &QWinMetaFile::polyPolygon },
+ { "RESIZEPALETTE", 0x0139, &QWinMetaFile::noop },
+ { "DIBBITBLT", 0x0940, &QWinMetaFile::dibBitBlt },
+ { "DIBSTRETCHBLT", 0x0b41, &QWinMetaFile::dibStretchBlt },
+ { "DIBCREATEPATTERNBRUSH", 0x0142, &QWinMetaFile::dibCreatePatternBrush },
+ { "STRETCHDIB", 0x0f43, &QWinMetaFile::stretchDib },
+ { "EXTFLOODFILL", 0x0548, &QWinMetaFile::noop },
+ { "DELETEOBJECT", 0x01f0, &QWinMetaFile::deleteObject },
+ { "CREATEPALETTE", 0x00f7, &QWinMetaFile::createEmptyObject },
+ { "CREATEPATTERNBRUSH", 0x01F9, &QWinMetaFile::createEmptyObject },
+ { "CREATEPENINDIRECT", 0x02FA, &QWinMetaFile::createPenIndirect },
+ { "CREATEFONTINDIRECT", 0x02FB, &QWinMetaFile::createFontIndirect },
+ { "CREATEBRUSHINDIRECT", 0x02FC, &QWinMetaFile::createBrushIndirect },
+ { "CREATEREGION", 0x06FF, &QWinMetaFile::createEmptyObject },
+ { "END", 0, &QWinMetaFile::end },
+ // always the latest in the table : in case of unknown function
+ { NULL, 0, &QWinMetaFile::noop },
+ };
+
+
+#endif /*metafunc_h*/
diff --git a/ktnef/gui/ms-tnef.desktop b/ktnef/gui/ms-tnef.desktop
new file mode 100644
index 000000000..309bd8cf5
--- /dev/null
+++ b/ktnef/gui/ms-tnef.desktop
@@ -0,0 +1,62 @@
+[Desktop Entry]
+Type=MimeType
+MimeType=application/ms-tnef
+Icon=tar
+Patterns=*.tnf;
+Comment=TNEF File
+Comment[af]=TNEF lêer
+Comment[be]=TNEF файл
+Comment[bg]=Файл TNEF
+Comment[br]=Restr TNEF
+Comment[bs]=TNEF datoteka
+Comment[ca]=Fitxer TNEF
+Comment[cs]=TNEF soubor
+Comment[cy]=Ffeil TNEF
+Comment[de]=TNEF-Datei
+Comment[el]=ΑÏχείο TNEF
+Comment[eo]=TNEF-dosiero
+Comment[es]=Archivo TNEF
+Comment[et]=TNEF-fail
+Comment[eu]=TNEF fitxategia
+Comment[fa]=پروندۀ TNEF
+Comment[fi]=TNEF-tiedosto
+Comment[fr]=Fichier TNEF
+Comment[fy]=TNEF-triem
+Comment[ga]=Comhad TNEF
+Comment[gl]=Ficheiro TNEF
+Comment[he]=קובץ TNEF
+Comment[hi]=टीà¤à¤¨à¤ˆà¤à¤« फ़ाइल
+Comment[hr]=TNEF datoteka
+Comment[hu]=TNEF-fájl
+Comment[is]=TNEF skrá
+Comment[it]=File TNEF
+Comment[ja]=TNEF ファイル
+Comment[ka]=TNEF ფáƒáƒ˜áƒšáƒ˜
+Comment[kk]=TNEF файлы
+Comment[km]=ឯកសារ TNEF
+Comment[lt]=TNEF byla
+Comment[mk]=TNEF-датотека
+Comment[ms]=Fail TNEF
+Comment[nb]=TNEF-fil
+Comment[nds]=TNEF-Datei
+Comment[ne]=TNEF फाइल
+Comment[nl]=TNEF-bestand
+Comment[nn]=TNEF-fil
+Comment[pl]=Plik TNEF
+Comment[pt]=Ficheiro TNEF
+Comment[pt_BR]=Arquivo TNEF
+Comment[ro]=FiÅŸier TNEF
+Comment[ru]=Файл TNEF
+Comment[sk]=TNEF súbor
+Comment[sl]=Datoteka TNEF
+Comment[sr]=TNEF фајл
+Comment[sr@Latn]=TNEF fajl
+Comment[sv]=TNEF-fil
+Comment[ta]=TNEF கோபà¯à®ªà¯
+Comment[tg]=Файли TNEF
+Comment[tr]=TNEF Dosyası
+Comment[uk]=Файл TNEF
+Comment[uz]=TNEF-fayli
+Comment[uz@cyrillic]=TNEF-файли
+Comment[zh_CN]=TNEF 文件
+Comment[zh_TW]=TNEF 檔案
diff --git a/ktnef/gui/pics/Makefile.am b/ktnef/gui/pics/Makefile.am
new file mode 100644
index 000000000..43938ee02
--- /dev/null
+++ b/ktnef/gui/pics/Makefile.am
@@ -0,0 +1,4 @@
+KDE_ICON = ktnef
+
+icons_ICON = ktnef_extract_all_to ktnef_extract_to
+iconsdir = $(kde_datadir)/ktnef/icons
diff --git a/ktnef/gui/pics/hi22-action-ktnef_extract_all_to.png b/ktnef/gui/pics/hi22-action-ktnef_extract_all_to.png
new file mode 100644
index 000000000..d49470a02
--- /dev/null
+++ b/ktnef/gui/pics/hi22-action-ktnef_extract_all_to.png
Binary files differ
diff --git a/ktnef/gui/pics/hi22-action-ktnef_extract_to.png b/ktnef/gui/pics/hi22-action-ktnef_extract_to.png
new file mode 100644
index 000000000..a52fb6af2
--- /dev/null
+++ b/ktnef/gui/pics/hi22-action-ktnef_extract_to.png
Binary files differ
diff --git a/ktnef/gui/pics/hi48-app-ktnef.png b/ktnef/gui/pics/hi48-app-ktnef.png
new file mode 100644
index 000000000..deee685e4
--- /dev/null
+++ b/ktnef/gui/pics/hi48-app-ktnef.png
Binary files differ
diff --git a/ktnef/gui/pics/lo16-action-ktnef_extract_all_to.png b/ktnef/gui/pics/lo16-action-ktnef_extract_all_to.png
new file mode 100644
index 000000000..8dc72abc6
--- /dev/null
+++ b/ktnef/gui/pics/lo16-action-ktnef_extract_all_to.png
Binary files differ
diff --git a/ktnef/gui/pics/lo16-action-ktnef_extract_to.png b/ktnef/gui/pics/lo16-action-ktnef_extract_to.png
new file mode 100644
index 000000000..c86449ae3
--- /dev/null
+++ b/ktnef/gui/pics/lo16-action-ktnef_extract_to.png
Binary files differ
diff --git a/ktnef/gui/pics/lo16-app-ktnef.png b/ktnef/gui/pics/lo16-app-ktnef.png
new file mode 100644
index 000000000..383df318b
--- /dev/null
+++ b/ktnef/gui/pics/lo16-app-ktnef.png
Binary files differ
diff --git a/ktnef/gui/pics/lo32-app-ktnef.png b/ktnef/gui/pics/lo32-app-ktnef.png
new file mode 100644
index 000000000..b566ff91d
--- /dev/null
+++ b/ktnef/gui/pics/lo32-app-ktnef.png
Binary files differ
diff --git a/ktnef/gui/qwmf.cpp b/ktnef/gui/qwmf.cpp
new file mode 100644
index 000000000..6a10cc006
--- /dev/null
+++ b/ktnef/gui/qwmf.cpp
@@ -0,0 +1,1258 @@
+/* Windows Meta File Loader/Painter Class Implementation
+ *
+ * Copyright ( C ) 1998 Stefan Taferner
+ * Modified 2002 thierry lorthiois
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or ( at your
+ * option ) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABLILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details. You should have received a copy
+ * of the GNU General Public License along with this program; if not, write
+ * to the Free Software Foundation, Inc, 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA.
+ */
+
+#include <math.h>
+#include <assert.h>
+#include <qfileinfo.h>
+#include <qpixmap.h>
+#include <qpainter.h>
+#include <qdatastream.h>
+#include <qapplication.h>
+#include <qbuffer.h>
+#include <kdebug.h>
+
+bool qwmfDebug = false;
+
+#include "qwmf.h"
+#include "wmfstruct.h"
+#include "metafuncs.h"
+
+#define QWMF_DEBUG 0
+
+
+class WmfCmd
+{
+public:
+ ~WmfCmd() { if ( next ) delete next; }
+ WmfCmd* next;
+ unsigned short funcIndex;
+ long numParm;
+ short* parm;
+};
+
+
+class WinObjHandle
+{
+public:
+ virtual void apply( QPainter& p ) = 0;
+};
+
+class WinObjBrushHandle: public WinObjHandle
+{
+public:
+ virtual void apply( QPainter& p );
+ QBrush brush;
+ virtual ~WinObjBrushHandle() {};
+};
+
+class WinObjPenHandle: public WinObjHandle
+{
+public:
+ virtual void apply( QPainter& p );
+ QPen pen;
+ virtual ~WinObjPenHandle() {};
+};
+
+class WinObjPatternBrushHandle: public WinObjHandle
+{
+public:
+ virtual void apply( QPainter& p );
+ QBrush brush;
+ QPixmap image;
+ virtual ~WinObjPatternBrushHandle() {};
+};
+
+class WinObjFontHandle: public WinObjHandle
+{
+public:
+ virtual void apply( QPainter& p );
+ QFont font;
+ int rotation;
+ virtual ~WinObjFontHandle() {};
+};
+
+void WinObjBrushHandle::apply( QPainter& p )
+{
+ p.setBrush( brush );
+}
+
+void WinObjPenHandle::apply( QPainter& p )
+{
+ p.setPen( pen );
+}
+
+void WinObjPatternBrushHandle::apply( QPainter& p )
+{
+ p.setBrush( brush );
+}
+
+void WinObjFontHandle::apply( QPainter& p )
+{
+ p.setFont( font );
+}
+
+#define MAX_OBJHANDLE 64
+
+
+
+//-----------------------------------------------------------------------------
+QWinMetaFile::QWinMetaFile()
+{
+ mValid = false;
+ mFirstCmd = NULL;
+ mObjHandleTab = NULL;
+ mDpi = 1000;
+}
+
+
+//-----------------------------------------------------------------------------
+QWinMetaFile::~QWinMetaFile()
+{
+ if ( mFirstCmd ) delete mFirstCmd;
+ if ( mObjHandleTab ) delete[] mObjHandleTab;
+}
+
+
+//-----------------------------------------------------------------------------
+bool QWinMetaFile::load( const QString &filename )
+{
+ QFile file( filename );
+
+ if ( !file.exists() )
+ {
+ kdDebug() << "File " << QFile::encodeName(filename) << " does not exist" << endl;
+ return false;
+ }
+
+ if ( !file.open( IO_ReadOnly ) )
+ {
+ kdDebug() << "Cannot open file " << QFile::encodeName(filename) << endl;
+ return false;
+ }
+
+ QByteArray ba = file.readAll();
+ file.close();
+
+ QBuffer buffer( ba );
+ buffer.open( IO_ReadOnly );
+ return load( buffer );
+}
+
+//-----------------------------------------------------------------------------
+bool QWinMetaFile::load( QBuffer &buffer )
+{
+ QDataStream st;
+ WmfEnhMetaHeader eheader;
+ WmfMetaHeader header;
+ WmfPlaceableHeader pheader;
+ WORD checksum;
+ int filePos, idx, i;
+ WmfCmd *cmd, *last;
+ DWORD rdSize;
+ WORD rdFunc;
+
+ mTextAlign = 0;
+ mRotation = 0;
+ mTextColor = Qt::black;
+ if ( mFirstCmd ) delete mFirstCmd;
+ mFirstCmd = NULL;
+
+ st.setDevice( &buffer );
+ st.setByteOrder( QDataStream::LittleEndian ); // Great, I love Qt !
+
+ //----- Read placeable metafile header
+ st >> pheader.key;
+ mIsPlaceable = ( pheader.key==( DWORD )APMHEADER_KEY );
+ if ( mIsPlaceable )
+ {
+ st >> pheader.hmf;
+ st >> pheader.bbox.left;
+ st >> pheader.bbox.top;
+ st >> pheader.bbox.right;
+ st >> pheader.bbox.bottom;
+ st >> pheader.inch;
+ st >> pheader.reserved;
+ st >> pheader.checksum;
+ checksum = calcCheckSum( &pheader );
+ if ( pheader.checksum!=checksum ) mIsPlaceable = false;
+
+ mDpi = pheader.inch;
+ mBBox.setLeft( pheader.bbox.left );
+ mBBox.setTop( pheader.bbox.top );
+ mBBox.setRight( pheader.bbox.right );
+ mBBox.setBottom( pheader.bbox.bottom );
+ mHeaderBoundingBox = mBBox;
+ if ( QWMF_DEBUG )
+ {
+ kdDebug() << endl << "-------------------------------------------------" << endl;
+ kdDebug() << "WMF Placeable Header ( " << static_cast<int>(sizeof( pheader ) ) << "):" << endl;
+ kdDebug() << " bbox=( " << mBBox.left() << "; " << mBBox.top() << "; " << mBBox.width()
+ << "; " << mBBox.height() << ")" << endl;
+ kdDebug() << " inch=" << pheader.inch << endl;
+ kdDebug() << " checksum=" << pheader.checksum << "( "
+ << (pheader.checksum==checksum?"ok":"wrong") << " )" << endl;
+ }
+ }
+ else buffer.at( 0 );
+
+ //----- Read as enhanced metafile header
+ filePos = buffer.at();
+ st >> eheader.iType;
+ st >> eheader.nSize;
+ st >> eheader.rclBounds.left;
+ st >> eheader.rclBounds.top;
+ st >> eheader.rclBounds.right;
+ st >> eheader.rclBounds.bottom;
+ st >> eheader.rclFrame.left;
+ st >> eheader.rclFrame.top;
+ st >> eheader.rclFrame.right;
+ st >> eheader.rclFrame.bottom;
+ st >> eheader.dSignature;
+ mIsEnhanced = ( eheader.dSignature==ENHMETA_SIGNATURE );
+ if ( mIsEnhanced ) // is it really enhanced ?
+ {
+ st >> eheader.nVersion;
+ st >> eheader.nBytes;
+ st >> eheader.nRecords;
+ st >> eheader.nHandles;
+ st >> eheader.sReserved;
+ st >> eheader.nDescription;
+ st >> eheader.offDescription;
+ st >> eheader.nPalEntries;
+ st >> eheader.szlDevice.width;
+ st >> eheader.szlDevice.height;
+ st >> eheader.szlMillimeters.width;
+ st >> eheader.szlMillimeters.height;
+
+ if ( QWMF_DEBUG )
+ {
+ kdDebug() << endl << "-------------------------------------------------" << endl;
+ kdDebug() << "WMF Extended Header:" << endl;
+ kdDebug() << " iType=" << eheader.iType << endl;
+ kdDebug() << " nSize=" << eheader.nSize << endl;
+ kdDebug() << " rclBounds=( " << eheader.rclBounds.left << "; " << eheader.rclBounds.top << "; "
+ << eheader.rclBounds.right << "; " << eheader.rclBounds.bottom << ")" << endl;
+ kdDebug() << " rclFrame=( " << eheader.rclFrame.left << "; " << eheader.rclFrame.top << "; "
+ << eheader.rclFrame.right << "; " << eheader.rclFrame.bottom << ")" << endl;
+ kdDebug() << " nBytes=" << eheader.nBytes << endl;
+ kdDebug() << "\nNOT YET IMPLEMENTED, SORRY." << endl;
+ }
+ }
+ else // no, not enhanced
+ {
+ //----- Read as standard metafile header
+ buffer.at( filePos );
+ st >> header.mtType;
+ st >> header.mtHeaderSize;
+ st >> header.mtVersion;
+ st >> header.mtSize;
+ st >> header.mtNoObjects;
+ st >> header.mtMaxRecord;
+ st >> header.mtNoParameters;
+ if ( QWMF_DEBUG ) {
+ kdDebug() << "WMF Header: " << "mtSize=" << header.mtSize << endl;
+ }
+ }
+
+ //----- Test header validity
+ mValid = ((header.mtHeaderSize == 9) && (header.mtNoParameters == 0)) || mIsEnhanced || mIsPlaceable;
+ if ( mValid )
+ {
+ //----- Read Metafile Records
+ last = NULL;
+ rdFunc = -1;
+ while ( !st.eof() && (rdFunc != 0) )
+ {
+ st >> rdSize;
+ st >> rdFunc;
+ idx = findFunc( rdFunc );
+ rdSize -= 3;
+
+ cmd = new WmfCmd;
+ cmd->next = NULL;
+ if ( last ) last->next = cmd;
+ else mFirstCmd = cmd;
+
+ cmd->funcIndex = idx;
+ cmd->numParm = rdSize;
+ cmd->parm = new WORD[ rdSize ];
+ last = cmd;
+
+ for ( i=0; i<rdSize && !st.eof(); i++ )
+ st >> cmd->parm[ i ];
+
+
+ if ( rdFunc == 0x020B ) { // SETWINDOWORG: dimensions
+ mBBox.setLeft( cmd->parm[ 1 ] );
+ mBBox.setTop( cmd->parm[ 0 ] );
+ }
+ if ( rdFunc == 0x020C ) { // SETWINDOWEXT: dimensions
+ mBBox.setWidth( cmd->parm[ 1 ] );
+ mBBox.setHeight( cmd->parm[ 0 ] );
+ }
+
+ if ( i<rdSize )
+ {
+ kdDebug() << "WMF : file truncated !" << endl;
+ return false;
+ }
+ }
+ //----- Test records validities
+ mValid = (rdFunc == 0) && (mBBox.width() != 0) && (mBBox.height() != 0);
+ if ( !mValid ) {
+ kdDebug() << "WMF : incorrect file format !" << endl;
+ }
+ }
+ else {
+ kdDebug() << "WMF Header : incorrect header !" << endl;
+ }
+
+ buffer.close();
+ return mValid;
+}
+
+
+//-----------------------------------------------------------------------------
+bool QWinMetaFile::paint( const QPaintDevice* aTarget, bool absolute )
+{
+ int idx, i;
+ WmfCmd* cmd;
+
+ if ( !mValid ) return false;
+
+ assert( aTarget!=NULL );
+ if ( mPainter.isActive() ) return false;
+
+ if ( mObjHandleTab ) delete[] mObjHandleTab;
+ mObjHandleTab = new WinObjHandle* [ MAX_OBJHANDLE ];
+ for ( i=MAX_OBJHANDLE-1; i>=0; i-- )
+ mObjHandleTab[ i ] = NULL;
+
+ mPainter.resetXForm();
+ mWinding = false;
+ mAbsoluteCoord = absolute;
+
+ mPainter.begin( aTarget );
+ if ( QWMF_DEBUG ) {
+ kdDebug() << "Bounding box : " << mBBox.left()
+ << " " << mBBox.top() << " " << mBBox.right() << " " << mBBox.bottom() << endl;
+ }
+
+ if ( mAbsoluteCoord ) {
+ mPainter.setWindow( mBBox.top(), mBBox.left(), mBBox.width(), mBBox.height() );
+ }
+ mInternalWorldMatrix.reset();
+
+ for ( cmd=mFirstCmd; cmd; cmd=cmd->next )
+ {
+ idx = cmd->funcIndex;
+ ( this->*metaFuncTab[ idx ].method )( cmd->numParm, cmd->parm );
+
+ if ( QWMF_DEBUG ) {
+ QString str = "", param;
+ if ( metaFuncTab[ idx ].name == NULL ) {
+ str += "UNKNOWN ";
+ }
+ if ( metaFuncTab[ idx ].method == &QWinMetaFile::noop ) {
+ str += "UNIMPLEMENTED ";
+ }
+ str += metaFuncTab[ idx ].name;
+ str += " : ";
+
+ for ( i=0 ; i < cmd->numParm ; i++ ) {
+ param.setNum( cmd->parm[ i ] );
+ str += param;
+ str += " ";
+ }
+ kdDebug() << str << endl;
+ }
+ }
+/*
+ // TODO: cleanup this code when QPicture::setBoundingBox() is possible in KOClipart (QT31)
+ // because actually QPicture::boundingBox() != mBBox()
+ mWindowsCoord += 1;
+ if ( mWindowsCoord == 2 ) {
+ kdDebug() << "DRAW ANGLES " << endl;
+ mPainter.setPen( Qt::white );
+ mPainter.drawPoint( mBBox.left(), mBBox.top() );
+ mPainter.drawPoint( mBBox.right(), mBBox.bottom() );
+ }
+*/
+ mPainter.end();
+ return true;
+}
+
+
+//----------------s-------------------------------------------------------------
+// Metafile painter methods
+//-----------------------------------------------------------------------------
+void QWinMetaFile::setWindowOrg( long, short* parm )
+{
+ if ( mAbsoluteCoord ) {
+ QRect r = mPainter.window();
+ mPainter.setWindow( parm[ 1 ], parm[ 0 ], r.width(), r.height() );
+ }
+ else {
+ double dx = mInternalWorldMatrix.dx();
+ double dy = mInternalWorldMatrix.dy();
+
+ mInternalWorldMatrix.translate( -dx, -dy );
+ mInternalWorldMatrix.translate( -parm[ 1 ], -parm[ 0 ] );
+ mPainter.translate( -dx, -dy );
+ mPainter.translate( -parm[ 1 ], -parm[ 0 ] );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+void QWinMetaFile::setWindowExt( long, short* parm )
+{
+ // negative value allowed for width and height : QABS() forbidden
+ if ( mAbsoluteCoord ) {
+ QRect r = mPainter.window();
+ mPainter.setWindow( r.left(), r.top(), parm[ 1 ], parm[ 0 ] );
+ }
+ else {
+ if ( (parm[ 0 ] != 0) && (parm[ 1 ] != 0) ) {
+ QRect r = mPainter.window();
+ double dx = mInternalWorldMatrix.dx();
+ double dy = mInternalWorldMatrix.dy();
+ double sx = mInternalWorldMatrix.m11();
+ double sy = mInternalWorldMatrix.m22();
+
+ mInternalWorldMatrix.translate( -dx, -dy );
+ mInternalWorldMatrix.scale( 1/sx, 1/sy );
+ mPainter.translate( -dx, -dy );
+ mPainter.scale( 1/sx, 1/sy );
+
+ sx = (double)r.width() / (double)parm[ 1 ];
+ sy = (double)r.height() / (double)parm[ 0 ];
+
+ mInternalWorldMatrix.scale( sx, sy );
+ mInternalWorldMatrix.translate( dx, dy );
+ mPainter.scale( sx, sy );
+ mPainter.translate( dx, dy );
+ }
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Drawing
+//-----------------------------------------------------------------------------
+void QWinMetaFile::lineTo( long, short* parm )
+{
+ mPainter.lineTo( parm[ 1 ], parm[ 0 ] );
+}
+
+
+//-----------------------------------------------------------------------------
+void QWinMetaFile::moveTo( long, short* parm )
+{
+ mPainter.moveTo( parm[ 1 ], parm[ 0 ] );
+}
+
+
+//-----------------------------------------------------------------------------
+void QWinMetaFile::ellipse( long, short* parm )
+{
+ mPainter.drawEllipse( parm[ 3 ], parm[ 2 ], parm[ 1 ]-parm[ 3 ], parm[ 0 ]-parm[ 2 ] );
+}
+
+
+//-----------------------------------------------------------------------------
+void QWinMetaFile::polygon( long, short* parm )
+{
+ QPointArray* pa;
+
+ pa = pointArray( parm[ 0 ], &parm[ 1 ] );
+ mPainter.drawPolygon( *pa, mWinding );
+}
+
+
+//-----------------------------------------------------------------------------
+void QWinMetaFile::polyPolygon( long, short* parm )
+{
+ QRegion region;
+ int i, j, startPolygon;
+
+ mPainter.save();
+
+ // define clipping region
+ QRect win = bbox();
+ startPolygon = 1+parm[ 0 ];
+ for ( i=0 ; i < parm[ 0 ] ; i++ ) {
+ QPointArray pa1( parm[ 1+i ] );
+ for ( j=0 ; j < parm[ 1+i ] ; j++) {
+ pa1.setPoint ( j, parm[ startPolygon ], parm[ startPolygon+1 ] );
+ startPolygon += 2;
+ }
+ QRegion r( pa1 );
+ region = region.eor( r );
+ }
+ mPainter.setClipRegion( region, QPainter::CoordPainter );
+
+ // fill polygons
+ mPainter.fillRect( win.left(), win.top(), win.width(), win.height(), mPainter.brush() );
+
+ // draw polygon's border if necessary
+ if ( mPainter.pen().style() != Qt::NoPen ) {
+ mPainter.setClipping( false );
+ mPainter.setBrush( Qt::NoBrush );
+
+ QPointArray* pa;
+ int idxPolygon = 1 + parm[ 0 ];
+ for ( i=0 ; i < parm[ 0 ] ; i++ ) {
+ pa = pointArray( parm[ 1+i ], &parm[ idxPolygon ] );
+ mPainter.drawPolygon( *pa );
+ idxPolygon += parm[ 1+i ] * 2;
+ }
+ }
+
+ mPainter.restore();
+}
+
+
+//-----------------------------------------------------------------------------
+void QWinMetaFile::polyline( long, short* parm )
+{
+ QPointArray* pa;
+
+ pa = pointArray( parm[ 0 ], &parm[ 1 ] );
+ mPainter.drawPolyline( *pa );
+}
+
+
+//-----------------------------------------------------------------------------
+void QWinMetaFile::rectangle( long, short* parm )
+{
+ mPainter.drawRect( parm[ 3 ], parm[ 2 ], parm[ 1 ]-parm[ 3 ], parm[ 0 ]-parm[ 2 ] );
+}
+
+
+//-----------------------------------------------------------------------------
+void QWinMetaFile::roundRect( long, short* parm )
+{
+ int xRnd = 0, yRnd = 0;
+
+ // convert (xRound, yRound) in percentage
+ if ( (parm[ 3 ] - parm[ 5 ]) != 0 )
+ xRnd = (parm[ 1 ] * 100) / (parm[ 3 ] - parm[ 5 ]) ;
+ if ( (parm[ 2 ] - parm[ 4 ]) != 0 )
+ yRnd = (parm[ 0 ] * 100) / (parm[ 2 ] - parm[ 4 ]) ;
+
+ mPainter.drawRoundRect( parm[ 5 ], parm[ 4 ], parm[ 3 ]-parm[ 5 ], parm[ 2 ]-parm[ 4 ], xRnd, yRnd );
+}
+
+
+//-----------------------------------------------------------------------------
+void QWinMetaFile::arc( long, short* parm )
+{
+ int xCenter, yCenter, angleStart, aLength;
+
+ xCenter = parm[ 7 ] + ((parm[ 5 ] - parm[ 7 ]) / 2);
+ yCenter = parm[ 6 ] + ((parm[ 4 ] - parm[ 6 ]) / 2);
+
+ xyToAngle ( parm[ 3 ] - xCenter, yCenter - parm[ 2 ], parm[ 1 ] - xCenter, yCenter - parm[ 0 ], angleStart, aLength );
+
+ mPainter.drawArc( parm[ 7 ], parm[ 6 ], parm[ 5 ]-parm[ 7 ], parm[ 4 ]-parm[ 6 ], angleStart, aLength);
+}
+
+
+//-----------------------------------------------------------------------------
+void QWinMetaFile::chord( long, short* parm )
+{
+ int xCenter, yCenter, angleStart, aLength;
+
+ xCenter = parm[ 7 ] + ((parm[ 5 ] - parm[ 7 ]) / 2);
+ yCenter = parm[ 6 ] + ((parm[ 4 ] - parm[ 6 ]) / 2);
+
+ xyToAngle ( parm[ 3 ] - xCenter, yCenter - parm[ 2 ], parm[ 1 ] - xCenter, yCenter - parm[ 0 ], angleStart, aLength );
+
+ mPainter.drawChord( parm[ 7 ], parm[ 6 ], parm[ 5 ]-parm[ 7 ], parm[ 4 ]-parm[ 6 ], angleStart, aLength);
+}
+
+
+//-----------------------------------------------------------------------------
+void QWinMetaFile::pie( long, short* parm )
+{
+ int xCenter, yCenter, angleStart, aLength;
+
+ xCenter = parm[ 7 ] + ((parm[ 5 ] - parm[ 7 ]) / 2);
+ yCenter = parm[ 6 ] + ((parm[ 4 ] - parm[ 6 ]) / 2);
+
+ xyToAngle ( parm[ 3 ] - xCenter, yCenter - parm[ 2 ], parm[ 1 ] - xCenter, yCenter - parm[ 0 ], angleStart, aLength );
+
+ mPainter.drawPie( parm[ 7 ], parm[ 6 ], parm[ 5 ]-parm[ 7 ], parm[ 4 ]-parm[ 6 ], angleStart, aLength);
+}
+
+
+//-----------------------------------------------------------------------------
+void QWinMetaFile::setPolyFillMode( long, short* parm )
+{
+ mWinding = parm[ 0 ];
+}
+
+
+//-----------------------------------------------------------------------------
+void QWinMetaFile::setBkColor( long, short* parm )
+{
+ mPainter.setBackgroundColor( color( parm ) );
+}
+
+
+//-----------------------------------------------------------------------------
+void QWinMetaFile::setBkMode( long, short* parm )
+{
+ if ( parm[ 0 ]==1 ) mPainter.setBackgroundMode( Qt::TransparentMode );
+ else mPainter.setBackgroundMode( Qt::OpaqueMode );
+}
+
+
+//-----------------------------------------------------------------------------
+void QWinMetaFile::setPixel( long, short* parm )
+{
+ QPen pen = mPainter.pen();
+ mPainter.setPen( color( parm ) );
+ mPainter.drawPoint( parm[ 3 ], parm[ 2 ] );
+ mPainter.setPen( pen );
+}
+
+
+//-----------------------------------------------------------------------------
+void QWinMetaFile::setRop( long, short* parm )
+{
+ mPainter.setRasterOp( winToQtRaster( parm[ 0 ] ) );
+}
+
+
+//-----------------------------------------------------------------------------
+void QWinMetaFile::saveDC( long, short* )
+{
+ mPainter.save();
+}
+
+
+//-----------------------------------------------------------------------------
+void QWinMetaFile::restoreDC( long, short *parm )
+{
+ for ( int i=0; i > parm[ 0 ] ; i-- )
+ mPainter.restore();
+}
+
+
+//-----------------------------------------------------------------------------
+void QWinMetaFile::intersectClipRect( long, short* parm )
+{
+/* TODO: better implementation : need QT 3.0.2
+ QRegion region = mPainter.clipRegion();
+ if ( region.isEmpty() )
+ region = bbox();
+*/
+ QRegion region( bbox() );
+
+ QRegion newRegion( parm[ 3 ], parm[ 2 ], parm[ 1 ] - parm[ 3 ], parm[ 0 ] - parm[ 2 ] );
+ region = region.intersect( newRegion );
+
+ mPainter.setClipRegion( region, QPainter::CoordPainter );
+}
+
+
+//-----------------------------------------------------------------------------
+void QWinMetaFile::excludeClipRect( long, short* parm )
+{
+/* TODO: better implementation : need QT 3.0.2
+ QRegion region = mPainter.clipRegion();
+ if ( region.isEmpty() )
+ region = bbox();
+*/
+ QRegion region( bbox() );
+
+ QRegion newRegion( parm[ 3 ], parm[ 2 ], parm[ 1 ] - parm[ 3 ], parm[ 0 ] - parm[ 2 ] );
+ region = region.subtract( newRegion );
+
+ mPainter.setClipRegion( region, QPainter::CoordPainter );
+}
+
+
+//-----------------------------------------------------------------------------
+// Text
+//-----------------------------------------------------------------------------
+void QWinMetaFile::setTextColor( long, short* parm )
+{
+ mTextColor = color( parm );
+}
+
+
+//-----------------------------------------------------------------------------
+void QWinMetaFile::setTextAlign( long, short* parm )
+{
+ mTextAlign = parm[ 0 ];
+}
+
+
+//-----------------------------------------------------------------------------
+void QWinMetaFile::textOut( long num, short* parm )
+{
+
+ short *copyParm = new short[ num + 1 ];
+
+ // re-order parameters
+ int idxOffset = (parm[ 0 ] / 2) + 1 + (parm[ 0 ] & 1);
+ copyParm[ 0 ] = parm[ idxOffset ];
+ copyParm[ 1 ] = parm[ idxOffset + 1 ];
+ copyParm[ 2 ] = parm[ 0 ];
+ copyParm[ 3 ] = 0;
+ memcpy( &copyParm[ 4 ], &parm[ 1 ], parm[ 0 ] );
+
+ extTextOut( num + 1, copyParm );
+ delete [] copyParm;
+}
+
+
+//-----------------------------------------------------------------------------
+void QWinMetaFile::extTextOut( long num, short* parm )
+{
+ char* ptStr;
+ int x, y, width, height;
+ int idxOffset;
+
+ if ( parm[ 3 ] != 0 ) // ETO_CLIPPED flag add 4 parameters
+ ptStr = (char*)&parm[ 8 ];
+ else
+ ptStr = (char*)&parm[ 4 ];
+
+ QCString text( ptStr, parm[ 2 ] + 1 );
+
+ QFontMetrics fm( mPainter.font() );
+ width = fm.width( text ) + fm.descent(); // because fm.width(text) isn't rigth with Italic text
+ height = fm.height();
+
+ mPainter.save();
+
+ if ( mTextAlign & 0x01 ) { // (left, top) position = current logical position
+ QPoint pos = mPainter.pos();
+ x = pos.x();
+ y = pos.y();
+ }
+ else { // (left, top) position = parameters
+ x = parm[ 1 ];
+ y = parm[ 0 ];
+ }
+
+ if ( mRotation ) {
+ mPainter.translate( parm[ 1 ], parm[ 0 ]);
+ mPainter.rotate ( mRotation );
+ mPainter.translate( -parm[ 1 ], -parm[ 0 ] );
+ }
+
+ // alignment
+ if ( mTextAlign & 0x06 )
+ x -= ( width / 2 );
+ if ( mTextAlign & 0x08 )
+ y -= (height - fm.descent());
+
+ mPainter.setPen( mTextColor );
+ idxOffset = (parm[ 2 ] / 2) + 4 + (parm[ 2 ] & 1);
+ if ( ( parm[ 2 ] > 1 ) && ( num >= (idxOffset + parm[ 2 ]) ) && ( parm[ 3 ] == 0 ) ) {
+ // offset for each char
+ int left = x;
+ mPainter.drawText( left, y, width, height, Qt::AlignLeft | Qt::AlignTop, text.mid(0, 1) );
+ for ( int i = 1; i < parm[ 2 ] ; i++ ) {
+ left += parm[ idxOffset + i - 1 ];
+ mPainter.drawText( left, y, width, height, Qt::AlignLeft | Qt::AlignTop, text.mid(i, 1) );
+ }
+ }
+ else {
+ mPainter.drawText( x, y, width, height, Qt::AlignLeft | Qt::AlignTop, text );
+ }
+
+ mPainter.restore();
+
+}
+
+
+
+//-----------------------------------------------------------------------------
+// Bitmap
+//-----------------------------------------------------------------------------
+void QWinMetaFile::dibBitBlt( long num, short* parm )
+{
+ if ( num > 9 ) { // DIB image
+ QImage bmpSrc;
+
+ if ( dibToBmp( bmpSrc, (char*)&parm[ 8 ], (num - 8) * 2 ) ) {
+ long raster = toDWord( parm );
+
+ mPainter.setRasterOp( winToQtRaster( raster ) );
+
+ // wmf file allow negative width or height
+ mPainter.save();
+ if ( parm[ 5 ] < 0 ) { // width < 0 => horizontal flip
+ QWMatrix m( -1.0F, 0.0F, 0.0F, 1.0F, 0.0F, 0.0F );
+ mPainter.setWorldMatrix( m, true );
+ }
+ if ( parm[ 4 ] < 0 ) { // height < 0 => vertical flip
+ QWMatrix m( 1.0F, 0.0F, 0.0F, -1.0F, 0.0F, 0.0F );
+ mPainter.setWorldMatrix( m, true );
+ }
+ mPainter.drawImage( parm[ 7 ], parm[ 6 ], bmpSrc, parm[ 3 ], parm[ 2 ], parm[ 5 ], parm[ 4 ] );
+ mPainter.restore();
+ }
+ }
+ else {
+ kdDebug() << "QWinMetaFile::dibBitBlt without image: not implemented " << endl;
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+void QWinMetaFile::dibStretchBlt( long num, short* parm )
+{
+ QImage bmpSrc;
+
+ if ( dibToBmp( bmpSrc, (char*)&parm[ 10 ], (num - 10) * 2 ) ) {
+ long raster = toDWord( parm );
+
+ mPainter.setRasterOp( winToQtRaster( raster ) );
+
+ // wmf file allow negative width or height
+ mPainter.save();
+ if ( parm[ 7 ] < 0 ) { // width < 0 => horizontal flip
+ QWMatrix m( -1.0F, 0.0F, 0.0F, 1.0F, 0.0F, 0.0F );
+ mPainter.setWorldMatrix( m, true );
+ }
+ if ( parm[ 6 ] < 0 ) { // height < 0 => vertical flip
+ QWMatrix m( 1.0F, 0.0F, 0.0F, -1.0F, 0.0F, 0.0F );
+ mPainter.setWorldMatrix( m, true );
+ }
+ bmpSrc = bmpSrc.copy( parm[ 5 ], parm[ 4 ], parm[ 3 ], parm[ 2 ] );
+ // TODO: scale the bitmap ( QImage::scale(parm[ 7 ], parm[ 6 ]) is actually too slow )
+
+ mPainter.drawImage( parm[ 9 ], parm[ 8 ], bmpSrc );
+ mPainter.restore();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+void QWinMetaFile::stretchDib( long num, short* parm )
+{
+ QImage bmpSrc;
+
+ if ( dibToBmp( bmpSrc, (char*)&parm[ 11 ], (num - 11) * 2 ) ) {
+ long raster = toDWord( parm );
+
+ mPainter.setRasterOp( winToQtRaster( raster ) );
+
+ // wmf file allow negative width or height
+ mPainter.save();
+ if ( parm[ 8 ] < 0 ) { // width < 0 => horizontal flip
+ QWMatrix m( -1.0F, 0.0F, 0.0F, 1.0F, 0.0F, 0.0F );
+ mPainter.setWorldMatrix( m, true );
+ }
+ if ( parm[ 7 ] < 0 ) { // height < 0 => vertical flip
+ QWMatrix m( 1.0F, 0.0F, 0.0F, -1.0F, 0.0F, 0.0F );
+ mPainter.setWorldMatrix( m, true );
+ }
+ bmpSrc = bmpSrc.copy( parm[ 6 ], parm[ 5 ], parm[ 4 ], parm[ 3 ] );
+ // TODO: scale the bitmap ( QImage::scale(parm[ 8 ], parm[ 7 ]) is actually too slow )
+
+ mPainter.drawImage( parm[ 10 ], parm[ 9 ], bmpSrc );
+ mPainter.restore();
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+void QWinMetaFile::dibCreatePatternBrush( long num, short* parm )
+{
+ WinObjPatternBrushHandle* handle = new WinObjPatternBrushHandle;
+ addHandle( handle );
+ QImage bmpSrc;
+
+ if ( dibToBmp( bmpSrc, (char*)&parm[ 2 ], (num - 2) * 2 ) ) {
+ handle->image = bmpSrc;
+ handle->brush.setPixmap( handle->image );
+ }
+}
+
+
+//-----------------------------------------------------------------------------
+// Object handle
+//-----------------------------------------------------------------------------
+void QWinMetaFile::selectObject( long, short* parm )
+{
+ int idx = parm[ 0 ];
+ if ( idx>=0 && idx < MAX_OBJHANDLE && mObjHandleTab[ idx ] )
+ mObjHandleTab[ idx ]->apply( mPainter );
+}
+
+
+//-----------------------------------------------------------------------------
+void QWinMetaFile::deleteObject( long, short* parm )
+{
+ deleteHandle( parm[ 0 ] );
+}
+
+
+//-----------------------------------------------------------------------------
+void QWinMetaFile::createEmptyObject( long, short* )
+{
+ // allocation of an empty object (to keep object counting in sync)
+ WinObjPenHandle* handle = new WinObjPenHandle;
+ addHandle( handle );
+ kdDebug() << "QWinMetaFile: unimplemented createObject " << endl;
+}
+
+
+//-----------------------------------------------------------------------------
+void QWinMetaFile::createBrushIndirect( long, short* parm )
+{
+ static Qt::BrushStyle hatchedStyleTab[] =
+ {
+ Qt::HorPattern,
+ Qt::FDiagPattern,
+ Qt::BDiagPattern,
+ Qt::CrossPattern,
+ Qt::DiagCrossPattern
+ };
+ static Qt::BrushStyle styleTab[] =
+ { Qt::SolidPattern,
+ Qt::NoBrush,
+ Qt::FDiagPattern, /* hatched */
+ Qt::Dense4Pattern, /* should be custom bitmap pattern */
+ Qt::HorPattern, /* should be BS_INDEXED (?) */
+ Qt::VerPattern, /* should be device-independent bitmap */
+ Qt::Dense6Pattern, /* should be device-independent packed-bitmap */
+ Qt::Dense2Pattern, /* should be BS_PATTERN8x8 */
+ Qt::Dense3Pattern /* should be device-independent BS_DIBPATTERN8x8 */
+ };
+ Qt::BrushStyle style;
+ short arg;
+ WinObjBrushHandle* handle = new WinObjBrushHandle;
+ addHandle( handle );
+
+ arg = parm[ 0 ];
+ if ( arg==2 )
+ {
+ arg = parm[ 3 ];
+ if ( arg>=0 && arg<5 ) style = hatchedStyleTab[ arg ];
+ else
+ {
+ kdDebug() << "QWinMetaFile::createBrushIndirect: invalid hatched brush " << arg << endl;
+ style = Qt::SolidPattern;
+ }
+ }
+ else if ( arg>=0 && arg<9 )
+ style = styleTab[ arg ];
+ else
+ {
+ kdDebug() << "QWinMetaFile::createBrushIndirect: invalid brush " << arg << endl;
+ style = Qt::SolidPattern;
+ }
+ handle->brush.setStyle( style );
+ handle->brush.setColor( color( parm+1 ) );
+}
+
+
+//-----------------------------------------------------------------------------
+void QWinMetaFile::createPenIndirect( long, short* parm )
+{
+ static Qt::PenStyle styleTab[] =
+ { Qt::SolidLine, Qt::DashLine, Qt::DotLine, Qt::DashDotLine, Qt::DashDotDotLine,
+ Qt::NoPen, Qt::SolidLine };
+ Qt::PenStyle style;
+ WinObjPenHandle* handle = new WinObjPenHandle;
+ addHandle( handle );
+
+ if ( parm[ 0 ]>=0 && parm[ 0 ]<6 ) style=styleTab[ parm[ 0 ] ];
+ else
+ {
+ kdDebug() << "QWinMetaFile::createPenIndirect: invalid pen " << parm[ 0 ] << endl;
+ style = Qt::SolidLine;
+ }
+
+ handle->pen.setStyle( style );
+ handle->pen.setColor( color( parm+3 ) );
+ handle->pen.setCapStyle( Qt::RoundCap );
+
+ //int width = 0;
+ // TODO : width of pen proportional to device context width
+ // DOESN'T WORK
+/*
+ QRect devRec;
+ devRec = mPainter.xForm( mBBox );
+ width = ( parm[ 0 ] * devRec.width() ) / mBBox.width() ;
+ kdDebug() << "CreatePenIndirect: " << endl;
+ kdDebug() << " log coord. : " << mBBox.width() << " " << mBBox.height() << endl;
+ kdDebug() << " log. pen : " << parm[ 1 ] << " " << parm[ 2 ] << endl;
+ kdDebug() << " dev. pen : " << width << endl;
+ handle->pen.setWidth( width );
+*/
+}
+
+
+//-----------------------------------------------------------------------------
+void QWinMetaFile::createFontIndirect( long , short* parm)
+{
+ WinObjFontHandle* handle = new WinObjFontHandle;
+ addHandle( handle );
+
+ QString family( (const char*)&parm[ 9 ] );
+
+ mRotation = -parm[ 2 ] / 10; // text rotation (in 1/10 degree)
+ // TODO: memorisation of rotation in object Font
+ handle->font.setFamily( family );
+ handle->font.setFixedPitch( ((parm[ 8 ] & 0x01) == 0) );
+ // TODO: investigation why some test case need -2. (size of font in logical point)
+ handle->font.setPointSize( QABS(parm[ 0 ]) - 2 );
+ handle->font.setWeight( (parm[ 4 ] >> 3) );
+ handle->font.setItalic( (parm[ 5 ] & 0x01) );
+ handle->font.setUnderline( (parm[ 5 ] & 0x100) );
+}
+
+
+//-----------------------------------------------------------------------------
+// Misc
+//-----------------------------------------------------------------------------
+void QWinMetaFile::noop( long, short* )
+{
+}
+
+
+void QWinMetaFile::end( long, short* )
+{
+ // end of file :
+// kdDebug() << "END bbox=( " << mBBox.left() << "; " << mBBox.top() << "; " << mBBox.width() << "; " << mBBox.height() << ")" << endl;
+}
+
+
+//-----------------------------------------------------------------------------
+unsigned short QWinMetaFile::calcCheckSum( WmfPlaceableHeader* apmfh )
+{
+ WORD* lpWord;
+ WORD wResult, i;
+
+ // Start with the first word
+ wResult = *( lpWord = ( WORD* )( apmfh ) );
+ // XOR in each of the other 9 words
+ for( i=1; i<=9; i++ )
+ {
+ wResult ^= lpWord[ i ];
+ }
+ return wResult;
+}
+
+
+//-----------------------------------------------------------------------------
+int QWinMetaFile::findFunc( unsigned short aFunc ) const
+{
+ int i;
+
+ for ( i=0; metaFuncTab[ i ].name; i++ )
+ if ( metaFuncTab[ i ].func == aFunc ) return i;
+
+ // here : unknown function
+ return i;
+}
+
+//-----------------------------------------------------------------------------
+QPointArray* QWinMetaFile::pointArray( short num, short* parm )
+{
+ int i;
+
+ mPoints.resize( num );
+
+ for ( i=0; i<num; i++, parm+=2 )
+ mPoints.setPoint( i, parm[ 0 ], parm[ 1 ] );
+
+ return &mPoints;
+}
+
+//-----------------------------------------------------------------------------
+unsigned int QWinMetaFile::toDWord( short* parm )
+{
+ unsigned int l;
+
+#if !defined( WORDS_BIGENDIAN )
+ l = *( unsigned int* )( parm );
+#else
+ char *bytes;
+ char swap[ 4 ];
+ bytes = ( char* )parm;
+ swap[ 0 ] = bytes[ 2 ];
+ swap[ 1 ] = bytes[ 3 ];
+ swap[ 2 ] = bytes[ 0 ];
+ swap[ 3 ] = bytes[ 1 ];
+ l = *( unsigned int* )( swap );
+#endif
+
+ return l;
+}
+
+
+//-----------------------------------------------------------------------------
+QColor QWinMetaFile::color( short* parm )
+{
+ unsigned int colorRef;
+ int red, green, blue;
+
+ colorRef = toDWord( parm ) & 0xffffff;
+ red = colorRef & 255;
+ green = ( colorRef>>8 ) & 255;
+ blue = ( colorRef>>16 ) & 255;
+
+ return QColor( red, green, blue );
+}
+
+
+//-----------------------------------------------------------------------------
+void QWinMetaFile::xyToAngle( int xStart, int yStart, int xEnd, int yEnd, int& angleStart, int& angleLength )
+{
+ float aStart, aLength;
+
+ aStart = atan2( double(yStart), double(xStart) );
+ aLength = atan2( double(yEnd), double(xEnd) ) - aStart;
+
+ angleStart = (int)(aStart * 2880 / 3.14166);
+ angleLength = (int)(aLength * 2880 / 3.14166);
+ if ( angleLength < 0 ) angleLength = 5760 + angleLength;
+}
+
+
+//-----------------------------------------------------------------------------
+void QWinMetaFile::addHandle( WinObjHandle* handle )
+{
+ int idx;
+
+ for ( idx=0; idx < MAX_OBJHANDLE ; idx++ )
+ if ( mObjHandleTab[ idx ] == NULL ) break;
+
+ if ( idx < MAX_OBJHANDLE )
+ mObjHandleTab[ idx ] = handle;
+ else
+ kdDebug() << "QWinMetaFile error: handle table full !" << endl;
+}
+
+//-----------------------------------------------------------------------------
+void QWinMetaFile::deleteHandle( int idx )
+{
+ if ( idx >= 0 && idx < MAX_OBJHANDLE && mObjHandleTab[ idx ] )
+ {
+ delete mObjHandleTab[ idx ];
+ mObjHandleTab[ idx ] = NULL;
+ }
+}
+
+//-----------------------------------------------------------------------------
+Qt::RasterOp QWinMetaFile::winToQtRaster( short parm ) const
+{
+ static const Qt::RasterOp opTab[] =
+ {
+ Qt::CopyROP,
+ Qt::ClearROP, Qt::NandROP, Qt::NotAndROP, Qt::NotCopyROP,
+ Qt::AndNotROP, Qt::NotROP, Qt::XorROP, Qt::NorROP,
+ Qt::AndROP, Qt::NotXorROP, Qt::NopROP, Qt::NotOrROP,
+ Qt::CopyROP, Qt::OrNotROP, Qt::OrROP, Qt::SetROP
+ };
+
+ if ( parm > 0 && parm <= 16 )
+ return opTab[ parm ];
+ else
+ return Qt::CopyROP;
+}
+
+//-----------------------------------------------------------------------------
+Qt::RasterOp QWinMetaFile::winToQtRaster( long parm ) const
+{
+ /* TODO: Ternary raster operations
+ 0x00C000CA dest = (source AND pattern)
+ 0x00F00021 dest = pattern
+ 0x00FB0A09 dest = DPSnoo
+ 0x005A0049 dest = pattern XOR dest */
+ static const struct OpTab
+ {
+ long winRasterOp;
+ Qt::RasterOp qtRasterOp;
+ } opTab[] =
+ {
+ { 0x00CC0020, Qt::CopyROP },
+ { 0x00EE0086, Qt::OrROP },
+ { 0x008800C6, Qt::AndROP },
+ { 0x00660046, Qt::XorROP },
+ { 0x00440328, Qt::AndNotROP },
+ { 0x00330008, Qt::NotCopyROP },
+ { 0x001100A6, Qt::NandROP },
+ { 0x00C000CA, Qt::CopyROP },
+ { 0x00BB0226, Qt::NotOrROP },
+ { 0x00F00021, Qt::CopyROP },
+ { 0x00FB0A09, Qt::CopyROP },
+ { 0x005A0049, Qt::CopyROP },
+ { 0x00550009, Qt::NotROP },
+ { 0x00000042, Qt::ClearROP },
+ { 0x00FF0062, Qt::SetROP }
+ };
+
+ int i;
+ for ( i=0 ; i < 15 ; i++ )
+ if ( opTab[ i ].winRasterOp == parm )
+ break;
+
+ if ( i < 15 )
+ return opTab[ i ].qtRasterOp;
+ else
+ return Qt::CopyROP;
+}
+
+//-----------------------------------------------------------------------------
+bool QWinMetaFile::dibToBmp( QImage& bmp, const char* dib, long size )
+{
+ typedef struct _BMPFILEHEADER {
+ WORD bmType;
+ DWORD bmSize;
+ WORD bmReserved1;
+ WORD bmReserved2;
+ DWORD bmOffBits;
+ } BMPFILEHEADER;
+
+ int sizeBmp = size + 14;
+
+ QByteArray pattern( sizeBmp ); // BMP header and DIB data
+ pattern.fill(0);
+ memcpy( &pattern[ 14 ], dib, size );
+
+ // add BMP header
+ BMPFILEHEADER* bmpHeader;
+ bmpHeader = (BMPFILEHEADER*)((const char*)pattern);
+ bmpHeader->bmType = 0x4D42;
+ bmpHeader->bmSize = sizeBmp;
+
+ if ( !bmp.loadFromData( (const uchar*)bmpHeader, pattern.size(), "BMP" ) ) {
+ kdDebug() << "QWinMetaFile::dibToBmp: invalid bitmap " << endl;
+ return false;
+ }
+ else {
+// if ( bmp.save("/home/software/kde-cvs/qt/examples/wmf/test.bmp", "BMP") )
+// if ( bmp.load( "/home/software/kde-cvs/qt/examples/wmf/test.bmp", "BMP" ) )
+// fprintf(stderr, "Bitmap ok \n");
+ return true;
+ }
+}
+
diff --git a/ktnef/gui/qwmf.h b/ktnef/gui/qwmf.h
new file mode 100644
index 000000000..b655a3fd3
--- /dev/null
+++ b/ktnef/gui/qwmf.h
@@ -0,0 +1,228 @@
+/* Windows Meta File Loader
+ *
+ * Copyright ( C ) 1998 Stefan Taferner
+ * Modified 2002 thierry lorthiois
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or ( at your
+ * option ) any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABLILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details. You should have received a copy
+ * of the GNU General Public License along with this program; if not, write
+ * to the Free Software Foundation, Inc, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301,
+ * USA.
+ */
+#ifndef qwmf_h
+#define qwmf_h
+
+#include <qstring.h>
+#include <qpainter.h>
+#include <qwmatrix.h>
+#include <qpointarray.h>
+#include <qpen.h>
+#include <qcolor.h>
+#include <qimage.h>
+#include <qrect.h>
+
+class QBuffer;
+class QString;
+class WmfCmd;
+class WinObjHandle;
+class WinObjPenHandle;
+class WinObjBrushHandle;
+struct WmfPlaceableHeader;
+
+/**
+ * QWinMetaFile is a WMF viewer based on QT toolkit
+ * How to use QWinMetaFile :
+ * #include "qwmf.h"
+ * QWinMetaFile wmf;
+ * QPicture pic; // or QImage pic;
+ * if ( wmf.load( filename )
+ *   wmf.paint( &pic );
+ */
+
+
+class QWinMetaFile
+{
+public:
+ QWinMetaFile();
+ virtual ~QWinMetaFile();
+
+ /**
+ * Load WMF file. Returns true on success.
+ */
+ virtual bool load( const QString &fileName );
+ virtual bool load( QBuffer &buffer );
+
+ /**
+ * Paint metafile to given paint-device using absolute or relative coordinate.
+ * abosute coord. reset the world transfomation Matrix
+ * relative coord. use the existing world transfomation Matrix
+ * Returns true on success.
+ */
+ virtual bool paint( const QPaintDevice* target, bool absolute=false );
+
+ /**
+ * Returns true if the metafile is placeable.
+ */
+ bool isPlaceable( void ) const { return mIsPlaceable; }
+
+ /**
+ * Returns true if the metafile is enhanced.
+ */
+ bool isEnhanced( void ) const { return mIsEnhanced; }
+
+ /**
+ * Returns bounding rectangle
+ */
+ QRect bbox( void ) const { return mBBox; }
+ void setBbox( QRect r ) { mBBox = r; }
+
+public: // should be protected but cannot
+ /** Metafile painter methods */
+
+ // set window origin
+ void setWindowOrg( long num, short* parms );
+ // set window extents
+ void setWindowExt( long num, short* parms );
+
+ /****************** Drawing *******************/
+ // draw line to coord
+ void lineTo( long num, short* parms );
+ // move pen to coord
+ void moveTo( long num, short* parms );
+ // draw ellipse
+ void ellipse( long num, short* parms );
+ // draw polygon
+ void polygon( long num, short* parms );
+ /* draw a list of polygons */
+ void polyPolygon( long num, short* parms );
+ // draw series of lines
+ void polyline( long num, short* parms );
+ /* draw a rectangle */
+ void rectangle( long num, short* parms );
+ /* draw round rectangle */
+ void roundRect( long num, short* parms );
+ /* draw arc */
+ void arc( long num, short* parms );
+ /* draw chord */
+ void chord( long num, short* parms );
+ /* draw pie */
+ void pie( long num, short* parms );
+ // set polygon fill mode
+ void setPolyFillMode( long num, short* parms );
+ // set background pen color
+ void setBkColor( long num, short* parms );
+ // set background pen mode
+ void setBkMode( long num, short* parms );
+ /* set a pixel */
+ void setPixel( long num, short* parms );
+ // Set raster operation mode
+ void setRop( long num, short* parms );
+ /* save device context */
+ void saveDC( long num, short* parms );
+ /* restore device context */
+ void restoreDC( long num, short* parms );
+ /* clipping region is the intersection of this region and the original region */
+ void intersectClipRect( long num, short* parms );
+ /* delete a clipping rectangle of the original region */
+ void excludeClipRect( long num, short* parms );
+
+ /****************** Text *******************/
+ /* set text color */
+ void setTextColor( long num, short* parms );
+ /* set text alignment */
+ void setTextAlign( long num, short* parms );
+ /* draw text */
+ void textOut( long num, short* parms );
+ void extTextOut( long num, short* parms );
+
+ /****************** Bitmap *******************/
+ /* copies a DIB into a dest location */
+ void dibBitBlt( long num, short* parms );
+ /* stretches a DIB into a dest location */
+ void dibStretchBlt( long num, short* parms );
+ void stretchDib( long num, short* parms );
+ /* create a pattern brush */
+ void dibCreatePatternBrush( long num, short* parms );
+
+ /****************** Object handle *******************/
+ // Activate object handle
+ void selectObject( long num, short* parms );
+ // Free object handle
+ void deleteObject( long num, short* parms );
+ /* create an empty object in the object list */
+ void createEmptyObject( long num, short* parms );
+ // create a logical brush
+ void createBrushIndirect( long num, short* parms );
+ // create a logical pen
+ void createPenIndirect( long num, short* parms );
+ /* create a logical font */
+ void createFontIndirect( long num, short* parms );
+
+ /****************** misc *******************/
+ // nothing to do
+ void noop( long , short* );
+ // end of meta file
+ void end( long /*num*/, short* /*parms*/ );
+ // Resolution of the image in dots per inch
+ int dpi( void ) const { return mDpi; }
+
+protected:
+ /** Calculate header checksum */
+ unsigned short calcCheckSum( WmfPlaceableHeader* );
+
+ /** Find function in metafunc table by metafile-function.
+ Returns index or -1 if not found. */
+ virtual int findFunc( unsigned short aFunc ) const;
+
+ /** Fills given parms into mPoints. */
+ QPointArray* pointArray( short num, short* parms );
+
+ /** Returns color given by the two parameters */
+ QColor color( short* parm );
+
+ /** Converts two parameters to long */
+ unsigned int toDWord( short* parm );
+
+ /** Convert (x1,y1) and (x2, y2) positions in angle and angleLength */
+ void xyToAngle( int xStart, int yStart, int xEnd, int yEnd, int& angle, int& aLength );
+
+ /** Handle win-object-handles */
+ void addHandle( WinObjHandle* );
+ void deleteHandle( int );
+
+ /** Convert windows rasterOp in QT rasterOp */
+ Qt::RasterOp winToQtRaster( short parm ) const;
+ Qt::RasterOp winToQtRaster( long parm ) const;
+
+ /** Converts DIB to BMP */
+ bool dibToBmp( QImage& bmp, const char* dib, long size);
+
+protected:
+ QPainter mPainter;
+ bool mIsPlaceable, mIsEnhanced, mValid;
+
+ // coordinate system
+ bool mAbsoluteCoord;
+ QWMatrix mInternalWorldMatrix; // memorisation of WMF matrix transformation
+ QRect mHeaderBoundingBox;
+ QRect mBBox;
+
+ // informtion shared between Metafile Functions
+ QColor mTextColor;
+ int mTextAlign, mRotation;
+ bool mWinding;
+
+ WmfCmd* mFirstCmd;
+ WinObjHandle** mObjHandleTab;
+ QPointArray mPoints;
+ int mDpi;
+};
+
+#endif /*qwmf_h*/
diff --git a/ktnef/gui/wmfstruct.h b/ktnef/gui/wmfstruct.h
new file mode 100644
index 000000000..ca4f1f7db
--- /dev/null
+++ b/ktnef/gui/wmfstruct.h
@@ -0,0 +1,107 @@
+/* WMF Metafile Structures
+ * Author: Stefan Taferner <taferner@kde.org>
+ */
+#ifndef wmfstruct_h
+#define wmfstruct_h
+
+typedef short WORD;
+typedef int DWORD;
+typedef Q_INT32 LONG;
+typedef void* _HANDLE;
+
+typedef struct _RECT
+{
+ WORD left;
+ WORD top;
+ WORD right;
+ WORD bottom;
+} RECT;
+
+typedef struct _RECTL
+{
+ LONG left;
+ LONG top;
+ LONG right;
+ LONG bottom;
+} RECTL;
+
+typedef struct _SIZE
+{
+ WORD width;
+ WORD height;
+} SIZE;
+
+typedef struct _SIZEL
+{
+ LONG width;
+ LONG height;
+} SIZEL;
+
+
+struct WmfEnhMetaHeader
+{
+ DWORD iType; // Record type EMR_HEADER
+ DWORD nSize; // Record size in bytes. This may be greater
+ // than the sizeof( ENHMETAHEADER ).
+ RECTL rclBounds; // Inclusive-inclusive bounds in device units
+ RECTL rclFrame; // Inclusive-inclusive Picture Frame of metafile
+ // in .01 mm units
+ DWORD dSignature; // Signature. Must be ENHMETA_SIGNATURE.
+ DWORD nVersion; // Version number
+ DWORD nBytes; // Size of the metafile in bytes
+ DWORD nRecords; // Number of records in the metafile
+ WORD nHandles; // Number of handles in the handle table
+ // Handle index zero is reserved.
+ WORD sReserved; // Reserved. Must be zero.
+ DWORD nDescription; // Number of chars in the unicode description string
+ // This is 0 if there is no description string
+ DWORD offDescription; // Offset to the metafile description record.
+ // This is 0 if there is no description string
+ DWORD nPalEntries; // Number of entries in the metafile palette.
+ SIZEL szlDevice; // Size of the reference device in pels
+ SIZEL szlMillimeters; // Size of the reference device in millimeters
+};
+#define ENHMETA_SIGNATURE 0x464D4520
+
+
+struct WmfMetaHeader
+{
+ WORD mtType;
+ WORD mtHeaderSize;
+ WORD mtVersion;
+ DWORD mtSize;
+ WORD mtNoObjects;
+ DWORD mtMaxRecord;
+ WORD mtNoParameters;
+};
+
+
+struct WmfPlaceableHeader
+{
+ DWORD key;
+ WORD hmf;
+ RECT bbox;
+ WORD inch;
+ DWORD reserved;
+ WORD checksum;
+};
+#define APMHEADER_KEY 0x9AC6CDD7
+
+
+struct WmfMetaRecord
+{
+ DWORD rdSize; // Record size ( in words ) of the function
+ WORD rdFunction; // Record function number
+ WORD rdParm[ 1 ]; // WORD array of parameters
+};
+
+
+struct WmfEnhMetaRecord
+{
+ DWORD iType; // Record type EMR_xxx
+ DWORD nSize; // Record size in bytes
+ DWORD dParm[ 1 ]; // DWORD array of parameters
+};
+
+
+#endif /*wmfstruct_h*/
diff --git a/ktnef/ktnef/Makefile.am b/ktnef/ktnef/Makefile.am
new file mode 100644
index 000000000..c04f16440
--- /dev/null
+++ b/ktnef/ktnef/Makefile.am
@@ -0,0 +1,4 @@
+ktnefinclude_HEADERS = ktnefparser.h ktnefattach.h ktnefproperty.h \
+ ktnefpropertyset.h ktnefmessage.h ktnefwriter.h ktnefdefs.h
+ktnefincludedir = $(includedir)/ktnef
+INCLUDES = $(all_includes)
diff --git a/ktnef/ktnef/ktnefattach.h b/ktnef/ktnef/ktnefattach.h
new file mode 100644
index 000000000..846c4a6b8
--- /dev/null
+++ b/ktnef/ktnef/ktnefattach.h
@@ -0,0 +1,70 @@
+/*
+ ktnefattach.h
+
+ Copyright (C) 2002 Michael Goffioul <kdeprint@swing.be>
+
+ This file is part of KTNEF, the KDE TNEF support library/program.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef KTNEFATTACH_H
+#define KTNEFATTACH_H
+
+#include <qstring.h>
+#include <qmap.h>
+#include <qvariant.h>
+#include <ktnef/ktnefpropertyset.h>
+#include <kdepimmacros.h>
+
+class KTNEFProperty;
+
+class KDE_EXPORT KTNEFAttach : public KTNEFPropertySet
+{
+public:
+ enum ParseState { Unparsed = 0x0000, TitleParsed = 0x0001, DataParsed = 0x0002, InfoParsed = 0x0004};
+
+ KTNEFAttach();
+ ~KTNEFAttach();
+
+ void setTitleParsed();
+ void setDataParsed();
+ void unsetDataParser();
+ void setInfoParsed();
+ bool titleParsed() const;
+ bool dataParsed() const;
+ bool infoParsed() const;
+ bool checkState(int state) const;
+
+ int offset() const;
+ void setOffset(int n);
+ int size() const;
+ void setSize(int s);
+ int displaySize() const;
+ void setDisplaySize(int s);
+ QString name() const;
+ void setName(const QString& str);
+ int index() const;
+ void setIndex(int i);
+ QString fileName() const;
+ void setFileName(const QString& str);
+ QString displayName() const;
+ void setDisplayName(const QString& str);
+ QString mimeTag() const;
+ void setMimeTag(const QString& str);
+ QString extension() const;
+ void setExtension(const QString& str);
+
+private:
+ class AttachPrivate;
+ AttachPrivate *d;
+};
+
+#endif
diff --git a/ktnef/ktnef/ktnefdefs.h b/ktnef/ktnef/ktnefdefs.h
new file mode 100644
index 000000000..6e9e96fd8
--- /dev/null
+++ b/ktnef/ktnef/ktnefdefs.h
@@ -0,0 +1,256 @@
+#ifndef KTNEFDEFS_H
+#define KTNEFDEFS_H
+
+#define TNEF_SIGNATURE 0x223e9f78
+#define LVL_MESSAGE 0x01
+#define LVL_ATTACHMENT 0x02
+
+#define atpSTRING 0x0001
+#define atpTEXT 0x0002
+#define atpDATE 0x0003
+#define atpSHORT 0x0004
+#define atpLONG 0x0005
+#define atpBYTE 0x0006
+#define atpWORD 0x0007
+#define atpDWORD 0x0008
+
+#define attDATESTART 0x0006
+#define attDATEEND 0x0007
+#define attAIDOWNER 0x0008
+#define attREQUESTRES 0x0009
+#define attFROM 0x8000
+#define attSUBJECT 0x8004
+#define attDATESENT 0x8005
+#define attDATERECD 0x8006
+#define attMSGSTATUS 0x8007
+#define attMSGCLASS 0x8008
+#define attMSGID 0x8009
+#define attBODY 0x800c
+#define attMSGPRIORITY 0x800d
+#define attATTACHDATA 0x800f /* Attachment Data */
+#define attATTACHTITLE 0x8010 /* Attachment File Name */
+#define attATTACHMETAFILE 0x8011
+#define attATTACHCREATEDATE 0x8012
+#define attATTACHMODDATE 0x8013
+#define attDATEMODIFIED 0x8020
+#define attATTACHRENDDATA 0x9002
+#define attMAPIPROPS 0x9003
+#define attRECIPTABLE 0x9004
+#define attATTACHMENT 0x9005 /* Attachment properties (?) */
+#define attTNEFVERSION 0x9006
+#define attOEMCODEPAGE 0x9007
+
+/* These are found in TNEF documentation, but have so far not been implemented
+#define attATTACHCREATEDATE 0x0000
+#define attATTACHTRANSPORTFILENAME 0x0000
+#define attCONVERSATIONID 0x0000
+#define attORIGINALMSGCLASS 0x0000
+#define attOWNER 0x0000
+#define attPARENTID 0x0000
+#define attNULL 0x0000
+#define attDELEGATE 0x0000
+#define attSENTFOR 0x0000
+*/
+
+#define fmsModified 0x01
+#define fmsLocal 0x02
+#define fmsSubmitted 0x04
+#define fmsRead 0x20
+#define fmsHasAttach 0x80
+#define MSGFLAG_READ 0x00000001
+#define MSGFLAG_UNMODIFIED 0x00000002
+#define MSGFLAG_SUBMIT 0x00000004
+#define MSGFLAG_UNSENT 0x00000008
+#define MSGFLAG_HASATTACH 0x00000010
+
+// supported MAPI types
+#define MAPI_TYPE_NONE 0x0000
+#define MAPI_TYPE_UINT16 0x0002
+#define MAPI_TYPE_ULONG 0x0003
+#define MAPI_TYPE_FLOAT 0x0004
+#define MAPI_TYPE_DOUBLE 0x0005
+#define MAPI_TYPE_BOOLEAN 0x000b
+#define MAPI_TYPE_OBJECT 0x000d
+#define MAPI_TYPE_TIME 0x0040
+#define MAPI_TYPE_STRING8 0x001e
+#define MAPI_TYPE_USTRING 0x001f
+#define MAPI_TYPE_BINARY 0x0102
+#define MAPI_TYPE_VECTOR 0x1000
+
+// supported MAPI tags
+#define MAPI_TAG_INDEX 0x0e21
+#define MAPI_TAG_SIZE 0x0e20
+#define MAPI_TAG_FILENAME 0x3707
+#define MAPI_TAG_DISPLAYNAME 0x3001
+#define MAPI_TAG_DATA 0x3701
+#define MAPI_TAG_ATTACHENCODING 0x3702
+#define MAPI_TAG_EXTENSION 0x3703
+#define MAPI_TAG_ATTACHMETHOD 0x3705
+#define MAPI_TAG_RENDERINGPOS 0x370b
+#define MAPI_TAG_MIMETAG 0x370e
+#define MAPI_TAG_ATTACHFLAGS 0x3714
+
+#define MAPI_IID_IMessage 0x00020307
+
+
+// unsupported Outlook Contact Properties
+// note: properties beginning with MAPI_TAG_CONTACT
+// are 'named' properties
+#define MAPI_TAG_PR_MESSAGE_DELIVERY_TIME 0x0E060040 // CreationTime
+#define MAPI_TAG_PR_MESSAGE_SIZE 0x0E080003 // Size
+#define MAPI_TAG_PR_SENSITIVITY 0x00360003 // Sensitivity
+#define MAPI_TAG_PR_MESSAGE_CLASS 0x001A001F // MessageClass
+#define MAPI_TAG_PR_IMPORTANCE 0x00170003 // Importance
+#define MAPI_TAG_PR_ENTRYID 0x0FFF0102 // EntryID
+#define MAPI_TAG_PR_BODY 0x1000001F // Body
+#define MAPI_TAG_CONTACT_Categories "Keywords" // Categories
+#define MAPI_TAG_PR_DISPLAY_NAME 0x3001001F // FullName
+#define MAPI_TAG_PR_TITLE 0x3A17001F // JobTitle
+#define MAPI_TAG_PR_COMPANY_NAME 0x3A16001F // CompanyName
+#define MAPI_TAG_PR_DISPLAY_NAME_PREFIX 0x3A45001E // Title
+#define MAPI_TAG_PR_SURNAME 0x3A11001E // LastName
+#define MAPI_TAG_PR_MIDDLE_NAME 0x3A44001F // MiddleName
+#define MAPI_TAG_PR_GIVEN_NAME 0x3A06001F // FirstName
+#define MAPI_TAG_PR_GENERATION 0x3A05001E // Suffix
+#define MAPI_TAG_PR_BUSINESS_HOME_PAGE 0x3A51001F // BusinessHomePage
+#define MAPI_TAG_PR_PERSONAL_HOME_PAGE 0x3A50001F // PersonalHomePage
+#define MAPI_TAG_PR_FTP_SITE 0x3A4C001E // FTPSite
+#define MAPI_TAG_PR_INITIALS 0x3A0A001E // Initials
+
+#define MAPI_TAG_CONTACT_FILEUNDER "0x8005" // FileAs
+
+#define MAPI_TAG_CONTACT_LASTNAMEANDFIRSTNAME "0x8017" // LastNameandFirstName
+#define MAPI_TAG_CONTACT_COMPANYANDFULLNAME "0x8018" // CompanyAndFullName
+#define MAPI_TAG_CONTACT_FULLNAMEANDCOMPANY "0x8019" // FullNameAndCompany
+
+#define MAPI_TAG_CONTACT_HOMEADDRESS "0x801A" // HomeAddress
+#define MAPI_TAG_CONTACT_BUSINESSADDRESS "0x801B" // BusinessAddress
+#define MAPI_TAG_CONTACT_OTHERADDRESS "0x801C" // OtherAddress
+#define MAPI_TAG_CONTACT_SELECTEDADDRESS "0x8022" // SelectedMailingAddress:
+ // 0 = None
+ // 1 = Home
+ // 2 = Business
+ // 3 = Other
+
+#define MAPI_TAG_CONTACT_WEBPAGE "0x802B" // WebPage
+#define MAPI_TAG_CONTACT_YOMIFIRSTNAME "0x802C" // YomiFirstName
+#define MAPI_TAG_CONTACT_YOMILASTNAME "0x802D" // YomiLastName
+#define MAPI_TAG_CONTACT_YOMICOMPANYNAME "0x802E" // YomiCompanyName
+
+#define MAPI_TAG_CONTACT_LASTFIRSTNOSPACE "0x8030" // LastFirstNoSpace
+#define MAPI_TAG_CONTACT_LASTFIRSTSPACEONLY "0x8031" // LastFirstSpaceOnly
+#define MAPI_TAG_CONTACT_COMPANYLASTFIRSTNOSPACE "0x8032" // CompanyLastFirstNoSpace
+#define MAPI_TAG_CONTACT_COMPANYLASTFIRSTSpaceOnly "0x8033" // CompanyLastFirstSpaceOnly
+#define MAPI_TAG_CONTACT_LASTFIRSTNOSPACECOMPANY "0x8034" // LastFirstNoSpaceCompany
+#define MAPI_TAG_CONTACT_LASTFIRSTSPACEONLYCOMPANY "0x8035" // LastFirstSpaceOnlyCompany
+#define MAPI_TAG_CONTACT_LASTFIRSTANDSuffix "0x8036" // LastFirstAndSuffix
+
+#define MAPI_TAG_CONTACT_BUSINESSADDRESSSTREET "0x8045" // BusinessAddressStreet
+#define MAPI_TAG_CONTACT_BUSINESSADDRESSCITY "0x8046" // BusinessAddressCity
+#define MAPI_TAG_CONTACT_BUSINESSADDRESSSTATE "0x8047" // BusinessAddressState
+#define MAPI_TAG_CONTACT_BUSINESSADDRESSPOSTALCODE "0x8048" // BusinessAddressPostalCode
+#define MAPI_TAG_CONTACT_BUSINESSADDRESSCOUNTRY "0x8049" // BusinessAddressCountry
+#define MAPI_TAG_CONTACT_BUSINESSADDRESSPOBOX "0x804A" // BusinessAddressPostOfficeBox
+
+#define MAPI_TAG_CONTACT_USERFIELD1 "0x804F" // UserField1
+#define MAPI_TAG_CONTACT_USERFIELD2 "0x8050" // UserField2
+#define MAPI_TAG_CONTACT_USERFIELD3 "0x8051" // UserField3
+#define MAPI_TAG_CONTACT_USERFIELD4 "0x8052" // UserField4
+
+#define MAPI_TAG_CONTACT_IMADDRESS "0x8062" // InternetMailAddress (only >= Outlook 2002)
+
+#define MAPI_TAG_CONTACT_EMAIL1ADDRTYPE "0x8082" // EMail1AddressType
+#define MAPI_TAG_CONTACT_EMAIL1EMAILADDRESS "0x8083" // EMail1Address
+#define MAPI_TAG_CONTACT_EMAIL1ORIGINALDISPLAYNAME "0x8084" // EMail1DisplayName
+#define MAPI_TAG_CONTACT_EMAIL1ORIGINALENTRYID "0x8085" // EMail1EntryID
+
+#define MAPI_TAG_CONTACT_EMAIL2ADDRTYPE "0x8092" // EMail2AddressType
+#define MAPI_TAG_CONTACT_EMAIL2EMAILADDRESS "0x8093" // EMail2Address
+#define MAPI_TAG_CONTACT_EMAIL2ORIGINALDISPLAYNAME "0x8094" // EMail2DisplayName
+#define MAPI_TAG_CONTACT_EMAIL2ORIGINALENTRYID "0x8095" // EMail2EntryID
+
+#define MAPI_TAG_CONTACT_EMAIL3ADDRTYPE "0x80A2" // EMail3AddressType
+#define MAPI_TAG_CONTACT_EMAIL3EMAILADDRESS "0x80A3" // EMail3Address
+#define MAPI_TAG_CONTACT_EMAIL3ORIGINALDISPLAYNAME "0x80A4" // EMail3DisplayName
+#define MAPI_TAG_CONTACT_EMAIL3ORIGINALENTRYID "0x80A5" // EMail3EntryID
+
+#define MAPI_TAG_CONTACT_INTERNETFREEBUSYADDRESS "0x80D8" // InternetFreeBusyAddress
+
+#define MAPI_TAG_CONTACT_BILLINGINFORMATION "0x8535" // BillingInformation
+#define MAPI_TAG_CONTACT_REMINDERTIME "0x8502" // N/A
+#define MAPI_TAG_CONTACT_MILEAGE "0x8534" // Mileage
+
+#define MAPI_TAG_PR_ASSISTANT_TELEPHONE_NUMBER 0x3A2E001F // AssistantTelephoneNumber
+#define MAPI_TAG_PR_BUSINESS_TELEPHONE_NUMBER 0x3A08001F // BusinessTelephoneNumber
+#define MAPI_TAG_PR_BUSINESS2_TELEPHONE_NUMBER 0x3A1B001F // Business2TelephoneNumber
+#define MAPI_TAG_PR_BUSINESS_FAX_NUMBER 0x3A24001F // BusinessFaxNumber
+#define MAPI_TAG_PR_CALLBACK_TELEPHONE_NUMBER 0x3A02001F // CallbackTelephoneNumber
+#define MAPI_TAG_PR_CAR_TELEPHONE_NUMBER 0x3A1E001F // CarTelephoneNumber
+
+#define MAPI_TAG_PR_COMPANY_MAIN_PHONE_NUMBER 0x3A57001F // CompanyMainTelephoneNumber
+
+#define MAPI_TAG_PR_HOME_TELEPHONE_NUMBER 0x3A09001F // HomeTelephoneNumber
+
+#define MAPI_TAG_PR_HOME2_TELEPHONE_NUMBER 0x3A2F001F // Home2TelephoneNumber
+#define MAPI_TAG_PR_HOME_FAX_NUMBER 0x3A25001F // HomeFaxNumber
+#define MAPI_TAG_PR_ISDN_NUMBER 0x3A2D001F // ISDNNumber
+
+#define MAPI_TAG_PR_MOBILE_TELEPHONE_NUMBER 0x3A1C001F // MobileTelephoneNumber
+
+#define MAPI_TAG_PR_OTHER_TELEPHONE_NUMBER 0x3A1F001F // OtherTelephoneNumber
+#define MAPI_TAG_PR_PRIMARY_FAX_NUMBER 0x3A23001F // OtherFaxNumber
+#define MAPI_TAG_PR_PAGER_TELEPHONE_NUMBER 0x3A21001F // PagerNumber
+#define MAPI_TAG_PR_PRIMARY_TELEPHONE_NUMBER 0x3A1A001F // PrimaryTelephoneNumber
+
+#define MAPI_TAG_PR_RADIO_TELEPHONE_NUMBER 0x3A1D001F // RadioTelephoneNumber
+
+#define MAPI_TAG_PR_TELEX_NUMBER 0x3A2C001F // TelexNumber
+#define MAPI_TAG_PR_TTYTDD_PHONE_NUMBER 0x3A4B001F // TTYTDDTelephoneNumber
+#define MAPI_TAG_PR_POSTAL_ADDRESS 0x3A15001F // MailingAddress
+
+#define MAPI_TAG_PR_BUSINESS_ADDRESS_COUNTRY 0x3A26001E // MailingAddressCountry
+#define MAPI_TAG_PR_LOCALITY 0x3A27001F // MailingAddressCity
+#define MAPI_TAG_PR_STATE_OR_PROVINCE 0x3A28001E // MailingAddressState
+#define MAPI_TAG_PR_STREET_ADDRESS 0x3A29001F // MailingAddressStreet
+#define MAPI_TAG_PR_POSTAL_CODE 0x3A2A001E // MailingAddressPostalCode
+#define MAPI_TAG_PR_PO_BOX 0x3A2B001E // MailingAddressPostOfficeBox
+
+#define MAPI_TAG_PR_HOME_ADDRESS_CITY 0x3A59001E // HomeAddressCity
+#define MAPI_TAG_PR_HOME_ADDRESS_STREET 0x3A5D001E // HomeAddressStreet
+#define MAPI_TAG_PR_HOME_ADDRESS_STATE_OR_PROVINCE 0x3A5C001E // HomeAddressState
+#define MAPI_TAG_PR_HOME_ADDRESS_COUNTRY 0x3A5A001E // HomeAddressCountry
+#define MAPI_TAG_PR_HOME_ADDRESS_PO_BOX 0x3A5E001E // HomeAddressPostOfficeBox
+#define MAPI_TAG_PR_HOME_ADDRESS_POSTAL_CODE 0x3A5B001E // HomeAddressPostalCode
+
+#define MAPI_TAG_PR_OTHER_ADDRESS_CITY 0x3A5F001E // OtherAddressCity
+#define MAPI_TAG_PR_OTHER_ADDRESS_STREET 0x3A63001E // OtherAddressStreet
+#define MAPI_TAG_PR_OTHER_ADDRESS_STATE_OR_PROVINCE 0x3A62001E // OtherAddressState
+#define MAPI_TAG_PR_OTHER_ADDRESS_COUNTRY 0x3A60001E // OtherAddressCountry
+#define MAPI_TAG_PR_OTHER_ADDRESS_POSTAL_CODE 0x3A61001E // OtherAddressPostalCode
+#define MAPI_TAG_PR_OTHER_ADDRESS_PO_BOX 0x3A64001E // OtherAddressPostOfficeBox
+
+#define MAPI_TAG_PR_DEPARTMENT_NAME 0x3A18001F // Department
+#define MAPI_TAG_PR_MANAGER_NAME 0x3A4E001F // ManagerName
+#define MAPI_TAG_PR_OFFICE_LOCATION 0x3A19001F // Location
+#define MAPI_TAG_PR_ASSISTANT 0x3A30001F // AssistantName
+#define MAPI_TAG_PR_PROFESSION 0x3A46001F // Profession
+#define MAPI_TAG_PR_NICKNAME 0x3A4F001F // NickName
+#define MAPI_TAG_PR_BIRTHDAY 0x3A420040 // Birthday
+#define MAPI_TAG_PR_SPOUSE_NAME 0x3A48001F // SpouseName
+#define MAPI_TAG_PR_WEDDING_ANNIVERSARY 0x3A410040 // Anniversary
+#define MAPI_TAG_PR_ACCOUNT 0x3A00001E // Account
+#define MAPI_TAG_PR_COMPUTER_NETWORK_NAME 0x3A49001E // ComputerNetworkName
+#define MAPI_TAG_PR_CHILDRENS_NAMES 0x3A58101E // Children
+#define MAPI_TAG_PR_CUSTOMER_ID 0x3A4A001E // CustomerID
+#define MAPI_TAG_PR_GENDER 0x3A4D0002 // Gender:
+ // 0 = Unspecified
+ // 1 = Female
+ // 2 = Male
+#define MAPI_TAG_PR_GOVERNMENT_ID_NUMBER 0x3A07001E // GovernmentIDNumber
+#define MAPI_TAG_PR_HOBBIES 0x3A43001E // Hobby
+#define MAPI_TAG_PR_LANGUAGE 0x3A0C001E // Language
+#define MAPI_TAG_PR_LOCATION 0x3A0D001E // OfficeLocation
+#define MAPI_TAG_PR_ORGANIZATIONAL_ID_NUMBER 0x3A10001E // OrganizationalIDNumber
+#define MAPI_TAG_PR_REFERRED_BY_NAME 0X3A47001E // ReferredBy
+
+#endif /* KTNEFDEFS_H */
diff --git a/ktnef/ktnef/ktnefmessage.h b/ktnef/ktnef/ktnefmessage.h
new file mode 100644
index 000000000..efdc236a8
--- /dev/null
+++ b/ktnef/ktnef/ktnefmessage.h
@@ -0,0 +1,44 @@
+/*
+ ktnefmessage.h
+
+ Copyright (C) 2002 Michael Goffioul <kdeprint@swing.be>
+
+ This file is part of KTNEF, the KDE TNEF support library/program.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef KTNEFMESSAGE_H
+#define KTNEFMESSAGE_H
+
+#include <ktnef/ktnefpropertyset.h>
+#include <qptrlist.h>
+#include <kdepimmacros.h>
+
+class KTNEFAttach;
+
+class KDE_EXPORT KTNEFMessage : public KTNEFPropertySet
+{
+public:
+ KTNEFMessage();
+ ~KTNEFMessage();
+
+ const QPtrList<KTNEFAttach>& attachmentList() const;
+ KTNEFAttach* attachment( const QString& filename ) const;
+ void addAttachment( KTNEFAttach* attach );
+ void clearAttachments();
+ QString rtfString();
+
+private:
+ class MessagePrivate;
+ MessagePrivate *d;
+};
+
+#endif /* KTNEFMESSAGE_H */
diff --git a/ktnef/ktnef/ktnefparser.h b/ktnef/ktnef/ktnefparser.h
new file mode 100644
index 000000000..3696cd17c
--- /dev/null
+++ b/ktnef/ktnef/ktnefparser.h
@@ -0,0 +1,58 @@
+/*
+ ktnefparser.h
+
+ Copyright (C) 2002 Michael Goffioul <kdeprint@swing.be>
+
+ This file is part of KTNEF, the KDE TNEF support library/program.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef KTNEFPARSER_H
+#define KTNEFPARSER_H
+
+#include <qptrlist.h>
+#include <qstring.h>
+#include <qmap.h>
+#include <kdepimmacros.h>
+
+class KTNEFAttach;
+class KTNEFMessage;
+class KTNEFProperty;
+
+class KDE_EXPORT KTNEFParser
+{
+public:
+ KTNEFParser();
+ ~KTNEFParser();
+
+ bool openFile(const QString& filename);
+ bool openDevice( QIODevice *device );
+ bool extractFile(const QString& filename);
+ bool extractFileTo(const QString& filename, const QString& dirname);
+ bool extractAll();
+ void setDefaultExtractDir(const QString& dirname);
+ KTNEFMessage* message() const;
+
+private:
+ bool decodeAttachment();
+ bool decodeMessage();
+ bool extractAttachmentTo(KTNEFAttach *att, const QString& dirname);
+ bool parseDevice();
+ void checkCurrent(int state);
+ bool readMAPIProperties(QMap<int,KTNEFProperty*>& pros, KTNEFAttach *attach = 0);
+ void deleteDevice();
+
+private:
+ class ParserPrivate;
+ ParserPrivate *d;
+};
+
+#endif
diff --git a/ktnef/ktnef/ktnefproperty.h b/ktnef/ktnef/ktnefproperty.h
new file mode 100644
index 000000000..b56b9f802
--- /dev/null
+++ b/ktnef/ktnef/ktnefproperty.h
@@ -0,0 +1,63 @@
+/*
+ ktnefproperty.h
+
+ Copyright (C) 2002 Michael Goffioul <kdeprint@swing.be>
+
+ This file is part of KTNEF, the KDE TNEF support library/program.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef KTNEFPROPERTY_H
+#define KTNEFPROPERTY_H
+
+#include <qvariant.h>
+#include <qstring.h>
+#include <kdepimmacros.h>
+
+class KDE_EXPORT KTNEFProperty
+{
+public:
+ enum MAPIType
+ {
+ UInt16 = 0x0002,
+ ULong = 0x0003,
+ Float = 0x0004,
+ Double = 0x0005,
+ Boolean = 0x000B,
+ Object = 0x000D,
+ Time = 0x0040,
+ String8 = 0x001E,
+ UString = 0x001F,
+ Binary = 0x0102
+ };
+
+ KTNEFProperty();
+ KTNEFProperty( int key_, int type_, const QVariant& value_, const QVariant& name_ = QVariant() );
+ KTNEFProperty( const KTNEFProperty& p );
+
+ QString keyString();
+ QString valueString();
+ static QString formatValue( const QVariant& v, bool beautify=true );
+
+ int key() const;
+ int type() const;
+ QVariant value() const;
+ QVariant name() const;
+ bool isVector() const;
+
+private:
+ int _key;
+ int _type;
+ QVariant _value;
+ QVariant _name;
+};
+
+#endif /* KTNEFPROPERTY_H */
diff --git a/ktnef/ktnef/ktnefpropertyset.h b/ktnef/ktnef/ktnefpropertyset.h
new file mode 100644
index 000000000..387acbd3a
--- /dev/null
+++ b/ktnef/ktnef/ktnefpropertyset.h
@@ -0,0 +1,54 @@
+/*
+ ktnefpropertyset.h
+
+ Copyright (C) 2002 Michael Goffioul <kdeprint@swing.be>
+
+ This file is part of KTNEF, the KDE TNEF support library/program.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef KTNEFPROPERTYSET_H
+#define KTNEFPROPERTYSET_H
+
+#include <qmap.h>
+#include <qvariant.h>
+#include <kdepimmacros.h>
+
+class KTNEFProperty;
+
+class KDE_EXPORT KTNEFPropertySet
+{
+public:
+ KTNEFPropertySet();
+ ~KTNEFPropertySet();
+
+ /* MAPI properties interface */
+ void addProperty( int key, int type, const QVariant& value, const QVariant& name = QVariant(), bool overwrite = false );
+ QString findProp( int key, const QString& fallback=QString::null, bool convertToUpper=false);
+ QString findNamedProp(const QString& name, const QString& fallback=QString::null, bool convertToUpper=false);
+ QMap<int,KTNEFProperty*>& properties();
+ const QMap<int,KTNEFProperty*>& properties() const;
+ QVariant property( int key ) const;
+
+ /* TNEF attributes interface */
+ void addAttribute( int key, int type, const QVariant& value, bool overwrite = false );
+ QMap<int,KTNEFProperty*>& attributes();
+ const QMap<int,KTNEFProperty*>& attributes() const;
+ QVariant attribute( int key ) const;
+
+ void clear( bool deleteAll = false );
+
+private:
+ QMap<int,KTNEFProperty*> properties_; /* used to store MAPI properties */
+ QMap<int,KTNEFProperty*> attributes_; /* used to store TNEF attributes */
+};
+
+#endif /* KTNEFPROPERTYSET_H */
diff --git a/ktnef/ktnef/ktnefwriter.h b/ktnef/ktnef/ktnefwriter.h
new file mode 100644
index 000000000..ab04c0b37
--- /dev/null
+++ b/ktnef/ktnef/ktnefwriter.h
@@ -0,0 +1,92 @@
+/*
+ ktnefwriter.cpp
+
+ Copyright (C) 2002 Bo Thorsen <bo@sonofthor.dk>
+
+ This file is part of KTNEF, the KDE TNEF support library/program.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef KTNEFWRITER_H
+#define KTNEFWRITER_H
+
+class QString;
+class QVariant;
+class QIODevice;
+class QDataStream;
+class QDateTime;
+class QStringList;
+
+class KTNEFWriter {
+public:
+ KTNEFWriter();
+ ~KTNEFWriter();
+
+ void addProperty( int tag, int type, const QVariant& value );
+
+ bool writeFile( QIODevice &file );
+ bool writeFile( QDataStream &stream );
+
+ bool writeProperty( QDataStream &stream, int &bytes, int type);
+
+ enum MessageType {
+ Appointment, MeetingCancelled, MeetingRequest,
+ MeetingNo, MeetingYes, MeetingTent
+ };
+
+ enum Method {
+ PublishNew, Obsolete, RequestNew, RequestUpdate, Unknown
+ };
+
+ enum Role {
+ ReqParticipant, OptParticipant, NonParticipant, Chair
+ };
+
+ enum PartStat {
+ NeedsAction, Accepted, Declined, Tentative,
+ Delegated, Completed, InProcess
+ };
+
+ enum Priority {
+ High = 2, Normal = 3, Low = 1
+ };
+
+ enum AlarmAction {
+ Display
+ };
+
+ // This set of functions sets all properties on the file you want to save
+ void setSender(const QString &name, const QString &email);
+ void setMessageType(MessageType m);
+ void setMethod( Method m );
+ void clearAttendees();
+ void addAttendee( const QString& cn, Role r, PartStat p, bool rsvp,
+ const QString& mailto );
+ void setOrganizer( const QString& organizer ); // Is that the same as sender???
+ void setDtStart( const QDateTime& dtStart );
+ void setDtEnd( const QDateTime& dtEnd );
+ void setLocation( const QString& location );
+ void setUID( const QString& uid );
+ void setDtStamp( const QDateTime& dtStamp );
+ void setCategories( const QStringList& );
+ void setDescription( const QString& );
+ void setSummary( const QString& );
+ void setPriority( Priority p );
+ void setAlarm( const QString& description, AlarmAction action,
+ const QDateTime& wakeBefore );
+
+private:
+ class PrivateData;
+ PrivateData *mData;
+};
+
+
+#endif // KTNEFWRITER_H
diff --git a/ktnef/lib/Makefile.am b/ktnef/lib/Makefile.am
new file mode 100644
index 000000000..731e3a377
--- /dev/null
+++ b/ktnef/lib/Makefile.am
@@ -0,0 +1,11 @@
+INCLUDES = -I$(top_srcdir)/ktnef $(all_includes)
+
+lib_LTLIBRARIES = libktnef.la
+
+libktnef_la_SOURCES = ktnefparser.cpp ktnefproperty.cpp ktnefattach.cpp mapi.cpp \
+ ktnefpropertyset.cpp ktnefmessage.cpp ktnefwriter.cpp lzfu.cpp
+libktnef_la_LIBADD = $(LIB_KDECORE) $(LIB_KIO)
+libktnef_la_LDFLAGS = $(all_libraries) -version-info 1:0:0 -no-undefined
+libktnef_la_METASOURCES = AUTO
+
+noinst_HEADERS = mapi.h lzfu.h
diff --git a/ktnef/lib/ktnefattach.cpp b/ktnef/lib/ktnefattach.cpp
new file mode 100644
index 000000000..76b1aeef0
--- /dev/null
+++ b/ktnef/lib/ktnefattach.cpp
@@ -0,0 +1,127 @@
+/*
+ ktnefattach.cpp
+
+ Copyright (C) 2002 Michael Goffioul <kdeprint@swing.be>
+
+ This file is part of KTNEF, the KDE TNEF support library/program.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "ktnef/ktnefattach.h"
+#include "ktnef/ktnefproperty.h"
+
+class KTNEFAttach::AttachPrivate
+{
+public:
+ int state_;
+ int size_;
+ int offset_;
+ int displaysize_;
+ QString name_;
+ int index_;
+ QString filename_;
+ QString displayname_;
+ QString mimetag_;
+ QString extension_;
+};
+
+KTNEFAttach::KTNEFAttach()
+{
+ d = new AttachPrivate;
+ d->state_ = Unparsed;
+ d->offset_ = -1;
+ d->size_ = 0;
+ d->displaysize_ = 0;
+ d->index_ = -1;
+}
+
+KTNEFAttach::~KTNEFAttach()
+{
+ delete d;
+}
+
+void KTNEFAttach::setTitleParsed()
+{ d->state_ |= TitleParsed; }
+
+void KTNEFAttach::setDataParsed()
+{ d->state_ |= DataParsed; }
+
+void KTNEFAttach::unsetDataParser()
+{ d->state_ = ( d->state_ & ~DataParsed ); }
+
+void KTNEFAttach::setInfoParsed()
+{ d->state_ |= InfoParsed; }
+
+bool KTNEFAttach::titleParsed() const
+{ return (d->state_ & TitleParsed); }
+
+bool KTNEFAttach::dataParsed() const
+{ return (d->state_ & DataParsed); }
+
+bool KTNEFAttach::infoParsed() const
+{ return (d->state_ & InfoParsed); }
+
+bool KTNEFAttach::checkState(int state) const
+{ return (d->state_ & state); }
+
+int KTNEFAttach::offset() const
+{ return d->offset_; }
+
+void KTNEFAttach::setOffset(int n)
+{ setDataParsed(); d->offset_ = n; }
+
+int KTNEFAttach::size() const
+{ return d->size_; }
+
+void KTNEFAttach::setSize(int s)
+{ d->size_ = s; }
+
+int KTNEFAttach::displaySize() const
+{ return d->displaysize_; }
+
+void KTNEFAttach::setDisplaySize(int s)
+{ d->displaysize_ = s; }
+
+QString KTNEFAttach::name() const
+{ return d->name_; }
+
+void KTNEFAttach::setName(const QString& str)
+{ setTitleParsed(); d->name_ = str; }
+
+int KTNEFAttach::index() const
+{ return d->index_; }
+
+void KTNEFAttach::setIndex(int i)
+{ setInfoParsed(); d->index_ = i; }
+
+QString KTNEFAttach::fileName() const
+{ return d->filename_; }
+
+void KTNEFAttach::setFileName(const QString& str)
+{ d->filename_ = str; }
+
+QString KTNEFAttach::displayName() const
+{ return d->displayname_; }
+
+void KTNEFAttach::setDisplayName(const QString& str)
+{ d->displayname_ = str; }
+
+QString KTNEFAttach::mimeTag() const
+{ return d->mimetag_; }
+
+void KTNEFAttach::setMimeTag(const QString& str)
+{ d->mimetag_ = str; }
+
+QString KTNEFAttach::extension() const
+{ return d->extension_; }
+
+void KTNEFAttach::setExtension(const QString& str)
+{ d->extension_ = str; }
diff --git a/ktnef/lib/ktnefmessage.cpp b/ktnef/lib/ktnefmessage.cpp
new file mode 100644
index 000000000..d94efb6c4
--- /dev/null
+++ b/ktnef/lib/ktnefmessage.cpp
@@ -0,0 +1,82 @@
+/*
+ ktnefmessage.cpp
+
+ Copyright (C) 2002 Michael Goffioul <kdeprint@swing.be>
+
+ This file is part of KTNEF, the KDE TNEF support library/program.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "ktnef/ktnefmessage.h"
+#include "ktnef/ktnefattach.h"
+
+#include "lzfu.h"
+#include <qbuffer.h>
+
+class KTNEFMessage::MessagePrivate
+{
+public:
+ MessagePrivate()
+ {
+ attachments_.setAutoDelete( true );
+ }
+
+ QPtrList<KTNEFAttach> attachments_;
+};
+
+KTNEFMessage::KTNEFMessage()
+{
+ d = new MessagePrivate;
+}
+
+KTNEFMessage::~KTNEFMessage()
+{
+ delete d;
+}
+
+const QPtrList<KTNEFAttach>& KTNEFMessage::attachmentList() const
+{
+ return d->attachments_;
+}
+
+KTNEFAttach* KTNEFMessage::attachment( const QString& filename ) const
+{
+ QPtrListIterator<KTNEFAttach> it( d->attachments_ );
+ for ( ; it.current(); ++it )
+ if ( it.current()->name() == filename )
+ return it.current();
+ return 0;
+}
+
+void KTNEFMessage::addAttachment( KTNEFAttach *attach )
+{
+ d->attachments_.append( attach );
+}
+
+void KTNEFMessage::clearAttachments()
+{
+ d->attachments_.clear();
+}
+
+QString KTNEFMessage::rtfString()
+{
+ QVariant prop = property( 0x1009 );
+ if ( prop.isNull() || prop.type() != QVariant::ByteArray)
+ return QString::null;
+ else
+ {
+ QByteArray rtf;
+ QBuffer input( prop.asByteArray() ), output( rtf );
+ if ( input.open( IO_ReadOnly ) && output.open( IO_WriteOnly ) )
+ lzfu_decompress( &input, &output );
+ return QString( rtf );
+ }
+}
diff --git a/ktnef/lib/ktnefparser.cpp b/ktnef/lib/ktnefparser.cpp
new file mode 100644
index 000000000..0c9881400
--- /dev/null
+++ b/ktnef/lib/ktnefparser.cpp
@@ -0,0 +1,883 @@
+/*
+ ktnefparser.cpp
+
+ Copyright (C) 2002 Michael Goffioul <kdeprint@swing.be>
+
+ This file is part of KTNEF, the KDE TNEF support library/program.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include "ktnef/ktnefparser.h"
+#include "ktnef/ktnefattach.h"
+#include "ktnef/ktnefproperty.h"
+#include "ktnef/ktnefmessage.h"
+
+#include <qdatetime.h>
+#include <qdatastream.h>
+#include <qfile.h>
+#include <qvariant.h>
+#include <kdebug.h>
+#include <kmimetype.h>
+#include <ksavefile.h>
+
+#ifdef HAVE_INTTYPES_H
+#include <inttypes.h>
+#endif /* HAVE_INTTYPES_H */
+
+#include "ktnef/ktnefdefs.h"
+
+
+typedef struct {
+ Q_UINT16 type;
+ Q_UINT16 tag;
+ QVariant value;
+ struct {
+ Q_UINT32 type;
+ QVariant value;
+ } name;
+} MAPI_value;
+
+void clearMAPIName( MAPI_value& mapi );
+void clearMAPIValue(MAPI_value& mapi, bool clearName = true);
+QString readMAPIString( QDataStream& stream, bool isUnicode = false, bool align = true, int len = -1 );
+Q_UINT16 readMAPIValue(QDataStream& stream, MAPI_value& mapi);
+QDateTime readTNEFDate( QDataStream& stream );
+QString readTNEFAddress( QDataStream& stream );
+QByteArray readTNEFData( QDataStream& stream, Q_UINT32 len );
+QVariant readTNEFAttribute( QDataStream& stream, Q_UINT16 type, Q_UINT32 len );
+QDateTime formatTime( Q_UINT32 lowB, Q_UINT32 highB );
+QString formatRecipient( const QMap<int,KTNEFProperty*>& props );
+
+//------------------------------------------------------------------------------------
+
+class KTNEFParser::ParserPrivate
+{
+public:
+ ParserPrivate()
+ {
+ defaultdir_ = "/tmp/";
+ current_ = 0;
+ deleteDevice_ = false;
+ device_ = 0;
+ message_ = new KTNEFMessage;
+ }
+ ~ParserPrivate()
+ {
+ delete message_;
+ }
+
+ QDataStream stream_;
+ QIODevice *device_;
+ bool deleteDevice_;
+ QString defaultdir_;
+ KTNEFAttach *current_;
+ KTNEFMessage *message_;
+};
+
+KTNEFParser::KTNEFParser()
+{
+ d = new ParserPrivate;
+}
+
+KTNEFParser::~KTNEFParser()
+{
+ deleteDevice();
+ delete d;
+}
+
+KTNEFMessage* KTNEFParser::message() const
+{
+ return d->message_;
+}
+
+void KTNEFParser::deleteDevice()
+{
+ if ( d->deleteDevice_ )
+ delete d->device_;
+ d->device_ = 0;
+ d->deleteDevice_ = false;
+}
+
+bool KTNEFParser::decodeMessage()
+{
+ Q_UINT32 i1, i2, off;
+ Q_UINT16 u, tag, type;
+ QVariant value;
+
+ // read (type+name)
+ d->stream_ >> i1;
+ u = 0;
+ tag = ( i1 & 0x0000FFFF );
+ type = ( ( i1 & 0xFFFF0000 ) >> 16 );
+ // read data length
+ d->stream_ >> i2;
+ // offset after reading the value
+ off = d->device_->at() + i2;
+ switch ( tag )
+ {
+ case attAIDOWNER:
+ d->stream_ >> value.asUInt();
+ d->message_->addProperty( 0x0062, MAPI_TYPE_ULONG, value );
+ kdDebug() << "Message Owner Appointment ID" << " (length=" << i2 << ")" << endl;
+ break;
+ case attREQUESTRES:
+ d->stream_ >> u;
+ d->message_->addProperty( 0x0063, MAPI_TYPE_UINT16, u );
+ value = ( bool )u;
+ kdDebug() << "Message Request Response" << " (length=" << i2 << ")" << endl;
+ break;
+ case attDATERECD:
+ value = readTNEFDate( d->stream_ );
+ d->message_->addProperty( 0x0E06, MAPI_TYPE_TIME, value );
+ kdDebug() << "Message Receive Date" << " (length=" << i2 << ")" << endl;
+ break;
+ case attMSGCLASS:
+ value = readMAPIString( d->stream_, false, false, i2 );
+ d->message_->addProperty( 0x001A, MAPI_TYPE_STRING8, value );
+ kdDebug() << "Message Class" << " (length=" << i2 << ")" << endl;
+ break;
+ case attMSGPRIORITY:
+ d->stream_ >> u;
+ d->message_->addProperty( 0x0026, MAPI_TYPE_ULONG, 2-u );
+ value = u;
+ kdDebug() << "Message Priority" << " (length=" << i2 << ")" << endl;
+ break;
+ case attMAPIPROPS:
+ kdDebug() << "Message MAPI Properties" << " (length=" << i2 << ")" << endl;
+ {
+ int nProps = d->message_->properties().count();
+ i2 += d->device_->at();
+ readMAPIProperties( d->message_->properties(), 0 );
+ d->device_->at( i2 );
+ kdDebug() << "Properties: " << d->message_->properties().count() << endl;
+ value = QString( "< %1 properties >" ).arg( d->message_->properties().count() - nProps );
+ }
+ break;
+ case attTNEFVERSION:
+ d->stream_ >> value.asUInt();
+ kdDebug() << "Message TNEF Version" << " (length=" << i2 << ")" << endl;
+ break;
+ case attFROM:
+ d->message_->addProperty( 0x0024, MAPI_TYPE_STRING8, readTNEFAddress( d->stream_ ) );
+ d->device_->at( d->device_->at() - i2 );
+ value = readTNEFData( d->stream_, i2 );
+ kdDebug() << "Message From" << " (length=" << i2 << ")" << endl;
+ break;
+ case attSUBJECT:
+ value = readMAPIString( d->stream_, false, false, i2 );
+ d->message_->addProperty( 0x0037, MAPI_TYPE_STRING8, value );
+ kdDebug() << "Message Subject" << " (length=" << i2 << ")" << endl;
+ break;
+ case attDATESENT:
+ value = readTNEFDate( d->stream_ );
+ d->message_->addProperty( 0x0039, MAPI_TYPE_TIME, value );
+ kdDebug() << "Message Date Sent" << " (length=" << i2 << ")" << endl;
+ break;
+ case attMSGSTATUS:
+ {
+ Q_UINT8 c;
+ Q_UINT32 flag = 0;
+ d->stream_ >> c;
+ if ( c & fmsRead ) flag |= MSGFLAG_READ;
+ if ( !( c & fmsModified ) ) flag |= MSGFLAG_UNMODIFIED;
+ if ( c & fmsSubmitted ) flag |= MSGFLAG_SUBMIT;
+ if ( c & fmsHasAttach ) flag |= MSGFLAG_HASATTACH;
+ if ( c & fmsLocal ) flag |= MSGFLAG_UNSENT;
+ d->message_->addProperty( 0x0E07, MAPI_TYPE_ULONG, flag );
+ value = c;
+ }
+ kdDebug() << "Message Status" << " (length=" << i2 << ")" << endl;
+ break;
+ case attRECIPTABLE:
+ {
+ Q_UINT32 rows;
+ QValueList<QVariant> recipTable;
+ d->stream_ >> rows;
+ for ( uint i=0; i<rows; i++ )
+ {
+ QMap<int,KTNEFProperty*> props;
+ readMAPIProperties( props, 0 );
+ recipTable << formatRecipient( props );
+ }
+ d->message_->addProperty( 0x0E12, MAPI_TYPE_STRING8, recipTable );
+ d->device_->at( d->device_->at() - i2 );
+ value = readTNEFData( d->stream_, i2 );
+ }
+ kdDebug() << "Message Recipient Table" << " (length=" << i2 << ")" << endl;
+ break;
+ case attBODY:
+ value = readMAPIString( d->stream_, false, false, i2 );
+ d->message_->addProperty( 0x1000, MAPI_TYPE_STRING8, value );
+ kdDebug() << "Message Body" << " (length=" << i2 << ")" << endl;
+ break;
+ case attDATEMODIFIED:
+ value = readTNEFDate( d->stream_ );
+ d->message_->addProperty( 0x3008, MAPI_TYPE_TIME, value );
+ kdDebug() << "Message Date Modified" << " (length=" << i2 << ")" << endl;
+ break;
+ case attMSGID:
+ value = readMAPIString( d->stream_, false, false, i2 );
+ d->message_->addProperty( 0x300B, MAPI_TYPE_STRING8, value );
+ kdDebug() << "Message ID" << " (length=" << i2 << ")" << endl;
+ break;
+ case attOEMCODEPAGE:
+ value = readTNEFData( d->stream_, i2 );
+ kdDebug() << "Message OEM Code Page" << " (length=" << i2 << ")" << endl;
+ break;
+ default:
+ value = readTNEFAttribute( d->stream_, type, i2 );
+ kdDebug().form( "Message: type=%x, length=%d, check=%x\n", i1, i2, u );
+ break;
+ }
+ // skip data
+ if ( d->device_->at() != off && !d->device_->at( off ) )
+ return false;
+ // get checksum
+ d->stream_ >> u;
+ // add TNEF attribute
+ d->message_->addAttribute( tag, type, value, true );
+ //kdDebug() << "stream: " << d->device_->at() << endl;
+ return true;
+}
+
+bool KTNEFParser::decodeAttachment()
+{
+ Q_UINT32 i;
+ Q_UINT16 tag, type, u;
+ QVariant value;
+ QString str;
+
+ d->stream_ >> i; // i <- attribute type & name
+ tag = ( i & 0x0000FFFF );
+ type = ( ( i & 0xFFFF0000 ) >> 16 );
+ d->stream_ >> i; // i <- data length
+ checkCurrent( tag );
+ switch (tag)
+ {
+ case attATTACHTITLE:
+ value = readMAPIString( d->stream_, false, false, i );
+ d->current_->setName( value.toString() );
+ kdDebug() << "Attachment Title: " << d->current_->name() << endl;
+ break;
+ case attATTACHDATA:
+ d->current_->setSize( i );
+ d->current_->setOffset( d->device_->at() );
+ d->device_->at( d->device_->at() + i );
+ value = QString( "< size=%1 >" ).arg( i );
+ kdDebug() << "Attachment Data: size=" << i << endl;
+ break;
+ case attATTACHMENT: // try to get attachment info
+ i += d->device_->at();
+ readMAPIProperties( d->current_->properties(), d->current_ );
+ d->device_->at( i );
+ d->current_->setIndex( d->current_->property( MAPI_TAG_INDEX ).toUInt() );
+ d->current_->setDisplaySize( d->current_->property( MAPI_TAG_SIZE ).toUInt() );
+ str = d->current_->property( MAPI_TAG_DISPLAYNAME ).toString();
+ if ( !str.isEmpty() )
+ d->current_->setDisplayName( str );
+ d->current_->setFileName( d->current_->property( MAPI_TAG_FILENAME ).toString() );
+ str = d->current_->property( MAPI_TAG_MIMETAG ).toString();
+ if ( !str.isEmpty() )
+ d->current_->setMimeTag( str );
+ d->current_->setExtension( d->current_->property( MAPI_TAG_EXTENSION ).toString() );
+ value = QString( "< %1 properties >" ).arg( d->current_->properties().count() );
+ break;
+ case attATTACHMODDATE:
+ value = readTNEFDate( d->stream_ );
+ kdDebug() << "Attachment Modification Date: " << value.toString() << endl;
+ break;
+ case attATTACHCREATEDATE:
+ value = readTNEFDate( d->stream_ );
+ kdDebug() << "Attachment Creation Date: " << value.toString() << endl;
+ break;
+ case attATTACHMETAFILE:
+ kdDebug() << "Attachment Metafile: size=" << i << endl;
+ //value = QString( "< size=%1 >" ).arg( i );
+ //d->device_->at( d->device_->at()+i );
+ value = readTNEFData( d->stream_, i );
+ break;
+ default:
+ value = readTNEFAttribute( d->stream_, type, i );
+ kdDebug().form( "Attachment unknown field: tag=%x, length=%d\n", tag, i);
+ break;
+ }
+ d->stream_ >> u; // u <- checksum
+ // add TNEF attribute
+ d->current_->addAttribute( tag, type, value, true );
+ //kdDebug() << "stream: " << d->device_->at() << endl;
+
+ return true;
+}
+
+void KTNEFParser::setDefaultExtractDir(const QString& dirname)
+{
+ d->defaultdir_ = dirname;
+}
+
+bool KTNEFParser::parseDevice()
+{
+ Q_UINT16 u;
+ Q_UINT32 i;
+ Q_UINT8 c;
+
+ d->message_->clearAttachments();
+ if (d->current_)
+ {
+ delete d->current_;
+ d->current_ = 0;
+ }
+
+ if ( !d->device_->open( IO_ReadOnly ) ) {
+ kdDebug() << "Couldn't open device" << endl;
+ return false;
+ }
+
+ d->stream_.setDevice( d->device_ );
+ d->stream_.setByteOrder( QDataStream::LittleEndian );
+ d->stream_ >> i;
+ if (i == TNEF_SIGNATURE)
+ {
+ d->stream_ >> u;
+ kdDebug().form( "Attachment cross reference key: 0x%04x\n",u );
+ //kdDebug() << "stream: " << d->device_->at() << endl;
+ while (!d->stream_.eof())
+ {
+ d->stream_ >> c;
+ switch (c)
+ {
+ case LVL_MESSAGE:
+ if (!decodeMessage()) goto end;
+ break;
+ case LVL_ATTACHMENT:
+ if (!decodeAttachment()) goto end;
+ break;
+ default:
+ kdDebug() << "Unknown Level: " << c << ", at offset " << d->device_->at() << endl;
+ goto end;
+ }
+ }
+ if (d->current_)
+ {
+ checkCurrent(attATTACHDATA); // this line has the effect to append the
+ // attachment, if it has data. If not it does
+ // nothing, and the attachment will be discarded
+ delete d->current_;
+ d->current_ = 0;
+ }
+ return true;
+ }
+ else
+ {
+ kdDebug() << "This is not a TNEF file" << endl;
+end: d->device_->close();
+ return false;
+ }
+}
+
+bool KTNEFParser::extractFile(const QString& filename)
+{
+ KTNEFAttach *att = d->message_->attachment(filename);
+ if (!att) return false;
+ return extractAttachmentTo(att, d->defaultdir_);
+}
+
+bool KTNEFParser::extractAttachmentTo(KTNEFAttach *att, const QString& dirname)
+{
+ QString filename = dirname + "/" + att->name();
+ if (!d->device_->isOpen())
+ return false;
+ if (!d->device_->at(att->offset()))
+ return false;
+ KSaveFile saveFile( filename );
+ QFile *outfile = saveFile.file();
+ if ( !outfile )
+ return false;
+
+ Q_UINT32 len = att->size(), sz(16384);
+ int n(0);
+ char *buf = new char[sz];
+ bool ok(true);
+ while (ok && len > 0)
+ {
+ n = d->device_->readBlock(buf,QMIN(sz,len));
+ if (n < 0)
+ ok = false;
+ else
+ {
+ len -= n;
+ if (outfile->writeBlock(buf,n) != n)
+ ok = false;
+ }
+ }
+ delete [] buf;
+
+ return ok;
+}
+
+bool KTNEFParser::extractAll()
+{
+ QPtrListIterator<KTNEFAttach> it(d->message_->attachmentList());
+ for (;it.current();++it)
+ if (!extractAttachmentTo(it.current(),d->defaultdir_)) return false;
+ return true;
+}
+
+bool KTNEFParser::extractFileTo(const QString& filename, const QString& dirname)
+{
+ kdDebug() << "Extracting attachment: filename=" << filename << ", dir=" << dirname << endl;
+ KTNEFAttach *att = d->message_->attachment(filename);
+ if (!att) return false;
+ return extractAttachmentTo(att, dirname);
+}
+
+bool KTNEFParser::openFile(const QString& filename)
+{
+ deleteDevice();
+ delete d->message_;
+ d->message_ = new KTNEFMessage();
+ d->device_ = new QFile( filename );
+ d->deleteDevice_ = true;
+ return parseDevice();
+}
+
+bool KTNEFParser::openDevice( QIODevice *device )
+{
+ deleteDevice();
+ d->device_ = device;
+ return parseDevice();
+}
+
+void KTNEFParser::checkCurrent( int key )
+{
+ if ( !d->current_ )
+ d->current_ = new KTNEFAttach();
+ else
+ {
+ if ( d->current_->attributes().contains( key ) )
+ {
+ if (d->current_->offset() >= 0 )
+ {
+ if (d->current_->name().isEmpty())
+ d->current_->setName("Unnamed");
+ if ( d->current_->mimeTag().isEmpty() )
+ {
+ // No mime type defined in the TNEF structure,
+ // try to find it from the attachment filename
+ // and/or content (using at most 32 bytes)
+ KMimeType::Ptr mimetype;
+ if ( !d->current_->fileName().isEmpty() )
+ mimetype = KMimeType::findByPath( d->current_->fileName(), 0, true );
+ if (!mimetype) return; // FIXME
+ if ( mimetype->name() == "application/octet-stream" && d->current_->size() > 0 )
+ {
+ int oldOffset = d->device_->at();
+ QByteArray buffer( QMIN( 32, d->current_->size() ) );
+ d->device_->at( d->current_->offset() );
+ d->device_->readBlock( buffer.data(), buffer.size() );
+ mimetype = KMimeType::findByContent( buffer );
+ d->device_->at( oldOffset );
+ }
+ d->current_->setMimeTag( mimetype->name() );
+ }
+ d->message_->addAttachment( d->current_ );
+ d->current_ = 0;
+ }
+ else
+ { // invalid attachment, skip it
+ delete d->current_;
+ d->current_ = 0;
+ }
+ d->current_ = new KTNEFAttach();
+ }
+ }
+}
+
+//----------------------------------------------------------------------------------------
+
+#define ALIGN( n, b ) if ( n & ( b-1 ) ) { n = ( n + b ) & ~( b-1 ); }
+#define ISVECTOR( m ) ( ( ( m ).type & 0xF000 ) == MAPI_TYPE_VECTOR )
+
+void clearMAPIName( MAPI_value& mapi )
+{
+ mapi.name.value.clear();
+}
+
+void clearMAPIValue(MAPI_value& mapi, bool clearName)
+{
+ mapi.value.clear();
+ if ( clearName )
+ clearMAPIName( mapi );
+}
+
+QDateTime formatTime( Q_UINT32 lowB, Q_UINT32 highB )
+{
+ QDateTime dt;
+#if ( SIZEOF_UINT64_T == 8 )
+ uint64_t u64;
+#elif ( SIZEOF_UNSIGNED_LONG_LONG == 8 )
+ unsigned long long u64;
+#elif ( SIZEOF_UNSIGNED_LONG == 8 )
+ unsigned long u64;
+#else
+ kdWarning() << "Unable to perform date conversion on this system, no 64-bits integer found" << endl;
+ dt.setTime_t( 0xffffffffU );
+ return dt;
+#endif
+ u64 = highB;
+ u64 <<= 32;
+ u64 |= lowB;
+ u64 -= 116444736000000000LL;
+ u64 /= 10000000;
+ if ( u64 <= 0xffffffffU )
+ dt.setTime_t( ( unsigned int )u64 );
+ else
+ {
+ kdWarning().form( "Invalid date: low byte=0x%08X, high byte=0x%08X\n", lowB, highB );
+ dt.setTime_t( 0xffffffffU );
+ }
+ return dt;
+}
+
+QString formatRecipient( const QMap<int,KTNEFProperty*>& props )
+{
+ QString s, dn, addr, t;
+ QMap<int,KTNEFProperty*>::ConstIterator it;
+ if ( ( it = props.find( 0x3001 ) ) != props.end() )
+ dn = ( *it )->valueString();
+ if ( ( it = props.find( 0x3003 ) ) != props.end() )
+ addr = ( *it )->valueString();
+ if ( ( it = props.find( 0x0C15 ) ) != props.end() )
+ switch ( ( *it )->value().toInt() )
+ {
+ case 0: t = "From:"; break;
+ case 1: t = "To:"; break;
+ case 2: t = "Cc:"; break;
+ case 3: t = "Bcc:"; break;
+ }
+
+ if ( !t.isEmpty() )
+ s.append( t );
+ if ( !dn.isEmpty() )
+ s.append( " " + dn );
+ if ( !addr.isEmpty() && addr != dn )
+ s.append( " <" + addr + ">" );
+
+ return s.stripWhiteSpace();
+}
+
+QDateTime readTNEFDate( QDataStream& stream )
+{
+ // 14-bytes long
+ Q_UINT16 y, m, d, hh, mm, ss, dm;
+ stream >> y >> m >> d >> hh >> mm >> ss >> dm;
+ return QDateTime( QDate( y, m, d ), QTime( hh, mm, ss ) );
+}
+
+QString readTNEFAddress( QDataStream& stream )
+{
+ Q_UINT16 totalLen, strLen, addrLen;
+ QString s;
+ stream >> totalLen >> totalLen >> strLen >> addrLen;
+ s.append( readMAPIString( stream, false, false, strLen ) );
+ s.append( " <" );
+ s.append( readMAPIString( stream, false, false, addrLen ) );
+ s.append( ">" );
+ Q_UINT8 c;
+ for ( int i=8+strLen+addrLen; i<totalLen; i++ )
+ stream >> c;
+ return s;
+}
+
+QByteArray readTNEFData( QDataStream& stream, Q_UINT32 len )
+{
+ QByteArray array( len );
+ if ( len > 0 )
+ stream.readRawBytes( array.data(), len );
+ return array;
+}
+
+QVariant readTNEFAttribute( QDataStream& stream, Q_UINT16 type, Q_UINT32 len )
+{
+ switch ( type )
+ {
+ case atpTEXT:
+ case atpSTRING:
+ return readMAPIString( stream, false, false, len );
+ case atpDATE:
+ return readTNEFDate( stream );
+ default:
+ return readTNEFData( stream, len );
+ }
+}
+
+QString readMAPIString( QDataStream& stream, bool isUnicode, bool align, int len_ )
+{
+ Q_UINT32 len;
+ char *buf = 0;
+ if ( len_ == -1 )
+ stream >> len;
+ else
+ len = len_;
+ Q_UINT32 fullLen = len;
+ if ( align )
+ ALIGN( fullLen, 4 );
+ buf = new char[ len ];
+ stream.readRawBytes( buf, len );
+ Q_UINT8 c;
+ for ( uint i=len; i<fullLen; i++ )
+ stream >> c;
+ QString res;
+ if ( isUnicode )
+ res = QString::fromUcs2( ( const unsigned short* )buf );
+ else
+ res = QString::fromLocal8Bit( buf );
+ delete [] buf;
+ return res;
+}
+
+Q_UINT16 readMAPIValue(QDataStream& stream, MAPI_value& mapi)
+{
+ Q_UINT32 d;
+
+ clearMAPIValue(mapi);
+ stream >> d;
+ mapi.type = (d & 0x0000FFFF);
+ mapi.tag = ((d & 0xFFFF0000) >> 16);
+ if ( mapi.tag >= 0x8000 && mapi.tag <= 0xFFFE )
+ {
+ // skip GUID
+ stream >> d >> d >> d >> d;
+ // name type
+ stream >> mapi.name.type;
+ // name
+ if ( mapi.name.type == 0 )
+ stream >> mapi.name.value.asUInt();
+ else if ( mapi.name.type == 1 )
+ mapi.name.value.asString() = readMAPIString( stream, true );
+ }
+
+ int n = 1;
+ QVariant value;
+ if ( ISVECTOR( mapi ) )
+ {
+ stream >> n;
+ mapi.value = QValueList<QVariant>();
+ }
+ for ( int i=0; i<n; i++ )
+ {
+ value.clear();
+ switch(mapi.type & 0x0FFF)
+ {
+ case MAPI_TYPE_UINT16:
+ stream >> d;
+ value.asUInt() = ( d & 0x0000FFFF );
+ break;
+ case MAPI_TYPE_BOOLEAN:
+ case MAPI_TYPE_ULONG:
+ stream >> value.asUInt();
+ break;
+ case MAPI_TYPE_FLOAT:
+ stream >> d;
+ break;
+ case MAPI_TYPE_DOUBLE:
+ stream >> value.asDouble();
+ break;
+ case MAPI_TYPE_TIME:
+ {
+ Q_UINT32 lowB, highB;
+ stream >> lowB >> highB;
+ value = formatTime( lowB, highB );
+ }
+ break;
+ case MAPI_TYPE_STRING8:
+ // in case of a vector'ed value, the number of elements
+ // has already been read in the upper for-loop
+ if ( ISVECTOR( mapi ) )
+ d = 1;
+ else
+ stream >> d;
+ for (uint i=0;i<d;i++)
+ {
+ value.clear();
+ value.asString() = readMAPIString( stream );
+ }
+ break;
+ case MAPI_TYPE_USTRING:
+ mapi.type = MAPI_TYPE_NONE;
+ break;
+ case MAPI_TYPE_OBJECT:
+ case MAPI_TYPE_BINARY:
+ if ( ISVECTOR( mapi ) )
+ d = 1;
+ else
+ stream >> d;
+ for (uint i=0;i<d;i++)
+ {
+ value.clear();
+ Q_UINT32 len;
+ stream >> len;
+ value = QByteArray( len );
+ if (len > 0)
+ {
+ int fullLen = len;
+ ALIGN(fullLen, 4);
+ stream.readRawBytes(value.asByteArray().data(), len);
+ Q_UINT8 c;
+ for ( int i=len; i<fullLen; i++ )
+ stream >> c;
+ }
+ }
+ break;
+ default:
+ mapi.type = MAPI_TYPE_NONE;
+ break;
+ }
+ if ( ISVECTOR( mapi ) )
+ mapi.value.asList().append( value );
+ else
+ mapi.value = value;
+ }
+ return mapi.tag;
+}
+
+bool KTNEFParser::readMAPIProperties( QMap<int,KTNEFProperty*>& props, KTNEFAttach *attach )
+{
+ Q_UINT32 n;
+ MAPI_value mapi;
+ KTNEFProperty *p;
+ QMap<int,KTNEFProperty*>::ConstIterator it;
+ bool foundAttachment = false;
+
+ // some initializations
+ mapi.type = MAPI_TYPE_NONE;
+ mapi.value.clear();
+
+ // get number of properties
+ d->stream_ >> n;
+ kdDebug() << "MAPI Properties: " << n << endl;
+ for (uint i=0;i<n;i++)
+ {
+ if (d->stream_.eof())
+ {
+ clearMAPIValue(mapi);
+ return false;
+ }
+ readMAPIValue(d->stream_, mapi);
+ if (mapi.type == MAPI_TYPE_NONE)
+ {
+ kdDebug().form( "MAPI unsupported: tag=%x, type=%x\n", mapi.tag, mapi.type );
+ clearMAPIValue(mapi);
+ return false;
+ }
+ int key = mapi.tag;
+ switch (mapi.tag)
+ {
+ case MAPI_TAG_DATA:
+ {
+ if ( mapi.type == MAPI_TYPE_OBJECT && attach )
+ {
+ QByteArray data = mapi.value.toByteArray();
+ int len = data.size();
+ ALIGN( len, 4 );
+ d->device_->at( d->device_->at()-len );
+ Q_UINT32 interface_ID;
+ d->stream_ >> interface_ID;
+ if ( interface_ID == MAPI_IID_IMessage )
+ {
+ // embedded TNEF file
+ attach->unsetDataParser();
+ attach->setOffset( d->device_->at()+12 );
+ attach->setSize( data.size()-16 );
+ attach->setMimeTag( "application/ms-tnef" );
+ attach->setDisplayName( "Embedded Message" );
+ kdDebug() << "MAPI Embedded Message: size=" << data.size() << endl;
+ }
+ d->device_->at( d->device_->at() + ( len-4 ) );
+ break;
+ }
+ else if ( mapi.type == MAPI_TYPE_BINARY && attach && attach->offset() < 0 )
+ {
+ foundAttachment = true;
+ int len = mapi.value.toByteArray().size();
+ ALIGN( len, 4 )
+ attach->setSize( len );
+ attach->setOffset( d->device_->at() - len );
+ attach->addAttribute( attATTACHDATA, atpBYTE, QString( "< size=%1 >" ).arg( len ), false );
+ }
+ }
+ kdDebug().form( "MAPI data: size=%d\n", mapi.value.toByteArray().size() );
+ break;
+ default:
+ {
+ QString mapiname = "";
+ if ( mapi.tag >= 0x8000 && mapi.tag <= 0xFFFE )
+ {
+ if ( mapi.name.type == 0 )
+ mapiname = QString().sprintf( " [name = 0x%04x]", mapi.name.value.toUInt() );
+ else
+ mapiname = QString( " [name = %1]" ).arg( mapi.name.value.toString() );
+ }
+ switch ( mapi.type & 0x0FFF )
+ {
+ case MAPI_TYPE_UINT16:
+ kdDebug().form( "(tag=%04x) MAPI short%s: 0x%x\n", mapi.tag, mapiname.ascii(), mapi.value.toUInt() );
+ break;
+ case MAPI_TYPE_ULONG:
+ kdDebug().form( "(tag=%04x) MAPI long%s: 0x%x\n", mapi.tag, mapiname.ascii(), mapi.value.toUInt() );
+ break;
+ case MAPI_TYPE_BOOLEAN:
+ kdDebug().form( "(tag=%04x) MAPI boolean%s: %s\n", mapi.tag, mapiname.ascii(), ( mapi.value.toBool() ? "true" : "false" ) );
+ break;
+ case MAPI_TYPE_TIME:
+ kdDebug().form( "(tag=%04x) MAPI time%s: %s\n", mapi.tag, mapiname.ascii(), mapi.value.toString().ascii() );
+ break;
+ case MAPI_TYPE_USTRING:
+ case MAPI_TYPE_STRING8:
+ kdDebug().form( "(tag=%04x) MAPI string%s: size=%d \"%s\"\n", mapi.tag, mapiname.ascii(), mapi.value.toByteArray().size(), mapi.value.toString().ascii() );
+ break;
+ case MAPI_TYPE_BINARY:
+ kdDebug().form( "(tag=%04x) MAPI binary%s: size=%d\n", mapi.tag, mapiname.ascii(), mapi.value.toByteArray().size() );
+ break;
+ }
+ }
+ break;
+ }
+ // do not remove potential existing similar entry
+ if ( ( it = props.find( key ) ) == props.end() )
+ {
+ p = new KTNEFProperty( key, ( mapi.type & 0x0FFF ), mapi.value, mapi.name.value );
+ props[ p->key() ] = p;
+ }
+ //kdDebug() << "stream: " << d->device_->at() << endl;
+ }
+
+ if ( foundAttachment && attach )
+ {
+ attach->setIndex( attach->property( MAPI_TAG_INDEX ).toUInt() );
+ attach->setDisplaySize( attach->property( MAPI_TAG_SIZE ).toUInt() );
+ QString str = attach->property( MAPI_TAG_DISPLAYNAME ).toString();
+ if ( !str.isEmpty() )
+ attach->setDisplayName( str );
+ attach->setFileName( attach->property( MAPI_TAG_FILENAME ).toString() );
+ str = attach->property( MAPI_TAG_MIMETAG ).toString();
+ if ( !str.isEmpty() )
+ attach->setMimeTag( str );
+ attach->setExtension( attach->property( MAPI_TAG_EXTENSION ).toString() );
+ if ( attach->name().isEmpty() )
+ attach->setName( attach->fileName() );
+ }
+
+ return true;
+}
diff --git a/ktnef/lib/ktnefproperty.cpp b/ktnef/lib/ktnefproperty.cpp
new file mode 100644
index 000000000..3845b8d88
--- /dev/null
+++ b/ktnef/lib/ktnefproperty.cpp
@@ -0,0 +1,99 @@
+/*
+ ktnefproperty.cpp
+
+ Copyright (C) 2002 Michael Goffioul <kdeprint@swing.be>
+
+ This file is part of KTNEF, the KDE TNEF support library/program.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "ktnef/ktnefproperty.h"
+#include "mapi.h"
+#include <qdatetime.h>
+#include <ctype.h>
+
+KTNEFProperty::KTNEFProperty()
+{
+}
+
+KTNEFProperty::KTNEFProperty( int key_, int type_, const QVariant& value_, const QVariant& name_ )
+ : _key( key_ ), _type( type_ ), _value( value_ ), _name( name_ )
+{
+}
+
+KTNEFProperty::KTNEFProperty( const KTNEFProperty& p )
+ : _key( p._key ), _type( p._type ), _value( p._value ), _name( p._name )
+{
+}
+
+QString KTNEFProperty::keyString()
+{
+ if ( _name.isValid() )
+ {
+ if ( _name.type() == QVariant::String )
+ return _name.asString();
+ else
+ return mapiNamedTagString( _name.asUInt(), _key );
+ }
+ else
+ return mapiTagString( _key );
+}
+
+QString KTNEFProperty::formatValue( const QVariant& value, bool beautify )
+{
+ if ( value.type() == QVariant::ByteArray )
+ {
+ // check the first bytes (up to 8) if they are
+ // printable characters
+ QByteArray arr = value.toByteArray();
+ bool printable = true;
+ for ( int i=QMIN( arr.size(), 8 )-1; i>=0 && printable; i-- )
+ printable = ( isprint( arr[ i ] ) != 0 );
+ if ( !printable )
+ {
+ QString s;
+ uint i;
+ uint txtCount = beautify ? QMIN( arr.size(), 32 ) : arr.size();
+ for ( i=0; i < txtCount; ++i )
+ {
+ s.append( QString().sprintf( "%02X", ( uchar )arr[ i ] ) );
+ if( beautify )
+ s.append( " " );
+ }
+ if ( i < arr.size() )
+ s.append( "... (size=" + QString::number( arr.size() ) + ")" );
+ return s;
+ }
+ }
+ //else if ( value.type() == QVariant::DateTime )
+ // return value.toDateTime().toString();
+ return value.toString();
+}
+
+QString KTNEFProperty::valueString()
+{
+ return formatValue( _value );
+}
+
+int KTNEFProperty::key() const
+{ return _key; }
+
+int KTNEFProperty::type() const
+{ return _type; }
+
+QVariant KTNEFProperty::value() const
+{ return _value; }
+
+QVariant KTNEFProperty::name() const
+{ return _name; }
+
+bool KTNEFProperty::isVector() const
+{ return ( _value.type() == QVariant::List ); }
diff --git a/ktnef/lib/ktnefpropertyset.cpp b/ktnef/lib/ktnefpropertyset.cpp
new file mode 100644
index 000000000..cf35362fe
--- /dev/null
+++ b/ktnef/lib/ktnefpropertyset.cpp
@@ -0,0 +1,155 @@
+/*
+ ktnefpropertyset.cpp
+
+ Copyright (C) 2002 Michael Goffioul <kdeprint@swing.be>
+
+ This file is part of KTNEF, the KDE TNEF support library/program.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "ktnef/ktnefpropertyset.h"
+#include "ktnef/ktnefproperty.h"
+#include <kdebug.h>
+
+KTNEFPropertySet::KTNEFPropertySet()
+{
+}
+
+KTNEFPropertySet::~KTNEFPropertySet()
+{
+ clear( true );
+}
+
+void KTNEFPropertySet::addProperty( int key, int type, const QVariant& value, const QVariant& name, bool overwrite )
+{
+ QMap<int,KTNEFProperty*>::ConstIterator it = properties_.find( key );
+ if ( it != properties_.end() )
+ {
+ if ( overwrite )
+ delete ( *it );
+ else
+ return;
+ }
+ KTNEFProperty *p = new KTNEFProperty( key, type, value, name );
+ properties_[ p->key() ] = p;
+}
+
+
+QString KTNEFPropertySet::findProp(int key, const QString& fallback, bool upper)
+{
+ QMap<int,KTNEFProperty*>::Iterator it = properties_.find( key );
+ if( properties_.end() != it )
+ return upper ? KTNEFProperty::formatValue( (*it)->value(), false ).upper()
+ : KTNEFProperty::formatValue( (*it)->value(), false );
+ else
+ return fallback;
+}
+
+
+QString KTNEFPropertySet::findNamedProp(const QString& name, const QString& fallback, bool upper)
+{
+ for ( QMap<int,KTNEFProperty*>::Iterator it = properties_.begin();
+ it != properties_.end();
+ ++it ){
+ if ( (*it)->name().isValid() ){
+ QString s;
+ if ( (*it)->name().type() == QVariant::String )
+ s = (*it)->name().asString();
+ else
+ s = QString().sprintf( "0X%04X", (*it)->name().asUInt() );
+
+ if( s.upper() == name.upper() ){
+ QVariant value = ( *it )->value();
+ if( value.type() == QVariant::List ){
+ s = "";
+ for ( QValueList<QVariant>::ConstIterator lit = value.listBegin();
+ lit != value.listEnd();
+ ++lit ){
+ if( !s.isEmpty() )
+ s += ',';
+ s += KTNEFProperty::formatValue( *lit, false );
+ }
+ }else{
+ s = KTNEFProperty::formatValue( value, false );
+ }
+ return upper ? s.upper() : s;
+ }
+ }
+ }
+ return fallback;
+}
+
+
+QMap<int,KTNEFProperty*>& KTNEFPropertySet::properties()
+{
+ return properties_;
+}
+
+const QMap<int,KTNEFProperty*>& KTNEFPropertySet::properties() const
+{
+ return properties_;
+}
+
+QVariant KTNEFPropertySet::property( int key ) const
+{
+ QMap<int,KTNEFProperty*>::ConstIterator it = properties_.find( key );
+ if ( it == properties_.end() )
+ return QVariant();
+ else
+ return ( *it )->value();
+}
+
+void KTNEFPropertySet::clear( bool deleteAll )
+{
+ if ( deleteAll )
+ {
+ for ( QMap<int,KTNEFProperty*>::ConstIterator it=properties_.begin(); it!=properties_.end(); ++it )
+ delete ( *it );
+ for ( QMap<int,KTNEFProperty*>::ConstIterator it=attributes_.begin(); it!=attributes_.end(); ++it )
+ delete ( *it );
+ }
+ properties_.clear();
+ attributes_.clear();
+}
+
+void KTNEFPropertySet::addAttribute( int key, int type, const QVariant& value, bool overwrite )
+{
+ QMap<int,KTNEFProperty*>::ConstIterator it = attributes_.find( key );
+ if ( it != attributes_.end() )
+ {
+ if ( overwrite )
+ delete ( *it );
+ else
+ return;
+ }
+ KTNEFProperty *p = new KTNEFProperty( key, type, value, QVariant() );
+ attributes_[ p->key() ] = p;
+}
+
+QMap<int,KTNEFProperty*>& KTNEFPropertySet::attributes()
+{
+ return attributes_;
+}
+
+const QMap<int,KTNEFProperty*>& KTNEFPropertySet::attributes() const
+{
+ return attributes_;
+}
+
+QVariant KTNEFPropertySet::attribute( int key ) const
+{
+ QMap<int,KTNEFProperty*>::ConstIterator it = attributes_.find( key );
+ if ( it == attributes_.end() )
+ return QVariant();
+ else
+ return ( *it )->value();
+}
+
diff --git a/ktnef/lib/ktnefwriter.cpp b/ktnef/lib/ktnefwriter.cpp
new file mode 100644
index 000000000..ce35dbd20
--- /dev/null
+++ b/ktnef/lib/ktnefwriter.cpp
@@ -0,0 +1,497 @@
+/*
+ ktnefwriter.cpp
+
+ Copyright (C) 2002 Bo Thorsen <bo@sonofthor.dk>
+
+ This file is part of KTNEF, the KDE TNEF support library/program.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif /* HAVE_CONFIG_H */
+
+#include "ktnef/ktnefwriter.h"
+#include "ktnef/ktnefproperty.h"
+#include "ktnef/ktnefpropertyset.h"
+
+#include <qfile.h>
+#include <qdatetime.h>
+#include <qdatastream.h>
+#include <kdebug.h>
+#include <assert.h>
+
+#include "ktnef/ktnefdefs.h"
+
+
+class KTNEFWriter::PrivateData {
+public:
+ PrivateData() { mFirstAttachNum = QDateTime::currentDateTime().toTime_t(); }
+
+ KTNEFPropertySet properties;
+ Q_UINT16 mFirstAttachNum;
+};
+
+
+KTNEFWriter::KTNEFWriter() {
+ mData = new PrivateData;
+
+ // This is not something the user should fiddle with
+ // First set the TNEF version
+ QVariant v(0x00010000);
+ addProperty( attTNEFVERSION, atpDWORD, v );
+
+ // Now set the code page to something reasonable. TODO: Use the right one
+ QVariant v1( (Q_UINT32)0x4e4 );
+ QVariant v2( (Q_UINT32)0x0 );
+ QValueList<QVariant> list;
+ list << v1;
+ list << v2;
+ v = QVariant( list );
+ addProperty( attOEMCODEPAGE, atpBYTE, list );
+}
+
+KTNEFWriter::~KTNEFWriter() {
+ delete mData;
+}
+
+
+void KTNEFWriter::addProperty( int tag, int type, const QVariant& value ) {
+ mData->properties.addProperty( tag, type, value );
+}
+
+
+void addToChecksum( Q_UINT32 i, Q_UINT16 &checksum ) {
+ checksum += i & 0xff;
+ checksum += (i >> 8) & 0xff;
+ checksum += (i >> 16) & 0xff;
+ checksum += (i >> 24) & 0xff;
+}
+
+void addToChecksum( QCString &cs, Q_UINT16 &checksum ) {
+ int len = cs.length();
+ for (int i=0; i<len; i++)
+ checksum += (Q_UINT8)cs[i];
+}
+
+void writeCString( QDataStream &stream, QCString &str ) {
+ stream.writeRawBytes( str.data(), str.length() );
+ stream << (Q_UINT8)0;
+}
+
+Q_UINT32 mergeTagAndType( Q_UINT32 tag, Q_UINT32 type ) {
+ return ( ( type & 0xffff ) << 16 ) | ( tag & 0xffff );
+}
+
+/* This writes a TNEF property to the file.
+ *
+ * A TNEF property has a 1 byte type (LVL_MESSAGE or LVL_ATTACHMENT),
+ * a 4 byte type/tag, a 4 byte length, the data and finally the checksum.
+ *
+ * The checksum is a 16 byte int with all bytes in the data added.
+ */
+bool KTNEFWriter::writeProperty( QDataStream &stream, int &bytes, int tag) {
+ QMap<int,KTNEFProperty*>& properties = mData->properties.properties();
+ QMap<int,KTNEFProperty*>::Iterator it = properties.find( tag );
+
+ if ( it == properties.end() )
+ return false;
+
+ KTNEFProperty *property = *it;
+
+ Q_UINT32 i;
+ Q_UINT16 checksum = 0;
+ QValueList<QVariant> list;
+ QString s;
+ QCString cs, cs2;
+ QDateTime dt;
+ QDate date;
+ QTime time;
+ switch( tag ) {
+ case attMSGSTATUS:
+ // Q_UINT8
+ i = property->value().toUInt() & 0xff;
+ checksum = i;
+
+ stream << (Q_UINT8)LVL_MESSAGE;
+ stream << mergeTagAndType( tag, property->type() );
+ stream << (Q_UINT32)1;
+ stream << (Q_UINT8)i;
+
+ bytes += 10;
+ break;
+
+ case attMSGPRIORITY:
+ case attREQUESTRES:
+ // Q_UINT16
+ i = property->value().toUInt() & 0xffff;
+ addToChecksum( i, checksum );
+
+ stream << (Q_UINT8)LVL_MESSAGE;
+ stream << mergeTagAndType( tag, property->type() );
+ stream << (Q_UINT32)2;
+ stream << (Q_UINT16)i;
+
+ bytes += 11;
+ break;
+
+ case attTNEFVERSION:
+ // Q_UINT32
+ i = property->value().toUInt();
+ addToChecksum( i, checksum );
+
+ stream << (Q_UINT8)LVL_MESSAGE;
+ stream << mergeTagAndType( tag, property->type() );
+ stream << (Q_UINT32)4;
+ stream << (Q_UINT32)i;
+
+ bytes += 13;
+ break;
+
+ case attOEMCODEPAGE:
+ // 2 Q_UINT32
+ list = property->value().toList();
+ assert( list.count() == 2 );
+
+ stream << (Q_UINT8)LVL_MESSAGE;
+ stream << mergeTagAndType( tag, property->type() );
+ stream << (Q_UINT32)8;
+
+ i = list[0].toInt();
+ addToChecksum( i, checksum );
+ stream << (Q_UINT32)i;
+ i = list[1].toInt();
+ addToChecksum( i, checksum );
+ stream << (Q_UINT32)i;
+
+ bytes += 17;
+ break;
+
+ case attMSGCLASS:
+ case attSUBJECT:
+ case attBODY:
+ case attMSGID:
+ // QCString
+ cs = property->value().toString().local8Bit();
+ addToChecksum( cs, checksum );
+
+ stream << (Q_UINT8)LVL_MESSAGE;
+ stream << mergeTagAndType( tag, property->type() );
+ stream << (Q_UINT32)cs.length()+1;
+ writeCString( stream, cs );
+
+ bytes += 9 + cs.length()+1;
+ break;
+
+ case attFROM:
+ // 2 QString encoded to a TRP structure
+ list = property->value().toList();
+ assert( list.count() == 2 );
+
+ cs = list[0].toString().local8Bit(); // Name
+ cs2 = (QString("smtp:") + list[1].toString()).local8Bit(); // Email address
+ i = 18 + cs.length() + cs2.length(); // 2 * sizof(TRP) + strings + 2x'\0'
+
+ stream << (Q_UINT8)LVL_MESSAGE;
+ stream << mergeTagAndType( tag, property->type() );
+ stream << (Q_UINT32)i;
+
+ // The stream has to be aligned to 4 bytes for the strings
+ // TODO: Or does it? Looks like Outlook doesn't do this
+ // bytes += 17;
+ // Write the first TRP structure
+ stream << (Q_UINT16)4; // trpidOneOff
+ stream << (Q_UINT16)i; // totalsize
+ stream << (Q_UINT16)(cs.length()+1); // sizeof name
+ stream << (Q_UINT16)(cs2.length()+1); // sizeof address
+
+ // if ( bytes % 4 != 0 )
+ // Align the buffer
+
+ // Write the strings
+ writeCString( stream, cs );
+ writeCString( stream, cs2 );
+
+ // Write the empty padding TRP structure (just zeroes)
+ stream << (Q_UINT32)0 << (Q_UINT32)0;
+
+ addToChecksum( 4, checksum );
+ addToChecksum( i, checksum );
+ addToChecksum( cs.length()+1, checksum );
+ addToChecksum( cs2.length()+1, checksum );
+ addToChecksum( cs, checksum );
+ addToChecksum( cs2, checksum );
+
+ bytes += 10;
+ break;
+
+ case attDATESENT:
+ case attDATERECD:
+ case attDATEMODIFIED:
+ // QDateTime
+ dt = property->value().toDateTime();
+ time = dt.time();
+ date = dt.date();
+
+ stream << (Q_UINT8)LVL_MESSAGE;
+ stream << mergeTagAndType( tag, property->type() );
+ stream << (Q_UINT32)14;
+
+ i = (Q_UINT16)date.year();
+ addToChecksum( i, checksum );
+ stream << (Q_UINT16)i;
+ i = (Q_UINT16)date.month();
+ addToChecksum( i, checksum );
+ stream << (Q_UINT16)i;
+ i = (Q_UINT16)date.day();
+ addToChecksum( i, checksum );
+ stream << (Q_UINT16)i;
+ i = (Q_UINT16)time.hour();
+ addToChecksum( i, checksum );
+ stream << (Q_UINT16)i;
+ i = (Q_UINT16)time.minute();
+ addToChecksum( i, checksum );
+ stream << (Q_UINT16)i;
+ i = (Q_UINT16)time.second();
+ addToChecksum( i, checksum );
+ stream << (Q_UINT16)i;
+ i = (Q_UINT16)date.dayOfWeek();
+ addToChecksum( i, checksum );
+ stream << (Q_UINT16)i;
+ break;
+/*
+ case attMSGSTATUS:
+ {
+ Q_UINT8 c;
+ Q_UINT32 flag = 0;
+ if ( c & fmsRead ) flag |= MSGFLAG_READ;
+ if ( !( c & fmsModified ) ) flag |= MSGFLAG_UNMODIFIED;
+ if ( c & fmsSubmitted ) flag |= MSGFLAG_SUBMIT;
+ if ( c & fmsHasAttach ) flag |= MSGFLAG_HASATTACH;
+ if ( c & fmsLocal ) flag |= MSGFLAG_UNSENT;
+ d->stream_ >> c;
+
+ i = property->value().toUInt();
+ stream << (Q_UINT8)LVL_MESSAGE;
+ stream << (Q_UINT32)type;
+ stream << (Q_UINT32)2;
+ stream << (Q_UINT8)i;
+ addToChecksum( i, checksum );
+ // from reader: d->message_->addProperty( 0x0E07, MAPI_TYPE_ULONG, flag );
+ }
+ kdDebug() << "Message Status" << " (length=" << i2 << ")" << endl;
+ break;
+*/
+
+ default:
+ kdDebug() << "Unknown TNEF tag: " << tag << endl;
+ return false;
+ }
+
+ stream << (Q_UINT16)checksum;
+ return true;
+}
+
+
+bool KTNEFWriter::writeFile( QIODevice &file ) {
+ if ( !file.open( IO_WriteOnly ) )
+ return false;
+
+ QDataStream stream( &file );
+ return writeFile( stream );
+}
+
+
+bool KTNEFWriter::writeFile( QDataStream &stream ) {
+ stream.setByteOrder( QDataStream::LittleEndian );
+
+ // Start by writing the opening TNEF stuff
+ stream << TNEF_SIGNATURE;
+
+ // Store the PR_ATTACH_NUM value for the first attachment
+ // ( must be stored even if *no* attachments are stored )
+ stream << mData->mFirstAttachNum;
+
+ // Now do some writing
+ bool ok = true;
+ int bytesWritten = 0;
+ ok &= writeProperty( stream, bytesWritten, attTNEFVERSION );
+ ok &= writeProperty( stream, bytesWritten, attOEMCODEPAGE );
+ ok &= writeProperty( stream, bytesWritten, attMSGCLASS );
+ ok &= writeProperty( stream, bytesWritten, attMSGPRIORITY );
+ ok &= writeProperty( stream, bytesWritten, attSUBJECT );
+ ok &= writeProperty( stream, bytesWritten, attDATESENT );
+ ok &= writeProperty( stream, bytesWritten, attDATESTART );
+ ok &= writeProperty( stream, bytesWritten, attDATEEND );
+ // ok &= writeProperty( stream, bytesWritten, attAIDOWNER );
+ ok &= writeProperty( stream, bytesWritten, attREQUESTRES );
+ ok &= writeProperty( stream, bytesWritten, attFROM );
+ ok &= writeProperty( stream, bytesWritten, attDATERECD );
+ ok &= writeProperty( stream, bytesWritten, attMSGSTATUS );
+ ok &= writeProperty( stream, bytesWritten, attBODY );
+ return ok;
+}
+
+
+void KTNEFWriter::setSender(const QString &name, const QString &email) {
+ assert( !name.isEmpty() );
+ assert( !email.isEmpty() );
+
+ QVariant v1( name );
+ QVariant v2( email );
+
+ QValueList<QVariant> list;
+ list << v1;
+ list << v2;
+
+ QVariant v( list );
+ addProperty( attFROM, 0, list ); // What's up with the 0 here ??
+}
+
+void KTNEFWriter::setMessageType(MessageType m) {
+ // Note that the MessageType list here is probably not long enough,
+ // more entries are most likely needed later
+
+ QVariant v;
+ switch( m ) {
+ case Appointment:
+ v = QVariant( QString( "IPM.Appointment" ) );
+ break;
+
+ case MeetingCancelled:
+ v = QVariant( QString( "IPM.Schedule.Meeting.Cancelled" ) );
+ break;
+
+ case MeetingRequest:
+ v = QVariant( QString( "IPM.Schedule.Meeting.Request" ) );
+ break;
+
+ case MeetingNo:
+ v = QVariant( QString( "IPM.Schedule.Meeting.Resp.Neg" ) );
+ break;
+
+ case MeetingYes:
+ v = QVariant( QString( "IPM.Schedule.Meeting.Resp.Pos" ) );
+ break;
+
+ case MeetingTent:
+ // Tent?
+ v = QVariant( QString( "IPM.Schedule.Meeting.Resp.Tent" ) );
+ break;
+
+ default:
+ return;
+ }
+
+ addProperty( attMSGCLASS, atpWORD, v );
+}
+
+
+void KTNEFWriter::setMethod( Method )
+{
+
+}
+
+
+void KTNEFWriter::clearAttendees()
+{
+
+}
+
+
+void KTNEFWriter::addAttendee( const QString& /*cn*/, Role /*r*/, PartStat /*p*/,
+ bool /*rsvp*/, const QString& /*mailto*/ )
+{
+
+}
+
+
+// I assume this is the same as the sender?
+// U also assume that this is like "Name <address>"
+void KTNEFWriter::setOrganizer( const QString& organizer ) {
+ int i = organizer.find( '<' );
+
+ if ( i == -1 )
+ return;
+
+ QString name = organizer.left( i );
+ name.stripWhiteSpace();
+
+ QString email = organizer.right( i+1 );
+ email = email.left( email.length()-1 );
+ email.stripWhiteSpace();
+
+ setSender( name, email );
+}
+
+
+void KTNEFWriter::setDtStart( const QDateTime& dtStart ) {
+ QVariant v( dtStart );
+ addProperty( attDATESTART, atpDATE, v );
+}
+
+
+void KTNEFWriter::setDtEnd( const QDateTime& dtEnd ) {
+ QVariant v( dtEnd );
+ addProperty( attDATEEND, atpDATE, v );
+}
+
+
+void KTNEFWriter::setLocation( const QString& /*location*/ )
+{
+
+}
+
+
+void KTNEFWriter::setUID( const QString& uid ) {
+ QVariant v( uid );
+ addProperty( attMSGID, atpSTRING, v );
+}
+
+
+// Date sent
+void KTNEFWriter::setDtStamp( const QDateTime& dtStamp ) {
+ QVariant v( dtStamp );
+ addProperty( attDATESENT, atpDATE, v );
+}
+
+
+void KTNEFWriter::setCategories( const QStringList& )
+{
+
+}
+
+
+// I hope this is the body
+void KTNEFWriter::setDescription( const QString &body ) {
+ QVariant v( body );
+ addProperty( attBODY, atpTEXT, v );
+}
+
+
+void KTNEFWriter::setSummary( const QString &s ) {
+ QVariant v( s );
+ addProperty( attSUBJECT, atpSTRING, v );
+}
+
+// TNEF encoding: Normal = 3, high = 2, low = 1
+// MAPI encoding: Normal = -1, high = 0, low = 1
+void KTNEFWriter::setPriority( Priority p ) {
+ QVariant v( (Q_UINT32)p );
+ addProperty( attMSGPRIORITY, atpSHORT, v );
+}
+
+
+void KTNEFWriter::setAlarm( const QString& /*description*/, AlarmAction /*action*/,
+ const QDateTime& /*wakeBefore*/ )
+{
+
+}
diff --git a/ktnef/lib/lzfu.cpp b/ktnef/lib/lzfu.cpp
new file mode 100644
index 000000000..ab4fa36a0
--- /dev/null
+++ b/ktnef/lib/lzfu.cpp
@@ -0,0 +1,178 @@
+/*
+ lzfu.cpp
+
+ Copyright (C) 2003 Michael Goffioul <kdeprint@swing.be>
+
+ This file is part of KTNEF, the KDE TNEF support library/program.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "config.h"
+
+#include "lzfu.h"
+
+#ifdef HAVE_STDINT_H
+#include <stdint.h>
+#endif
+#include <sys/types.h>
+#include <string.h>
+#include <qiodevice.h>
+#include <stdio.h>
+
+//#define DO_DEBUG
+
+#define LZFU_COMPRESSED 0x75465a4c
+#define LZFU_UNCOMPRESSED 0x414c454d
+
+#define LZFU_INITDICT "{\\rtf1\\ansi\\mac\\deff0\\deftab720{\\fonttbl;}" \
+ "{\\f0\\fnil \\froman \\fswiss \\fmodern \\fscrip" \
+ "t \\fdecor MS Sans SerifSymbolArialTimes Ne" \
+ "w RomanCourier{\\colortbl\\red0\\green0\\blue0" \
+ "\r\n\\par \\pard\\plain\\f0\\fs20\\b\\i\\u\\tab" \
+ "\\tx"
+#define LZFU_INITLENGTH 207
+
+typedef struct _lzfuheader {
+ uint32_t cbSize;
+ uint32_t cbRawSize;
+ uint32_t dwMagic;
+ uint32_t dwCRC;
+} lzfuheader;
+
+#define FLAG(f,n) (f>>n)&0x1
+
+/*typedef struct _blockheader {
+ unsigned int offset:12;
+ unsigned int length:4;
+} blockheader;*/
+
+#define OFFSET(b) (b>>4)&0xFFF
+#define LENGTH(b) ((b&0xF)+2)
+
+int lzfu_decompress(QIODevice *input, QIODevice *output)
+{
+ unsigned char window[4096];
+ unsigned int wlength = 0, cursor = 0, ocursor = 0;
+ lzfuheader lzfuhdr;
+ //blockheader blkhdr;
+ uint16_t blkhdr;
+ char bFlags;
+ int nFlags;
+
+ memcpy(window, LZFU_INITDICT, LZFU_INITLENGTH);
+ wlength = LZFU_INITLENGTH;
+ if (input->readBlock((char*)&lzfuhdr, sizeof(lzfuhdr)) != sizeof(lzfuhdr))
+ {
+ fprintf(stderr, "unexpected eof, cannot read LZFU header\n");
+ return -1;
+ }
+ cursor += sizeof( lzfuhdr );
+#ifdef DO_DEBUG
+ fprintf(stdout, "total size : %d\n", lzfuhdr.cbSize+4);
+ fprintf(stdout, "raw size : %d\n", lzfuhdr.cbRawSize);
+ fprintf(stdout, "compressed : %s\n", (lzfuhdr.dwMagic == LZFU_COMPRESSED ? "yes" : "no"));
+ fprintf(stdout, "CRC : %x\n", lzfuhdr.dwCRC);
+ fprintf(stdout, "\n");
+#endif
+
+ while (cursor < lzfuhdr.cbSize+4 && ocursor < lzfuhdr.cbRawSize && !input->atEnd())
+ {
+ if (input->readBlock(&bFlags, 1) != 1)
+ {
+ fprintf(stderr, "unexpected eof, cannot read chunk flag\n");
+ return -1;
+ }
+ nFlags = 8;
+ cursor++;
+#ifdef DO_DEBUG
+ fprintf(stdout, "Flags : ");
+ for (int i=nFlags-1; i>=0; i--)
+ fprintf(stdout, "%d", FLAG(bFlags, i));
+ fprintf(stdout, "\n");
+#endif
+ for (int i=0; i<nFlags && ocursor<lzfuhdr.cbRawSize && cursor<lzfuhdr.cbSize+4; i++)
+ {
+ if (FLAG(bFlags, i))
+ {
+ // compressed chunck
+ char c1, c2;
+ if (input->readBlock(&c1, 1) != 1 || input->readBlock(&c2, 1) != 1)
+ {
+ fprintf(stderr, "unexpected eof, cannot read block header\n");
+ return -1;
+ }
+ blkhdr = c1;
+ blkhdr <<= 8;
+ blkhdr |= (0xFF&c2);
+ unsigned int offset = OFFSET(blkhdr), length = LENGTH(blkhdr);
+ cursor += 2;
+#ifdef DO_DEBUG
+ fprintf( stdout, "block : offset=%.4d [%d], length=%.2d (0x%04X)\n", OFFSET( blkhdr ), wlength, LENGTH( blkhdr ), blkhdr );
+#endif
+ //if (offset >= wlength)
+ //{
+ // break;
+ //}
+#ifdef DO_DEBUG
+ fprintf( stdout, "block : " );
+#endif
+ for (unsigned int i=0; i<length; i++)
+ {
+ c1 = window[( offset+i ) % 4096];
+ //if (wlength < 4096)
+ //{
+ window[wlength] = c1;
+ wlength = ( wlength+1 ) % 4096;
+ //}
+#ifdef DO_DEBUG
+ if ( c1 == '\n' )
+ fprintf( stdout, "\nblock : " );
+ else
+ fprintf( stdout, "%c", c1 );
+#endif
+ output->putch(c1);
+ ocursor++;
+ }
+#ifdef DO_DEBUG
+ fprintf( stdout, "\n" );
+#endif
+ }
+ else
+ {
+ // uncompressed chunk (char)
+ signed char c = (char)input->getch();
+ if (c == -1)
+ {
+ if (!input->atEnd())
+ {
+ fprintf(stderr, "unexpected eof, cannot read character\n");
+ return -1;
+ }
+ break;
+ }
+#ifdef DO_DEBUG
+ fprintf( stdout, "char : %c\n", c );
+#endif
+ cursor++;
+ //if (wlength < 4096)
+ //{
+ window[wlength] = c;
+ wlength = ( wlength+1 ) % 4096;
+ //}
+ output->putch(c);
+ ocursor++;
+ }
+ }
+
+ }
+
+ return 0;
+}
diff --git a/ktnef/lib/lzfu.h b/ktnef/lib/lzfu.h
new file mode 100644
index 000000000..4f8365586
--- /dev/null
+++ b/ktnef/lib/lzfu.h
@@ -0,0 +1,25 @@
+/*
+ lzfu.h
+
+ Copyright (C) 2003 Michael Goffioul <kdeprint@swing.be>
+
+ This file is part of KTNEF, the KDE TNEF support library/program.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef LZFU_H
+#define LZFU_H
+
+class QIODevice;
+
+int lzfu_decompress( QIODevice *input, QIODevice *output );
+
+#endif /* LZFU_H */
diff --git a/ktnef/lib/mapi.cpp b/ktnef/lib/mapi.cpp
new file mode 100644
index 000000000..8122153ce
--- /dev/null
+++ b/ktnef/lib/mapi.cpp
@@ -0,0 +1,222 @@
+/*
+ mapi.cpp
+
+ Copyright (C) 2002 Michael Goffioul <kdeprint@swing.be>
+
+ This file is part of KTNEF, the KDE TNEF support library/program.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#include "mapi.h"
+#include <qmap.h>
+#include <klocale.h>
+
+static struct
+{
+ int tag;
+ const char *str;
+} MAPI_TagStrings[] =
+{
+ { 0x0002, I18N_NOOP( "Alternate Recipient Allowed" ) },
+ { 0x001A, I18N_NOOP( "Message Class" ) },
+ { 0x0023, I18N_NOOP( "Originator Delivery Report Requested" ) },
+ { 0x0024, I18N_NOOP( "Originator Return Address" ) },
+ { 0x0026, I18N_NOOP( "Priority" ) },
+ { 0x0029, I18N_NOOP( "Read Receipt Requested" ) },
+ { 0x002B, I18N_NOOP( "Recipient Reassignment Prohibited" ) },
+ { 0x002E, I18N_NOOP( "Original Sensitivity" ) },
+ { 0x0031, I18N_NOOP( "Report Tag" ) },
+ { 0x0036, I18N_NOOP( "Sensitivity" ) },
+ { 0x0037, I18N_NOOP( "Subject" ) },
+ { 0x0039, I18N_NOOP( "Client Submit Time" ) },
+ { 0x003B, I18N_NOOP( "Sent Representing Search Key" ) },
+ { 0x003D, I18N_NOOP( "Subject Prefix" ) },
+ { 0x0041, I18N_NOOP( "Sent Representing Entry ID" ) },
+ { 0x0042, I18N_NOOP( "Sent Representing Name" ) },
+ { 0x0047, I18N_NOOP( "Message Submission ID" ) },
+ { 0x004D, I18N_NOOP( "Original Author Name" ) },
+ { 0x0062, I18N_NOOP( "Owner Appointment ID" ) },
+ { 0x0063, I18N_NOOP( "Response Requested" ) },
+ { 0x0064, I18N_NOOP( "Sent Representing Address Type" ) },
+ { 0x0065, I18N_NOOP( "Sent Representing E-mail Address" ) },
+ { 0x0070, I18N_NOOP( "Conversation Topic" ) },
+ { 0x0071, I18N_NOOP( "Conversation Index" ) },
+ { 0x007F, I18N_NOOP( "TNEF Correlation Key" ) },
+ { 0x0C17, I18N_NOOP( "Reply Requested" ) },
+ { 0x0C1A, I18N_NOOP( "Sender Name" ) },
+ { 0x0C1D, I18N_NOOP( "Sender Search Key" ) },
+ { 0x0C1E, I18N_NOOP( "Sender Address Type" ) },
+ { 0x0C1F, I18N_NOOP( "Sender E-mail Address" ) },
+ { 0x0E01, I18N_NOOP( "Delete After Submit" ) },
+ { 0x0E02, I18N_NOOP( "Display Bcc" ) },
+ { 0x0E03, I18N_NOOP( "Display Cc" ) },
+ { 0x0E04, I18N_NOOP( "Display To" ) },
+ { 0x0E06, I18N_NOOP( "Message Delivery Time" ) },
+ { 0x0E07, I18N_NOOP( "Message Flags" ) },
+ { 0x0E08, I18N_NOOP( "Message Size" ) },
+ { 0x0E09, I18N_NOOP( "Parent Entry ID" ) },
+ { 0x0E0A, I18N_NOOP( "Sent-Mail Entry ID" ) },
+ { 0x0E12, I18N_NOOP( "Message Recipients" ) },
+ { 0x0E14, I18N_NOOP( "Submit Flags" ) },
+ { 0x0E1B, I18N_NOOP( "Has Attachment" ) },
+ { 0x0E1D, I18N_NOOP( "Normalized Subject" ) },
+ { 0x0E1F, I18N_NOOP( "RTF In Sync" ) },
+ { 0x0E20, I18N_NOOP( "Attachment Size" ) },
+ { 0x0E21, I18N_NOOP( "Attachment Number" ) },
+ { 0x0FF4, I18N_NOOP( "Access" ) },
+ { 0x0FF7, I18N_NOOP( "Access Level" ) },
+ { 0x0FF8, I18N_NOOP( "Mapping Signature" ) },
+ { 0x0FF9, I18N_NOOP( "Record Key" ) },
+ { 0x0FFA, I18N_NOOP( "Store Record Key" ) },
+ { 0x0FFB, I18N_NOOP( "Store Entry ID" ) },
+ { 0x0FFE, I18N_NOOP( "Object Type" ) },
+ { 0x0FFF, I18N_NOOP( "Entry ID" ) },
+ { 0x1000, I18N_NOOP( "Message Body" ) },
+ { 0x1006, I18N_NOOP( "RTF Sync Body CRC" ) },
+ { 0x1007, I18N_NOOP( "RTF Sync Body Count" ) },
+ { 0x1008, I18N_NOOP( "RTF Sync Body Tag" ) },
+ { 0x1009, I18N_NOOP( "RTF Compressed" ) },
+ { 0x1010, I18N_NOOP( "RTF Sync Prefix Count" ) },
+ { 0x1011, I18N_NOOP( "RTF Sync Trailing Count" ) },
+ { 0x1013, I18N_NOOP( "HTML Message Body" ) },
+ { 0x1035, I18N_NOOP( "Message ID" ) },
+ { 0x1042, I18N_NOOP( "Parent's Message ID" ) },
+ { 0x1080, I18N_NOOP( "Action" ) },
+ { 0x1081, I18N_NOOP( "Action Flag" ) },
+ { 0x1082, I18N_NOOP( "Action Date" ) },
+ { 0x3001, I18N_NOOP( "Display Name" ) },
+ { 0x3007, I18N_NOOP( "Creation Time" ) },
+ { 0x3008, I18N_NOOP( "Last Modification Time" ) },
+ { 0x300B, I18N_NOOP( "Search Key" ) },
+ { 0x340D, I18N_NOOP( "Store Support Mask" ) },
+ { 0x3414, I18N_NOOP( "MDB Provider" ) },
+ { 0x3701, I18N_NOOP( "Attachment Data" ) },
+ { 0x3702, I18N_NOOP( "Attachment Encoding" ) },
+ { 0x3703, I18N_NOOP( "Attachment Extension" ) },
+ { 0x3705, I18N_NOOP( "Attachment Method" ) },
+ { 0x3707, I18N_NOOP( "Attachment Long File Name" ) },
+ { 0x370B, I18N_NOOP( "Attachment Rendering Position" ) },
+ { 0x370E, I18N_NOOP( "Attachment Mime Tag" ) },
+ { 0x3714, I18N_NOOP( "Attachment Flags" ) },
+ { 0x3A00, I18N_NOOP( "Account" ) },
+ { 0x3A05, I18N_NOOP( "Generation" ) },
+ { 0x3A06, I18N_NOOP( "Given Name" ) },
+ { 0x3A0A, I18N_NOOP( "Initials" ) },
+ { 0x3A0B, I18N_NOOP( "Keyword" ) },
+ { 0x3A0C, I18N_NOOP( "Language" ) },
+ { 0x3A0D, I18N_NOOP( "Location" ) },
+ { 0x3A11, I18N_NOOP( "Surname" ) },
+ { 0x3A16, I18N_NOOP( "Company Name" ) },
+ { 0x3A17, I18N_NOOP( "Title" ) },
+ { 0x3A18, I18N_NOOP( "Department Name" ) },
+ { 0x3A26, I18N_NOOP( "Country" ) },
+ { 0x3A27, I18N_NOOP( "Locality" ) },
+ { 0x3A28, I18N_NOOP( "State/Province" ) },
+ { 0x3A44, I18N_NOOP( "Middle Name" ) },
+ { 0x3A45, I18N_NOOP( "Display Name Prefix" ) },
+
+ /* Some TNEF attributes */
+ { 0x0008, I18N_NOOP( "Owner Appointment ID" ) },
+ { 0x0009, I18N_NOOP( "Response Requested" ) },
+ { 0x8000, I18N_NOOP( "From" ) },
+ { 0x8004, I18N_NOOP( "Subject" ) },
+ { 0x8005, I18N_NOOP( "Date Sent" ) },
+ { 0x8006, I18N_NOOP( "Date Received" ) },
+ { 0x8007, I18N_NOOP( "Message Status" ) },
+ { 0x8008, I18N_NOOP( "Message Class" ) },
+ { 0x8009, I18N_NOOP( "Message ID" ) },
+ { 0x800A, I18N_NOOP( "Parent ID" ) },
+ { 0x800B, I18N_NOOP( "Conversation ID" ) },
+ { 0x800C, I18N_NOOP( "Body" ) },
+ { 0x800D, I18N_NOOP( "Priority" ) },
+ { 0x800F, I18N_NOOP( "Attachment Data" ) },
+ { 0x8010, I18N_NOOP( "Attachment Title" ) },
+ { 0x8011, I18N_NOOP( "Attachment Meta File" ) },
+ { 0x8012, I18N_NOOP( "Attachment Create Date" ) },
+ { 0x8013, I18N_NOOP( "Attachment Modify Date" ) },
+ { 0x8020, I18N_NOOP( "Date Modified" ) },
+ { 0x9001, I18N_NOOP( "Attachment Transport File Name" ) },
+ { 0x9002, I18N_NOOP( "Attachment Rendering Data" ) },
+ { 0x9003, I18N_NOOP( "MAPI Properties" ) },
+ { 0x9004, I18N_NOOP( "Recipients Table" ) },
+ { 0x9005, I18N_NOOP( "Attachment MAPI Properties" ) },
+ { 0x9006, I18N_NOOP( "TNEF Version" ) },
+ { 0x9007, I18N_NOOP( "OEM Code Page" ) },
+
+ { 0, 0 }
+},
+MAPI_NamedTagStrings[] =
+{
+ { 0x8005, I18N_NOOP( "Contact File Under" ) },
+ { 0x8017, I18N_NOOP( "Contact Last Name And First Name" ) },
+ { 0x8018, I18N_NOOP( "Contact Company And Full Name" ) },
+
+ { 0x8080, I18N_NOOP( "Contact EMail-1 Full" ) },
+ { 0x8082, I18N_NOOP( "Contact EMail-1 Address Type" ) },
+ { 0x8083, I18N_NOOP( "Contact EMail-1 Address" ) },
+ { 0x8084, I18N_NOOP( "Contact EMail-1 Display Name" ) },
+ { 0x8085, I18N_NOOP( "Contact EMail-1 Entry ID" ) },
+
+ { 0x8090, I18N_NOOP( "Contact EMail-2 Full" ) },
+ { 0x8092, I18N_NOOP( "Contact EMail-2 Address Type" ) },
+ { 0x8093, I18N_NOOP( "Contact EMail-2 Address" ) },
+ { 0x8094, I18N_NOOP( "Contact EMail-2 Display Name" ) },
+ { 0x8095, I18N_NOOP( "Contact EMail-2 Entry ID" ) },
+
+ { 0x8208, I18N_NOOP( "Appointment Location" ) },
+ { 0x8208, I18N_NOOP( "Appointment Location" ) },
+ { 0x820D, I18N_NOOP( "Appointment Start Date" ) },
+ { 0x820E, I18N_NOOP( "Appointment End Date" ) },
+ { 0x8213, I18N_NOOP( "Appointment Duration" ) },
+ { 0x8218, I18N_NOOP( "Appointment Response Status" ) },
+ { 0x8223, I18N_NOOP( "Appointment Is Recurring" ) },
+ { 0x8231, I18N_NOOP( "Appointment Recurrence Type" ) },
+ { 0x8232, I18N_NOOP( "Appointment Recurrence Pattern" ) },
+ { 0x8502, I18N_NOOP( "Reminder Time" ) },
+ { 0x8503, I18N_NOOP( "Reminder Set" ) },
+ { 0x8516, I18N_NOOP( "Start Date" ) },
+ { 0x8517, I18N_NOOP( "End Date" ) },
+ { 0x8560, I18N_NOOP( "Reminder Next Time" ) },
+ { 0, 0 }
+};
+static QMap<int,QString> MAPI_TagMap;
+static QMap<int,QString> MAPI_NamedTagMap;
+
+QString mapiTagString( int key )
+{
+ if ( MAPI_TagMap.count() == 0 )
+ {
+ for ( int i=0; MAPI_TagStrings[ i ].str; i++ )
+ MAPI_TagMap[ MAPI_TagStrings[ i ].tag ] = i18n(MAPI_TagStrings[ i ].str);
+ }
+ QMap<int,QString>::ConstIterator it = MAPI_TagMap.find( key );
+ if ( it == MAPI_TagMap.end() )
+ return QString().sprintf( "0x%04X", key );
+ else
+ return QString().sprintf( "0x%04X ________: ", key ) + *it;
+}
+
+QString mapiNamedTagString( int key, int tag )
+{
+ if ( MAPI_NamedTagMap.count() == 0 )
+ {
+ for ( int i=0; MAPI_NamedTagStrings[ i ].str; i++ )
+ MAPI_NamedTagMap[ MAPI_NamedTagStrings[ i ].tag ] = i18n(MAPI_NamedTagStrings[ i ].str);
+ }
+ QMap<int,QString>::ConstIterator it = MAPI_NamedTagMap.find( key );
+ if ( it == MAPI_NamedTagMap.end() )
+ if ( tag >= 0 )
+ return QString().sprintf( "0x%04X [0x%04X]: ", tag, key ) + *it;
+ else
+ return QString().sprintf( "0x%04X ________:", key ) + *it;
+ else
+ return *it;
+}
diff --git a/ktnef/lib/mapi.h b/ktnef/lib/mapi.h
new file mode 100644
index 000000000..fe4a37bf1
--- /dev/null
+++ b/ktnef/lib/mapi.h
@@ -0,0 +1,26 @@
+/*
+ mapi.h
+
+ Copyright (C) 2002 Michael Goffioul <kdeprint@swing.be>
+
+ This file is part of KTNEF, the KDE TNEF support library/program.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software Foundation,
+ Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
+ */
+
+#ifndef MAPI_H
+#define MAPI_H
+
+#include <qstring.h>
+
+QString mapiTagString( int key );
+QString mapiNamedTagString( int key, int tag = -1 );
+
+#endif
diff --git a/ktnef/tests/Makefile.am b/ktnef/tests/Makefile.am
new file mode 100644
index 000000000..a2619c0ef
--- /dev/null
+++ b/ktnef/tests/Makefile.am
@@ -0,0 +1,10 @@
+AM_CPPFLAGS = -I$(top_srcdir)/ktnef $(all_includes) -DKDESRCDIR=\"$(srcdir)\"
+LDADD = ../lib/libktnef.la $(LIB_KDECORE)
+
+check_PROGRAMS = parsertest
+TESTS = parsertest
+
+parsertest_LDFLAGS = $(all_libraries) $(KDE_RPATH)
+parsertest_SOURCES = parsertest.cpp
+
+METASOURCES = AUTO
diff --git a/ktnef/tests/README b/ktnef/tests/README
new file mode 100644
index 000000000..5cff55b70
--- /dev/null
+++ b/ktnef/tests/README
@@ -0,0 +1 @@
+TNEF test files are taken from tnef.sf.net.
diff --git a/ktnef/tests/mapi_attach_data_obj.tnef b/ktnef/tests/mapi_attach_data_obj.tnef
new file mode 100644
index 000000000..aea529ec2
--- /dev/null
+++ b/ktnef/tests/mapi_attach_data_obj.tnef
Binary files differ
diff --git a/ktnef/tests/one-file.tnef b/ktnef/tests/one-file.tnef
new file mode 100644
index 000000000..fbb08ffa1
--- /dev/null
+++ b/ktnef/tests/one-file.tnef
Binary files differ
diff --git a/ktnef/tests/parsertest.cpp b/ktnef/tests/parsertest.cpp
new file mode 100644
index 000000000..2cbe11e91
--- /dev/null
+++ b/ktnef/tests/parsertest.cpp
@@ -0,0 +1,104 @@
+/*
+ Copyright (c) 2007 Volker Krause <vkrause@kde.org>
+
+ This library is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Library General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This library is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+#include "parsertest.h"
+
+#include <ktnef/ktnefparser.h>
+#include <ktnef/ktnefmessage.h>
+#include <ktnef/ktnefattach.h>
+
+#include "assert.h"
+
+void ParserTest::testSingleAttachment()
+{
+ KTNEFParser parser;
+ assert( parser.openFile( KDESRCDIR "/one-file.tnef" ) == true );
+
+ KTNEFMessage *msg = parser.message();
+ assert( msg != 0 );
+
+ QPtrList<KTNEFAttach> atts = msg->attachmentList();
+ assert( atts.count() == 1 );
+
+ KTNEFAttach* att = atts.first();
+ assert( att != 0 );
+ assert( att->size() == 244 );
+ assert( att->name() == QString( "AUTHORS" ) );
+}
+
+void ParserTest::testTwoAttachments()
+{
+ KTNEFParser parser;
+ assert( parser.openFile( KDESRCDIR "/two-files.tnef" ) == true );
+
+ KTNEFMessage *msg = parser.message();
+ assert( msg != 0 );
+
+ QPtrList<KTNEFAttach> atts = msg->attachmentList();
+ assert( atts.count() == 2 );
+
+ KTNEFAttach* att = atts.at( 0 );
+ assert( att != 0 );
+ assert( att->size() == 244 );
+ assert( att->name() == QString( "AUTHORS" ) );
+
+ att = atts.at( 1 );
+ assert( att != 0 );
+ assert( att->size() == 893 );
+ assert( att->name() == QString( "README" ) );
+}
+
+void ParserTest::testMAPIAttachments()
+{
+ KTNEFParser parser;
+ assert( parser.openFile( KDESRCDIR "/mapi_attach_data_obj.tnef" ) == true );
+
+ KTNEFMessage *msg = parser.message();
+ assert( msg != 0 );
+
+ QPtrList<KTNEFAttach> atts = msg->attachmentList();
+ assert( atts.count() == 3 );
+
+ KTNEFAttach* att = atts.at( 0 );
+ assert( att != 0 );
+ assert( att->size() == 61952 );
+ assert( att->name() == QString( "VIA_Nytt_1402.doc" ) );
+
+ att = atts.at( 1 );
+ assert( att != 0 );
+ assert( att->size() == 213688 );
+ assert( att->name() == QString( "VIA_Nytt_1402.pdf" ) );
+
+ att = atts.at( 2 );
+ assert( att != 0 );
+ assert( att->size() == 68920 );
+ assert( att->name() == QString( "VIA_Nytt_14021.htm" ) );
+}
+
+#include <kinstance.h>
+
+int main( int argc, char** argv )
+{
+ KInstance inst( "ktnef-parsertest" );
+ ParserTest test;
+ test.testSingleAttachment();
+ test.testTwoAttachments();
+ test.testMAPIAttachments();
+ return 0;
+}
diff --git a/ktnef/tests/parsertest.h b/ktnef/tests/parsertest.h
new file mode 100644
index 000000000..4c0bacbda
--- /dev/null
+++ b/ktnef/tests/parsertest.h
@@ -0,0 +1,32 @@
+/*
+ Copyright (c) 2007 Volker Krause <vkrause@kde.org>
+
+ This library is free software; you can redistribute it and/or modify it
+ under the terms of the GNU Library General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or (at your
+ option) any later version.
+
+ This library is distributed in the hope that it will be useful, but WITHOUT
+ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ FITNESS FOR A PARTICULAR PURPOSE. See the GNU Library General Public
+ License for more details.
+
+ You should have received a copy of the GNU Library General Public License
+ along with this library; see the file COPYING.LIB. If not, write to the
+ Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+*/
+
+#ifndef PARSERTEST_H
+#define PARSERTEST_H
+
+class ParserTest
+{
+ public:
+ void testSingleAttachment();
+ void testTwoAttachments();
+ void testMAPIAttachments();
+};
+
+
+#endif
diff --git a/ktnef/tests/two-files.tnef b/ktnef/tests/two-files.tnef
new file mode 100644
index 000000000..b33b64dc4
--- /dev/null
+++ b/ktnef/tests/two-files.tnef
Binary files differ