Skip to content

Commit

Permalink
Load up all subfolders from Maildir and MH boxes.
Browse files Browse the repository at this point in the history
Closes #123.
  • Loading branch information
kdeldycke committed Nov 5, 2020
1 parent 2fbe069 commit b82accc
Show file tree
Hide file tree
Showing 3 changed files with 38 additions and 13 deletions.
2 changes: 2 additions & 0 deletions changelog.rst
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ ChangeLog

.. note:: This version is not yet released and is under active development

* Load up all subfolders from ``Maildir`` and ``MH`` boxes. Closes #123.


`6.0.1 (2020-10-22) <https://github.com/kdeldycke/mail-deduplicate/compare/v6.0.0...v6.0.1>`_
---------------------------------------------------------------------------------------------
Expand Down
19 changes: 10 additions & 9 deletions mail_deduplicate/deduplicate.py
Original file line number Diff line number Diff line change
Expand Up @@ -329,15 +329,16 @@ def add_source(self, source_path):
if source_path in self.sources:
raise ValueError(f"{source_path} already added.")

# Open and register the mail source.
box = open_box(source_path, self.conf.input_format, self.conf.force_unlock)
assert source_path == box._path
self.sources[source_path] = box

# Track of global mail count.
mail_found = len(box)
logger.info(f"{mail_found} mails found.")
self.stats["mail_found"] += mail_found
# Open and register the mail source. Subfolders will be registered as their
# own box.
boxes = open_box(source_path, self.conf.input_format, self.conf.force_unlock)
for box in boxes:
self.sources[box._path] = box

# Track global mail count.
mail_found = len(box)
logger.info(f"{mail_found} mails found.")
self.stats["mail_found"] += mail_found

def hash_all(self):
"""Browse all mails from all registered sources, compute hashes and group mails
Expand Down
30 changes: 26 additions & 4 deletions mail_deduplicate/mailbox.py
Original file line number Diff line number Diff line change
Expand Up @@ -129,10 +129,10 @@ def autodetect_box_type(path):
def open_box(path, box_type=False, force_unlock=False):
"""Open a mailbox.
Returns the locked box, ready for operations.
Returns a list of boxes, one per sub-folder. All are locked, ready for operations.
If ``box_type`` is specified, forces the opening of the box in the
specified format. Else try to autodetect the type.
If ``box_type`` is provided, forces the opening of the box in the specified format.
Defaults to (crude) autodetection.
"""
logger.info(f"Opening {choice_style(path)} ...")
path = Path(path)
Expand All @@ -145,6 +145,14 @@ def open_box(path, box_type=False, force_unlock=False):
# Do not allow the constructor to create a new mailbox if not found.
box = constructor(path, create=False)

return open_subfolders(box, force_unlock)


def lock_box(box, force_unlock):
""" Lock an opened box and allows for forced unlocking.
Returns the locked box.
"""
try:
logger.debug("Locking box...")
box.lock()
Expand All @@ -160,11 +168,25 @@ def open_box(path, box_type=False, force_unlock=False):
# Re-raise error.
else:
raise

logger.debug("Box opened.")
return box


def open_subfolders(box, force_unlock):
""" Browse recursively the subfolder tree of a box.
Returns a list of opened and locked boxes, each for one subfolder.
"""
folder_list = [lock_box(box, force_unlock)]

# Skip box types not supporting subfolders.
if hasattr(box, "list_folders"):
for folder_id in box.list_folders():
logger.info(f"Opening subfolder {folder_id} ...")
folder_list += open_subfolders(box.get_folder(folder_id), force_unlock)
return folder_list


def create_box(path, box_type=False):
"""Creates a brand new box from scratch."""
assert isinstance(path, Path)
Expand Down

0 comments on commit b82accc

Please sign in to comment.