2008-11-18 Gonzalo Paniagua Javier <gonzalo@novell.com>
[mono.git] / mcs / class / System.Web / System.Web.Mail / SmtpStream.cs
1 //
2 // System.Web.Mail.SmtpStream.cs
3 //
4 // Author(s):
5 //   Per Arneng <pt99par@student.bth.se>
6 //
7 //
8
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 // 
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 // 
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 //
29 using System;
30 using System.IO;
31 using System.Collections;
32 using System.Text;
33 using System.Security.Cryptography;
34 using System.Diagnostics;
35
36 namespace System.Web.Mail {
37
38     internal class SmtpStream {
39         
40         protected Stream stream;
41         protected Encoding encoding;
42         protected SmtpResponse lastResponse;
43         protected string command = "";
44
45         public SmtpStream( Stream stream ) {
46             this.stream = stream;
47             encoding = new ASCIIEncoding();
48         }
49         
50         public Stream Stream {
51             get { return stream; }
52         }
53         
54         public SmtpResponse LastResponse {
55             get { return lastResponse; }
56         }
57         
58         public void WriteRset() {
59             command = "RSET";
60             WriteLine( command );
61             ReadResponse();
62             CheckForStatusCode( 250 );
63         
64         }
65         
66         public void WriteAuthLogin()
67         {
68                 command = "AUTH LOGIN";
69                 WriteLine( command );
70                 ReadResponse();         
71         }
72
73         public bool WriteStartTLS( ) 
74         { 
75                 command = "STARTTLS";
76                 WriteLine( command );
77                 ReadResponse();
78                 return LastResponse.StatusCode == 220;
79
80         }
81
82         public void WriteEhlo( string hostName ) 
83         { 
84                 command = "EHLO " + hostName;
85                 WriteLine( command );
86                 ReadResponse();
87                 CheckForStatusCode( 250 );
88         
89         }
90         
91         public void WriteHelo( string hostName ) { 
92             command = "HELO " + hostName;
93             WriteLine( command );
94             ReadResponse();
95             CheckForStatusCode( 250 );
96             
97         }
98         
99         public void WriteMailFrom( string from ) {
100             command = "MAIL FROM: <" + from + ">";
101             WriteLine( command );
102             ReadResponse();
103             CheckForStatusCode( 250 );
104             
105         }
106         
107         public void WriteRcptTo( string to ) {
108             command = "RCPT TO: <" + to + ">";  
109             WriteLine( command );
110             ReadResponse();
111             CheckForStatusCode( 250 );
112                     
113         }
114         
115
116         public void WriteData() {
117             command = "DATA";
118             WriteLine( command );
119             ReadResponse();
120             CheckForStatusCode( 354 );
121         
122         }
123         
124         public void WriteQuit() {
125             command = "QUIT";
126             WriteLine( command );
127             ReadResponse();
128             CheckForStatusCode( 221 );
129         
130         }
131                 
132         public void WriteBoundary( string boundary ) {
133         
134             WriteLine( "\r\n--{0}" , boundary );
135         
136         }
137         
138         public void WriteFinalBoundary( string boundary ) {
139         
140             WriteLine( "\r\n--{0}--" , boundary );
141         
142         }
143         
144         // single dot by itself
145         public void WriteDataEndTag() {
146             command = "\r\n.";
147             WriteLine( command );
148             ReadResponse();
149             CheckForStatusCode( 250 );
150         
151         }
152         
153         
154         public void WriteHeader( MailHeader header ) {
155             // write the headers
156             foreach( string key in header.Data.AllKeys )
157                 WriteLine( "{0}: {1}" , key , header.Data[ key ] );
158             
159             // write the header end tag
160             WriteLine( "" );
161         }
162         
163         public void CheckForStatusCode( int statusCode ) {
164             
165             if( LastResponse.StatusCode != statusCode ) {
166                 
167                 string msg = "" + 
168                     "Server reponse: '" + lastResponse.RawResponse + "';" +
169                     "Status code: '" +  lastResponse.StatusCode + "';" + 
170                     "Expected status code: '" + statusCode + "';" + 
171                     "Last command: '" + command + "'";
172                 
173                 throw new SmtpException( msg ); 
174                                         
175             }
176         }
177         
178         
179         // write buffer's bytes to the stream
180         public void WriteBytes( byte[] buffer ) {
181             stream.Write( buffer , 0 , buffer.Length );
182         }
183         
184         // writes a formatted line to the server
185         public void WriteLine( string format ,  params object[] args ) {
186             WriteLine( String.Format( format , args ) );
187         }
188         
189         // writes a line to the server
190         public void WriteLine( string line ) {
191             byte[] buffer = encoding.GetBytes( line + "\r\n" );
192             
193             stream.Write( buffer , 0 , buffer.Length );
194
195                 Debug.WriteLine ("smtp: {0}", line);
196         }
197         
198         // read a line from the server
199         public void ReadResponse( ) {
200                 
201                 byte[] buffer = new byte [512];
202                 int position = 0;
203                 bool lastLine = false;
204
205                 do {
206                         int readLength = stream.Read (buffer , position , buffer.Length - position);
207                         if (readLength > 0) { 
208                                 int available = position + readLength - 1;
209                                 if (available > 4 && (buffer [available] == '\n' || buffer [available] == '\r'))
210                                         for (int index = available - 3; ; index--) {
211                                                 if (index < 0 || buffer [index] == '\n' || buffer [index] == '\r') {
212                                                         lastLine = buffer [index + 4] == ' ';
213                                                         break;
214                                                 }
215                                         }
216
217                                 // move position
218                                 position += readLength;
219
220                                 // check if buffer is full
221                                 if (position == buffer.Length) {
222                                         byte [] newBuffer = new byte [buffer.Length * 2];
223                                         Array.Copy (buffer, 0, newBuffer, 0, buffer.Length);
224                                         buffer = newBuffer;
225                                 }
226                         }
227                 } while(!lastLine);
228
229                 string line = encoding.GetString (buffer , 0 , position - 1);
230                         
231             // parse the line to the lastResponse object
232             lastResponse = SmtpResponse.Parse (line);
233
234                 Debug.WriteLine ("smtp: {0}", line);
235         }
236
237     }
238
239
240 }