Protokol POP3
Transkrypt
Protokol POP3
Odbieranie wiadomości elektronicznych. Aplikacja KlientPop dr Zbigniew Lipiński Instytut Matematyki i Informatyki UO ul. Oleska 48, 50-204 Opole [email protected] Protokół POP3 POP3, (ang.) Post Office Protocol version 3. RFC 1939,J. Myers, M. Rose, Post Office Protocol - Version 3, May 1996, Obsoletes RFC 1725, Updated-By RFC 1957, RFC 2449 RFC 1957, R. Nelson, Some Observations on Implementations of the Post Office Protocol (POP3), June 1996, Updates RFC 1939, Status: INFO. RFC 2449, R. Gellens, C. Newman, L. Lundblade, POP3 Extension Mechanism, November 1998, Updates RFC 1939, Updated-By RFC 5034. Protokół służący do odbierania wiadomości email ze skrzynek pocztowych (ang. mailboxes) znajdujących się na serwerach POP3. W warstwie transportowej serwery POP3 wykorzystuje protokół TCP, port 110. Komunikaty POP mają strukturę wiadomości tekstowej w formacie 'Internet text messages‘, RFC 5322. RFC 5322, P. Resnick, Internet Message Format, 2008, Obsoletes RFC 2822, Status: DRAFT STANDARD 2 Obiór wiadomości z serwera POP3 Klient POP3 może połączyć sie z serwerem i pobrać wszystkie wiadomości z katalogu Inbox serwera. Sesja między klientem a serwerem POP podzielona jest na stany: • stan uwierzytelnienia i autoryzacji (AUTHORIZATION state), • stan transakcji (TRANSACTION state), • stan uaktualniania (UPDATE state). 3 Obiór wiadomości z serwera POP3 Po nawiązaniu połączenia TCP klienta z serwerem POP3, następuje rozpoczęcie sesji POP. Proces odbioru poczty z serwera POP: • nawiązanie połączenia klienta z serwerem (budowa połączenia TCP), • serwer wysyła sygnał gotowości (wiadomość 'greeting‘), • identyfikacja klienta na serwerze (uwierzytelnienie), przyznanie praw dostępu (autoryzacja), • pytanie o liczbę wiadomości do odbioru (stan transakcji), • wyznaczenie wielkości każdej wiadomości do odbioru (stan transakcji), • odbiór wiadomości (stan transakcji), • uaktualnianie stanu konta pocztowego po otrzymaniu komendy QUIT od klienta (stan aktualniania), • zamknięcie sesji przez serwer wiadomością 'goodbye', (stan uaktualniania). 4 Przykład sesji POP3 S: <wait for connection on TCP port 110> ... C: <open connection> S: +OK POP3 server ready <[email protected]> C: APOP mrose c4c9334bac560ecc979e58001b3e22fb S: +OK mrose's maildrop has 2 messages (320 octets) C: STAT S: +OK 2 320 C: LIST S: +OK 2 messages (320 octets) S: 1 120 S: 2 200 S: . C: RETR 1 S: +OK 120 octets S: <the POP3 server sends message 1> S: . C: DELE 1 S: +OK message 1 deleted C: RETR 2 S: +OK 200 octets S: <the POP3 server sends message 2> S: . C: DELE 2 S: +OK message 2 deleted C: QUIT S: +OK deley POP3 server signing off (maildrop empty) C: <close connection> S: <wait for next connection> 5 Komendy klienta POP3 – stan uwierzytelnienia Komendy klienta POP3 w stanie uwierzytelnienia: USER name - nazwa użytkownika. PASS password - hasło użytkownika (string). QUIT - koniec sesji, brak argumentów. Stan uwierzytelnienia sesji POP zaczyna się gdy serwer potwierdzi gotowość odbioru wiadomości: S: +OK POP3 server ready W stanie uwierzytelnienia sesji klient wysyła do serwera nazwę skrzynki i hasło. Przykład: Użycie komendy USER. C: USER frated S: -ERR sorry, no mailbox for frated here Przykład: Użycie komendy USER i PASS. C: USER mrose S: +OK mrose is a real hoopy frood C: PASS secret S: +OK mrose's maildrop has 2 messages (320 octets) Przykład: Użycie komendy PASS. C: PASS secret S: -ERR maildrop already locked 6 Komendy klienta POP3 – stan uwierzytelnienia Przed przejściem do stanu transakcji serwer POP blokuje skrzynkę do wyłącznego użycia przez klienta POP w otwartej sesji. Do momentu przejścia do stanu uaktualniania nie jest możliwa modyfikacja lub usunięcie wiadomości ze skrzynki. Po potwierdzeniu przez serwer blokady skrzynki komenda +OK, sesja przechodzi w stan transakcji. 7 Komendy klienta POP3 – stan transakcji Komendy klienta POP w stanie transakcji: STAT Pytanie o widomości, brak argumentów. Składania: STAT Odpowiedź: +OK liczbaMaili wielkoscMaili LIST Pytanie o wszystkie wiadomości lub wiadomości o określonym numerze maila (message-id). Składania: LIST [message-id] Odpowiedź: +OK liczbaMaili wielkoscMaili +OK kolejnyNumerMaila wielkoscMailia RETR Polecenie wysłania wiadomości o danym identyfikatorze (id). Składania: RETR message-id Odpowiedź: +OK wielkoscMailia, przesyłane są kolejno pakiety z danymi. DELE Polecenie usunięcia wiadomości, serwer zaznacza wiadomość jako: 'do usunięcia'. Usunięcie następuje w stanie uaktualniania. Składania: DELE message-id Odpowiedź: +OK message deleted lub -ERR no such message NOOP Oznacza brak działania serwera, brak argumentów. Po tej komendzie serwer POP3 zwraca komunikat: +OK. Składania: NOOP Odpowiedź: +OK RSET Brak argumentów, serwer usuwa status wiadomości 'do usunięcia', ostatnia wiadomość uzyskuje numer 0. Składania: RSET Odpowiedz: +OK liczbaWiadomosci. LAST Brak argumentów, serwer zwraca numer ostatniej wiadomości. Składania: LAST Odpowiedz: +OK nn 8 Komendy klienta POP3 – stan uaktualniania Komendy klienta POP w stanie uaktualniania: QUIT serwer usuwa odebrane wiadomości przez klienta. Składania: QUIT Odpowiedz: +OK 9 Opcjonalne komendy klienta POP3 Komendy opcjonalne w stanie uwierzytelnienia: APOP uwierzytelnienie bez wysyłania hasła, serwer przy powitaniu wysyła znacznik czasu (timestamp), np. <process-ID.clock@nazwa_serweraPOP>, klient POP wysyła user_id i liczbę 'digest‘ wyliczoną ze znacznika czasu algorytmem MD5). Składania: C: APOP nazwaSkrzynki digest Odpowiedź: S: +OK maildrop locked and ready lub -ERR permission denied Komendy opcjonalne w stanie transakcji: TOP serwer zwraca nagłówek wiadomości i liczbę linii wiadomości. Składania: TOP message-id n Odpowiedź: +OK, kolejne wiadomości zawierają: nagłówek, pusta linia, n linii wiadomości, lub -ERR UIDL Komenda 'unique-id listing'. Serwer zwraca identyfikatory wszystkich wiadomości lub identyfikator wiadomości o danym numerze msg. Identyfikator wiadomości to max. 70 bajtowy string (z zakresu 0x21 - 0x7E) nadawany przez serwer POP3 każdej wiadomości. Po komendzie UIDL wiadomości zaznaczone jako usunięte nie są zawracane przez serwer. Składania: UIDL [msg] Odpowiedź: +OK [numerWiadmosci] identyfikatory 10 Opcjonalne komendy klienta POP3 Przykład: Użycie komendy APOP. S: +OK POP3 server ready <[email protected]> C: APOP mrose c4c9334bac560ecc979e58001b3e22fb S: +OK maildrop has 1 message (369 octets) Przykład: Użycie komendy UIDL. C: UIDL S: +OK S: 1 whqtswO00WBw418f9t5JxYwZ S: 2 QhdPYR:00WBw1Ph7x7 S: . ... C: UIDL 2 S: +OK 2 QhdPYR:00WBw1Ph7x7 ... C: UIDL 3 S: -ERR no such message, only 2 messages in maildrop 11 Rozszerzania Protokołu POP3. RFC 2449. RFC 2449 definiują rozszerzania protokołu POP3 o mechanizmy zarządzania serwerem POP. Wprowadzono nowe polecenia: SASL, RESP-CODES, LOGIN-DELAY, PIPELINING, EXPIRE, IMPLEMENTATION. SASL - Simple Authentication and Security Layer. Lista 'możliwości' serwera - capabilities list zwracana jest po komendzie CAPA. Komenda CAPA może być stosowana w stanie uwierzytelnienia i w stanie transakcji. Składania: CAPA Początkowa lista parametrów (Initial Set of Capabilities): TOP polecenie TOP jest obsługiwane przez serwer. USER polecenia USER, PASS są obsługiwane przez serwer. SASL mechanizm identyfikacji SASL jest obsługiwany. RESP-CODES informacja, że tekst odpowiedzi w nawiasach ‘ [ ..] ‘ jest rozszerzeniem kodu odpowiedzi., LOGIN-DELAY określa min. czas (w sekundach) między logowaniami. PIPELINING serwer akceptuje przesłanie listy komend, zamiast trybu: polecenie-odpowiedź. EXPIRE serwer informuje klienta jak długo wiadomość będzie przechowywana na serwerze. UIDL polecenie UIDL jest obsługiwane przez serwer. IMPLEMENTATION serwer zwraca informacje o implementacji. 12 Przykład listy parametrów Przykład listy parametrów zwracanych przez serwer POP: C: CAPA S: +OK Capability list follows S: TOP S: USER S: SASL CRAM-MD5 KERBEROS_V4 S: RESP-CODES S: LOGIN-DELAY 900 S: PIPELINING S: EXPIRE 60 S: UIDL S: IMPLEMENTATION Shlemazle-Plotz-v302 S: . 13 Klient POP Namespace: Microsoft.Crm.Tools.Email.Providers Assembly: Microsoft.Crm.Tools.EmailProviders.dll E-mail Provider Object Model E-mail Provider Base Classes // Provides an overview of the e-mail provider base classes. Service Logging Classes // Provides an overview of the classes used to log errors. Configuration Classes // Provides an overview of the classes used to read information from E-mail Router configuration file. 14 E-mail Provider Base Classes 15 Klient POP Microsoft.Crm.Tools.Email.Providers Classes (wybór) EmailMessage //Represents an e-mail message. EmailProvider //Provides a base class for all providers. ExchangeEmailMessage //Represents an Exchange e-mail message. MimeEmailMessage //Represents an e-mail message in MIME format. Pop3Client //Provides the protocol for communications with a POP3 e-mail server. Pop3EmailMessage //Represents a POP3 e-mail message. 16 Pop3Client class Constructors Pop3Client // Initializes a new instance of the Pop3Client class. public public public public Pop3Client(IPAddress pop3Address, Pop3Client(string pop3Server, int Pop3Client(IPAddress pop3Address, Pop3Client(string pop3Server, int Static method CertificateValidationCallback int connectionTimeout); connectionTimeout); int pop3Port, int connectionTimeout); pop3Port, int connectionTimeout); // Validates a server certificate. public static bool CertificateValidationCallback( Object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors sslPolicyErrors ); 17 Pop3Client class Instance methods AuthenticateClearText AuthenticateNtlm Connect //Authenticates to the POP3 server using clear text. //Authenticates to the POP3 server using NTLM. //Connects to the POP3 server. public void Connect( DeleteMessage bool useSsl); // Deletes a message. public void DeleteMessage( int messagePos); Disconnect Dispose DownloadHeaders DownloadMessage // Disconnects from the POP3 server. // Disposes the Pop3Client object instance. // Downloads message headers. // Downloads the entire message (body and header). public string DownloadMessage(int messagePos); RetrieveMessageCount // Retrieves the message count. public int RetrieveMessageCount(); 18 Pop3Client class Instance Property ConnectionState Pop3Port Pop3Server WelcomeBanner // Gets the connection state. public ConnectionState ConnectionState {get;} Disconnected 0, Authorization 1,Transaction 2, Update 3 // Gets the POP3 server port. // Gets the POP3 server name. // Gets the POP3 server welcome banner. 19 IPAddress Class Public property (wybór) AddressFamily IsIPv4MappedToIPv6 IsIPv6Multicast IsIPv6SiteLocal ScopeId Public methods (wybór) GetAddressBytes GetHashCode GetType GetAddressBytes MapToIPv4 ToString //Gets the address family of the IP address. //Gets whether the IP address is an IPv4-mapped IPv6 address. //Gets whether the address is an IPv6 multicast global address. //Gets whether the address is an IPv6 site local address. //Gets or sets the IPv6 address scope identifier. //Provides a copy of the IPAddress as an array of bytes. //Returns a hash value for an IP address. //Gets the Type of the current instance. //Provides a copy of the IPAddress as an array of bytes. //Maps the IPAddress object to an IPv4 address. //Converts an Internet address to its standard notation. Public methodStatic (wybór) HostToNetworkOrder(Int32) //Converts an integer value from host byte order to network byte order. NetworkToHostOrder(Int32) //Converts an integer value from network byte order to host byte order. IsLoopback //Indicates whether the specified IP address is the loopback address. Parse //Converts an IP address string to an IPAddress instance. TryParse //Determines whether a string is a valid IP address. MapToIPv4 //Maps the IPAddress object to an IPv4 address. 20 Klient POP using using using using using using using using using System; System.Collections; System.IO; System.Net; System.Net.Sockets; System.Threading; System.Text; System.Text.RegularExpressions; System.Diagnostics; namespace Pop3 { public class Pop3Client { private Pop3Credential m_credential; private const int m_pop3port = 110; private const int MAX_BUFFER_READ_SIZE = 256; private private private private long m_inboxPosition = 0; long m_directPosition = -1; Socket m_socket = null; Pop3Message m_pop3Message = null; 21 public { set get } public Pop3Credential UserDetails { m_credential = value; } { return m_credential; } string From { get { return m_pop3Message.From; } } public string To { get { return m_pop3Message.To; } } public string Subject { get { return m_pop3Message.Subject; } } public string Body { get { return m_pop3Message.Body; } } public IEnumerator MultipartEnumerator { get { return m_pop3Message.MultipartEnumerator; } } public bool IsMultipart { get { return m_pop3Message.IsMultipart; } } public Pop3Client(string user, string pass, string server) { m_credential = new Pop3Credential(user,pass,server); } 22 Klient POP private Socket GetClientSocket() { Socket s = null; try { IPHostEntry hostEntry = null; // Get host related information. hostEntry = Dns.Resolve(m_credential.Server); foreach(IPAddress address in hostEntry.AddressList) { IPEndPoint ipe = new IPEndPoint(address, m_pop3port); Socket tempSocket = new Socket(ipe.AddressFamily, SocketType.Stream, ProtocolType.Tcp); tempSocket.Connect(ipe); if(tempSocket.Connected) { // we have a connection return this socket s = tempSocket; break; } else { continue; } } } 23 Klient POP catch(Exception e) { throw new Pop3ConnectException(e.ToString()); } // throw exception if can't connect ... if(s == null) { throw new Pop3ConnectException("Error : connecting to " +m_credential.Server); } return s; } 24 Klient POP //send the data to server private void Send(String data) { if(m_socket == null) { throw new Pop3MessageException("Pop3 connection is closed"); } try { // Convert the string data to byte data // using ASCII encoding. byte[] byteData = Encoding.ASCII.GetBytes(data+"\r\n"); // Begin sending the data to the remote device. m_socket.Send(byteData); } catch(Exception e) { throw new Pop3SendException(e.ToString()); } } 25 Klient POP private string GetPop3String() { if(m_socket == null) { throw new Pop3MessageException("Connection to POP3 server is closed"); } byte[] buffer = new byte[MAX_BUFFER_READ_SIZE]; string line = null; try { int byteCount = m_socket.Receive(buffer,buffer.Length,0); line = Encoding.ASCII.GetString(buffer, 0, byteCount); } catch(Exception e) { throw new Pop3ReceiveException(e.ToString()); } return line; } 26 Klient POP private void LoginToInbox() { string returned; // send username ... Send("user "+m_credential.User); // get response ... returned = GetPop3String(); if( !returned.Substring(0,3).Equals("+OK") ) { throw new Pop3LoginException("login not excepted"); } // send password ... Send("pass "+m_credential.Pass); // get response ... returned = GetPop3String(); if( !returned.Substring(0,3).Equals("+OK") ) { throw new Pop3LoginException("login/password not accepted"); } } 27 Klient POP public long MessageCount { get { long count = 0; if(m_socket==null) { throw new Pop3MessageException("Pop3 server not connected"); } Send("stat"); string returned = GetPop3String(); // if values returned ... if( Regex.Match(returned, @"^.*\+OK[ | ]+([0-9]+)[ | ]+.*$").Success ) { // get number of emails ... count = long.Parse( Regex.Replace(returned.Replace("\r\n","") , @"^.*\+OK[ | ]+([0-9]+)[ | ]+.*$" ,"$1") ); } return(count); } } 28 Klient POP public void CloseConnection() { Send("quit"); m_socket = null; m_pop3Message = null; } public bool DeleteEmail() { bool ret = false; Send("dele "+m_inboxPosition); string returned = GetPop3String(); if( Regex.Match(returned, @"^.*\+OK.*$").Success ) { ret = true; } return ret; } 29 public bool NextEmail(long directPosition) { bool ret; if( directPosition >= 0 ) { m_directPosition = directPosition; ret = NextEmail(); } else { throw new Pop3MessageException("Position less than zero"); } return ret; } public bool NextEmail() { string returned; long pos; if(m_directPosition == -1) { if(m_inboxPosition == 0) { pos = 1; } else { pos = m_inboxPosition + 1; } } else { pos = m_directPosition+1; m_directPosition = -1; } 30 Klient POP // send username ... Send("list "+pos.ToString()); // get response ... returned = GetPop3String(); // if email does not exist at this position // then return false ... if( returned.Substring(0,4).Equals("-ERR") ) { return false; } m_inboxPosition = pos; // strip out CRLF ... string[] noCr = returned.Split(new char[]{ '\r' }); // get size ... string[] elements = noCr[0].Split(new char[]{ ' ' }); long size = long.Parse(elements[2]); // ... else read email data m_pop3Message = new Pop3Message(m_inboxPosition,size,m_socket); return true; } 31 Klient POP public void OpenInbox() { // get a socket ... m_socket = GetClientSocket(); // get initial header from POP3 server ... string header = GetPop3String(); if( !header.Substring(0,3).Equals("+OK") ) { throw new Exception("Invalid initial POP3 response"); } // send login details ... LoginToInbox(); } } } 32 33