public static void AddJob(JobInfo info) { Logger.DebugFormat("adding print job {0}", info.JobID); lock (ManagementLock) { JobDictionary[info.JobID] = info; WriteJobs(); } }
static void Main(string[] args) { // parse args if (args.Length < 4 || args.Length > 6) { UsageAndExit(); } var pseudoUri = new Uri(string.Format("lpd://{0}", args[0])); var host = pseudoUri.Host; var port = 515; if (!pseudoUri.IsDefaultPort) { port = pseudoUri.Port; } var queue = args[1]; var user = args[2]; var localFilename = args[3]; var remoteFilename = (args.Length > 4) ? args[4] : Path.GetFileName(localFilename); var localHostname = (args.Length > 5) ? args[5] : System.Net.Dns.GetHostName().Split('.')[0]; // sanity check var fileInfo = new FileInfo(localFilename); if (!fileInfo.Exists) { Console.Error.WriteLine("Local file '{0}' does not exist!", localFilename); UsageAndExit(); } var fileSize = fileInfo.Length; // prepare the JobInfo var jobInfo = new JobInfo { DataFilePath = localFilename, DataFileSize = fileSize, DocumentName = remoteFilename, HostName = localHostname, Status = JobInfo.JobStatus.ReadyToPrint, TimeOfArrival = DateTimeOffset.Now, UserName = user }; // prepare the sender var sender = new LpdSender { Host = host, Port = port, QueueName = queue }; sender.Send(jobInfo); Console.WriteLine("Job sent."); }
public void Send(JobInfo job) { Logger.InfoFormat("sending job {0} to {1}", job.JobID, Host); Logger.DebugFormat("connecting to {0}", Host); var client = new TcpClient(); client.Connect(Host, Port); var stream = client.GetStream(); var message = new List<byte>(); int thisJobNumber = IncrementJobCounter(); var dataFileName = string.Format("dfA{0:D3}{1}", thisJobNumber, job.HostName); var controlFileName = string.Format("cfA{0:D3}{1}", thisJobNumber, job.HostName); Logger.DebugFormat("LpdSender job number is {0}; control file name is '{1}' and data file name is '{2}'", Host, controlFileName, dataFileName); Logger.Debug("initiating the print request"); message.Add(0x02); message.AddRange(Encoding.ASCII.GetBytes(QueueName)); message.Add(0x0A); stream.Write(message.ToArray(), 0, message.Count); message.Clear(); // read ACK int b = stream.ReadByte(); if (b != 0x00) { Logger.WarnFormat("got 0x{0:X2} after initiating the print request", b); throw new BadResponseException("creating a new print job", b); } Logger.Debug("preparing the control file"); var controlFile = new StringBuilder(); controlFile.AppendFormat("H{0}\n", job.HostName); controlFile.AppendFormat("P{0}\n", job.UserName); controlFile.AppendFormat("J{0}\n", job.DocumentName); controlFile.AppendFormat("l{0}\n", dataFileName); controlFile.AppendFormat("U{0}\n", dataFileName); controlFile.AppendFormat("N{0}\n", job.DocumentName); var controlFileBytes = Encoding.Default.GetBytes(controlFile.ToString()); // send the control file metadata Logger.Debug("sending the control file metadata"); message.Add(0x02); message.AddRange(Encoding.ASCII.GetBytes(controlFileBytes.Length.ToString(CultureInfo.InvariantCulture))); message.Add(0x20); message.AddRange(Encoding.ASCII.GetBytes(controlFileName)); message.Add(0x0A); stream.Write(message.ToArray(), 0, message.Count); message.Clear(); // read ACK b = stream.ReadByte(); if (b != 0x00) { Logger.WarnFormat("got 0x{0:X2} after sending the control file metadata", b); throw new BadResponseException("preparing to send control data", b); } Logger.Debug("sending the control file data"); stream.Write(controlFileBytes, 0, controlFileBytes.Length); stream.WriteByte(0x00); // read ACK b = stream.ReadByte(); if (b != 0x00) { Logger.WarnFormat("got 0x{0:X2} after sending the control file data", b); throw new BadResponseException("sending control data", b); } Logger.Debug("sending the data file metadata"); message.Add(0x03); message.AddRange(Encoding.ASCII.GetBytes(job.DataFileSize.ToString(CultureInfo.InvariantCulture))); message.Add(0x20); message.AddRange(Encoding.ASCII.GetBytes(dataFileName)); message.Add(0x0A); stream.Write(message.ToArray(), 0, message.Count); message.Clear(); // read ACK b = stream.ReadByte(); if (b != 0x00) { Logger.WarnFormat("got 0x{0:X2} after sending the data file metadata", b); throw new BadResponseException("preparing to send data", b); } Logger.Debug("sending the data file data"); using (var inStream = new FileStream(job.DataFilePath, FileMode.Open, FileAccess.Read)) { Util.CopyStream(inStream, stream, job.DataFileSize); } stream.WriteByte(0x00); // read ACK b = stream.ReadByte(); if (b != 0x00) { Logger.WarnFormat("got 0x{0:X2} after sending the data file data", b); throw new BadResponseException("sending data", b); } // close Logger.Debug("job sent"); client.Close(); }
public JobInfoDrop(JobInfo info) { Info = info; if (info.DataFileSize < 1024L) { SizeString = info.DataFileSize + " B"; } else if (info.DataFileSize < 1024L * 1024L) { SizeString = (info.DataFileSize / 1024L) + " KB"; } else if (info.DataFileSize < 1024L * 1024L * 1024L) { SizeString = (info.DataFileSize / (1024L * 1024L)) + " MB"; } else if (info.DataFileSize < 1024L * 1024L * 1024L * 1024L) { SizeString = (info.DataFileSize / (1024L * 1024L * 1024L)) + " GB"; } else { SizeString = (info.DataFileSize / (1024L * 1024L * 1024L * 1024L)) + " TB"; } }
private void HandleJobSubmission(NetworkStream stream) { var jobFiles = new Dictionary<string, byte[]>(); var jobFileReferences = new Dictionary<string, string>(); var jobFileLengths = new Dictionary<string, long>(); string controlFileName = null; // create a new job, reserving a new job ID var jobInfo = new JobInfo(); for (; ; ) { byte[] command; try { command = ReadUntilLineFeed(stream); } catch (EndOfStreamException) { // it's over! break; } switch (command[0]) { case (byte)JobCommandCode.AbortJob: { ReturnSuccess(stream); Logger.Debug("Received: abort current job"); // nothing left to do here return; } case (byte)JobCommandCode.ReceiveControlFile: { var controlFileDataString = GetSingleStringArgument(command); var controlFileData = WhiteSpacePattern.Split(controlFileDataString, 2); if (controlFileData.Length != 2) { Logger.WarnFormat("'receive control file' command '{0}' not in format 'length filename'", controlFileDataString); ReturnInvalidSyntax(stream); throw new InvalidDataException("invalid syntax"); } var length = int.Parse(controlFileData[0]); controlFileName = controlFileData[1]; Logger.DebugFormat("Received: receive {0} bytes of control file named {1}", length, controlFileName); // parse the name var controlFileNameMatch = ControlFileNamePattern.Match(controlFileName); if (!controlFileNameMatch.Success) { Logger.WarnFormat("'receive control file' filename '{0}' has invalid format", controlFileName); ReturnInvalidSyntax(stream); throw new InvalidDataException("control file name doesn't match expected pattern"); } // signal that we parsed the command successfully ReturnSuccess(stream); var controlBytes = ReadBytes(length, stream); // store the control file jobFiles[controlFileName] = controlBytes; // read the last byte var b = stream.ReadByte(); if (b == 0) { // "thanks!" ReturnSuccess(stream); } else { Logger.Warn("'receive control file' control file contents not succeeded by NUL"); ReturnInvalidSyntax(stream); throw new InvalidDataException("control file not succeeded by NUL"); } break; } case (byte)JobCommandCode.ReceiveDataFile: { var dataFileDataString = GetSingleStringArgument(command); var dataFileData = WhiteSpacePattern.Split(dataFileDataString, 2); if (dataFileData.Length != 2) { Logger.WarnFormat("'receive data file' command '{0}' not in format 'length filename'", dataFileDataString); ReturnInvalidSyntax(stream); throw new InvalidDataException("invalid syntax"); } var length = int.Parse(dataFileData[0]); var lpdDataFileName = dataFileData[1]; Logger.DebugFormat("Received: receive {0} bytes of data file named {1}", length, lpdDataFileName); // parse the name var dataFileNameMatch = DataFileNamePattern.Match(lpdDataFileName); if (!dataFileNameMatch.Success) { Logger.WarnFormat("'receive data file' filename '{0}' has invalid format", lpdDataFileName); ReturnInvalidSyntax(stream); throw new InvalidDataException("data file name doesn't match expected pattern"); } // must send this so that the client responds ReturnSuccess(stream); var outFileName = Path.Combine(Config.JobDirectory, GetJobDataFilename(jobInfo.JobID, lpdDataFileName)); using (var outStream = new FileStream(outFileName, FileMode.CreateNew, FileAccess.Write)) { long? copyLength = (length == 0) ? null : (long?)length; long actualLength = Util.CopyStream(stream, outStream, copyLength); jobFileReferences[lpdDataFileName] = outFileName; jobFileLengths[lpdDataFileName] = actualLength; } if (length == 0) { // "thanks!" ReturnSuccess(stream); } else { // read the last byte var b = stream.ReadByte(); if (b == 0) { // "thanks!" ReturnSuccess(stream); } else { Logger.Warn("'receive data file' data file contents not succeeded by NUL"); ReturnInvalidSyntax(stream); throw new InvalidDataException("data file not succeeded by NUL"); } } break; } } } // decode the control file string controlString; try { controlString = Utf8Encoding.GetString(jobFiles[controlFileName]); } catch (DecoderFallbackException) { controlString = Encoding.Default.GetString(jobFiles[controlFileName]); } // parse it, with all the magic try { jobInfo = ParseJobInfo(jobInfo, controlString, jobFileReferences, jobFileLengths); } catch (FormatException) { ReturnUnsupportedPrintType(stream); return; } OnNewJobReceived(jobInfo); }
protected virtual void OnNewJobReceived(JobInfo job) { if (NewJobReceived != null) { NewJobReceived(this, job); } }
protected static JobInfo ParseJobInfo(JobInfo jobInfo, string jobInfoString, Dictionary<string, string> dataFilePaths, Dictionary<string, long> dataFileSizes) { jobInfo.Status = JobInfo.JobStatus.ReadyToPrint; jobInfo.TimeOfArrival = DateTimeOffset.UtcNow; foreach (var line in jobInfoString.Split('\n')) { if (line.Length < 2) { continue; } var letter = line[0]; var param = line.Substring(1); switch (letter) { case (char)ControlFileCharacters.HostName: jobInfo.HostName = param; break; case (char)ControlFileCharacters.UserIdentification: jobInfo.UserName = param; break; case (char)ControlFileCharacters.JobName: jobInfo.DocumentName = param; break; case (char)ControlFileCharacters.NameOfSourceFile: jobInfo.DocumentName = param; break; case (char)ControlFileCharacters.PrintFileWithControlCharacters: jobInfo.DataFilePath = dataFilePaths[param]; jobInfo.DataFileSize = dataFileSizes[param]; break; case (char)ControlFileCharacters.UnlinkDataFile: dataFilePaths.Remove(param); dataFileSizes.Remove(param); break; case (char)ControlFileCharacters.PlotCifFile: case (char)ControlFileCharacters.PrintDviFile: case (char)ControlFileCharacters.PrintFormattedFile: case (char)ControlFileCharacters.PlotBerkeleyFile: case (char)ControlFileCharacters.PrintDitroffOutput: case (char)ControlFileCharacters.PrintPostscript: case (char)ControlFileCharacters.PrintFortranCarriageControlFile: case (char)ControlFileCharacters.PrintTroffOutput: case (char)ControlFileCharacters.PrintRasterFile: Logger.WarnFormat("requested printing in unsupported format '{0}'", letter); throw new FormatException("cannot print this format"); default: // ignore it... Logger.WarnFormat("ignoring unknown LPD command file command '{0}'", letter); break; } } return jobInfo; }
private void HandleJobSubmission(NetworkStream stream) { var jobFiles = new Dictionary <string, byte[]>(); var jobFileReferences = new Dictionary <string, string>(); var jobFileLengths = new Dictionary <string, long>(); string controlFileName = null; // create a new job, reserving a new job ID var jobInfo = new JobInfo(); for (; ;) { byte[] command; try { command = ReadUntilLineFeed(stream); } catch (EndOfStreamException) { // it's over! break; } switch (command[0]) { case (byte)JobCommandCode.AbortJob: { ReturnSuccess(stream); Logger.Debug("Received: abort current job"); // nothing left to do here return; } case (byte)JobCommandCode.ReceiveControlFile: { var controlFileDataString = GetSingleStringArgument(command); var controlFileData = WhiteSpacePattern.Split(controlFileDataString, 2); if (controlFileData.Length != 2) { Logger.WarnFormat("'receive control file' command '{0}' not in format 'length filename'", controlFileDataString); ReturnInvalidSyntax(stream); throw new InvalidDataException("invalid syntax"); } var length = int.Parse(controlFileData[0]); controlFileName = controlFileData[1]; Logger.DebugFormat("Received: receive {0} bytes of control file named {1}", length, controlFileName); // parse the name var controlFileNameMatch = ControlFileNamePattern.Match(controlFileName); if (!controlFileNameMatch.Success) { Logger.WarnFormat("'receive control file' filename '{0}' has invalid format", controlFileName); ReturnInvalidSyntax(stream); throw new InvalidDataException("control file name doesn't match expected pattern"); } // signal that we parsed the command successfully ReturnSuccess(stream); var controlBytes = ReadBytes(length, stream); // store the control file jobFiles[controlFileName] = controlBytes; // read the last byte var b = stream.ReadByte(); if (b == 0) { // "thanks!" ReturnSuccess(stream); } else { Logger.Warn("'receive control file' control file contents not succeeded by NUL"); ReturnInvalidSyntax(stream); throw new InvalidDataException("control file not succeeded by NUL"); } break; } case (byte)JobCommandCode.ReceiveDataFile: { var dataFileDataString = GetSingleStringArgument(command); var dataFileData = WhiteSpacePattern.Split(dataFileDataString, 2); if (dataFileData.Length != 2) { Logger.WarnFormat("'receive data file' command '{0}' not in format 'length filename'", dataFileDataString); ReturnInvalidSyntax(stream); throw new InvalidDataException("invalid syntax"); } var length = int.Parse(dataFileData[0]); var lpdDataFileName = dataFileData[1]; Logger.DebugFormat("Received: receive {0} bytes of data file named {1}", length, lpdDataFileName); // parse the name var dataFileNameMatch = DataFileNamePattern.Match(lpdDataFileName); if (!dataFileNameMatch.Success) { Logger.WarnFormat("'receive data file' filename '{0}' has invalid format", lpdDataFileName); ReturnInvalidSyntax(stream); throw new InvalidDataException("data file name doesn't match expected pattern"); } // must send this so that the client responds ReturnSuccess(stream); var outFileName = Path.Combine(Config.JobDirectory, GetJobDataFilename(jobInfo.JobID, lpdDataFileName)); using (var outStream = new FileStream(outFileName, FileMode.CreateNew, FileAccess.Write)) { long?copyLength = (length == 0) ? null : (long?)length; long actualLength = Util.CopyStream(stream, outStream, copyLength); jobFileReferences[lpdDataFileName] = outFileName; jobFileLengths[lpdDataFileName] = actualLength; } if (length == 0) { // "thanks!" ReturnSuccess(stream); } else { // read the last byte var b = stream.ReadByte(); if (b == 0) { // "thanks!" ReturnSuccess(stream); } else { Logger.Warn("'receive data file' data file contents not succeeded by NUL"); ReturnInvalidSyntax(stream); throw new InvalidDataException("data file not succeeded by NUL"); } } break; } } } // decode the control file string controlString; try { controlString = Utf8Encoding.GetString(jobFiles[controlFileName]); } catch (DecoderFallbackException) { controlString = Encoding.Default.GetString(jobFiles[controlFileName]); } // parse it, with all the magic try { jobInfo = ParseJobInfo(jobInfo, controlString, jobFileReferences, jobFileLengths); } catch (FormatException) { ReturnUnsupportedPrintType(stream); return; } OnNewJobReceived(jobInfo); }
protected static JobInfo ParseJobInfo(JobInfo jobInfo, string jobInfoString, Dictionary <string, string> dataFilePaths, Dictionary <string, long> dataFileSizes) { jobInfo.Status = JobInfo.JobStatus.ReadyToPrint; jobInfo.TimeOfArrival = DateTimeOffset.UtcNow; foreach (var line in jobInfoString.Split('\n')) { if (line.Length < 2) { continue; } var letter = line[0]; var param = line.Substring(1); switch (letter) { case (char)ControlFileCharacters.HostName: jobInfo.HostName = param; break; case (char)ControlFileCharacters.UserIdentification: jobInfo.UserName = param; break; case (char)ControlFileCharacters.JobName: jobInfo.DocumentName = param; break; case (char)ControlFileCharacters.NameOfSourceFile: jobInfo.DocumentName = param; break; case (char)ControlFileCharacters.PrintFileWithControlCharacters: jobInfo.DataFilePath = dataFilePaths[param]; jobInfo.DataFileSize = dataFileSizes[param]; break; case (char)ControlFileCharacters.UnlinkDataFile: dataFilePaths.Remove(param); dataFileSizes.Remove(param); break; case (char)ControlFileCharacters.PlotCifFile: case (char)ControlFileCharacters.PrintDviFile: case (char)ControlFileCharacters.PrintFormattedFile: case (char)ControlFileCharacters.PlotBerkeleyFile: case (char)ControlFileCharacters.PrintDitroffOutput: case (char)ControlFileCharacters.PrintPostscript: case (char)ControlFileCharacters.PrintFortranCarriageControlFile: case (char)ControlFileCharacters.PrintTroffOutput: case (char)ControlFileCharacters.PrintRasterFile: Logger.WarnFormat("requested printing in unsupported format '{0}'", letter); throw new FormatException("cannot print this format"); default: // ignore it... Logger.WarnFormat("ignoring unknown LPD command file command '{0}'", letter); break; } } return(jobInfo); }