using System;
using System.Text.RegularExpressions;
namespace BulkArchiveMailer.Core
{
/// Result of successfully parsing an archive file name.
public sealed class ParsedFilename
{
public ParsedFilename(string login, string suffix)
{
Login = login;
Suffix = suffix;
}
/// Lower-cased login exactly as it appears in the file name (hyphens intact).
public string Login { get; }
///
/// Lower-cased suffix exactly as it appears in the file name (the
/// part between the login and ".7z"), e.g. "ssh_access" or
/// "config_update" for the two built-in templates, or whatever
/// FileSuffix a custom template in AppSettingsData.Templates uses.
/// Whether this suffix corresponds to any *configured* template is
/// NOT checked here - that is ArchiveScanner's job, since it is the
/// one holding the list of templates.
///
public string Suffix { get; }
}
///
/// Parses the generic "{login}_{suffix}.7z" file name shape
/// ssh-access-tui produces (see internal/keymgr/pack.go and
/// internal/keymgr/configonly.go in the main repo for the producing
/// side, and config.default.json/SettingsForm for how an operator adds
/// further suffixes via custom templates). Anything else (wrong
/// extension, no underscore-separated suffix, stray file dropped in the
/// export folder by a human) simply fails to parse - the caller
/// (ArchiveScanner) is responsible for routing that into the
/// "unrecognized" bucket instead of blocking the batch. Whether a
/// syntactically valid suffix actually matches a configured template is
/// also ArchiveScanner's job, not this parser's.
///
public static class FilenameParser
{
// Matches the login part ssh-access-tui itself accepts for a Linux
// username: lowercase alnum segments joined by single hyphens (no
// leading/trailing/double hyphens), followed by an underscore and
// any lowercase alnum/underscore suffix. Case-insensitive purely as
// a defensive measure in case a file was renamed by hand on a
// case-insensitive filesystem; the captured login/suffix are
// normalized to lower case before use.
private static readonly Regex Pattern = new Regex(
@"^(?[a-z0-9]+(?:-[a-z0-9]+)*)_(?[a-z0-9_]+)\.7z$",
RegexOptions.IgnoreCase | RegexOptions.Compiled);
public static bool TryParse(string fileName, out ParsedFilename parsed)
{
parsed = null;
if (string.IsNullOrEmpty(fileName))
{
return false;
}
var match = Pattern.Match(fileName);
if (!match.Success)
{
return false;
}
var login = match.Groups["login"].Value.ToLowerInvariant();
var suffix = match.Groups["suffix"].Value.ToLowerInvariant();
parsed = new ParsedFilename(login, suffix);
return true;
}
}
}