Skip to content

Commit a96a4ca

Browse files
V1.2.0
1 parent ff84016 commit a96a4ca

File tree

10 files changed

+65
-33
lines changed

10 files changed

+65
-33
lines changed

CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
**v1.2.0**
2+
* Updated to new version set of extract-msg (>=0.33.0, <0.34.0). Version 0.32.0 was skipped intentionally due to some issues in the code as well as to prioritize the release of version 0.33.0.
3+
* Fixed issue where double clicking attachments no longer worked (forgot to update the type checks to use the enum).
4+
* Fixed bug that caused streams in embedded MSG files to not be found if you loaded it to be the current MSG file.
5+
* Fixed typo that caused string viewer to not clear (forgot to add `.ui` before a ui element name).
6+
17
**v1.1.0**
28
* Updated to new version set of extract-msg (>=0.31.0, <0.32.0).
39
* Added sorting to many of the displays. Updated internal way data is handled to help this.

README.rst

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -77,8 +77,8 @@ Credits
7777
.. |License: GPL v3| image:: https://img.shields.io/badge/License-GPLv3-blue.svg
7878
:target: LICENSE.txt
7979

80-
.. |PyPI3| image:: https://img.shields.io/badge/pypi-1.1.0-blue.svg
81-
:target: https://pypi.org/project/msg-explorer/1.1.0/
80+
.. |PyPI3| image:: https://img.shields.io/badge/pypi-1.2.0-blue.svg
81+
:target: https://pypi.org/project/msg-explorer/1.2.0/
8282

8383
.. |PyPI2| image:: https://img.shields.io/badge/python-3.6+-brightgreen.svg
8484
:target: https://www.python.org/downloads/release/python-367/

msg_explorer/__init__.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,8 @@
2727
# along with this program. If not, see <http://www.gnu.org/licenses/>.
2828

2929
__author__ = 'Destiny Peterson'
30-
__date__ = '2022-06-06'
31-
__version__ = '1.1.0'
30+
__date__ = '2022-06-08'
31+
__version__ = '1.2.0'
3232

3333
# When this module is imported, we should try to compile the forms. They only
3434
# compile when they are outdated.

msg_explorer/attachments_browser.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
# This Python file uses the following encoding: utf-8
2+
import logging
3+
24
import extract_msg
35

46
from PySide6 import QtCore
@@ -9,6 +11,9 @@
911
from .ui.ui_attachments_browser import Ui_AttachmentsBrowser
1012

1113

14+
logger = logging.getLogger(__name__)
15+
logger.addHandler(logging.NullHandler())
16+
1217
class AttachmentsBrowser(QtWidgets.QWidget):
1318
# Signals that an attachment was double clicked.
1419
attachmentSelected = Signal(int)
@@ -77,3 +82,5 @@ def _cellDoubleClicked(self, row : int, column : int):
7782
self.signedAttachmentSelected.emit(int(data))
7883
else:
7984
self.attachmentSelected.emit(int(data))
85+
else:
86+
logger.warn(f'Received index on cell double click that was outside of table (row: {row}, colunn {column}).')

msg_explorer/main_window.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ def __init__(self, parent = None):
4949
# Connect the double click from the tree to the stream view.
5050
self.ui.pageTreeView.fileDoubleClicked.connect(self.ui.pageStreamView.openStream)
5151
self.ui.pageTreeView.fileDoubleClicked.connect(self._streamSelected)
52-
self.ui.pageNamedProperties.namedPropertySelected.connect(lambda x : self.ui.pageStreamView.openStream(x, True))
52+
self.ui.pageNamedProperties.namedPropertySelected.connect(self.ui.pageStreamView.openStream)
5353
self.ui.pageNamedProperties.namedPropertySelected.connect(self._streamSelected)
5454

5555
self.ui.actionIncrease_Font.triggered.connect(self.increaseFont)
@@ -80,10 +80,10 @@ def attachmentSelected(self, index):
8080
attachment = self.__msg.attachments[index]
8181

8282
if isinstance(attachment, extract_msg.Attachment):
83-
if attachment.type == 'data':
83+
if attachment.type == extract_msg.enums.AttachmentType.DATA:
8484
self.ui.pageStreamView.openStream(attachment.dir.split('/') + ['__substg1.0_37010102'])
8585
self.ui.tabWidget.setCurrentWidget(self.ui.pageStreamView)
86-
elif attachment.type == 'msg':
86+
elif attachment.type == extract_msg.enums.AttachmentType.MSG:
8787
if QMessageBox.question(self, 'Open Embedded Msg', 'Would you like to open the embedded MSG file?') == QMessageBox.Yes:
8888
self.__parentMsgs.append(self.__msg)
8989
self.__msg = attachment.data

msg_explorer/msg_details_page.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,6 @@ def msgOpened(self, msgFile):
3535
self.ui.labelClassType.setText(msgFile.classType)
3636
self.ui.labelEncoding.setText(msgFile.stringEncoding)
3737
self.ui.labelAttachCount.setText(str(len(msgFile.attachments)))
38-
self.ui.labelRecipCount.setText(str(len(msgFile.recipients)))
3938
if isinstance(msgFile, extract_msg.MessageBase):
39+
self.ui.labelRecipCount.setText(str(len(msgFile.recipients)))
4040
self.ui.labelSubject.setText(msgFile.subject)

msg_explorer/named_properties_viewer.py

Lines changed: 40 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -26,44 +26,45 @@ def __init__(self, parent = None):
2626

2727
self.ui = Ui_NamedPropertiesViewer()
2828
self.ui.setupUi(self)
29+
self.__loading = False
2930
self.__msg = None
31+
# This is the named instance for the MSG file. It is used to get a list
32+
# of all available properties.
33+
self.__named : extract_msg.Named = None
34+
self.__attachments = None
3035

3136
self.ui.tableNamedProperties.cellDoubleClicked.connect(self._cellDoubleClicked)
3237
self.ui.comboBoxInstance.currentTextChanged.connect(self._comboBoxChanged)
3338

34-
def loadNamed(self, namedInstance, attachment = None):
39+
def loadNamed(self):
3540
"""
36-
Load the named properties instance. If it is from an attachment,
37-
provide the instance so details can be acquired properly.
41+
Load the named properties instance. This loads the main sections for each
42+
property, not the data.
3843
"""
39-
getStream = attachment._getTypedStream if attachment else self.__msg._getTypedStream
40-
named = namedInstance.namedProperties
41-
keys = sorted(named.keys())
42-
self.ui.tableNamedProperties.setRowCount(len(named))
43-
for index, key in enumerate(keys):
44+
self.ui.tableNamedProperties.setRowCount(len(self.__named))
45+
for index, key in enumerate(self.__named):
4446
self.ui.tableNamedProperties.setItem(index, 0, QTableWidgetItem(key))
45-
self.ui.tableNamedProperties.setItem(index, 1, NamedPIDItem(str(named[key].namedPropertyID)))
46-
# We need to figure out what to display for the data.
47-
if isinstance(named[key].data, (int, float, bool, None.__class__)):
48-
# This helps to shortcut a bunch of properties.
49-
self.ui.tableNamedProperties.setItem(index, 2, QTableWidgetItem(utils.dataToString(named[key].data)))
50-
elif isinstance(named[key].data, (bytes, list, tuple)) or getStream(f'__substg1.0_{0x8000 + named[key].namedPropertyID:04X}')[0]:
51-
self.ui.tableNamedProperties.setItem(index, 2, QTableWidgetItem('[Stream]'))
52-
else:
53-
self.ui.tableNamedProperties.setItem(index, 2, QTableWidgetItem(utils.dataToString(named[key].data)))
47+
self.ui.tableNamedProperties.setItem(index, 1, NamedPIDItem(str(self.__named[key].namedPropertyID)))
5448

5549
@Slot()
5650
def msgClosed(self):
5751
self.ui.comboBoxInstance.clear()
5852
self.ui.tableNamedProperties.clearContents()
5953
self.__msg = None
54+
self.__named = None
55+
self.__attachments = None
6056

6157
@Slot(extract_msg.MSGFile)
6258
def msgOpened(self, msgFile):
59+
self.__loading = True
6360
self.__msg = msgFile
61+
self.__named = msgFile.named
62+
self.__attachments = msgFile._rawAttachments if isinstance(msgFile, extract_msg.MessageSignedBase) else msgFile.attachments
6463
self.ui.comboBoxInstance.addItem('MSG File')
65-
self.ui.comboBoxInstance.addItems((f'Attachment {x}' for x in range(len(msgFile.attachments))))
66-
self.loadNamed(msgFile.named)
64+
self.ui.comboBoxInstance.addItems((f'Attachment {x}' for x in range(len(self.__attachments))))
65+
self.loadNamed()
66+
self.__loading = False
67+
self._comboBoxChanged('MSG File')
6768

6869
@Slot(int, int)
6970
def _cellDoubleClicked(self, row, column):
@@ -86,11 +87,29 @@ def _cellDoubleClicked(self, row, column):
8687

8788
@Slot(str)
8889
def _comboBoxChanged(self, entry):
90+
# Prevent this from running while data is being loaded.
91+
if self.__loading:
92+
return
8993
if entry:
9094
if entry == 'MSG File':
91-
self.loadNamed(self.__msg.named)
95+
getData = self.__msg.namedProperties.get
96+
getStream = self.__msg._getTypedStream
9297
else:
93-
self.loadNamed(self.__msg.attachments[int(self.ui.comboBoxInstance.currentText().split(" ")[1])].namedProperties)
98+
attachment = self.__attachments[int(entry.split(' ')[-1])]
99+
getData = attachment.namedProperties.get
100+
getStream = attachment._getTypedStream
101+
102+
for index in range(self.ui.tableNamedProperties.rowCount()):
103+
key = self.ui.tableNamedProperties.item(index, 0).data(0)
104+
# We need to figure out what to display for the data.
105+
data = getData(self.__named[key])
106+
if isinstance(data, (int, float, bool, None.__class__)):
107+
# This helps to shortcut a bunch of properties.
108+
self.ui.tableNamedProperties.setItem(index, 2, QTableWidgetItem(utils.dataToString(data)))
109+
elif isinstance(data, (bytes, list, tuple)) or getStream(f'__substg1.0_{self.__named[key].propertyStreamID}')[0]:
110+
self.ui.tableNamedProperties.setItem(index, 2, QTableWidgetItem('[Stream]'))
111+
else:
112+
self.ui.tableNamedProperties.setItem(index, 2, QTableWidgetItem(utils.dataToString(data)))
94113

95114

96115

msg_explorer/stream_viewer.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ def msgOpened(self, msgFile):
7373
self.__msg = msgFile
7474

7575
@Slot(list)
76-
def openStream(self, name, prefix = False):
76+
def openStream(self, name, prefix = True):
7777
"""
7878
Loads the data for the specified stream. Will automatically
7979
determine how best to show it.
@@ -85,7 +85,7 @@ def openStream(self, name, prefix = False):
8585
# just telling the function to run again with the main stream.
8686
return self.openStream(name[:-1] + [name[-1][:-9]])
8787

88-
self.ui.pageHexViewer.loadHexData(self.__msg._getStream(name))
88+
self.ui.pageHexViewer.loadHexData(self.__msg._getStream(name, False))
8989
self.ui.labelStreamName.setText('/'.join(name))
9090
# Now determine how to load the rest of the data.
9191
if name[-1] == '__properties_version1.0':

msg_explorer/string_viewer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ def __init__(self):
1616
@Slot()
1717
def clear(self):
1818
self.ui.labelType.setText('')
19-
self.textDisplay.setPlainText('')
19+
self.ui.textDisplay.setPlainText('')
2020

2121
@Slot(str, str)
2222
def loadString(self, data, _type):

requirements.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
11

22
# First level requirements
3-
extract-msg>=0.31.1, <0.32.0
3+
extract-msg>=0.33.0, <0.34.0
44
PySide6>=6.3.0

0 commit comments

Comments
 (0)