Thread

Index > Scribe > Recursively Delete Duplicate Messages in nested folders
Author/Date Recursively Delete Duplicate Messages in nested folders
Scott
17/06/2018 6:59am
Is there any way to create a script which recursively calls the DeleteDuplicateMessages() for all the folders contained in the current folder or even the entire mailbox (one folder at a time).

Occasionally, the ISP re-indexes the mail causing quite a few folders to contain duplicates and it's a pain going through each folder to remove the duplicates.
fret
22/06/2018 8:27am
It's definitely possible, I just haven't had time to explore. You would have to iterate over the ThingContainer.Child and ThingContainer.Next to explore all the sub-folders. Then call the existing function with the folder object.
fret
25/06/2018 11:29am
So recursive functions in the script engine are broken... sigh.
fret
30/06/2018 9:18am
I've fixed the recursive functions in the scripting engine. With the next release you will be able to iterate over the folders with this script:

function RecurseFolder(Folder)
{
    Print("Path="+Folder.Path+"\n");
    for (c = Folder.Child; c; c = c.Next)
    {
        RecurseFolder(c);
    }
}

function RecurseFolders(App)
{
    Roots = App.RootFolders;
    for (i=0; i<Roots.Length; i++)
    {
        f = GetFolder(Roots[i]);
        if (f)
        {
            RecurseFolder(f);
        }
    }
}

function Main(App)
{
    if (!AddToolsMenuItem("Recurse Test", "RecurseFolders"))
        MsgBox(App, "Couldn't add hook for RecurseFolders");
    return 1;
}



Then you could pull in the remove duplicates code from the other script and call it from inside RecurseFolder.
Scott
30/03/2019 9:02pm
I've created the script (see below) as described, however, it only seems to detect duplicates in some folders. It is supposed to process all mail folders, but if I rerun the script it finds new duplicates in different folders. I have not been able to detect a pattern.
If I search from the App.CurrentFolder, using the commented-out code, I get several of the following errors:
Code\ScribeApp.cpp:8412 - No option 'Folder-50'
RecursiveDupRemoval.script:73 IDomGet warning: Can't deref NULL object.
Deleting duplicates from Path=(null)
RecursiveDupRemoval.script:70 IArrayGet warning: Can't array deref variant type 8

Here is the script:

function DeleteDuplicateMessages(Folder)
{
    if (Folder && Folder.ItemType == 0xAAFF0001)
    {
        Msgs = New("HashTable");
        Dupes = New("List");
        Len = Folder.Length;

        for (i=0; i<Len; i++)
        {
            t = Folder.Item[i];
            if (t)
            {
                Id = t.MessageID;
                if (Id != NULL)
                {
                    Existing = Msgs[Id];
                    if (Existing)
                    {
                        // Decide which email is older
                        if (t.DateReceived < Existing.DateReceived)
                        {
                            // t is earlier, t replaces existing item
                            Dupes[-1] = Existing;
                            Msgs[Id] = t;
                        }
                        else
                        {
                            // existing is earlier, delete t
                            Dupes[-1] = t;
                        }
                    }
                    else
                    {
                        Msgs[Id] = t;
                    }
                }
                else Print("No msgid at " + i + "\n");
            }
            else Print("No item at " + i + "\n");
        }

        if (Dupes.Length > 0)
        {
            Print("Path="+Folder.Path+"\n");
            for (i=0; i<Dupes.Length; i++)
            {
               Print("Delete:"+Dupes[i].Subject+"\n");

                DeleteThing(Dupes[i]);
            }
        }
    }
} 


function RecurseFolder(Folder)
{
    for (c = Folder.Child; c; c = c.Next)
    {
        DeleteDuplicateMessages(c);
        RecurseFolder(c);
    }
}

function RecurseFolders(App)
{
//    Flder = App.CurrentFolder;
    Flder = App.RootFolders;
    for (i=0; i<Flder.Length; i++)
    {
        f = GetFolder(Flder[i]);
        Print("Deleting duplicates from Path="+f.Path+"\n");
        if (f)
        {
            RecurseFolder(f);
        }
    }
    Print("done."+"\n");
}

function Main(App)
{
    if (!AddToolsMenuItem("Recursive Dupe Removal", "RecurseFolders"))
        MsgBox(App, "Couldn't add hook for RecurseFolders");
    return 1;
}

Scott
30/03/2019 9:12pm
Hmm, I seem to have missed the trailing "[/pre]". The preview displayed correctly.
I'll send the file in an email.
Scott
30/03/2019 9:16pm
It seems to be only looking in the current folder. Apart from some extra logging, it does the same thing as the regular delete duplicates script.
Scott
19/04/2020 1:03am
Using 2.4.13, the recursive Folder.Length is returning 0 for most folders with messages. It works correctly for the default mail box and folders with filters or contacts.

This can be demonstrated in your original script, if you change this line:
   Print("Path="+Folder.Path+"\n");

with this one:
   Print("Path="+Folder.Path+":"+Folder.Length+"\n");


fret
19/04/2020 9:59am
In here add a 'LoadFolder' call:


function RecurseFolder(Folder)
{
    for (c = Folder.Child; c; c = c.Next)
    {
        LoadFolder(c);
        DeleteDuplicateMessages(c);
        RecurseFolder(c);
    }
}
Scott
19/04/2020 11:30am
Thanks, works like a charm.
Reply