Ghostscript.NET how to handle input on StdIn - c#

I'm attempting to create a simple C# application which can accept input on StdIn and process that with Ghostscript to create a PDF, eventually I'd like to do other things with the output PDF, but for now just creating the PDF is enough.
I was thinking of running the Ghostscript .exe with a Process, but then I found Ghostscript.NET, the thing I'm struggling with is how to pass the data received on StdIn to the Ghostscript.NET Processor.
using (GhostscriptProcessor ghostscript = new GhostscriptProcessor(gvi))
{
List<string> switches = new List<string>();
switches.Add("-sDEVICE=pdfwrite");
switches.Add("-r300");
switches.Add("-dBATCH");
switches.Add("-dNOPAUSE");
switches.Add("-dSAFER");
switches.Add("-dNOPROMPT");
switches.Add("-sPAPERSIZE=a4");
switches.Add("-sOutputFile = \"" + filename + "\"");
switches.Add("-c");
switches.Add(".setpdfwrite");
switches.Add(#"-f");
switches.Add("-");
ghostscript.Process(switches.ToArray(), new ConsoleStdIO(true, true, true));
}
This was from the GitHub repo, but I'm not sure if it's what I need or not:
public class ConsoleStdIO : Ghostscript.NET.GhostscriptStdIO
{
public ConsoleStdIO(bool handleStdIn, bool handleStdOut, bool handleStdErr) : base(handleStdIn, handleStdOut, handleStdErr) { }
public override void StdIn(out string input, int count)
{
char[] userInput = new char[count];
Console.In.ReadBlock(userInput, 0, count);
input = new string(userInput);
}
public override void StdOut(string output)
{
Console.Write(output);
}
public override void StdError(string error)
{
Console.Write(error);
}
}

public static string[] PStoPDFArguments(string fileName) =>
new string[]
{
"-dBATCH",
"-dNOPAUSE",
"-sDEVICE=pdfwrite",
"-sPAPERSIZE=a4",
"-dPDFSETTINGS=/prepress",
$"-sOutputFile=\"{fileName}\"",
"-"
};
//...
public override void StdIn(out string input, int count)
{
var buffer = new char[count];
Console.In.ReadBlock(buffer, 0, count);
input = buffer[0] == '\0'
? null
: new string(buffer);
}
//...

Related

C# pass file text to list when file is entered via command line argument

I am writing a program for an assignment that is meant to read two text files and use their data to write to a third text file. I was instructed to pass the contents of the one file to a list. I have done something similar, passing the contents to an array (see below). But I can't seem to get it to work with a list.
Here is what I have done in the past with arrays:
StreamReader f1 = new StreamReader(args[0]);
StreamReader f2 = new StreamReader(args[1]);
StreamWriter p = new StreamWriter(args[2]);
double[] array1 = new double[20];
double[] array2 = new double[20];
double[] array3 = new double[20];
string line;
int index;
double value;
while ((line = f1.ReadLine()) != null)
{
string[] currentLine = line.Split('|');
index = Convert.ToInt16(currentLine[0]);
value = Convert.ToDouble(currentLine[1]);
array1[index] = value;
}
If it is of any interest, this is my current setup:
static void Main(String[] args)
{
// Create variables to hold the 3 elements of each item that you will read from the file
// Create variables for all 3 files (2 for READ, 1 for WRITE)
int ID;
string InvName;
int Number;
string IDString;
string NumberString;
string line;
List<InventoryNode> Inventory = new List<InventoryNode>();
InventoryNode Item = null;
StreamReader f1 = new StreamReader(args[0]);
StreamReader f2 = new StreamReader(args[1]);
StreamWriter p = new StreamWriter(args[2]);
// Read each item from the Update File and process the data
//Data is separated by pipe |
If you want to convert Array to List, you can just call Add or Insert to make it happen.
According to your code, you can do Inventory.Add(Item).
while ((line = f1.ReadLine()) != null)
{
string[] currentLine = line.Split('|');
Item = new InventoryItem {
Index = Convert.ToInt16(currentLine[0]),
Value = Convert.ToDouble(currentLine[1])
};
Inventory.Add(Item);
}
like this.
If I understand it correctly all you want to do is read two input file, parse the data in these file in a particular format (in this case int|double) and then write it to a new file. If this is the requirement, please try out the following code, as it is not sure how you want the data to be presented in the third file I have kept the format as it is (i.e. int|double)
static void Main(string[] args)
{
if (args == null || args.Length < 3)
{
Console.WriteLine("Wrong Input");
return;
}
if (!ValidateFilePath(args[0]) || !ValidateFilePath(args[1]))
{
return;
}
Dictionary<int, double> parsedFileData = new Dictionary<int, double>();
//Read the first file
ReadFileData(args[0], parsedFileData);
//Read second file
ReadFileData(args[1], parsedFileData);
//Write to third file
WriteFileData(args[2], parsedFileData);
}
private static bool ValidateFilePath(string filePath)
{
try
{
return File.Exists(filePath);
}
catch (Exception)
{
Console.WriteLine($"Failed to read file : {filePath}");
return false;
}
}
private static void ReadFileData(string filePath, Dictionary<int, double> parsedFileData)
{
try
{
using (StreamReader fileStream = new StreamReader(filePath))
{
string line;
while ((line = fileStream.ReadLine()) != null)
{
string[] currentLine = line.Split('|');
int index = Convert.ToInt16(currentLine[0]);
double value = Convert.ToDouble(currentLine[1]);
parsedFileData.Add(index, value);
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Exception : {ex.Message}");
}
}
private static void WriteFileData(string filePath, Dictionary<int, double> parsedFileData)
{
try
{
using (StreamWriter fileStream = new StreamWriter(filePath))
{
foreach (var parsedLine in parsedFileData)
{
var line = parsedLine.Key + "|" + parsedLine.Value;
fileStream.WriteLine(line);
}
}
}
catch (Exception ex)
{
Console.WriteLine($"Exception : {ex.Message}");
}
}
There are few things you should always remember while writing a C# code :
1) Validate command line inputs before using.
2) Always lookout for any class that has dispose method, instantiate it inside using block.
3) Proper mechanism in the code to catch exceptions, else your program would crash at runtime with invalid inputs or inputs that you could not validate!

Keylogger API and converting to a string

I'm attempting to write a simple keylogger that will check typed words against a blacklist and fire a screenshot when a word is triggered. This is because we have a new PREVENT agenda that we have to use in UK schools to capture any possible extremist views.
I've been looking at the Keylogger API from https://github.com/fabriciorissetto/KeystrokeAPI
I'm using the following code as a test but i'm trying to add the characters to a string so i can then fire a comparison with a word list when the user presses the spacebar. The trouble i'm having is that i cannot convert character into a string. Is it possible do this so i can append it to another string a whilst waiting for a spacebar key?
class Program
{
static void Main(string[] args)
{
using (var api = new KeystrokeAPI())
{
api.CreateKeyboardHook((character) => { Console.Write(character); });
Application.Run();
}
}
}
This is what i have so far, the error i get is on the if statement converting character to a string.
static void Main(string[] args)
{
string line = "";
using (var api = new KeystrokeAPI())
{
api.CreateKeyboardHook((character) => {
line += character.ToString();
if (character.ToString() = "space")
{
Console.Write("Spacebar Hit");
}
Console.Write(character.KeyCode);
});
Application.Run();
}
}
Edit.
I rewrote this.
Captures both spaces and enter commands
static void Main(string[] args)
{
string line = string.Empty;
using (var api = new KeystrokeAPI())
{
api.CreateKeyboardHook((character) => {
if (character.KeyCode.ToString() == "Space" || character.KeyCode.ToString() == "Return")
{
if(BannedWordsCheck(line))
{
Console.WriteLine("Banned Word Typed: " + line);
}
line = string.Empty;
}
else
{
line += character.KeyCode.ToString();
}
});
Application.Run();
}
}
static bool BannedWordsCheck(string word)
{
if(word.ToLower().Contains("terror"))
{
return true;
}
else
{
return false;
}
}
The error you are receiving in your code is due to the following line
if (character.ToString() = "space")
You are attempting to assign the string literal "space" to character.ToString(), I also have this error in my comment which I can't edit anymore.
Here's a snippet that will check the key code against an enum instead of a string, it will then call the HandleComparison method if Space was pressed, and then clear out the StringBuilder
The only issue I found here is that pressing Shift will prefix the string with <shift>, so some additional logic will have to be applied for action keys, but this is a base to get you started with a working code sample.
I hope this helps.
class Program
{
private static StringBuilder builder;
static void Main(string[] args)
{
using (var api = new KeystrokeAPI())
{
builder = new StringBuilder();
api.CreateKeyboardHook(HandleKeyPress);
Application.Run();
}
}
private static void HandleKeyPress(KeyPressed obj)
{
// To be more reliable, lets use the KeyCode enum instead
if (obj.KeyCode == KeyCode.Space)
{
// Spacebar was pressed, let's check the word and flush the StringBuilder
HandleComparison(builder.ToString());
builder.Clear();
return;
}
// Space wasn't pressed, let's add the word to the StringBuilder
builder.Append(obj);
}
// Handle comparison logic here, I.E check word if exists on blacklist
private static void HandleComparison(string compareString)
{
Console.WriteLine(compareString);
}
}
Could you use the StringBuilder as a buffer?
something like this
var buffer = new StringBuilder();
using (var api = new KeystrokeAPI())
{
api.CreateKeyboardHook((character) => {
if (character.ToString() == " ")
{
//check the word
CallSomeMethodToCheckWord(buffer.ToString());
//reset the buffer
buffer = new StringBuilder();
}
else
{
//ToString returns special characters in it, so you could append here and parse later, or parse here.
buffer.Append(character.ToString());
}
});
Application.Run();
}

EntityTooSmall in CompleteMultipartUploadResponse

using .NET SDK v.1.5.21.0
I'm trying to upload a large file (63Mb) and I'm following the example at:
http://docs.aws.amazon.com/AmazonS3/latest/dev/LLuploadFileDotNet.html
But using a helper instead the hole code and using jQuery File Upload
https://github.com/blueimp/jQuery-File-Upload/blob/master/basic-plus.html
what I have is:
string bucket = "mybucket";
long totalSize = long.Parse(context.Request.Headers["X-File-Size"]),
maxChunkSize = long.Parse(context.Request.Headers["X-File-MaxChunkSize"]),
uploadedBytes = long.Parse(context.Request.Headers["X-File-UloadedBytes"]),
partNumber = uploadedBytes / maxChunkSize + 1,
fileSize = partNumber * inputStream.Length;
bool lastPart = inputStream.Length < maxChunkSize;
// http://docs.aws.amazon.com/AmazonS3/latest/dev/LLuploadFileDotNet.html
if (partNumber == 1) // initialize upload
{
iView.Utilities.Amazon_S3.S3MultipartUpload.InitializePartToCloud(fileName, bucket);
}
try
{
// upload part
iView.Utilities.Amazon_S3.S3MultipartUpload.UploadPartToCloud(fs, fileName, bucket, (int)partNumber, uploadedBytes, maxChunkSize);
if (lastPart)
// wrap it up and go home
iView.Utilities.Amazon_S3.S3MultipartUpload.CompletePartToCloud(fileName, bucket);
}
catch (System.Exception ex)
{
// Huston, we have a problem!
//Console.WriteLine("Exception occurred: {0}", exception.Message);
iView.Utilities.Amazon_S3.S3MultipartUpload.AbortPartToCloud(fileName, bucket);
}
and
public static class S3MultipartUpload
{
private static string accessKey = System.Configuration.ConfigurationManager.AppSettings["AWSAccessKey"];
private static string secretAccessKey = System.Configuration.ConfigurationManager.AppSettings["AWSSecretKey"];
private static AmazonS3 client = Amazon.AWSClientFactory.CreateAmazonS3Client(accessKey, secretAccessKey);
public static InitiateMultipartUploadResponse initResponse;
public static List<UploadPartResponse> uploadResponses;
public static void InitializePartToCloud(string destinationFilename, string destinationBucket)
{
// 1. Initialize.
uploadResponses = new List<UploadPartResponse>();
InitiateMultipartUploadRequest initRequest =
new InitiateMultipartUploadRequest()
.WithBucketName(destinationBucket)
.WithKey(destinationFilename.TrimStart('/'));
initResponse = client.InitiateMultipartUpload(initRequest);
}
public static void UploadPartToCloud(Stream fileStream, string destinationFilename, string destinationBucket, int partNumber, long uploadedBytes, long maxChunkedBytes)
{
// 2. Upload Parts.
UploadPartRequest request = new UploadPartRequest()
.WithBucketName(destinationBucket)
.WithKey(destinationFilename.TrimStart('/'))
.WithUploadId(initResponse.UploadId)
.WithPartNumber(partNumber)
.WithPartSize(maxChunkedBytes)
.WithFilePosition(uploadedBytes)
.WithInputStream(fileStream) as UploadPartRequest;
uploadResponses.Add(client.UploadPart(request));
}
public static void CompletePartToCloud(string destinationFilename, string destinationBucket)
{
// Step 3: complete.
CompleteMultipartUploadRequest compRequest =
new CompleteMultipartUploadRequest()
.WithBucketName(destinationBucket)
.WithKey(destinationFilename.TrimStart('/'))
.WithUploadId(initResponse.UploadId)
.WithPartETags(uploadResponses);
CompleteMultipartUploadResponse completeUploadResponse =
client.CompleteMultipartUpload(compRequest);
}
public static void AbortPartToCloud(string destinationFilename, string destinationBucket)
{
// abort.
client.AbortMultipartUpload(new AbortMultipartUploadRequest()
.WithBucketName(destinationBucket)
.WithKey(destinationFilename.TrimStart('/'))
.WithUploadId(initResponse.UploadId));
}
}
my maxChunckedSize is 6Mb (6 * (1024*1024)) as I have read that the minimum is 5Mb...
why am I getting "Your proposed upload is smaller than the minimum allowed size" exception? What am I doing wrong?
The error is:
<Error>
<Code>EntityTooSmall</Code>
<Message>Your proposed upload is smaller than the minimum allowed size</Message>
<ETag>d41d8cd98f00b204e9800998ecf8427e</ETag>
<MinSizeAllowed>5242880</MinSizeAllowed>
<ProposedSize>0</ProposedSize>
<RequestId>C70E7A23C87CE5FC</RequestId>
<HostId>pmhuMXdRBSaCDxsQTHzucV5eUNcDORvKY0L4ZLMRBz7Ch1DeMh7BtQ6mmfBCLPM2</HostId>
<PartNumber>1</PartNumber>
</Error>
How can I get ProposedSize if I'm passing the stream and stream length?
Here is a working solution for the latest Amazon SDK (as today: v.1.5.37.0)
Amazon S3 Multipart Upload works like:
Initialize the request using client.InitiateMultipartUpload(initRequest)
Send chunks of the file (loop until the end) using client.UploadPart(request)
Complete the request using client.CompleteMultipartUpload(compRequest)
If anything goes wrong, remember to dispose the client and request, as well fire the abort command using client.AbortMultipartUpload(abortMultipartUploadRequest)
I keep the client in Session as we need this for each chunk upload as well, keep an hold of the ETags that are now used to complete the process.
You can see an example and simple way of doing this in Amazon Docs itself, I ended up having a class to do everything, plus, I have integrated with the lovely jQuery File Upload plugin (Handler code below as well).
The S3MultipartUpload is as follow
public class S3MultipartUpload : IDisposable
{
string accessKey = System.Configuration.ConfigurationManager.AppSettings.Get("AWSAccessKey");
string secretAccessKey = System.Configuration.ConfigurationManager.AppSettings.Get("AWSSecretKey");
AmazonS3 client;
public string OriginalFilename { get; set; }
public string DestinationFilename { get; set; }
public string DestinationBucket { get; set; }
public InitiateMultipartUploadResponse initResponse;
public List<PartETag> uploadPartETags;
public string UploadId { get; private set; }
public S3MultipartUpload(string destinationFilename, string destinationBucket)
{
if (client == null)
{
System.Net.WebRequest.DefaultWebProxy = null; // disable proxy to make upload quicker
client = Amazon.AWSClientFactory.CreateAmazonS3Client(accessKey, secretAccessKey, new AmazonS3Config()
{
RegionEndpoint = Amazon.RegionEndpoint.EUWest1,
CommunicationProtocol = Protocol.HTTP
});
this.OriginalFilename = destinationFilename.TrimStart('/');
this.DestinationFilename = string.Format("{0:yyyy}{0:MM}{0:dd}{0:HH}{0:mm}{0:ss}{0:fffff}_{1}", DateTime.UtcNow, this.OriginalFilename);
this.DestinationBucket = destinationBucket;
this.InitializePartToCloud();
}
}
private void InitializePartToCloud()
{
// 1. Initialize.
uploadPartETags = new List<PartETag>();
InitiateMultipartUploadRequest initRequest = new InitiateMultipartUploadRequest();
initRequest.BucketName = this.DestinationBucket;
initRequest.Key = this.DestinationFilename;
// make it public
initRequest.AddHeader("x-amz-acl", "public-read");
initResponse = client.InitiateMultipartUpload(initRequest);
}
public void UploadPartToCloud(Stream fileStream, long uploadedBytes, long maxChunkedBytes)
{
int partNumber = uploadPartETags.Count() + 1; // current part
// 2. Upload Parts.
UploadPartRequest request = new UploadPartRequest();
request.BucketName = this.DestinationBucket;
request.Key = this.DestinationFilename;
request.UploadId = initResponse.UploadId;
request.PartNumber = partNumber;
request.PartSize = fileStream.Length;
//request.FilePosition = uploadedBytes // remove this line?
request.InputStream = fileStream; // as UploadPartRequest;
var up = client.UploadPart(request);
uploadPartETags.Add(new PartETag() { ETag = up.ETag, PartNumber = partNumber });
}
public string CompletePartToCloud()
{
// Step 3: complete.
CompleteMultipartUploadRequest compRequest = new CompleteMultipartUploadRequest();
compRequest.BucketName = this.DestinationBucket;
compRequest.Key = this.DestinationFilename;
compRequest.UploadId = initResponse.UploadId;
compRequest.PartETags = uploadPartETags;
string r = "Something went badly wrong";
using (CompleteMultipartUploadResponse completeUploadResponse = client.CompleteMultipartUpload(compRequest))
r = completeUploadResponse.ResponseXml;
return r;
}
public void AbortPartToCloud()
{
// abort.
client.AbortMultipartUpload(new AbortMultipartUploadRequest()
{
BucketName = this.DestinationBucket,
Key = this.DestinationFilename,
UploadId = initResponse.UploadId
});
}
public void Dispose()
{
if (client != null) client.Dispose();
if (initResponse != null) initResponse.Dispose();
}
}
I use DestinationFilename as the destination file so I can avoid the same name, but I keep the OriginalFilename as I needed later.
Using jQuery File Upload Plugin, all works inside a Generic Handler, and the process is something like this:
// Upload partial file
private void UploadPartialFile(string fileName, HttpContext context, List<FilesStatus> statuses)
{
if (context.Request.Files.Count != 1)
throw new HttpRequestValidationException("Attempt to upload chunked file containing more than one fragment per request");
var inputStream = context.Request.Files[0].InputStream;
string contentRange = context.Request.Headers["Content-Range"]; // "bytes 0-6291455/14130271"
int fileSize = int.Parse(contentRange.Split('/')[1]);,
maxChunkSize = int.Parse(context.Request.Headers["X-Max-Chunk-Size"]),
uploadedBytes = int.Parse(contentRange.Replace("bytes ", "").Split('-')[0]);
iView.Utilities.AWS.S3MultipartUpload s3Upload = null;
try
{
// ######################################################################################
// 1. Initialize Amazon S3 Client
if (uploadedBytes == 0)
{
HttpContext.Current.Session["s3-upload"] = new iView.Utilities.AWS.S3MultipartUpload(fileName, awsBucket);
s3Upload = (iView.Utilities.AWS.S3MultipartUpload)HttpContext.Current.Session["s3-upload"];
string msg = System.String.Format("Upload started: {0} ({1:N0}Mb)", s3Upload.DestinationFilename, (fileSize / 1024));
this.Log(msg);
}
// cast current session object
if (s3Upload == null)
s3Upload = (iView.Utilities.AWS.S3MultipartUpload)HttpContext.Current.Session["s3-upload"];
// ######################################################################################
// 2. Send Chunks
s3Upload.UploadPartToCloud(inputStream, uploadedBytes, maxChunkSize);
// ######################################################################################
// 3. Complete Upload
if (uploadedBytes + maxChunkSize > fileSize)
{
string completeRequest = s3Upload.CompletePartToCloud();
this.Log(completeRequest); // log S3 response
s3Upload.Dispose(); // dispose all objects
HttpContext.Current.Session["s3-upload"] = null; // we don't need this anymore
}
}
catch (System.Exception ex)
{
if (ex.InnerException != null)
while (ex.InnerException != null)
ex = ex.InnerException;
this.Log(string.Format("{0}\n\n{1}", ex.Message, ex.StackTrace)); // log error
s3Upload.AbortPartToCloud(); // abort current upload
s3Upload.Dispose(); // dispose all objects
statuses.Add(new FilesStatus(ex.Message));
return;
}
statuses.Add(new FilesStatus(s3Upload.DestinationFilename, fileSize, ""));
}
Keep in mind that to have a Session object inside a Generic Handler, you need to implement IRequiresSessionState so your handler will look like:
public class UploadHandlerSimple : IHttpHandler, IRequiresSessionState
Inside fileupload.js (under _initXHRData) I have added an extra header called X-Max-Chunk-Size so I can pass this to Amazon and calculate if it's the last part of the uploaded file.
Fell free to comment and make smart edits for everyone to use.
I guess you didn't set the content-length of the part inside the UploadPartToCloud() function.

How to write english transcription in console correctly?

I want to write english transcription in console.
In debugger I have this səˈdʒest
but in console I have s??d?est.
How to resolve this problem ? Thanks!
Up
Client for getting transcription
class TranslationFormattedResult
{
public string Transcription { get; set; }
public List<string> TranslatedWordList = new List<string>();
}
class TranslatorClient
{
private TranslationServiceSoapClient _client = new TranslationServiceSoapClient("TranslationServiceSoap");
public async Task<TranslationFormattedResult> GetTranslationAsync(string word)
{
var result = await _client.GetTranslationAsync("er", "General",
word,
lang: "ru",
limit: 3000,
useAutoDetect: true,
key: "",
ts: "MainSite",
tid: "");
var translationResult = new TranslationFormattedResult {Transcription = await GetTranscriptionAsync(result)};
return translationResult;
}
private async Task<string> GetTranscriptionAsync(TranslationResult result)
{
var task = new Task<string>(() =>
{
string pr = null;
string pattern = "\\[.+\\]";
var match = Regex.Match(result.result, pattern);
if(match.Success)
{
pr = match.Value.Trim('[', ']');
}
return pr;
});
task.Start();
return await task;
}
}
And main method
class Program
{
static void Main(string[] args)
{
//this works
var client = new TranslatorClient();
var ts = client.GetTranslationAsync("suggest")
.ContinueWith(r =>
{
var transcription = r.Result.Transcription;
Console.OutputEncoding = Encoding.Unicode;
Console.WriteLine(transcription);
Console.WriteLine("press any key");
Console.ReadKey();
}
);
ts.Wait();
}
}
You should:
set the OutputEncoding to Unicode: Console.OutputEncoding = Encoding.Unicode;
run your program
right click on the console window
in the properties window change the console font and set it to Consolas.
class Program {
static void Main( string[ ] args ) {
Console.OutputEncoding = Encoding.Unicode;
Console.WriteLine( "səˈdʒest" );
}
}
The result in the console is:
Is this Russian?
If so, try running chcp 866 at the command line.
Refer to this
http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/chcp.mspx?mfr=true
This answer also suggests a specific (or at least, different) font may need to be selected (not sure if this applies to Russian or not) Unicode characters in Windows command line - how?

spamassassin check score C# code

Is there a way to check the score in an ASP.Net application? A class or something similar for .Net? How about other Spam Filters out there.
--Edited
I am looking for a way to check the spam score of the email messages in C#.
Here is my super simplified "just check the score" code for connecting to a running Spam Assassin email check from C# which I wrote for http://elasticemail.com. Just setup SA to run on a server and set the access permissions.
Then you can use this code to call it:
public class SimpleSpamAssassin
{
public class RuleResult
{
public double Score = 0;
public string Rule = "";
public string Description = "";
public RuleResult() { }
public RuleResult(string line)
{
Score = double.Parse(line.Substring(0, line.IndexOf(" ")).Trim());
line = line.Substring(line.IndexOf(" ") + 1);
Rule = line.Substring(0, 23).Trim();
Description = line.Substring(23).Trim();
}
}
public static List<RuleResult> GetReport(string serverIP, string message)
{
string command = "REPORT";
StringBuilder sb = new StringBuilder();
sb.AppendFormat("{0} SPAMC/1.2\r\n", command);
sb.AppendFormat("Content-Length: {0}\r\n\r\n", message.Length);
sb.AppendFormat(message);
byte[] messageBuffer = Encoding.ASCII.GetBytes(sb.ToString());
using (Socket spamAssassinSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp))
{
spamAssassinSocket.Connect(serverIP, 783);
spamAssassinSocket.Send(messageBuffer);
spamAssassinSocket.Shutdown(SocketShutdown.Send);
int received;
string receivedMessage = string.Empty;
do
{
byte[] receiveBuffer = new byte[1024];
received = spamAssassinSocket.Receive(receiveBuffer);
receivedMessage += Encoding.ASCII.GetString(receiveBuffer, 0, received);
}
while (received > 0);
spamAssassinSocket.Shutdown(SocketShutdown.Both);
return ParseResponse(receivedMessage);
}
}
private static List<RuleResult> ParseResponse(string receivedMessage)
{
//merge line endings
receivedMessage = receivedMessage.Replace("\r\n", "\n");
receivedMessage = receivedMessage.Replace("\r", "\n");
string[] lines = receivedMessage.Split('\n');
List<RuleResult> results = new List<RuleResult>();
bool inReport = false;
foreach (string line in lines)
{
if (inReport)
{
try
{
results.Add(new RuleResult(line.Trim()));
}
catch
{
//past the end of the report
}
}
if (line.StartsWith("---"))
inReport = true;
}
return results;
}
}
Usage is quite easy:
List<RuleResult> spamCheckResult = SimpleSpamAssassin.GetReport(IP OF SA Server, FULL Email including headers);
It will return the list of spam check rules you hit and the resulting score impact.
I am not exactly sure if that's what you are searching for, but there is a C# wrapper that simplifies the communication with a SpamAssassin server on Code Project:
A C# Wrapper for the SpamAssassin Protocol
Hope that helps!

Categories