Skip to content
Snippets Groups Projects
Program.cs 11 KiB
Newer Older
joalhelk's avatar
joalhelk committed
using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
joalhelk's avatar
joalhelk committed
using System.Threading.Tasks;
joalhelk's avatar
joalhelk committed
using System.IO;
joalhelk's avatar
joalhelk committed

namespace STMPServer
{
    class Program
    {
        static void Main(string[] args)
        {
joalhelk's avatar
joalhelk committed
            //int[] ports = new int[] { 25000, 110 };
joalhelk's avatar
joalhelk committed
            int[] ports = new int[] { 25000 }; // testing purposes
            string[] inbox = new string[1];

joalhelk's avatar
joalhelk committed
            for (int i = 0; i < ports.Length; i++)
joalhelk's avatar
joalhelk committed
            {
joalhelk's avatar
joalhelk committed
                Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                IPEndPoint iep = new IPEndPoint(IPAddress.Loopback, ports[i]);
                socket.Bind(iep);

                // Kuinka monta asiakasta saa olla 
                socket.Listen(1);
                bool while_on = true;
joalhelk's avatar
joalhelk committed
                string mail;
joalhelk's avatar
joalhelk committed
                Console.WriteLine("SMTP Palvelin käynnissä portissa: " + ports[i]);

                while (while_on)
                {
                    // Tähän joku timeout ??
joalhelk's avatar
joalhelk committed
                    mail = HandleSMTPClient(socket);
                    if(mail != "") { inbox[0] = mail; }
joalhelk's avatar
joalhelk committed
                    //HandlePOP3Client(socket);
joalhelk's avatar
joalhelk committed
                }
                Console.ReadKey();
                socket.Close();
            }
        }

        enum POPTila : UInt16
        {
joalhelk's avatar
joalhelk committed
            Aloitus,
            Authorization,
joalhelk's avatar
joalhelk committed
            Transaction,
            Update
        }

        enum AuthState : UInt16
        {
            UserState,
            PassState
joalhelk's avatar
joalhelk committed
        }


        static void HandlePOP3Client(Socket socket)
        {
            Socket asiakas = socket.Accept();
            string ip = ((IPEndPoint)(asiakas.RemoteEndPoint)).Address.ToString();
            string asiakas_port = ((IPEndPoint)(asiakas.RemoteEndPoint)).Port.ToString();
            Console.WriteLine("Uusi asiakas: {0} portista: {1}", ip, asiakas_port);

            POPTila tila = POPTila.Aloitus;
joalhelk's avatar
joalhelk committed
            AuthState authState = AuthState.UserState;

joalhelk's avatar
joalhelk committed
            bool keskustelu = true;
joalhelk's avatar
joalhelk committed
            string[] viestit = new string[] { "viesti 1", "viesti2", "viestriiii3" };
joalhelk's avatar
joalhelk committed

            // 10min timeout jos ei vastaa?
            while(keskustelu)
            {
joalhelk's avatar
joalhelk committed
                byte[] buffer = new byte[2048];
joalhelk's avatar
joalhelk committed
                string asiakas_vastaus = "";
                int state;
joalhelk's avatar
joalhelk committed
                switch (tila)
joalhelk's avatar
joalhelk committed
                {
joalhelk's avatar
joalhelk committed
                    case POPTila.Aloitus:
                        VastaaAsiakas("+OK TIES323 POP3 server ready", asiakas);
                        tila = POPTila.Authorization;
                        break;
                    case POPTila.Authorization:
joalhelk's avatar
joalhelk committed
                        asiakas.Receive(buffer);
                        asiakas_vastaus = TrimVastaus(Encoding.UTF8.GetString(buffer), asiakas);

                        state = CheckAuthorization(asiakas_vastaus, authState, asiakas);
                        if (state == 1) { authState = AuthState.PassState; }
                        if (state == 2) { authState = AuthState.UserState; tila = POPTila.Transaction; }
                        if (state == 3) { keskustelu = false; }
joalhelk's avatar
joalhelk committed
                        break;
                    case POPTila.Transaction:
joalhelk's avatar
joalhelk committed
                        asiakas.Receive(buffer);
                        asiakas_vastaus = TrimVastaus(Encoding.UTF8.GetString(buffer), asiakas);

                        state = HandleTransaction(asiakas_vastaus, asiakas, viestit);
                        if(state == 1) { tila = POPTila.Update; }
                        break;
                    case POPTila.Update:
                        HandleQuit(asiakas);
                        keskustelu = false;
joalhelk's avatar
joalhelk committed
                        break;
                    default:
joalhelk's avatar
joalhelk committed
                        VastaaAsiakas("Some error happened... shutting down", asiakas);
                        keskustelu = false;
joalhelk's avatar
joalhelk committed
                        break;
                }
            }
        }
joalhelk's avatar
joalhelk committed

joalhelk's avatar
joalhelk committed
        static void HandleQuit(Socket socket)
        {
            string vastaus = "+OK TIES323 POP3 server signing off";
            VastaaAsiakas(vastaus, socket);
        }

        static string TrimVastaus(string vastaus, Socket socket)
        {
            string ip = ((IPEndPoint)(socket.RemoteEndPoint)).Address.ToString();
            string asiakas_port = ((IPEndPoint)(socket.RemoteEndPoint)).Port.ToString();

            string[] user = vastaus.Split(
                new[] { "\r\n", "\r", "\n" },
                    StringSplitOptions.None
                );
            Console.WriteLine("[{0}:{1}]: {2}", ip, asiakas_port, user[0]);
            return user[0];
        }

        static int CheckAuthorization(string msg, AuthState state, Socket socket)
        {
            string[] array = msg.Split(' ');
            int change_state = 0;
            string new_msg = "";
            if (state == AuthState.UserState && array[0] == "USER")
            {
                if (array[1] == "joalhelk") 
                {
                    new_msg = "+OK " + array[1] + " is a real hoopy frood";
                    change_state = 1;
                } else
                {
                    new_msg = "-ERR sorry, no mailbox for " + array[1] + " here";
                }
            } else if (state == AuthState.PassState && array[0] == "PASS")
            {
                if (array[1] == "secretpass")
                {
                    new_msg = "+OK maildrop locked and ready";
                    change_state = 2;
                } else
                {
                    new_msg = "-ERR invalid password";
                }
            } else if(array[0] == "QUIT")
            {
                new_msg = "+OK TIES323 POP3 server signing off";
                change_state = 3;
            }
            VastaaAsiakas(new_msg, socket);
            return change_state;
        }

        static int HandleTransaction(string msg, Socket socket, string[] viestit)
joalhelk's avatar
joalhelk committed
        {
joalhelk's avatar
joalhelk committed
            string[] array = msg.Split(' ');
            int tila = 0;
            if (array[0] == "LIST")
            {
                int koko = 0;
                if(array.Length > 1)
                {
                    int num = Int32.Parse(array[1]);
                    if(num <= viestit.Length)
                    {
                        string vastaus = string.Format("+OK {0} {1}", num, Encoding.UTF8.GetByteCount(viestit[num - 1]));
                        VastaaAsiakas(vastaus, socket);
                    } else
                    {
                        string vastaus = string.Format("-ERR no such message, only {0} messages in maildrop", viestit.Length);
                        VastaaAsiakas(vastaus, socket);
                    }
                } else
                {
                    for (int i = 0; i < viestit.Length; i++)
                    {
                        koko += Encoding.UTF8.GetByteCount(viestit[i]);
                    }
                    string vastaus = string.Format("+OK {0} messages ({1} octets)", viestit.Length, koko);
                    VastaaAsiakas(vastaus, socket);
                    for(int i = 0; i < viestit.Length; i++)
                    {
                        vastaus = "" + (i+1) + " " + Encoding.UTF8.GetByteCount(viestit[i]);
                        VastaaAsiakas(vastaus, socket);
                    }
                    VastaaAsiakas(".", socket);
                }
            } else if (array[0] == "QUIT")
            {
                tila = 1;
            }
joalhelk's avatar
joalhelk committed

joalhelk's avatar
joalhelk committed
            return tila;
joalhelk's avatar
joalhelk committed
        }

joalhelk's avatar
joalhelk committed
        static string HandleSMTPClient(Socket socket)
joalhelk's avatar
joalhelk committed
        {
            Socket asiakas = socket.Accept();
            string ip = ((IPEndPoint)(asiakas.RemoteEndPoint)).Address.ToString();
            string asiakas_port = ((IPEndPoint)(asiakas.RemoteEndPoint)).Port.ToString();
            Console.WriteLine("Uusi asiakas: {0} portista: {1}", ip, asiakas_port);
            // Aloitetaan keskustelu
            asiakas.Send(Encoding.UTF8.GetBytes("220 TIES323 Postipalvelin\r\n"));
            bool keskustelu = true;
            bool data_vipu = false;
joalhelk's avatar
joalhelk committed
            string mail = "";

joalhelk's avatar
joalhelk committed
            while (keskustelu)
            {
                byte[] buffer = new byte[2048];
                asiakas.Receive(buffer);
                string asiakas_vastaus = Encoding.UTF8.GetString(buffer);
                Console.WriteLine("[{0}:{1}]: {2}", ip, asiakas_port, asiakas_vastaus);
                string[] lines = asiakas_vastaus.Split(
                    new[] { "\r\n", "\r", "\n" },
                        StringSplitOptions.None
                    );

                int tila = 0;
                if (data_vipu)
                {
joalhelk's avatar
joalhelk committed
                    mail = ValidoiData(lines, asiakas);
                    tila = 0;
joalhelk's avatar
joalhelk committed
                }
                else
                {
                    tila = ValidoiVastaus(lines[0], asiakas, data_vipu);
                }
                switch (tila)
                {
                    case 1:
                        data_vipu = true;
                        break;
                    case 2:
                        asiakas.Close();
                        keskustelu = false;
                        break;
                    default:
                        data_vipu = false;
                        break;
joalhelk's avatar
joalhelk committed
                }
            }
joalhelk's avatar
joalhelk committed
            return mail;
joalhelk's avatar
joalhelk committed
        }

        static int ValidoiVastaus(string vastaus, Socket socket, bool data_vipu)
        {
            int tila = 0;
            string msg = "500 Syntax error!";
            
            if(vastaus.Split(' ')[0] == "HELO")
            {
                string ip = ((IPEndPoint)(socket.RemoteEndPoint)).Address.ToString();
                msg = "250 TIES323 Postipalvelin HELO " + ip;
            } 
            else if (vastaus.Split(':')[0] == "MAIL FROM")
            {
                msg = "250 2.1.0 Sender... " + vastaus.Split(':')[1].Trim() + " you are ok.";
            } 
            else if (vastaus.Split(':')[0] == "RCPT TO")
            {
                msg = "250 2.1.5 Recipient... " + vastaus.Split(':')[1].Trim() + " is ok!";
            } 
            else if (vastaus == "DATA")
            {
                msg = "354 Enter mail, end with \".\" n a line by itself";
                tila = 1;
            }
            else if (vastaus == "QUIT")
            {
                msg = "221 2.0.0 TIES323 postipalvelin sulkee yhteyden...";
                tila = 2;
            } 

            VastaaAsiakas(msg, socket);
            return tila;
        }

joalhelk's avatar
joalhelk committed
        static string ValidoiData(string[] arr, Socket socket)
joalhelk's avatar
joalhelk committed
        {
            string[] data;
joalhelk's avatar
joalhelk committed
            string mail = "";

joalhelk's avatar
joalhelk committed
            for(int i = 0; i < arr.Length - 1; i++)
            {
                if(arr[i] == ".")
                {
                    string msg = "250 2.0.0 Message displayed on Server Screen.";
                    VastaaAsiakas(msg, socket);
joalhelk's avatar
joalhelk committed
                    return mail;
                }
                else
                {
                    mail = mail + arr[i] + " ";
joalhelk's avatar
joalhelk committed
                }
            }
joalhelk's avatar
joalhelk committed
            return mail;
joalhelk's avatar
joalhelk committed
        }

        static void VastaaAsiakas(string msg, Socket asiakas)
        {
            byte[] respond = Encoding.UTF8.GetBytes(msg + "\r\n");
            asiakas.Send(respond);
        }
    }
}