= RedMon = Redirection Port Monitor (RedMon) is a virtual printer port that can redirect output to a file or program which can in turn process the printer data or send it to a physical printer. {{:software:redmon:redmon_overview.png?nolink&600|}} == Installation == * Download RedMon: [[http://pages.cs.wisc.edu/~ghost/redmon/]] or here: {{software:redmon:redmon19.zip|1.9}} | {{software:redmon:redmon17.zip|1.7}} * Unpack and run ''setup.exe'' or ''setup64.exe''. * Add an RPT1: port. == Add Redirected Port (RPT1:) == * Run ''cmd'' as Administrator. * Run one of these commands: * Add new printer: ''C:\> rundll32 printui.dll,PrintUIEntry /il'' * Update current printer: ''C:\> rundll32 printui.dll,PrintUIEntry /n "Printer Name" /p'' * Add Port: Inside the Printer Properties, select Ports (tab) > New Port > Redirected Port > Port Name: "RPT1:" {{:software:redmon:redmon-add-printerports.png?nolink|}} == Configure Redirected Port (RPT1:) == Select a printer, then go to the "Printer Properties" (right-click printer). Assign the ''RPT:'' port for that printer, then click on the button "Configure Port". {{:software:redmon:redmon-configure-port.png?nolink|}} Set the ''RPT1:'' port properties * Program to which redirect. * Arguments for program. ''"%1"'' is for ''STDIN''. * Output. Choose from: * Program handles output * Prompt for filename * Copy stdout to printer * Copy temporary file to printer * Copy pipe to printer * Printer. This handles the output from the program selected. {{:software:redmon:redmon-configure-port-rpt1_properties-4.png?nolink|}} == Example Translator == RedMon passes the original print job via STDIN to the program ''C:\Apps\PrnTranslator.exe''. It also passes a command line argument specifying where ''PrinterTranslator'' should save the output print job after making its changes. RedMon then takes the file and spools it directly to the selected printer, in this case "Xerox Phaser". ''PrinterTranslator'' is a basic program which accepts the STDIN input from RedMon, makes a few changes to the formatting and outputs the file. You can see the source code below. using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.IO; namespace PrinterTranslator { class Program { static void Main(string[] args) { // Check if an output filename was provided and close if it wasn't. string Filename = ""; if (args.Length == 0) { Console.WriteLine("No file was specified to write the translated data to... closing."); return; } else { Filename = args[0]; } bool UsingSTDIN = false; string InputFile = ""; try { // This function throws an InvalidOperationException when the input is coming from STDIN. UsingSTDIN = System.Console.KeyAvailable; if (!UsingSTDIN) return; } catch (InvalidOperationException e) { // Since we got this exception we know we got data from STDIN. InputFile = System.Console.In.ReadToEnd(); } string[] LinesToProcess = InputFile.Split('\f'); // Prep the file so we can save the fixed lines as we run through them. StreamWriter OutFile = new StreamWriter(Filename); // Fix the file formatting. foreach (string Line in LinesToProcess) { string newLine = Line; // Make sure all quotes are ended. if (Line.Contains('"')) { int FirstQuote = Line.IndexOf('"'); if (FirstQuote != -1) { int LastQuote = Line.LastIndexOf('"'); if (FirstQuote == LastQuote) newLine += '"'; } } // Write out the fixed line. // Check if the string already contains a carriage return. // In that case, we do not want to do a WriteLine as // we will actually write 2 lines. if (!(newLine == "\r\n")) { OutFile.WriteLine(newLine); } } OutFile.Close(); } } } == Example Uploader == using System; using System.Collections.Generic; using System.IO; using System.Net; using System.Net.Security; using System.Web; namespace PrinterUploader { class Program { const string LABEL_LOG_URL = "http://audina.net/support/print-log/web/api-raw/create"; static void Main(string[] args) { bool CreateInputCopy = false; string InputFilename = string.Empty; string InputFileContent = string.Empty; string InputCopyFilename = string.Empty; #region Process command line parameters // Check if an output filename was provided and close if it wasn't. if (args.Length > 0) { foreach (string Argument in args) { if (Argument.StartsWith("/input=")) { InputFilename = Argument.Substring(Argument.IndexOf('=') + 1); } else if (Argument.StartsWith("/copyinput=")) { CreateInputCopy = true; InputCopyFilename = Argument.Substring(Argument.IndexOf('=') + 1); } } } #endregion #region Get input from file/stdin // Try using standard in if an input filename isn't passed in if (InputFilename == string.Empty) { try { // This function throws an InvalidOperationException when the input is coming from STDIN. Console.WriteLine("Checking for standard in input."); bool test = System.Console.KeyAvailable; Console.WriteLine("Standard in input not available."); if (args.Length == 0) { Console.WriteLine("Closing due to no input."); return; } } catch (InvalidOperationException) { // Since we got this exception we know we got data from STDIN. Console.WriteLine("Using standard in input."); InputFileContent = System.Console.In.ReadToEnd(); Console.WriteLine(InputFileContent); } } else { try { Console.WriteLine("Getting input from filename, {0}", InputFilename); using (TextReader tr = File.OpenText(InputFilename)) { InputFileContent = tr.ReadToEnd(); } } catch (Exception e) { if (e is FileNotFoundException || e is DirectoryNotFoundException) { Console.WriteLine("Input file was not found."); System.Threading.Thread.Sleep(5 * 1000); } return; } } if (InputFileContent == string.Empty) { Console.WriteLine("No input file content was found."); System.Threading.Thread.Sleep(5 * 1000); return; } #endregion #region Output copies and handle passthrough if (CreateInputCopy) { Console.WriteLine("Creating an input copy, {0}", InputCopyFilename); try { using (StreamWriter CopyFile = new StreamWriter(InputCopyFilename)) { CopyFile.Write(InputFileContent); CopyFile.Close(); } } catch { Console.WriteLine(string.Format("Copying input to {0} failed.", InputCopyFilename)); Console.WriteLine(InputFileContent); System.Threading.Thread.Sleep(5 * 1000); } } #endregion #region Upload the file // Upload the file LogAddressLabel(InputFileContent); #endregion } public static string LogAddressLabel(string LabelText) { Dictionary postParameters = new Dictionary(); if (LabelText == string.Empty) LabelText = "empty"; postParameters.Add("category", "Address Label"); postParameters.Add("data", LabelText); string result = ""; try { result = HttpPostRequest(LABEL_LOG_URL, postParameters); } catch (WebException exc) { // Only ignore errors with: 404 Not Found. if (!exc.Message.Contains("(404) Not Found.")) { throw exc; } } return result; } public static string HttpPostRequest(string url, Dictionary postParameters, bool mustAuthenticate=false, string aUsername="", string aPassword="") { string postData = ""; foreach (string key in postParameters.Keys) { postData += HttpUtility.UrlEncode(key) + "=" + HttpUtility.UrlEncode(postParameters[key]) + "&"; } HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(url); webRequest.Method = "POST"; // authentication if (mustAuthenticate) { webRequest.PreAuthenticate = mustAuthenticate; webRequest.AuthenticationLevel = AuthenticationLevel.MutualAuthRequested; var cache = new CredentialCache(); cache.Add(new System.Uri(url), "Basic", new NetworkCredential(aUsername, aPassword)); webRequest.Credentials = cache; //ServicePointManager.ServerCertificateValidationCallback = new RemoteCertificateValidationCallback(AcceptAllCertifications); } byte[] data = System.Text.Encoding.ASCII.GetBytes(postData); webRequest.ContentType = "application/x-www-form-urlencoded"; //webRequest.ContentType = "application/json; charset=utf-8"; webRequest.ContentLength = data.Length; Stream requestStream = webRequest.GetRequestStream(); requestStream.Write(data, 0, data.Length); requestStream.Close(); string responseFromServer = ""; try { HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse(); Stream responseStream = webResponse.GetResponseStream(); StreamReader streamReader = new StreamReader(responseStream, System.Text.Encoding.Default); responseFromServer = streamReader.ReadToEnd(); streamReader.Close(); responseStream.Close(); webResponse.Close(); } catch (WebException exc) { // Do not ignore any web exception throw exc; } return responseFromServer; } } }