Getting attachment size from smtp server - c#

I have problem with getting attachment size from smtp server.
For example user wants to send mail from smtp.gmail.com, I need to know how big attachment can I attach.
So, I want to send EHLO command to smtp server, but I have problem with it.
private long GetSizeAttachament()
{
long Size = 0;
TcpClient smtpTest = new TcpClient();
try
{
smtpTest.Connect(conf.SmtpServer, 25);
if (smtpTest.Connected)
{
NetworkStream ns = smtpTest.GetStream();
StreamReader clientStreamReader = new StreamReader(ns);
StreamWriter clientStreamWriter = new StreamWriter(ns);
clientStreamReader.ReadLine();
clientStreamWriter.WriteLine("EHLO somehost");
while (true)
{
string line = clientStreamReader.ReadLine();
if(line.StartsWith("250"))
{
if (Regex.Match(line, "250-SIZE (.*?)$").Groups.Count > 1)
{
Size = long.Parse(Regex.Match(line, "250-SIZE (.*?)$").Groups[1].Value);
break;
}
}
}
}
}
catch
{
}
smtpTest.Close();
return Size;
}
conf.SmtpServer is smtp server name - for exmaple smtp.gmail.com.
This code is freezing at
string line = clientStreamReader.ReadLine();
Any ideas why?

Related

The way of building a simple http proxy

I'm trying to build a simple http proxy, which does four really basic things:
Accepts connection from web-browser (using TcpClient/TcpListener).
Reads request from its stream.
Reads hostname and initiates connection with host.
Loads content from webpage and forwards it back to the client.
The troubles i met with:
Sometimes page wouldn't load at all.
Sometimes browser gives me an error 'The content has wrong encryption'(in firefox).
Seldom i can see content corruption(plain text instead of HTML).
What i've done:
HttpListener class that contains methods for listening for incoming requests and invoking event OnNewRequestReceived:
public void Listen()
{
Listener.Start();
while (true)
{
var client = Listener.AcceptTcpClient();
Task.Run(() => StartReceivingData(client));
}
}
public void StartReceivingData(TcpClient client)
{
NetworkStream clientStream = client.GetStream();
var buffer = new byte[16000];
while (true)
{
try
{
if (!clientStream.CanRead)
return;
//connection is closed
if (clientStream.Read(buffer).Equals(0))
return;
OnNewRequestReceived?.Invoke(this, new RequestReceivedEventArgs() { User = client, Request = buffer });
} // when clientStream is disposed, exception is thrown.
catch { return; }
}
}
HttpClient class which basically contains a method that subscribes to event described above:
private void Listener_OnNewConnectionReceived(object sender, RequestReceivedEventArgs e)
{
string hostname = HttpQueryParser.GetHostName(e.Request);
NetworkStream proxyClientStream = e.User.GetStream();
try
{
if (firewall.CheckIfBlocked(hostname))
{
//send error page
e.User.GetStream().Write(Encoding.ASCII.GetBytes("<html><body style=\"padding:0; margin:0;\"><img style=\"padding:0; margin:0; width:100%; height:100%;\" src=\"https://www.hostinger.co.id/tutorial/wp-content/uploads/sites/11/2017/08/what-is-403-forbidden-error-and-how-to-fix-it.jpg\"</body></html>"));
return;
}
var targetServer = new TcpClient(hostname, 80);
NetworkStream targetServerStream = targetServer.GetStream();
targetServerStream.Write(e.Request);
var responseBuffer = new byte[32];
for (int offsetCounter = 0; true; ++offsetCounter)
{
var bytesRead = targetServerStream.Read(responseBuffer, 0, responseBuffer.Length);
// Console.WriteLine($"Read {bytesRead} from {hostname}.");
if (bytesRead.Equals(0))
return;
proxyClientStream.Write(responseBuffer, 0, responseBuffer.Length);
if (offsetCounter.Equals(0))
{
var headers = Encoding.UTF8.GetString(responseBuffer).Split("\r\n");
logger.Log(new HttpRequestEntry()
{
ResponseCode = headers[0].Substring(headers[0].IndexOf(" ") + 1),
Hostname = hostname
});
}
}
}
catch { return; }
finally { proxyClientStream.Dispose(); }
}
So, i'm guessing there's a problem with my buffer size, but changing it to higher values actually doesn't change anything .
Ok so i don't know what's the problem with my byte arrays was, but i made it work, using Stream.CopyTo , which i was quite surprized about - it works on two NetworkStreams.
Here's working method if you are curious:
private void Listener_OnNewConnectionReceived(object sender, RequestReceivedEventArgs e)
{
string hostname = HttpQueryParser.GetHostName(e.Request);
NetworkStream proxyClientStream = e.User.GetStream();
try
{
if (firewall.CheckIfBlocked(hostname))
{
//send error page
e.User.GetStream().Write(Encoding.ASCII.GetBytes("<html><body style=\"padding:0; margin:0;\"><img style=\"padding:0; margin:0; width:100%; height:100%;\" src=\"https://www.hostinger.co.id/tutorial/wp-content/uploads/sites/11/2017/08/what-is-403-forbidden-error-and-how-to-fix-it.jpg\"</body></html>"));
return;
}
var targetServer = new TcpClient(hostname, 80);
NetworkStream targetServerStream = targetServer.GetStream();
targetServerStream.Write(e.Request);
var responseBuffer = new byte[32];
//this is to capture status of http request and log it.
targetServerStream.Read(responseBuffer, 0, responseBuffer.Length);
proxyClientStream.Write(responseBuffer, 0, responseBuffer.Length);
var headers = Encoding.UTF8.GetString(responseBuffer).Split("\r\n");
logger.Log(new HttpRequestEntry()
{
ResponseCode = headers[0].Substring(headers[0].IndexOf(" ") + 1),
Hostname = hostname
});
targetServerStream.CopyTo(proxyClientStream);
}
catch { return; }
finally { proxyClientStream.Dispose(); }
}

Very basic web server in C#

I'm wanting to run a little socket server in C# to be accessed by a browser. I have a socket listener up and running on a specific port, and am trying to access it via the browser:
class WebSocketServer
{
private static string output = string.Empty;
public void CreateListener()
{
TcpListener tcpListener = null;
var ipAddress = Dns.GetHostEntry("localhost").AddressList[0];
try
{
tcpListener = new TcpListener(ipAddress, 1313);
tcpListener.Start();
output = "Waiting for a connection";
}
catch (Exception e)
{
throw;
}
var socketHelper = new SocketHelper();
while (true)
{
Thread.Sleep(10);
TcpClient tcpClient = tcpListener.AcceptTcpClient();
byte[] bytes = new byte[256];
var stream = tcpClient.GetStream();
stream.Read(bytes, 0, bytes.Length);
socketHelper.ProcessMessage(tcpClient, stream, bytes);
}
}
}
class SocketHelper
{
private static int counter = 0;
public void ProcessMessage(TcpClient tcpClient, NetworkStream stream, byte[] bytesReceived)
{
// handle message received and send response to client
var msg = Encoding.ASCII.GetString(bytesReceived);
string response = string.Empty;
if (msg.Substring(0, 10) == "GET / HTTP")
{
response = "";// html page
}
byte[] bytesToSend = Encoding.ASCII.GetBytes(response);
stream.Write(bytesToSend, 0, bytesToSend.Length);
}
The browser appears to connect to it, but it never seems to display the html - what's wrong? I'm eventually wanting to be able to serve up JSON data via a REST interface. In addition, is there a much easier solution to (I assume) this common problem.

C# FTP server never receives incoming transfer connection after processing EPRT command

I am building an FTP server that will get images from a camera and store the photos in a local directory. I am having issues grabbing the file from the port given to me. Here is the conversation:
Server(me):"220 Ready!"
Client:"USER Guest"
Server: "331 Username ok, need password"
Client:"PASS "
Server: "230 user logged in"
Client: "PWD"
Server: "257 \"/\""
Client: "EPRT |1|172.22.22.103|58719|
Server:"500 IDK"
Client: "PORT 172,22,22,103,147,237"
Server:"200 Ready for Transport"
Client: "TYPE I"
Server:"200 I understand it is an image file"
Client: "STOR .TEST.RHPRYI"
I found the port by converting the last two numbers to hexadecimal (93,ED) appending them and then converting back to decimal. My final port is 37869.
I then create a new TcpClient to use as a download, but my TcpListener never picks up the camera. Also I am not sure my download method is correct.
I got lots of my code from here:
http://www.codeproject.com/Articles/380769/Creating-an-FTP-Server-in-Csharp-with-IPv-Support
Really my question comes down to: How do I get the file being sent by the client as an FTP server in C#?
Here is my code:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Net;
using System.Threading;
using System.Net.Sockets;
using System.Drawing;
using Microsoft.VisualBasic;
//Creates a TcpServer that is used to transfer images from the Axis Camera to a directory on a computer
//ftpdmin was chosen as the name because it was supposed to be a replica of a program in c just made in csharp
//However, it was really hard to transfer from c because all of the struct names and functions were nonintuitive
//This program is completely made from internet sources, and there are definitely bugs. For instance it does not implement
// many FTP calls.
namespace ftpdmin
{
class Server
{
//TCPListener listens to a given IP and port to wait for a connection with the camera
//Download Listener listens to the port given by the camera in the PORT command, which is the
//port at which the files needed to be downloaded are stored.
//Listen thread implements tcpListener. We do not want to be stuck in an infinite loop, but
//we always want to be listening to the camera. That is why we use another thread.
//Downlaod thread implements the downloadlistener for the same reason as above
//File name is the download files name given by the camera in the STOR command.
//direct is the directory to save the files at on the local computer. It was given in the main
// method of the console program. See Program.cs
private TcpListener tcpListener;
private TcpListener downloadListener;
private Thread listenThread;
private Thread downloadThread;
private string fileName;
private string direct;
//Initialize Ip adress and threads
public Server(string dir)
{
direct = dir;
this.tcpListener = new TcpListener(IPAddress.Parse("172.22.22.104"), 3000);
this.listenThread = new Thread(new ThreadStart(ListenForClients));
this.listenThread.Start();
}
private void ListenForClients()
{
//Start listening
this.tcpListener.Start();
while (true)
{
//blocks until a client has connected to the server
TcpClient client = this.tcpListener.AcceptTcpClient();
//create a thread to handle communication
//with connected client
Thread clientThread = new Thread(new ParameterizedThreadStart(HandleClientComm));
clientThread.Start(client);
}
}
private void ListenForDownloads()
{
this.downloadThread.Start();
while(true)
{
TcpClient downloadClient = this.downloadListener.AcceptTcpClient();
Thread clientDownloadThread = new Thread(new ParameterizedThreadStart(HandleClientDownload));
clientDownloadThread.Start(downloadClient);
}
}
private void HandleClientDownload(object downloadClient)
{
Console.WriteLine("IM HERE");
TcpClient downloaderClient = (TcpClient) downloadClient;
NetworkStream downloadStream = downloaderClient.GetStream();
StreamWriter downloadWriter = new StreamWriter(downloadStream, Encoding.ASCII);
StreamReader downloadReader = new StreamReader(downloadStream);
try
{
//Sets up the path to store the file
string path = Path.Combine(direct, fileName);
FileStream file = File.Create(path);
//Implements the method to download a file
CopyStream(file, downloadStream);
file.Close();
}
catch (Exception e)
{
Console.WriteLine("a socket error has occured:" + e);
}
}
private void HandleClientComm(object client)
{
//A Server is TCP has to respond to a bunch of commands from the client. The first thing it
//does when it connects is send code 220 which says it is good to continue.
TcpClient tcpClient = (TcpClient)client;
NetworkStream clientStream = tcpClient.GetStream();
StreamWriter writer = new StreamWriter(clientStream, Encoding.ASCII);
StreamReader reader=new StreamReader(clientStream);
writer.WriteLine("220 Ready!");
writer.Flush();
string command=reader.ReadLine().ToUpperInvariant();
int downloadPort=0;
string ipOfDownload="";
Console.WriteLine(command);
while(!command.Equals("QUIT"))
{
//USER comes with the username given to the client. Here I do not check if the cameras username
//is the same as the username in the program. I just give the command 331 which means continue.
if(command.Contains("USER"))
{
writer.WriteLine("331 Username ok, need password");
writer.Flush();
}
//PASS is the same as username. I do not check the passwords, I just give 230 which continues the FTP.
else if(command.Contains("PASS"))
{
writer.WriteLine("230 User Logged In");
writer.Flush();
}
//PWD is Print working directory. I send 257 to say I have a PWD, and I send / because that is what is saved
// in the camera. I am not actually going to save files at this directory, I just want to continue.
else if(command.Contains("PWD"))
{
writer.WriteLine("257 \"/\"");
writer.Flush();
}
//This is an important command. The client is sending an IP where it wants to do file transfers. It comes in a
//Weird format so all this function is doing is allowing me store Ip as "172.22.22.103" instead of "PORT 172,22,22,103"
//Also there is a port listed at the end, but it is given in 2 numbers. The conversion to one port number is done by
//changing the two numbers to hexadecimal, appending them, and then transforming them back to decimal.
else if(command.Contains("PORT"))
{
string portPart1 = "";
string portPart2 = "";
Console.WriteLine(command);
int numberOfCommas=0;
int i=0;
bool notPort=true;
bool isNotPortPart2=true;
while(i<command.Length && notPort)
{
if(command[i].Equals(','))
{
if(numberOfCommas==3)
{
notPort=false;
}
else
{
ipOfDownload+=".";
numberOfCommas++;
}
}
else if(Information.IsNumeric(command[i]))
{
ipOfDownload+=command[i];
}
i++;
}
while(i<command.Length && isNotPortPart2)
{
if(Information.IsNumeric(command[i]))
{
portPart1+=command[i];
}
else
{
isNotPortPart2=false;
}
i++;
}
while(i<command.Length)
{
portPart2+=command[i];
i++;
}
Console.WriteLine("IP=" +ipOfDownload);
Console.WriteLine("PortPart1="+portPart1);
Console.WriteLine("PortPart2="+portPart2);
int portPart1int = int.Parse(portPart1);
int portPart2int = int.Parse(portPart2);
string portPart1Hex = portPart1int.ToString("X");
string portPart2Hex = portPart2int.ToString("X");
string downloadPortHex = portPart1Hex + portPart2Hex;
downloadPort = Convert.ToInt32(downloadPortHex, 16);
Console.WriteLine("PortPart1Hex=" + portPart1Hex);
Console.WriteLine("PortPart2Hex=" + portPart2Hex);
Console.WriteLine("FinalPort: " + downloadPort);
this.downloadListener = new TcpListener(IPAddress.Parse(ipOfDownload), downloadPort);
this.downloadThread = new Thread(new ThreadStart(ListenForDownloads));
writer.WriteLine("200 Ready for Transport");
writer.Flush();
}
//The client sends TYPE I for image. usually an ftp would switchto binary mode because that is the only way
//a file can be transferred cleanly.
else if(command.Contains("TYPE"))
{
writer.WriteLine("200 I understand it is an image file");
writer.Flush();
}
//This command gives the name of the file being transferred. I substring to get rid of
//The STOR . that comes before the file name
else if(command.Contains("STOR"))
{
fileName = command.Substring(6);
Console.WriteLine(fileName);
}
//For all other commands sent by the client, I send 500 which means I'm not implementing those commands.
else
{
writer.WriteLine("500 IDK");
writer.Flush();
}
command=reader.ReadLine().ToUpperInvariant();
Console.WriteLine(command);
}
writer.WriteLine("221 BYE");
writer.Flush();
tcpClient.Close();
}
private static long CopyStream(Stream input, Stream output, int bufferSize)
{
byte[] buffer = new byte[bufferSize];
int count = 0;
long total = 0;
while ((count = input.Read(buffer, 0, buffer.Length)) > 0)
{
output.Write(buffer, 0, count);
total += count;
}
return total;
}
private static long CopyStreamAscii(Stream input, Stream output, int bufferSize)
{
char[] buffer = new char[bufferSize];
int count = 0;
long total = 0;
using (StreamReader rdr = new StreamReader(input))
{
using (StreamWriter wtr = new StreamWriter(output, Encoding.ASCII))
{
while ((count = rdr.Read(buffer, 0, buffer.Length)) > 0)
{
wtr.Write(buffer, 0, count);
total += count;
}
}
}
return total;
}
private long CopyStream(Stream input, Stream output)
{
//if (_transferType == "I")
//{
return CopyStream(input, output, 4096);
//}
//else
//{
// return CopyStreamAscii(input, output, 4096);
//}
}
}
By the ERTP (or PORT) command, the client tells your server where the client is listening for incoming transfer connections to be initiated by the server. Instead you start listening too. So both parties are listening and nothing can happen.
So instead of TcpListener, you need to create TcpClient and actively connect.
See RFC 2428.
What you have implemented resembles passive mode (EPSV or PASV command), while the client is using an active mode.
Anyway you should better use an existing implementation of FTP server instead of trying to implement your own.

TCP error on reply

I created a simple network game that uses TCP sockets in order to get the other player's data. I have two different classes, a server and a client. Everything was perfectly fine when I was only sending one message at a time like so:
Client:
public void ClientTester()
{
thread = new Thread(SendPosition);
thread.Start();
}
private void SendPosition()
{
while (true)
{
using (TcpClient client = new TcpClient())
{
client.Connect("127.0.0.1", 82);
using (NetworkStream n = client.GetStream())
{
BinaryWriter w = new BinaryWriter(n);
w.Write("Position:" + GameFiles.Player.Player.position.ToString());
w.Flush();
string msg = new BinaryReader(n).ReadString();
parseString(msg, "Position:", 9);
}
}
Thread.Sleep(60);
}
}
Server:
public void ServerTester()
{
thread = new Thread(TheadedMethod);
thread.Start();
}
private void TheadedMethod()
{
while (true)
{
TcpListener listener = new TcpListener(IPAddress.Any, 82);
listener.Start();
using (TcpClient c = listener.AcceptTcpClient())
using (NetworkStream n = c.GetStream())
{
parseString(msg, "Position:", 9);
BinaryWriter w = new BinaryWriter(n);
w.Write("Position:" + GameFiles.Player.Player.position.ToString());
w.Flush();
}
listener.Stop();
}
}
Here is the new code:
Client:
public void ClientTester()
{
thread = new Thread(SendPosition);
thread.Start();
SendMousePosition();
}
private void SendPosition()
{
while (true)
{
using (TcpClient client = new TcpClient())
{
client.Connect("127.0.0.1", 82);
using (NetworkStream n = client.GetStream())
{
BinaryWriter w = new BinaryWriter(n);
w.Write("Position:" + GameFiles.Player.Player.position.ToString());
w.Flush();
string msg = new BinaryReader(n).ReadString();
parseString(msg, "Position:", 9);
}
}
Thread.Sleep(60);
}
}
private void SendMousePosition()
{
using (TcpClient client = new TcpClient())
{
client.Connect("127.0.0.1", 82);
using (NetworkStream n = client.GetStream())
{
BinaryWriter w = new BinaryWriter(n);
w.Write("MousePosition:" + cursor.mousePosition());
w.Flush();
string msg = new BinaryReader(n).ReadString();
parseString(msg, "MousePosition:", 14);
}
}
}
Server:
public void ServerTester()
{
thread = new Thread(TheadedMethod);
thread.Start();
}
private void TheadedMethod()
{
while (true)
{
TcpListener listener = new TcpListener(IPAddress.Any, 82);
listener.Start();
using (TcpClient c = listener.AcceptTcpClient())
using (NetworkStream n = c.GetStream())
{
string msg = new BinaryReader(n).ReadString();
if (msg == "Position:")
{
parseString(msg, "Position:", 9);
BinaryWriter w = new BinaryWriter(n);
w.Write("Position:" + GameFiles.Player.Player.position.ToString());
w.Flush();
}
if (msg == "MousePosition:")
{
parseString(msg, "MousePosition:", 14);
BinaryWriter w = new BinaryWriter(n);
w.Write("MousePosition:" + cursor.mousePosition());
w.Flush();
}
}
listener.Stop();
}
}
When I try to send two messages in I receive an error:
Unable to read beyond the end of the stream.
on this line from the client's method SendPosition():
string msg = new BinaryReader(n).ReadString();
Why doesn't this work even though I have created a new instance of BinaryReader? Shouldn't the server automatically respond to each message sent to it?
You are doing two things wrong: The fist is that you create and re-create the connection all the time. Instead create the listener once, enter the loop and read messages. Setting up a new connection in TCP ads a lot of overhead, especially if you're just sending small messages. Same thing in the client, connect once, and then send when needed.
The second problem is that TCP is a streaming protocol, and that there is no message boundaries. That means that when you read from a TCP connection you can't know beforehand how much data you will read, you need to provide a way to separate messages yourself: You can add message boundaries, you can prepend each message with a header containing the message size, of you have have all messages being the same fixed size. Either way, you might have to read multiple times to get a complete message, or one read could give you more than one message.
Regarding the second problem, you can't of course attempt to read more than have been received, which is probably what the error message is telling you.

How to read the body of the message in the mail retrieve from gmail by using pop3 in c #?

This is code:
protected void Button9_Click(object sender, EventArgs e)
{
try
{
// create an instance of TcpClient
TcpClient tcpclient = new TcpClient();
// HOST NAME POP SERVER and gmail uses port number 995 for POP
tcpclient.Connect("pop.gmail.com", 995);
// This is Secure Stream // opened the connection between client and POP Server
System.Net.Security.SslStream sslstream = new SslStream(tcpclient.GetStream());
// authenticate as client
sslstream.AuthenticateAsClient("pop.gmail.com");
//bool flag = sslstream.IsAuthenticated; // check flag
// Asssigned the writer to stream
System.IO.StreamWriter sw = new StreamWriter(sslstream);
// Assigned reader to stream
System.IO.StreamReader reader = new StreamReader(sslstream);
// refer POP rfc command, there very few around 6-9 command
sw.WriteLine("USER your_gmail_user_name#gmail.com");
// sent to server
sw.Flush(); sw.WriteLine("PASS your_gmail_password");
sw.Flush();
// RETR 1 will retrive your first email. it will read content of your first email
sw.WriteLine("RETR 1");
sw.Flush();
// close the connection
sw.WriteLine("Quit ");
sw.Flush(); string str = string.Empty;
string strTemp = string.Empty;
while ((strTemp = reader.ReadLine()) != null)
{
// find the . character in line
if (strTemp == ".")
{
break;
}
if (strTemp.IndexOf("-ERR") != -1)
{
break;
}
str += strTemp;
}
textbox1.text = str;
textbox1.text += "<BR>" + "Congratulation.. ....!!! You read your first gmail email ";
}
catch (Exception ex)
{
Response.Write(ex.Message);
}
}
The message body is a bunch of what appears to be random characters. I know it's not just a bunch of random characters but some code that needs to be parsed and converted. How can I read content in "message body"?
I know i'm not directly replying to your answer but reading email is a really complex task and I think you can achieve this better and faster with an external library instead of implementing it by yourself.
There are many good implementation, i usually use OpenPop.NET which works fine and is opensource.
https://sourceforge.net/projects/hpop/
You can find many example on internet because it is really popular.
http://hpop.sourceforge.net/examples.php
you can get all mail easly:
using(Pop3Client client = new Pop3Client())
{
// Connect to the server
client.Connect("pop.gmail.com", 995, true);
// Authenticate ourselves towards the server
client.Authenticate("username#gmail.com", "password", AuthenticationMethod.UsernameAndPassword);
// Get the number of messages in the inbox
int messageCount = client.GetMessageCount();
// We want to download all messages
List<Message> allMessages = new List<Message>(messageCount);
// Messages are numbered in the interval: [1, messageCount]
// Ergo: message numbers are 1-based.
// Most servers give the latest message the highest number
for (int i = messageCount; i > 0; i--)
{
allMessages.Add(client.GetMessage(i));
}
}
you can get the full raw message
var mailbody = ASCIIEncoding.ASCII.GetString(message.RawMessage);
or if it is an utf8 encoded email:
var encodedStringAsBytes = System.Convert.FromBase64String(message.RawMessage);
var rawMessage =System.Text.Encoding.UTF8.GetString(encodedStringAsBytes);
Instead if you want only the mail body you have to dig into the mail structure:
http://hpop.sourceforge.net/documentation/OpenPop~OpenPop.Mime.MessagePart.html
I know it is not an easy task but as I stated above emails are complex objects.

Categories

Resources