singrdk/base/Windows/SmtpClient/SmtpClient.cs

298 lines
10 KiB
C#

using System;
using System.IO;
using System.Net;
using System.Net.Sockets;
using System.Text;
using Microsoft.Singularity.Smtp;
namespace Microsoft.Singularity.Smtp.Clients
{
public class SmtpClient
{
public const int _port = 25;
public static bool verbose = false;
//////////////////////////////////////////////////////////////////////////////
//
private static void Usage()
{
Console.WriteLine("Usage:");
Console.WriteLine(" cli [operation] [options]");
Console.WriteLine("Options:");
Console.WriteLine(" /s:server Send to server.");
Console.WriteLine(" /? Print this help information.");
}
public static int Main(string[] args)
{
bool needHelp = false;
String client = Dns.GetHostName();
String server = "127.0.0.1";
String[] files = null;
if (args.Length == 0) {
needHelp = true;
}
Console.WriteLine("Self: {0}", client);
for (int a = 0; a < args.Length && !needHelp; a++) {
String arg = args[a];
if (arg[0] == '/') {
int colon = arg.IndexOf(':');
String option;
String values;
if (colon > 1) {
option = arg.Substring(1, colon - 1).ToLower();
values = arg.Substring(colon + 1);
}
else {
option = arg.Substring(1).ToLower();
values = null;
}
switch (option[0]) {
// Commands:
case '?': // Help
needHelp = true;
break;
case 's': // Server
case 'S':
server = values;
break;
case 'v': // Verbose
verbose = true;
break;
default:
Console.WriteLine("Unknown option: {0}", arg);
needHelp = true;
break;
}
}
else {
String file = Path.GetFileName(arg);
String dir = Path.GetDirectoryName(arg);
String path = (dir == String.Empty) ?
Directory.GetCurrentDirectory() :
Path.GetFullPath(dir);
files = Directory.GetFiles(path, file);
}
}
if (files == null) {
needHelp = true;
}
if (needHelp) {
Usage();
return 1;
}
// Send the file.
String line;
Socket socket = new Socket(AddressFamily.InterNetwork,
SocketType.Stream,
ProtocolType.Tcp);
try {
IPAddress addr = IPAddress.Parse(server);
socket.Connect(new IPEndPoint(addr, _port));
} catch (SocketException e) {
Console.WriteLine("Socket connect failure: {0}", e.Message);
return 2;
}
Session session = new Session(socket);
session.Verbose = verbose;
try {
// Establish SMPT connection.
line = session.ReadLine7();
if (session.Result != 220) {
Console.WriteLine(":: Aborting due to {0}", session.Result);
return session.Quit();
}
session.WriteLine7("EHLO ", client);
for (;;) {
line = session.ReadLine7();
if (session.Result != 250) {
Console.WriteLine(":: Aborting due to {0}", session.Result);
return session.Quit();
}
if (line[3] != '-') {
break;
}
}
// Send files.
foreach (string file in files) {
Console.WriteLine(":: {0}", file);
String[] lines = File.ReadAllLines(file);
#if false
// Sanitize the data.
for (int i = 0; i < lines.Length; i++) {
String data = lines[i];
if (data.Length >= 2 &&
data[data.Length - 2] == '\r' &&
data[data.Length - 1] == '\n') {
lines[i] = data.Substring(0, data.Length - 2);
}
else if (data.Length >= 1 &&
data[data.Length - 1] == '\n') {
lines[i] = data.Substring(0, data.Length - 1);
}
else if (data.Length >= 1 &&
data[data.Length - 1] == '\r') {
lines[i] = data.Substring(0, data.Length - 1);
}
}
#endif
session.WriteLine7("NOOP ", file);
line = session.ReadLine7();
if (session.Result != 250) {
Console.WriteLine(":: Aborting due to {0}", session.Result);
return session.Quit();
}
string from = FindFrom(lines).ToLower();
session.WriteLine7("MAIL FROM: <", from, ">");
line = session.ReadLine7();
if (session.Result != 250) {
Console.WriteLine(":: Aborting due to {0}", session.Result);
return session.Quit();
}
string to = FindTo("To: ", lines);
string cc = FindTo("Cc: ", lines);
string bcc = FindTo("Bcc: ", lines);
if (to == null) {
to = cc;
cc = null;
}
if (to == null) {
to = bcc;
bcc = null;
}
if (cc != null) {
to = to + "," + cc;
}
if (bcc != null) {
to = to + "," + bcc;
}
if (to == null || to.Length == 0) {
Console.WriteLine(":: Couldn't find receipients.");
return session.Quit();
}
string[] rcpts = to.Split(new Char[]{','});
for (int i = 0; i < rcpts.Length; i++) {
rcpts[i] = rcpts[i].Trim().ToLower();
if (rcpts[i].Length == 0) {
rcpts[i] = null;
}
}
for (int i = 0; i < rcpts.Length; i++) {
for (int j = i + 1; j < rcpts.Length; j++) {
if (rcpts[i] == rcpts[j]) {
rcpts[j] = null;
}
}
}
foreach (string rcpt in rcpts) {
if (rcpt != null) {
session.WriteLine7("RCPT TO: <", rcpt, ">");
line = session.ReadLine7();
if (session.Result != 250) {
Console.WriteLine(":: Aborting due to {0}", session.Result);
return session.Quit();
}
}
}
session.WriteLine7("DATA");
line = session.ReadLine7();
if (session.Result != 354) {
Console.WriteLine(":: Aborting due to {0}", session.Result);
return session.Quit();
}
foreach (string data in lines) {
if (data.Length > 0 && data[0] == '.') {
session.WritePrefix((byte)'.');
}
session.WriteLine7(data);
}
session.WriteLine7(".");
line = session.ReadLine7();
if (session.Result != 250) {
Console.WriteLine(":: Aborting due to {0}", session.Result);
return session.Quit();
}
}
session.Quit();
}
catch (SocketException e) {
Console.WriteLine("Caught socket exception: {0}", e.Message);
}
return 0;
}
//////////////////////////////////////////////////////////////////////////////
public static String FindFrom(String[] lines)
{
foreach (string line in lines) {
if (line.Length == 0) {
return null; // Header ended.
}
if (line.StartsWith("From: ")) {
return line.Substring(6);
}
}
return null;
}
public static string FindTo(String prefix, String[] lines)
{
for (int i = 0; i < lines.Length; i++) {
if (lines[i].Length == 0) {
return null; // Header ended.
}
if (lines[i].StartsWith(prefix)) {
string to = lines[i++].Substring(prefix.Length);
while (lines[i].Length > 0 && (lines[i][0] == ' ' || lines[i][0] == '\t')) {
to = to + lines[i++];
}
return to;
}
}
return null;
}
}
}