using System; using System.Collections.Generic; using System.IO; using System.Linq; using System.Security.Principal; using AmagnoVirtualPrinter.Agent.Core.Enums; using AmagnoVirtualPrinter.Agent.Core.Interfaces; using AmagnoVirtualPrinter.Agent.Core.Model; using AmagnoVirtualPrinter.Logging; using Cassia; using JetBrains.Annotations; using AmagnoVirtualPrinter.Agent.Core; namespace AmagnoVirtualPrinter.Agent.Lib.Misc { public class JobFactory : IJobFactory { [NotNull] private readonly IVirtualPrinterLogger _logger; private readonly IDirectoryHelper _directoryHelper; [NotNull] private readonly IRegistryRepository _registryRepository; public JobFactory ( [NotNull]IRegistryRepository registryRepository, [NotNull]IVirtualPrinterLogger logger, [NotNull]IDirectoryHelper directoryHelper ) { if (registryRepository == null) { throw new ArgumentNullException(nameof(registryRepository)); } if (logger == null) { throw new ArgumentNullException(nameof(logger)); } if (directoryHelper == null) { throw new ArgumentNullException(nameof(logger)); } _registryRepository = registryRepository; _logger = logger; _directoryHelper = directoryHelper; } public IJob Create(string printerName, Stream stream) { if (printerName == null) { throw new ArgumentNullException(nameof(printerName)); } if (stream == null) { throw new ArgumentNullException(nameof(stream)); } try { var now = DateTime.Now; var jobInfo = PrintJobReader.GetCurrentPrintJobs(printerName).FirstOrDefault(); if (jobInfo == null) { throw new InvalidOperationException(); } var sessions = GetCurrentSessions(jobInfo).ToArray(); var session = sessions.FirstOrDefault(s => s.FoundDomain) ?? sessions.FirstOrDefault(); var config = _registryRepository.GetRegistryConfig(); var userConfig = _registryRepository.GetUserRegistryConfig(session.Sid); var root = _directoryHelper.GetOutputDirectory(userConfig); var iniName = GenerateFileName(now, jobInfo.JobId, 0, config.FileNameMask, "ini"); var iniPath = Path.Combine(root, iniName); var extension = GetRawFileExtension(config.IntermediateFormat); var rawName = $"{Path.GetFileNameWithoutExtension(iniName)}.{extension}"; var rawPath = Path.Combine(root, rawName); using (var output = File.Create(rawPath)) { stream.CopyTo(output); } return new Job { RawDataPath = rawPath, IniDataPath = iniPath, JobInfo = jobInfo, SessionInfo = session }; } catch (Exception exception) { LogError(exception, "Failed to create job."); return null; } } public IJob Create(string iniPath, string rawPath, IJobInfo jobInfo, ISessionInfo sessionInfo) { if (string.IsNullOrWhiteSpace(iniPath)) { throw new ArgumentException("Value cannot be null or whitespace.", nameof(iniPath)); } if (string.IsNullOrWhiteSpace(rawPath)) { throw new ArgumentException("Value cannot be null or whitespace.", nameof(rawPath)); } return new Job { IniDataPath = iniPath, RawDataPath = rawPath, JobInfo = jobInfo, SessionInfo = sessionInfo }; } [NotNull] private string GenerateFileName(DateTime time, int job, int page, [NotNull]string pattern, [NotNull]string ending) { var fileName = pattern; fileName = fileName.Replace("{yyyy}", $"{time.Year:0000}"); fileName = fileName.Replace("{MM}", $"{time.Month:00}"); fileName = fileName.Replace("{DD}", $"{time.Day:00}"); fileName = fileName.Replace("{hh}", $"{time.Hour:00}"); fileName = fileName.Replace("{mm}", $"{time.Minute:00}"); fileName = fileName.Replace("{ss}", $"{time.Second:00}"); fileName = fileName.Replace("{fff}", $"{time.Millisecond:000}"); fileName = fileName.Replace("{job05}", $"{job:00000}"); fileName = fileName.Replace("{page03}", $"{page:000}"); return $"{fileName}.{ending}"; } private IEnumerable GetCurrentSessions([NotNull]IJobInfo job) { var domain = job.DomainName; var machine = job.MachineName?.TrimStart('\\'); var username = job.UserName; LogDebug($"Searching for session of {domain}\\{username} on {machine}!"); if (domain == null || machine == null || username == null) { yield break; } const StringComparison cmp = StringComparison.OrdinalIgnoreCase; using (var server = new TerminalServicesManager().GetLocalServer()) { var sessions = server.GetSessions().Where(s => s.UserName != null && s.DomainName != null); foreach (var session in sessions) { if (!session.UserName.Equals(username, cmp)) { continue; } var isSingleUser = session.DomainName.Equals(machine, cmp); var isDomainUser = session.DomainName.Equals(domain, cmp); if (!isSingleUser && !isDomainUser) { LogWarn("Found Session {sessionId} for {username} but its not of domain {domain} or {machine}", session.SessionId, username, domain, machine); } var sessionId = session.SessionId; var desktopName = session.WindowStationName; var account = session.UserAccount; yield return new SessionInfo { Id = sessionId, Desktop = desktopName, Sid = account.Translate(typeof(SecurityIdentifier)).Value, FoundDomain = isSingleUser || isDomainUser }; } } } [NotNull] private string GetRawFileExtension(IntermediateFormat format) { switch (format) { case IntermediateFormat.Xps: return "xps"; case IntermediateFormat.Ps: return "ps"; default: throw new ArgumentOutOfRangeException(); } } private void LogDebug(string message) { _logger.Debug(message); } private void LogError(Exception exception, string message, params object[] args) { _logger.Error(exception, message, args); } private void LogWarn(string message, params object[] args) { _logger.Warn(message, args); } } }