1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4 
5 using System;
6 using System.Collections;
7 using System.Globalization;
8 using System.IO;
9 using System.Net.Mime;
10 using System.Runtime.ExceptionServices;
11 using System.Text;
12 
13 namespace System.Net.Mail
14 {
15     internal static class CheckCommand
16     {
17         private static readonly AsyncCallback s_onReadLine = new AsyncCallback(OnReadLine);
18         private static readonly AsyncCallback s_onWrite = new AsyncCallback(OnWrite);
19 
BeginSend(SmtpConnection conn, AsyncCallback callback, object state)20         internal static IAsyncResult BeginSend(SmtpConnection conn, AsyncCallback callback, object state)
21         {
22             MultiAsyncResult multiResult = new MultiAsyncResult(conn, callback, state);
23             multiResult.Enter();
24             IAsyncResult writeResult = conn.BeginFlush(s_onWrite, multiResult);
25             if (writeResult.CompletedSynchronously)
26             {
27                 conn.EndFlush(writeResult);
28                 multiResult.Leave();
29             }
30             SmtpReplyReader reader = conn.Reader.GetNextReplyReader();
31             multiResult.Enter();
32 
33             //this actually does a read on the stream.
34             IAsyncResult result = reader.BeginReadLine(s_onReadLine, multiResult);
35             if (result.CompletedSynchronously)
36             {
37                 LineInfo info = reader.EndReadLine(result);
38                 if (!(multiResult.Result is Exception))
39                     multiResult.Result = info;
40                 multiResult.Leave();
41             }
42             multiResult.CompleteSequence();
43             return multiResult;
44         }
45 
46 
EndSend(IAsyncResult result, out string response)47         internal static object EndSend(IAsyncResult result, out string response)
48         {
49             object commandResult = MultiAsyncResult.End(result);
50             if (commandResult is Exception e)
51             {
52                 ExceptionDispatchInfo.Throw(e);
53             }
54 
55             LineInfo info = (LineInfo)commandResult;
56             response = info.Line;
57             return info.StatusCode;
58         }
59 
OnReadLine(IAsyncResult result)60         private static void OnReadLine(IAsyncResult result)
61         {
62             if (!result.CompletedSynchronously)
63             {
64                 MultiAsyncResult multiResult = (MultiAsyncResult)result.AsyncState;
65                 try
66                 {
67                     SmtpConnection conn = (SmtpConnection)multiResult.Context;
68                     LineInfo info = conn.Reader.CurrentReader.EndReadLine(result);
69                     if (!(multiResult.Result is Exception))
70                         multiResult.Result = info;
71                     multiResult.Leave();
72                 }
73                 catch (Exception e)
74                 {
75                     multiResult.Leave(e);
76                 }
77             }
78         }
79 
OnWrite(IAsyncResult result)80         private static void OnWrite(IAsyncResult result)
81         {
82             if (!result.CompletedSynchronously)
83             {
84                 MultiAsyncResult multiResult = (MultiAsyncResult)result.AsyncState;
85                 try
86                 {
87                     SmtpConnection conn = (SmtpConnection)multiResult.Context;
88                     conn.EndFlush(result);
89                     multiResult.Leave();
90                 }
91                 catch (Exception e)
92                 {
93                     multiResult.Leave(e);
94                 }
95             }
96         }
97 
Send(SmtpConnection conn, out string response)98         internal static SmtpStatusCode Send(SmtpConnection conn, out string response)
99         {
100             conn.Flush();
101             SmtpReplyReader reader = conn.Reader.GetNextReplyReader();
102             LineInfo info = reader.ReadLine();
103             response = info.Line;
104             reader.Close();
105             return info.StatusCode;
106         }
107     }
108 
109     internal static class ReadLinesCommand
110     {
111         private static readonly AsyncCallback s_onReadLines = new AsyncCallback(OnReadLines);
112         private static readonly AsyncCallback s_onWrite = new AsyncCallback(OnWrite);
113 
BeginSend(SmtpConnection conn, AsyncCallback callback, object state)114         internal static IAsyncResult BeginSend(SmtpConnection conn, AsyncCallback callback, object state)
115         {
116             MultiAsyncResult multiResult = new MultiAsyncResult(conn, callback, state);
117             multiResult.Enter();
118             IAsyncResult writeResult = conn.BeginFlush(s_onWrite, multiResult);
119             if (writeResult.CompletedSynchronously)
120             {
121                 conn.EndFlush(writeResult);
122                 multiResult.Leave();
123             }
124             SmtpReplyReader reader = conn.Reader.GetNextReplyReader();
125             multiResult.Enter();
126             IAsyncResult readLinesResult = reader.BeginReadLines(s_onReadLines, multiResult);
127             if (readLinesResult.CompletedSynchronously)
128             {
129                 LineInfo[] lines = conn.Reader.CurrentReader.EndReadLines(readLinesResult);
130                 if (!(multiResult.Result is Exception))
131                     multiResult.Result = lines;
132                 multiResult.Leave();
133             }
134             multiResult.CompleteSequence();
135             return multiResult;
136         }
137 
EndSend(IAsyncResult result)138         internal static LineInfo[] EndSend(IAsyncResult result)
139         {
140             object commandResult = MultiAsyncResult.End(result);
141             if (commandResult is Exception e)
142             {
143                 ExceptionDispatchInfo.Throw(e);
144             }
145             return (LineInfo[])commandResult;
146         }
147 
OnReadLines(IAsyncResult result)148         private static void OnReadLines(IAsyncResult result)
149         {
150             if (!result.CompletedSynchronously)
151             {
152                 MultiAsyncResult multiResult = (MultiAsyncResult)result.AsyncState;
153                 try
154                 {
155                     SmtpConnection conn = (SmtpConnection)multiResult.Context;
156                     LineInfo[] lines = conn.Reader.CurrentReader.EndReadLines(result);
157                     if (!(multiResult.Result is Exception))
158                         multiResult.Result = lines;
159                     multiResult.Leave();
160                 }
161                 catch (Exception e)
162                 {
163                     multiResult.Leave(e);
164                 }
165             }
166         }
167 
OnWrite(IAsyncResult result)168         private static void OnWrite(IAsyncResult result)
169         {
170             if (!result.CompletedSynchronously)
171             {
172                 MultiAsyncResult multiResult = (MultiAsyncResult)result.AsyncState;
173                 try
174                 {
175                     SmtpConnection conn = (SmtpConnection)multiResult.Context;
176                     conn.EndFlush(result);
177                     multiResult.Leave();
178                 }
179                 catch (Exception e)
180                 {
181                     multiResult.Leave(e);
182                 }
183             }
184         }
Send(SmtpConnection conn)185         internal static LineInfo[] Send(SmtpConnection conn)
186         {
187             conn.Flush();
188             return conn.Reader.GetNextReplyReader().ReadLines();
189         }
190     }
191 
192     internal static class AuthCommand
193     {
BeginSend(SmtpConnection conn, string type, string message, AsyncCallback callback, object state)194         internal static IAsyncResult BeginSend(SmtpConnection conn, string type, string message, AsyncCallback callback, object state)
195         {
196             PrepareCommand(conn, type, message);
197             return ReadLinesCommand.BeginSend(conn, callback, state);
198         }
199 
BeginSend(SmtpConnection conn, string message, AsyncCallback callback, object state)200         internal static IAsyncResult BeginSend(SmtpConnection conn, string message, AsyncCallback callback, object state)
201         {
202             PrepareCommand(conn, message);
203             return ReadLinesCommand.BeginSend(conn, callback, state);
204         }
205 
CheckResponse(LineInfo[] lines)206         private static LineInfo CheckResponse(LineInfo[] lines)
207         {
208             if (lines == null || lines.Length == 0)
209             {
210                 throw new SmtpException(SR.SmtpAuthResponseInvalid);
211             }
212             System.Diagnostics.Debug.Assert(lines.Length == 1, "Did not expect more than one line response for auth command");
213             return lines[0];
214         }
215 
EndSend(IAsyncResult result)216         internal static LineInfo EndSend(IAsyncResult result)
217         {
218             return CheckResponse(ReadLinesCommand.EndSend(result));
219         }
PrepareCommand(SmtpConnection conn, string type, string message)220         private static void PrepareCommand(SmtpConnection conn, string type, string message)
221         {
222             conn.BufferBuilder.Append(SmtpCommands.Auth);
223             conn.BufferBuilder.Append(type);
224             conn.BufferBuilder.Append((byte)' ');
225             conn.BufferBuilder.Append(message);
226             conn.BufferBuilder.Append(SmtpCommands.CRLF);
227         }
228 
PrepareCommand(SmtpConnection conn, string message)229         private static void PrepareCommand(SmtpConnection conn, string message)
230         {
231             conn.BufferBuilder.Append(message);
232             conn.BufferBuilder.Append(SmtpCommands.CRLF);
233         }
234 
Send(SmtpConnection conn, string type, string message)235         internal static LineInfo Send(SmtpConnection conn, string type, string message)
236         {
237             PrepareCommand(conn, type, message);
238             return CheckResponse(ReadLinesCommand.Send(conn));
239         }
240 
Send(SmtpConnection conn, string message)241         internal static LineInfo Send(SmtpConnection conn, string message)
242         {
243             PrepareCommand(conn, message);
244             return CheckResponse(ReadLinesCommand.Send(conn));
245         }
246     }
247 
248     internal static class DataCommand
249     {
BeginSend(SmtpConnection conn, AsyncCallback callback, object state)250         internal static IAsyncResult BeginSend(SmtpConnection conn, AsyncCallback callback, object state)
251         {
252             PrepareCommand(conn);
253             return CheckCommand.BeginSend(conn, callback, state);
254         }
255 
CheckResponse(SmtpStatusCode statusCode, string serverResponse)256         private static void CheckResponse(SmtpStatusCode statusCode, string serverResponse)
257         {
258             switch (statusCode)
259             {
260                 case SmtpStatusCode.StartMailInput:
261                     {
262                         return;
263                     }
264                 case SmtpStatusCode.LocalErrorInProcessing:
265                 case SmtpStatusCode.TransactionFailed:
266                 default:
267                     {
268                         if ((int)statusCode < 400)
269                         {
270                             throw new SmtpException(SR.net_webstatus_ServerProtocolViolation, serverResponse);
271                         }
272 
273                         throw new SmtpException(statusCode, serverResponse, true);
274                     }
275             }
276         }
277 
EndSend(IAsyncResult result)278         internal static void EndSend(IAsyncResult result)
279         {
280             string response;
281             SmtpStatusCode statusCode = (SmtpStatusCode)CheckCommand.EndSend(result, out response);
282             CheckResponse(statusCode, response);
283         }
284 
PrepareCommand(SmtpConnection conn)285         private static void PrepareCommand(SmtpConnection conn)
286         {
287             if (conn.IsStreamOpen)
288             {
289                 throw new InvalidOperationException(SR.SmtpDataStreamOpen);
290             }
291 
292             conn.BufferBuilder.Append(SmtpCommands.Data);
293         }
294 
Send(SmtpConnection conn)295         internal static void Send(SmtpConnection conn)
296         {
297             PrepareCommand(conn);
298             string response;
299             SmtpStatusCode statusCode = CheckCommand.Send(conn, out response);
300             CheckResponse(statusCode, response);
301         }
302     }
303 
304     internal static class DataStopCommand
305     {
CheckResponse(SmtpStatusCode statusCode, string serverResponse)306         private static void CheckResponse(SmtpStatusCode statusCode, string serverResponse)
307         {
308             switch (statusCode)
309             {
310                 case SmtpStatusCode.Ok:
311                     {
312                         return;
313                     }
314                 case SmtpStatusCode.ExceededStorageAllocation:
315                 case SmtpStatusCode.TransactionFailed:
316                 case SmtpStatusCode.LocalErrorInProcessing:
317                 case SmtpStatusCode.InsufficientStorage:
318                 default:
319                     {
320                         if ((int)statusCode < 400)
321                         {
322                             throw new SmtpException(SR.net_webstatus_ServerProtocolViolation, serverResponse);
323                         }
324 
325                         throw new SmtpException(statusCode, serverResponse, true);
326                     }
327             }
328         }
329 
PrepareCommand(SmtpConnection conn)330         private static void PrepareCommand(SmtpConnection conn)
331         {
332             if (conn.IsStreamOpen)
333             {
334                 throw new InvalidOperationException(SR.SmtpDataStreamOpen);
335             }
336 
337             conn.BufferBuilder.Append(SmtpCommands.DataStop);
338         }
Send(SmtpConnection conn)339         internal static void Send(SmtpConnection conn)
340         {
341             PrepareCommand(conn);
342             string response;
343             SmtpStatusCode statusCode = CheckCommand.Send(conn, out response);
344             CheckResponse(statusCode, response);
345         }
346     }
347 
348     internal static class EHelloCommand
349     {
BeginSend(SmtpConnection conn, string domain, AsyncCallback callback, object state)350         internal static IAsyncResult BeginSend(SmtpConnection conn, string domain, AsyncCallback callback, object state)
351         {
352             PrepareCommand(conn, domain);
353             return ReadLinesCommand.BeginSend(conn, callback, state);
354         }
355 
CheckResponse(LineInfo[] lines)356         private static string[] CheckResponse(LineInfo[] lines)
357         {
358             if (lines == null || lines.Length == 0)
359             {
360                 throw new SmtpException(SR.SmtpEhloResponseInvalid);
361             }
362             if (lines[0].StatusCode != SmtpStatusCode.Ok)
363             {
364                 if ((int)lines[0].StatusCode < 400)
365                 {
366                     throw new SmtpException(SR.net_webstatus_ServerProtocolViolation, lines[0].Line);
367                 }
368 
369                 throw new SmtpException(lines[0].StatusCode, lines[0].Line, true);
370             }
371             string[] extensions = new string[lines.Length - 1];
372             for (int i = 1; i < lines.Length; i++)
373             {
374                 extensions[i - 1] = lines[i].Line;
375             }
376             return extensions;
377         }
378 
EndSend(IAsyncResult result)379         internal static string[] EndSend(IAsyncResult result)
380         {
381             return CheckResponse(ReadLinesCommand.EndSend(result));
382         }
PrepareCommand(SmtpConnection conn, string domain)383         private static void PrepareCommand(SmtpConnection conn, string domain)
384         {
385             if (conn.IsStreamOpen)
386             {
387                 throw new InvalidOperationException(SR.SmtpDataStreamOpen);
388             }
389 
390             conn.BufferBuilder.Append(SmtpCommands.EHello);
391             conn.BufferBuilder.Append(domain);
392             conn.BufferBuilder.Append(SmtpCommands.CRLF);
393         }
394 
Send(SmtpConnection conn, string domain)395         internal static string[] Send(SmtpConnection conn, string domain)
396         {
397             PrepareCommand(conn, domain);
398             return CheckResponse(ReadLinesCommand.Send(conn));
399         }
400     }
401 
402     internal static class HelloCommand
403     {
BeginSend(SmtpConnection conn, string domain, AsyncCallback callback, object state)404         internal static IAsyncResult BeginSend(SmtpConnection conn, string domain, AsyncCallback callback, object state)
405         {
406             PrepareCommand(conn, domain);
407             return CheckCommand.BeginSend(conn, callback, state);
408         }
409 
CheckResponse(SmtpStatusCode statusCode, string serverResponse)410         private static void CheckResponse(SmtpStatusCode statusCode, string serverResponse)
411         {
412             switch (statusCode)
413             {
414                 case SmtpStatusCode.Ok:
415                     {
416                         return;
417                     }
418                 default:
419                     {
420                         if ((int)statusCode < 400)
421                         {
422                             throw new SmtpException(SR.net_webstatus_ServerProtocolViolation, serverResponse);
423                         }
424 
425                         throw new SmtpException(statusCode, serverResponse, true);
426                     }
427             }
428         }
429 
EndSend(IAsyncResult result)430         internal static void EndSend(IAsyncResult result)
431         {
432             string response;
433             SmtpStatusCode statusCode = (SmtpStatusCode)CheckCommand.EndSend(result, out response);
434             CheckResponse(statusCode, response);
435         }
436 
PrepareCommand(SmtpConnection conn, string domain)437         private static void PrepareCommand(SmtpConnection conn, string domain)
438         {
439             if (conn.IsStreamOpen)
440             {
441                 throw new InvalidOperationException(SR.SmtpDataStreamOpen);
442             }
443 
444             conn.BufferBuilder.Append(SmtpCommands.Hello);
445             conn.BufferBuilder.Append(domain);
446             conn.BufferBuilder.Append(SmtpCommands.CRLF);
447         }
448 
Send(SmtpConnection conn, string domain)449         internal static void Send(SmtpConnection conn, string domain)
450         {
451             PrepareCommand(conn, domain);
452             string response;
453             SmtpStatusCode statusCode = CheckCommand.Send(conn, out response);
454             CheckResponse(statusCode, response);
455         }
456     }
457 
458     internal static class StartTlsCommand
459     {
BeginSend(SmtpConnection conn, AsyncCallback callback, object state)460         internal static IAsyncResult BeginSend(SmtpConnection conn, AsyncCallback callback, object state)
461         {
462             PrepareCommand(conn);
463             return CheckCommand.BeginSend(conn, callback, state);
464         }
465 
CheckResponse(SmtpStatusCode statusCode, string response)466         private static void CheckResponse(SmtpStatusCode statusCode, string response)
467         {
468             switch (statusCode)
469             {
470                 case SmtpStatusCode.ServiceReady:
471                     {
472                         return;
473                     }
474 
475                 case SmtpStatusCode.ClientNotPermitted:
476                 default:
477                     {
478                         if ((int)statusCode < 400)
479                         {
480                             throw new SmtpException(SR.net_webstatus_ServerProtocolViolation, response);
481                         }
482 
483                         throw new SmtpException(statusCode, response, true);
484                     }
485             }
486         }
487 
EndSend(IAsyncResult result)488         internal static void EndSend(IAsyncResult result)
489         {
490             string response;
491             SmtpStatusCode statusCode = (SmtpStatusCode)CheckCommand.EndSend(result, out response);
492             CheckResponse(statusCode, response);
493         }
494 
PrepareCommand(SmtpConnection conn)495         private static void PrepareCommand(SmtpConnection conn)
496         {
497             if (conn.IsStreamOpen)
498             {
499                 throw new InvalidOperationException(SR.SmtpDataStreamOpen);
500             }
501 
502             conn.BufferBuilder.Append(SmtpCommands.StartTls);
503             conn.BufferBuilder.Append(SmtpCommands.CRLF);
504         }
505 
Send(SmtpConnection conn)506         internal static void Send(SmtpConnection conn)
507         {
508             PrepareCommand(conn);
509             string response;
510             SmtpStatusCode statusCode = CheckCommand.Send(conn, out response);
511             CheckResponse(statusCode, response);
512         }
513     }
514 
515     internal static class MailCommand
516     {
BeginSend(SmtpConnection conn, byte[] command, MailAddress from, bool allowUnicode, AsyncCallback callback, object state)517         internal static IAsyncResult BeginSend(SmtpConnection conn, byte[] command, MailAddress from,
518             bool allowUnicode, AsyncCallback callback, object state)
519         {
520             PrepareCommand(conn, command, from, allowUnicode);
521             return CheckCommand.BeginSend(conn, callback, state);
522         }
523 
CheckResponse(SmtpStatusCode statusCode, string response)524         private static void CheckResponse(SmtpStatusCode statusCode, string response)
525         {
526             switch (statusCode)
527             {
528                 case SmtpStatusCode.Ok:
529                     {
530                         return;
531                     }
532                 case SmtpStatusCode.ExceededStorageAllocation:
533                 case SmtpStatusCode.LocalErrorInProcessing:
534                 case SmtpStatusCode.InsufficientStorage:
535                 default:
536                     {
537                         if ((int)statusCode < 400)
538                         {
539                             throw new SmtpException(SR.net_webstatus_ServerProtocolViolation, response);
540                         }
541 
542                         throw new SmtpException(statusCode, response, true);
543                     }
544             }
545         }
546 
EndSend(IAsyncResult result)547         internal static void EndSend(IAsyncResult result)
548         {
549             string response;
550             SmtpStatusCode statusCode = (SmtpStatusCode)CheckCommand.EndSend(result, out response);
551             CheckResponse(statusCode, response);
552         }
553 
PrepareCommand(SmtpConnection conn, byte[] command, MailAddress from, bool allowUnicode)554         private static void PrepareCommand(SmtpConnection conn, byte[] command, MailAddress from, bool allowUnicode)
555         {
556             if (conn.IsStreamOpen)
557             {
558                 throw new InvalidOperationException(SR.SmtpDataStreamOpen);
559             }
560             conn.BufferBuilder.Append(command);
561             string fromString = from.GetSmtpAddress(allowUnicode);
562             conn.BufferBuilder.Append(fromString, allowUnicode);
563             if (allowUnicode)
564             {
565                 conn.BufferBuilder.Append(" BODY=8BITMIME SMTPUTF8");
566             }
567             conn.BufferBuilder.Append(SmtpCommands.CRLF);
568         }
569 
Send(SmtpConnection conn, byte[] command, MailAddress from, bool allowUnicode)570         internal static void Send(SmtpConnection conn, byte[] command, MailAddress from, bool allowUnicode)
571         {
572             PrepareCommand(conn, command, from, allowUnicode);
573             string response;
574             SmtpStatusCode statusCode = CheckCommand.Send(conn, out response);
575             CheckResponse(statusCode, response);
576         }
577     }
578 
579     internal static class RecipientCommand
580     {
BeginSend(SmtpConnection conn, string to, AsyncCallback callback, object state)581         internal static IAsyncResult BeginSend(SmtpConnection conn, string to, AsyncCallback callback, object state)
582         {
583             PrepareCommand(conn, to);
584             return CheckCommand.BeginSend(conn, callback, state);
585         }
586 
CheckResponse(SmtpStatusCode statusCode, string response)587         private static bool CheckResponse(SmtpStatusCode statusCode, string response)
588         {
589             switch (statusCode)
590             {
591                 case SmtpStatusCode.Ok:
592                 case SmtpStatusCode.UserNotLocalWillForward:
593                     {
594                         return true;
595                     }
596                 case SmtpStatusCode.MailboxUnavailable:
597                 case SmtpStatusCode.UserNotLocalTryAlternatePath:
598                 case SmtpStatusCode.ExceededStorageAllocation:
599                 case SmtpStatusCode.MailboxNameNotAllowed:
600                 case SmtpStatusCode.MailboxBusy:
601                 case SmtpStatusCode.InsufficientStorage:
602                     {
603                         return false;
604                     }
605                 default:
606                     {
607                         if ((int)statusCode < 400)
608                         {
609                             throw new SmtpException(SR.net_webstatus_ServerProtocolViolation, response);
610                         }
611 
612                         throw new SmtpException(statusCode, response, true);
613                     }
614             }
615         }
616 
EndSend(IAsyncResult result, out string response)617         internal static bool EndSend(IAsyncResult result, out string response)
618         {
619             SmtpStatusCode statusCode = (SmtpStatusCode)CheckCommand.EndSend(result, out response);
620             return CheckResponse(statusCode, response);
621         }
622 
PrepareCommand(SmtpConnection conn, string to)623         private static void PrepareCommand(SmtpConnection conn, string to)
624         {
625             if (conn.IsStreamOpen)
626             {
627                 throw new InvalidOperationException(SR.SmtpDataStreamOpen);
628             }
629 
630             conn.BufferBuilder.Append(SmtpCommands.Recipient);
631             conn.BufferBuilder.Append(to, true); // Unicode validation was done prior
632             conn.BufferBuilder.Append(SmtpCommands.CRLF);
633         }
634 
635 
Send(SmtpConnection conn, string to, out string response)636         internal static bool Send(SmtpConnection conn, string to, out string response)
637         {
638             PrepareCommand(conn, to);
639             SmtpStatusCode statusCode = CheckCommand.Send(conn, out response);
640             return CheckResponse(statusCode, response);
641         }
642     }
643 
644 
645     internal static class SmtpCommands
646     {
647         internal static readonly byte[] Auth = Encoding.ASCII.GetBytes("AUTH ");
648         internal static readonly byte[] CRLF = Encoding.ASCII.GetBytes("\r\n");
649         internal static readonly byte[] Data = Encoding.ASCII.GetBytes("DATA\r\n");
650         internal static readonly byte[] DataStop = Encoding.ASCII.GetBytes("\r\n.\r\n");
651         internal static readonly byte[] EHello = Encoding.ASCII.GetBytes("EHLO ");
652         internal static readonly byte[] Expand = Encoding.ASCII.GetBytes("EXPN ");
653         internal static readonly byte[] Hello = Encoding.ASCII.GetBytes("HELO ");
654         internal static readonly byte[] Help = Encoding.ASCII.GetBytes("HELP");
655         internal static readonly byte[] Mail = Encoding.ASCII.GetBytes("MAIL FROM:");
656         internal static readonly byte[] Noop = Encoding.ASCII.GetBytes("NOOP\r\n");
657         internal static readonly byte[] Quit = Encoding.ASCII.GetBytes("QUIT\r\n");
658         internal static readonly byte[] Recipient = Encoding.ASCII.GetBytes("RCPT TO:");
659         internal static readonly byte[] Reset = Encoding.ASCII.GetBytes("RSET\r\n");
660         internal static readonly byte[] Send = Encoding.ASCII.GetBytes("SEND FROM:");
661         internal static readonly byte[] SendAndMail = Encoding.ASCII.GetBytes("SAML FROM:");
662         internal static readonly byte[] SendOrMail = Encoding.ASCII.GetBytes("SOML FROM:");
663         internal static readonly byte[] Turn = Encoding.ASCII.GetBytes("TURN\r\n");
664         internal static readonly byte[] Verify = Encoding.ASCII.GetBytes("VRFY ");
665         internal static readonly byte[] StartTls = Encoding.ASCII.GetBytes("STARTTLS");
666     }
667 
668 
669 
670     internal struct LineInfo
671     {
672         private string _line;
673         private SmtpStatusCode _statusCode;
674 
LineInfoSystem.Net.Mail.LineInfo675         internal LineInfo(SmtpStatusCode statusCode, string line)
676         {
677             _statusCode = statusCode;
678             _line = line;
679         }
680         internal string Line
681         {
682             get
683             {
684                 return _line;
685             }
686         }
687         internal SmtpStatusCode StatusCode
688         {
689             get
690             {
691                 return _statusCode;
692             }
693         }
694     }
695 }
696