module/src/Invoke-SieveFilterCmdlet.cs

 
using System;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using System.Linq;
using System.Management.Automation;
using System.Collections.Generic;
 
[Cmdlet("Invoke", "SieveFilter")]
public class InvokeSieveFilter : PSCmdlet {
 
    [Parameter(Mandatory = true)]
    public string SieveFile;
 
    [Parameter(Mandatory = true)]
    public string MaildirPath;
 
 
    Regex regex = new Regex("^To: (.*)$");
    Regex innerRegex = new Regex("<(.*?)>$");
 
 
    protected override void BeginProcessing() {
        var inboxPath = GetResolvedInboxPath(MaildirPath);
        var files = System.IO.Directory.EnumerateFiles(inboxPath);
 
        var filter = GetSieveFilter(SieveFile);
 
        foreach (var file in files) {
            var result = ReadFile(file);
 
            if (null != result) {
                string destination;
                filter.TryGetValue(result.Address, out destination);
 
                if (!string.IsNullOrEmpty(destination)) {
                    MoveEmail(result, GetResolvedMailfolderPath(MaildirPath, destination));
                }
            }
        }
    }
 
    private void MoveEmail(FileResult file, string destination) {
        string source = file.Path;
        string fileName = Path.GetFileName(source);
        string target = Path.Combine(destination, fileName);
        File.Move(source, target);
        WriteObject(string.Format("Move {0} to {1}", source, target));
    }
 
    private Dictionary<string, string> GetSieveFilter(string sievePath) {
        var resolvedSievePath = GetResolvedPath(sievePath);
        var filter = new SieveFilter(resolvedSievePath);
        return filter.Parse();
    }
 
    private string GetResolvedPath(string path) {
        string currentDirectory = Directory.GetCurrentDirectory();
        try {
            Directory.SetCurrentDirectory(this.SessionState.Path.CurrentFileSystemLocation.Path);
            return Path.GetFullPath(path);
        } finally {
            Directory.SetCurrentDirectory(currentDirectory);
        }
    }
 
    private string GetResolvedMailfolderPath(string path, string mailFolder) {
        return Path.Combine(GetResolvedPath(path), "Maildir", "." + mailFolder, "cur");
    }
 
    private string GetResolvedInboxPath(string path) {
        return Path.Combine(GetResolvedPath(path), "Maildir", "cur");
    }
 
    private class FileResult {
        public string Path;
        public string Line;
        public string Address;
    }
 
    private FileResult ReadFile(string path) {
        using (var reader = new StreamReader(path, Encoding.UTF8, true, 1024)) {
            string line;
 
            while ((line = reader.ReadLine()) != null) {
                var match = regex.Match(line);
 
                if (match.Success) {
                    var group = match.Groups[1].Value;
                    return new FileResult() {
                        Path = path,
                        Line = match.Groups[0].Value,
                        Address = InnerMatch(match.Groups[1].Value)
                    };
                }
            }
        }
 
        return null;
    }
 
    private string InnerMatch(string line) {
        var match = innerRegex.Match(line);
        if (match.Success) {
            return match.Groups[1].Value;
        } else {
            return line;
        }
    }
}
 
class SieveFilter {
 
    string path;
 
    Regex matchRegex = new Regex("^if header :contains \"to\" \"(.*)\"$");
    Regex ruleRegex = new Regex("fileinto \"(.*)\";$");
 
    public SieveFilter(string path) {
        this.path = path;
    }
 
    public Dictionary<string, string> Parse() {
        using (var reader = new StreamReader(path, Encoding.UTF8, true, 1024)) {
            Dictionary<string, string> result = new();
            string line;
 
            string value = "";
 
            while ((line = reader.ReadLine()) != null) {
                if (string.IsNullOrEmpty(value)) {
                    var match = matchRegex.Match(line);
 
                    if (match.Success) {
                        var group = match.Groups[1].Value;
                        value = match.Groups[1].Value;
                    }
                } else {
                    var match = ruleRegex.Match(line);
 
                    if (match.Success) {
                        result.Add(value, match.Groups[1].Value);
                        value = "";
                    }
                }
            }
 
            return result;
        }
    }
}