При нажатии на Сумма в примере ArbitraryMethod из Лекция 7, VS 2013 выдается ошибка: Необработанное исключение типа "System.InvalidOperationException" в System.Windows.Forms.dll Дополнительные сведения: Недопустимая операция в нескольких потоках: попытка доступа к элементу управления "lblResult" не из того потока, в котором он был создан. Затем: Необработанное исключение типа "System.InvalidOperationException" в mscorlib.dll Дополнительные сведения: Для каждой асинхронной операции метод EndInvoke может вызываться только один раз. |
Опубликован: 11.09.2006 | Уровень: специалист | Доступ: свободно
Лекция 3:
Работа с элементами управления (продолжение)
Получение сообщений – проект Mail
Классы для обработки исключений Exceptions
Класс CoreException.cs
using System; namespace Mail { /// <summary> /// Класс для обработки основных исключений. /// </summary> public class CoreException : ApplicationException { /// <summary> /// Инициализация исключения без дополнительных параметров. /// </summary> public CoreException() : base() { } /// <summary> /// Инициализация исключения с дополнительным описанием. /// </summary> public CoreException(string message) : base(message) { } /// <summary> /// Инициализация исключения с дополнительным описанием и внутренним исключением /// </summary> public CoreException(string message, System.Exception inner) : base(message, inner) { } } }Листинг 3.5.
Класс DeadConnectionException.cs
using System; namespace Mail { /// <summary> /// Класс для обработки исключений установки связи. /// </summary> public class DeadConnectException : CoreException { /// <summary> /// Инициализация исключения без дополнительных параметров. /// </summary> public DeadConnectException() : base() { } /// <summary> /// Инициализация исключения с дополнительным описанием. /// </summary> public DeadConnectException(string message) : base(message) { } /// <summary> /// Инициализация исключения с дополнительным описанием и внутренним исключением. /// </summary> public DeadConnectException(string message, System.Exception inner) : base(message, inner) { } } }Листинг 3.6.
Класс ParseException.cs
using System; namespace Mail { /// <summary> /// Класс для обработки исключений, возникающих в момент анализа ответа. /// <summary> public class ParseException: CoreException { public ParseException(string message) : base(message) { } public ParseException(string message, System.Exception inner) : base(message, inner) { } } }
Класс ResponseException.cs
using System; namespace Mail { /// <summary> /// Класс для обработки исключений POP3Unit /// </summary> public class ResponseException : CoreException { public ResponseException(string message) : base(message) { } public ResponseException(string message, System.Exception inner) : base(message, inner) { } } }
Класс ShutdownException.cs
using System; namespace Mail { /// <summary> /// Класс для обработки исключений POP3Unit /// </summary> public class ShutdownException: CoreException { public ShutdownException(string message) : base(message) { } public ShutdownException(string message, System.Exception inner) : base(message, inner) { } } }
Библиотека конвертирования Library
Класс FromQuotedPrintableTransform.cs
using System; using System.Security.Cryptography; using System.Text; namespace Mail { /// <summary> /// Конвертирование CryptoStream. /// <summary> public class FromQuotedPrintableTransform : ICryptoTransform, IDisposable { // максимальный размер входного\выходного блока. const int MAX_BUF = 3; // буфер byte [] _buf = null; /// <summary> /// Значение, указывающее на возможность повторного использования текущей трансформации /// </summary> public bool CanReuseTransform { get { return true; } } /// <summary> /// Значение, указывающее на возможность трансформации составных блоков. /// </summary> public bool CanTransformMultipleBlocks { get { return false; } } /// <summary> /// Возвращение выходного размера блока. /// </summary> public int OutputBlockSize { get { return MAX_BUF; } } /// <summary> /// Возвращение входного размера блока. /// </summary> public int InputBlockSize { get { return MAX_BUF; } } /// <summary> /// Удаление всех элементов. /// </summary> public void Dispose() { _buf = null; GC.SuppressFinalize(this); } /// <summary> /// Конвертирование указанного участка входящего массива байтов из quoted-printable (RFC 2045 (6.7)) /// и копирование результата в указанный участок выходного массива байтов. /// </summary> /// <param name="inputBuffer">Входящий массив байтов.</param> /// <param name="inputOffset">Начальная отметка участка, который нужно конвертировать.</param> /// <param name="inputCount">Количество байтов после индекса начала участка.</param> /// <param name="outputBuffer">Выходной массив байтов, в который требуется записать результат.</param> /// <param name="outputOffset">Начальная отметка участка, после которого необходимо вписать результат.</param> /// <returns>Количество вписанных байтов.</returns> public int TransformBlock(byte[] inputBuffer, int inputOffset, int inputCount, byte[] outputBuffer, int outputOffset) { // append unparsed characters if (_buf != null) { byte [] tmp = new byte[inputCount + _buf.Length]; Array.Copy(_buf, 0, tmp, 0, _buf.Length); Array.Copy(inputBuffer, inputOffset, tmp, _buf.Length, inputCount); inputBuffer = tmp; inputCount = tmp.Length; _buf = null; } else { byte [] tmp = new byte[inputCount]; Array.Copy(inputBuffer, inputOffset, tmp, 0, inputCount); inputBuffer = tmp; } int c = 0; int obi = outputOffset; while (c < inputCount) { byte cb = inputBuffer[c++]; // skip CRLFs if (cb == '=') { // impossible to get next 2 bytes, save unparsed characters // for next session if (c + 1 >= inputCount) { int len = inputCount - c; _buf = new byte[len + 1]; // +1 is for '=' Array.Copy(inputBuffer, c - 1, _buf, 0, len + 1); break; } // skip =\r\n if (!(inputBuffer[c] == '\r' && inputBuffer[c + 1] == '\n')) { // TODO Add check. Uppercase letters must be used (=DD); // lowercase letters are not allowed. try { byte b = Convert.ToByte(Encoding.ASCII.GetString(inputBuffer, c, 2), 16); outputBuffer[obi++] = b; } catch (FormatException e) { throw new ParseException("Incorrect sequence. Are you sure that it's quoted-printable?", e); } } // take next sequence c += 2; } // incorrect characters for quoted-printable, just skip it else if (!(cb == '\r' || cb == '\n')) { outputBuffer[obi++] = cb; } } return obi - outputOffset; } /// <summary> /// Конвертирование указанного участка входящего массива байтов из quoted-printable (RFC 2045 (6.7)). /// </summary> /// <param name="inputBuffer">Входящий массив байтов.</param> /// <param name="inputOffset">Начальная отметка участка, который нужно конвертировать.</param> /// <param name="inputCount">Количество байтов после индекса начала участка.</param> /// <returns>Полученный массив байтов.</returns> public byte[] TransformFinalBlock(byte[] inputBuffer, int inputOffset, int inputCount) { byte [] b = new byte[inputCount]; int s = TransformBlock(inputBuffer, inputOffset, inputCount, b, 0); byte [] c = new byte[s]; Array.Copy(b, 0, c, 0, s); return c; } } }Листинг 3.7.
Класс Utils.cs
using System; using System.Text.RegularExpressions; using System.Collections; using System.Text; using System.Web; namespace Mail { /// <summary> /// Класс, содержащий общие функции. /// </summary> public class Utils { // Архив кодировок. static Hashtable knownEncodings = new Hashtable(); static Utils() { } /// <summary> /// Извлечение простого текста из HTML-текста. /// </summary> /// <param name="html">HTML текст.</param> /// <returns>Простой текст.</returns> public static string ExtractTextFromHtml(string html) { // С помощью регулярных выражений удаляем или заменяем // HTML-теги. // удаление <!DOCTYPE ... > Regex r = new Regex(@"<![^>]+>"); // Создание регулярного выражения. html = r.Replace(html, ""); // Замена подходящей части текста на пустую строку. // удаление <head>...</head> r = new Regex(@"<head>.*?</head>", RegexOptions.IgnoreCase); // Создание регулярного выражения. // r = new Regex(@"<style[^>]+[>].*?</style>", RegexOptions.IgnoreCase); html = r.Replace(html, ""); // Замена подходящей части текста на пустую строку. // представляем, что </div>, <br />, </p> — это новая строка r = new Regex(@"(</div>|<[/]?br[^>]+>|</p>)", RegexOptions.IgnoreCase); // Создание регулярного выражения. html = r.Replace(html, "\r\n"); // Замена подходящей части текста на символы перехода на новую строку. // удаление всех тегов <...> r = new Regex(@"<[^>]+>", RegexOptions.Multiline); // Создание регулярного выражения, удаляющего все оставшиеся теги. html = r.Replace(html, ""); html = HttpUtility.HtmlDecode(html); return html; } /// <summary> /// Возвращение кодировки текста. /// </summary> /// <param name="charset">Текст, содержащий название кодировки.</param> /// <returns></returns> public static Encoding GetEncoding(string charset) { // Проверяем, есть ли данная кодировка в памяти класса, // и если есть, возвращаем ее. if (knownEncodings.ContainsKey(charset)) { return (Encoding)knownEncodings[charset]; } // Если кодировка не обнаружена, начинаем анализировать строку. Encoding e = Encoding.Default; try { e = Encoding.GetEncoding(charset); } catch {} // Добавляем кодировку в память класса. knownEncodings.Add(charset, e); // Возвращаем кодировку. return e; } /// <summary> /// Исключаем "byte-stuffed", следуя RFC1939 /// \r\n.[not \r\n] => \r\n[not \r\n] /// </summary> /// <param name="s"></param> /// <returns></returns> public static string RemoveByteStuffedSequence(string s) { Regex r = new Regex(@"(?<=\r\n)\.(?!\r\n)"); return r.Replace(s, ""); } /// <summary> /// Декодируем строку /// </summary> /// <param name="s">Строка</param> /// <returns></returns> public static string DecodeQuotedPrintable(string s, Encoding e) { _curEncoding = e; Regex re = new Regex(@"=([a-fA-F0-9]{2})"); return re.Replace(s, new MatchEvaluator(ReDigit)); } static Encoding _curEncoding; /// <summary> /// Конвертирует "ХХ" в байтовый аналог /// </summary> /// <param name="match">"XX" формат</param> /// <returns></returns> static string ReDigit(Match match) { byte [] tmp = {Convert.ToByte(match.Groups[1].Value, 16)}; return "" + _curEncoding.GetString(tmp); } /// <summary> /// RFC 2047 /// </summary> /// <param name="s"<</param> /// <returns<</returns> public static string WordDecoder(string input) { string charset = ""; string src; string tmp; src = input; Match m = Regex.Match(input, @"(?<ew>(?<n>\=\?(?<charset>[^?]+)\?(?<encoding>[QqBb])\?(?<content>[^?]+)\?\=)(\r\n)*\s*)(?=(?<isnext>\=\?[^?]+\?[QqBb]\?[^?]+\?\=)*)", RegexOptions.Multiline); if (m.Success) { while (m.Success) { charset = m.Groups["charset"].Value; string encoding = m.Groups["encoding"].Value.ToLower(); switch(encoding) { case "q": tmp = m.Groups["content"].Value.Replace("_", " "); tmp = DecodeQuotedPrintable(tmp, GetEncoding(m.Groups["charset"].Value)); break; case "b": tmp = GetEncoding(charset).GetString(Convert.FromBase64String(m.Groups["content"].Value)); break; default: throw new ParseException("Неизвестный метод кодировки"); } src = src.Replace(((m.Groups["isnext"].Value.Length == 0) ? m.Groups["n"].Value : m.Groups["ew"].Value), tmp); m = m.NextMatch(); } return src; } return GetEncoding(charset).GetString(Encoding.Default.GetBytes(src)); } } }Листинг 3.8.
Формирование сообщений
Класс MessageFile.cs
namespace Mail.Providers { using System; using System.IO; using System.Diagnostics; using System.Text; /// <summary> /// Провайдер для .eml-файлов. /// </summary> public class MessageFile : Provider { const string FiveOctalTerm = "\r\n.\r\n"; FileStream fs = null; /// <summary> /// Конструктор. /// </summary> /// <param name="filename">Адрес к файлу.</param> public MessageFile(string filename) { fs = new FileStream(filename, FileMode.Open, FileAccess.Read); TempDirectory = Path.GetTempPath(); } /// <summary> /// Не реализовано /// </summary> /// <param name="i"></param> public override void DeleteMessage(uint index) { Debug.WriteLine("Не реализовано"); } string TruncateTail(string message) { if (!message.EndsWith(FiveOctalTerm)) { Debug.WriteLine("Последние 5 символов: {" + message.Substring(message.Length - 5) + "}"); throw new ResponseException("Неправильные символы конца сообщения."); } return message.Remove(message.Length — FiveOctalTerm.Length, FiveOctalTerm.Length); } /// <summary> /// Не реализовано. /// </summary> /// <param name="i"></param> public override Message GetMessage(uint index) { byte [] buf = new byte[fs.Length]; fs.Read(buf, 0, buf.Length); fs.Position = 0; string message = Utils.RemoveByteStuffedSequence(Encoding.ASCII.GetString(buf)); return new Message(this, message, index); } /// <summary> /// Этот метод необязателен. /// </summary> /// <param name="name"></param> /// <param name="pass"></param> public override void LogIn(string name, string pass) { Debug.WriteLine("Не реализовано"); } /// <summary> /// Закрытие потока. /// </summary> public override void Dispose() { try { Quit(); } catch { } GC.SuppressFinalize(this); } /// <summary> /// Закрытие FilеStream. /// </summary> public override void Quit() { fs.Close(); } } }Листинг 3.9.
Класс MaildropStatus.cs
using System.Collections; namespace Mail.Providers { /// <summary> /// Содержание информации о почтовом ящике (размер и количество сообщений). /// </summary> class MaildropStatus { internal uint messages; internal uint size; // internal Hashtable messagelist; /// <summary> /// Конструктор с параметрами: количество сообщений и размер. /// </summary> /// <param name="messages">Количество сообщений.</param> /// <param name="size">Размер сообщений.</param> public MaildropStatus(uint messages, uint size) { this.messages = messages; this.size = size; } } }Листинг 3.10.
Класс Pop3.csM
//#define _DEBUG using System; using System.IO; using System.Net; using System.Net.Sockets; using System.Diagnostics; using System.Collections; using System.Text; using System.Text.RegularExpressions; namespace Mail.Providers { /// <summary> /// Реализация протокола POP3 /// </summary> /// <example>Пример получения сообщения. /// <code> /// using (Pop3 pop3 = new Pop3("host")) /// { /// pop3.LogIn("Username", "Password"); /// Console.WriteLine("Количество сообщений:" + pop3.NumberOfMessages); /// /// using(Message msg = pop3.GetMessage(1)) // получение первого сообщения /// { /// Console.WriteLine("Тема: " + msg.Subject); /// } /// } /// </code> /// </example> public class Pop3 : Provider { #region Constants const int MaxReceiveSize = 1024; const int POP3DefaultPort = 110; const int SendTimeout = 60000; // в милисекундах. public int ReceiveTimeout = 2000000; // в милисекундах. public int PollTimeout = 100000; // в микросекундах. const string CRLF = "\r\n"; const string FiveOctalTerm = "\r\n.\r\n"; const string STAT_OK = "+OK"; const string STAT_ERR = "-ERR"; const char SPACE = ' '; const char CR = '\r'; #endregion Socket _socket = null; MaildropStatus _status = null; uint [] _messagelist = null; bool _authenticated = false; #region DEBUG functions FileStream GetDebugStream() { return new FileStream(@"C:\trace_response.log", FileMode.Append); } [Conditional("_DEBUG")] void Trace(byte [] str) { FileStream fs = GetDebugStream(); fs.Write(str, 0, str.Length); fs.Close(); } [Conditional("_DEBUG")] void Trace(string str) { FileStream fs = GetDebugStream(); fs.Write(Encoding.ASCII.GetBytes(str), 0, str.Length); fs.Close(); } #endregion #region Constructors /// <summary> /// Инициализация класса установленным по умолчанию портом (110) и установка адреса временной папки /// на текущую системную временную папку. /// </summary> /// <param name="server">IP адрес сервера.</param> public Pop3(string server) { _server = server; _port = POP3DefaultPort; TempDirectory = Path.GetTempPath(); } /// <summary> /// Инициализация класса а установленным по умолчанию портом (110). /// </summary> /// <param name="server">IP адрес сервера.</param> /// <param name="temp">Адрес временной папки.</param> public Pop3(string server, string temp) { _server = server; _port = POP3DefaultPort; TempDirectory = temp; } /// <summary> /// Инициализация класса . /// </summary> /// <param name="server">IP адрес сервера.</param> /// <param name="port">Номер порта.</param> public Pop3(string server, int port) { _server = server; _port = port; TempDirectory = Path.GetTempPath(); } /// <summary> /// Инициализация класса . /// </summary> /// <param name="server">IP-адрес сервера.</param> /// <param name="port">Номер порта.</param> /// <param name="temp">Адрес временной папки.</param> public Pop3(string server, int port, string temp) { _server = server; _port = port; TempDirectory = temp; } #endregion #region Public properties /// <summary> /// Возвращается значение true, если в почтовом ящике есть сообщения. /// </summary> public bool IsMessages { get { return (NumberOfMessages > 0); } } /// <summary> /// Количество сообщений в ящике. /// </summary> public uint NumberOfMessages { get { // not initialized if (_status == null) { GetStatus(); } return _status.messages; } } #endregion #region Method-Property substitution /// <summary> /// Получение количества сообщений. /// </summary> /// <returns></returns> public uint GetNumberOfMessages() { return NumberOfMessages; } public bool GetIsMessages() { return IsMessages; } #endregion /// <summary> /// Анализ количества строк, полученных от сервера после отправки команды STAT. /// </summary> /// <example>Команда STAT. В ответ на вызов команды сервер выдает положительный ответ "+OK", /// за которым следует количество сообщений в почтовом ящике и их общий размер в символах. /// Сообщения, которые помечены для удаления, не учитываются в ответе сервера. /// </example> void GetStatus() { CheckConnection(); Send("STAT"); string tmp = Receive(); string [] tokens = tmp.Split(new Char[] {SPACE, CR}, 4); try { _status = new MaildropStatus( Convert.ToUInt32(tokens[1], 10), Convert.ToUInt32(tokens[2], 10) ); } catch (Exception e) { throw new CoreException("Невозможно проанализировать ответ", e); } } /// <summary> /// Установка соединения с сервером. /// </summary> /// <param name="server">Название сервера.</param> /// <param name="port">Номер порта.</param> void EstablishConnection(string server, int port) { // Получение IP-адреса сервера. IPAddress ipadr = Dns.Resolve(server).AddressList[0]; IPEndPoint ephost = new IPEndPoint(ipadr, port); // Создание Socket для передачи данных по протоколу TCP. _socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); LingerOption linger = new LingerOption(true, 10); _socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, linger); // Установка времени ожидания. _socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.SendTimeout, SendTimeout); _socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.ReceiveTimeout, ReceiveTimeout); // Соединение с сервером. _socket.Connect(ephost); if (!_socket.Connected) { throw new CoreException("Сервер не найден: " + server); } } /// <summary> /// Проверка соединения и авторизации пользователя. /// </summary> void CheckConnection() { if (_socket == null || !_socket.Connected) { throw new CoreException("Соединение не установлено."); } if (!_authenticated) { throw new CoreException("Пользователь не аутентифицирован (Метод LogIn). "); } } /// <summary> /// Отправка команды на сервер. /// </summary> /// <param name="command">Текст команды.</param> void Send(string command) { // Все команды заканчиваются парой CRLF. command += CRLF; // Сервер работает с кодировкой ASCII. Encoding tmp = Encoding.ASCII; Byte [] buf = tmp.GetBytes(command); int total = buf.Length; while (total > 0) { total -= _socket.Send(buf, command.Length, SocketFlags.None); } } /// <summary> /// Анализ POP3-строки. /// </summary> /// <param name="str">Строка.</param> void AnalyseResponse(string str) { Trace(str); // Debug.WriteLine(str); if (str.StartsWith(STAT_ERR)) { string msg; int i = str.IndexOf(CRLF); if (i < 0) { msg = "Ответ сервера: " + STAT_ERR; } else { // Если ответ слишком большой, отсекаем его. msg = str.Substring(STAT_ERR.Length + 1, Math.Min(i - STAT_ERR.Length - 1, 79)); } throw new ResponseException(msg); } } /// <summary> /// Получение сообщения в POP3-формате. /// </summary> /// <param name="index">Номер сообщения.</param> /// <returns></returns> public StringReader DumpMessage(int index) { CheckConnection(); Send("RETR " + index); return new StringReader(Receive()); } /// <summary> /// Удаление символов конца сообщения. /// </summary> /// <param name="message">Сообщение.</param> /// <returns></returns> string TruncateTail(string message) { if (!message.EndsWith(FiveOctalTerm)) { Debug.WriteLine("Последние 5 символов: {" + message.Substring(message.Length — 5) + "}"); throw new ResponseException("Неправильные символы конца сообщения."); } return message.Remove(message.Length — FiveOctalTerm.Length, FiveOctalTerm.Length); } /// <summary> /// Получение существующих номеров сообщений. /// </summary> /// <returns>Массив с существующими индексами сообщений.</returns> /// <example>Команда LIST. Сервер выдает информацию о всех сообщениях, находящихся в почтовом ящике. /// Сообщения, помеченные для удаления, не перечисляются. /// </example> public uint[] ListMessages() { CheckConnection(); if (_messagelist == null) { Send("LIST"); string tmp = Receive(); tmp = TruncateTail(tmp); int start = tmp.IndexOf(CRLF); if (start > 0) { start += CRLF.Length; ArrayList l = new ArrayList(); Regex r = new Regex(@"\r\n"); string [] list = r.Split(tmp.Substring(start)); if (list.Length > 0) { foreach (string s in list) { string [] f = s.Split(new char [] {' '}, 2); l.Add(Convert.ToUInt32(f[0], 10)); } } if (l.Count > 0) { _messagelist = (uint [])l.ToArray(typeof(uint)); } else _messagelist = new uint[0]; } else _messagelist = new uint[0]; } return _messagelist; } /// <summary> /// Отправляет команду NOOP на сервер. /// </summary> /// <remarks> /// <para>Используется для поддержания сеанса с сервером.</para> /// </remarks> /// <example>Команда NOOP. POP3-сервер ничего не делает и всегда отвечает положительно. /// </example> public void SendNoop() { CheckConnection(); Send("NOOP"); string tmp = Receive(); } /// <summary> /// Возвращает уникальный идентификатор сообщения. /// </summary> /// <remarks> /// <para> /// Если сообщение помечено на удаление, оно не учитывается. /// </para> /// </remarks> /// <param name="index">Номер сообщения.</param> /// <returns>Уникальный идентификатор пользователя.</returns> public string GetMessageUniqueID(uint index) { CheckConnection(); Send("UIDL " + index); string tmp = Receive(); string [] f = tmp.Split(new char [] {' ', '\r', '\n'}, 4); return f[2]; } /// <summary> /// Получение заголовка сообщения. /// </summary> /// <param name="index">Сообщение.</param> /// <param name="liens">Количество первых строк.</param> /// <returns>Сообщение с анализированными заголовками.</returns> /// <example>Команда TOP. Если ответ сервера положительный, /// он передает заголовки сообщения и указанное количество строк из тела сообщения. /// </example> public Message GetMessageHeader(uint index, int top) { CheckConnection(); Send("TOP " + index + " " + top); string message = Receive(); message = Utils.RemoveByteStuffedSequence(message); return new Message(this, TruncateTail(message), index); } /// <summary>Удаление сообщения. /// </summary> /// <param name="index">Номер сообщения.</param> /// <example>Команда DELETE. POP3-сервер помечает указанное сообщение как удаленное, /// но не удаляет его, пока сессия не перейдет в режим UPDATE. /// </example> public override void DeleteMessage(uint index) { CheckConnection(); Send("DELE " + index); string tmp = Receive(); } /// <summary> /// Получение сообщения. /// </summary> /// <param name="index">Номер сообщения.</param> /// <returns>Сообщение.</returns> /// <example>Команда RETR. После положительного ответа сервер передает содержание сообщения. /// </example> public override Message GetMessage(uint index) { CheckConnection(); Send("RETR " + index); string message = ReceiveMessage(); message = Utils.RemoveByteStuffedSequence(message); return new Message(this, TruncateTail(message), index); } public void OnRecievedData( IAsyncResult ar ) { } /// <summary> /// Получение ответа сервера без проверки подлинности. /// </summary> /// <returns>Ответ сервера.</returns> StringBuilder UnsafeReceive() { StringBuilder tmp = new StringBuilder(); Encoding cenc = Encoding.ASCII; IAsyncResult asynResult; byte[] buf = new byte[1024]; int recv = 0; do { asynResult = _socket.BeginReceive(buf, 0, buf.Length, SocketFlags.None, null, null); if (asynResult.AsyncWaitHandle.WaitOne()) { recv = _socket.EndReceive(asynResult); string t = cenc.GetString(buf, 0, recv); tmp.Append(t); if (t.LastIndexOf(FiveOctalTerm) > 0) break; } } while(_socket.Poll(PollTimeout, SelectMode.SelectRead)); return tmp; } /// <summary> /// Получение ответа сервера без проверки подлинности. /// </summary> /// <returns>Ответ сервера.</returns> StringBuilder UnsafeReceiveMessage() { StringBuilder tmp = new StringBuilder(); Encoding cenc = Encoding.ASCII; IAsyncResult asynResult; byte[] buf = new byte[1024]; int recv = 0; do { asynResult = _socket.BeginReceive(buf, 0, buf.Length, SocketFlags.None, null, null); if (asynResult.AsyncWaitHandle.WaitOne()) { recv = _socket.EndReceive(asynResult); string t = cenc.GetString(buf, 0, recv); tmp.Append(t); //if (t.LastIndexOf(FiveOctalTerm) > 0) // break; } } while(!tmp.ToString().EndsWith(FiveOctalTerm)); return tmp; } /// <summary> /// Возвращение ответа сервера. /// </summary> /// <returns>Ответ сервера.</returns> string Receive() { StringBuilder tmp = UnsafeReceive(); string str = tmp.ToString(); AnalyseResponse(str); return str; } /// <summary> /// Возвращение сообщения в виде строки. /// </summary> /// <returns></returns> string ReceiveMessage() { StringBuilder tmp = UnsafeReceiveMessage(); string str = tmp.ToString(); AnalyseResponse(str); return str; } /// <summary> /// Аутентификация пользователя. /// </summary> /// <param name="username">Имя пользователя.</param> /// <param name="password">Пароль.</param> /// <example>После установки соединения сервер находится в режиме авторизации пользователя. /// Пользователь должен идентифицировать себя на сервере, используя команды USER и PASS. /// Сначала надо отправить команду USER, после которой в качестве аргумента следует имя пользователя. /// Если сервер отвечает положительно, то теперь необходимо отправить команду PASS, за которой следует пароль. /// <code> /// Client: USER username /// Server: +OK username /// Client: PASS mypass /// Server: +OK username /// </code> /// </example> void AuthenticateYourSelf(string username, string password) { Send("USER " + username); Receive(); Send("PASS " + password); Receive(); _authenticated = true; } /// <summary> /// Соединение с сервером и аутентификация пользователя. /// </summary> /// <param name="username">Имя пользователя.</param> /// <param name="password">Пароль.</param> public override void LogIn(string username, string password) { try { if (_socket != null) { Quit(); ResetVariables(); } // Установка соеденения. EstablishConnection(_server, _port); Receive(); // Получение приветствия от сервера. AuthenticateYourSelf(username, password); } catch (ShutdownException e) { throw new CoreException("Невозможно завершить предыдущий сеанс.", e); } catch (Exception e) { throw new CoreException("Вход невозможен", e); } } /// <summary> /// Закрытие транзакции на сервере. /// </summary> public override void Quit() { try { CheckConnection(); // Сервер завершает POP3-сессию и переходит в режим UPDATE. Send("QUIT"); // Ответ нас не интересует } catch (Exception e) { throw new ShutdownException("Невозможно покинуть транзакцию", e); } CloseSocket(); } /// <summary> /// Свойство закрытия соединения. /// </summary> void CloseSocket() { try { _socket.Shutdown(SocketShutdown.Both); _socket.Close(); // Свойство 'Connected' установлено в false, когда соединение закрыто. if (_socket.Connected) { throw new CoreException("При закрытии socket возникло исключение: " + Convert.ToString(System.Runtime.InteropServices.Marshal.GetLastWin32Error())); } _socket = null; } catch (SocketException e) { throw new CoreException("Невозможно закрыть socket", e); } } /// <summary> /// Сброс переменных. /// </summary> void ResetVariables() { _authenticated = false; _status = null; _messagelist = null; } /// <summary> /// Закрытие сеанса. /// </summary> public override void Dispose() { try { Quit(); ResetVariables(); } catch // Обработчик всех возникших исключений. { Debug.WriteLine("Невозможно закрыть socket"); } GC.SuppressFinalize(this); } } }Листинг 3.11.
Класс Provider.cs
namespace Mail.Providers { using System; /// <summary> /// Общий абстрактный класс для всех провайдеров. /// </summary> public abstract class Provider : IDisposable { /// <summary> /// Название сервера. /// </summary> protected string _server; /// <summary> /// Номер порта. /// </summary> protected int _port; /// <summary> /// Временная папка для записи временных файлов. /// </summary> string _tempdir; /// <summary> /// Метод авторизации пользователя. /// </summary> /// <param name="login">Имя пользователя.</param> /// <param name="password">Пароль.</param> public abstract void LogIn(string login, string password); /// <summary> /// Закрытие сеанса. /// </summary> public abstract void Quit(); /// <summary> /// Удаление сообщения. /// </summary> /// <param name="index">Номер сообщения.</param> public abstract void DeleteMessage(uint index); /// <summary> /// Получение сообщения. /// </summary> /// <param name="index">Номер сообщения.</param> public abstract Message GetMessage(uint index); /// <summary> /// Путь к временной папке. /// </summary> public string TempDirectory { get { return _tempdir; } set { _tempdir = value; } } /// <summary> /// Уничтожение объекта. /// </summary> abstract public void Dispose(); } }Листинг 3.12.
Обработка вложений. Класс AttachDescriptor.cs
using System; using System.IO; using System.Security.Cryptography; using System.Text; namespace Mail { /// <summary> /// Содержит методы и информацию о вложениях в письмо. /// </summary> public class AttachDescriptor { string _oldname; string _tmpfile; internal AttachDescriptor(string name, string dir) { _oldname = name; _tmpfile = dir + Guid.NewGuid(); } /// <summary> /// Декодирование файла. /// </summary> /// <param name="message">Текст сообщения с вложенным файлом.</param> /// <param name="transform">Формат трансформации.</param> internal void DecodeFile(string message, ICryptoTransform transform) { try { // Создаем временный файл. FileStream tf = new FileStream(_tmpfile, FileMode.Create, FileAccess.Write); // Создаем поток трансформации для временного файла. CryptoStream cs = new CryptoStream(tf, transform, CryptoStreamMode.Write); // Конвертируем строки в массив байтов Encoding enc = Encoding.ASCII; byte [] b = enc.GetBytes(message); // Записываем байты в поток трансформации. cs.Write(b, 0, b.Length); // Закрываем потоки. cs.Close(); tf.Close(); } // Обрабатываем возникшие исключения. catch(System.Exception e) { Console.WriteLine(e.ToString()); throw new ParseException("Невозможно декодировать содержимое файла", e); } } /// <summary> /// Закрываем и удаляем временный файл. /// </summary> internal void Close() { File.Delete(_tmpfile); } /// <summary> /// Возвращаем файловый поток из файла временного вложения. /// </summary> /// <returns></returns> public FileStream GetFile() { FileStream tf = new FileStream(_tmpfile, FileMode.Open, FileAccess.Read); return tf; } #region Public properties /// <summary> /// Название. /// </summary> public string Name { get { return _oldname; } } /// <summary> /// Временный файл. /// </summary> public string TempFile { get { return _tmpfile; } } /// <summary> /// Размер. /// </summary> public long Size { get { FileInfo fi = new FileInfo(_tmpfile); return fi.Length; } } #endregion } }Листинг 3.13.
Основной класс сообщения. Common.cs
namespace Mail { using System; using System.Collections; using System.IO; using System.Text; using System.Text.RegularExpressions; using System.Security.Cryptography; using Mail.Providers; /// <summary> /// Основной класс для <see cref="Mime"/> и <see cref="Message"/>. /// Содержит общую информацию и различные методы. /// </summary> public class Common { internal const string DCRLF = "\r\n\r\n"; internal const string CRLF = "\r\n"; internal const char Colon = ':'; internal const string MIMEE = "--"; internal string _message; internal long _size; internal Provider _pop3; public Provider Parent { get { return _pop3; } } /// <summary> /// Список sub-mimes. /// </summary> public Mime [] ChildMimes = new Mime[0]; /// <summary> /// Заголовки. /// </summary> internal Hashtable Headers = new Hashtable(); /// <summary> /// Содержит все заголовки из <see cref="Message"/> или <see cref="Mime"/> /// </summary> /// <remarks> /// Все заголовки должны быть в нижнем регистре. /// </remarks> public Hashtable AllHeaders { get { return Headers; } } /// <summary> /// Размер сообщения. /// </summary> public long GetSize() { return _size; } /// <summary> /// Подготовка строки в зависимости от кодировки сообщения. /// </summary> /// <param name="mes">Текст сообщения.</param> /// <returns></returns> internal string PreparedString(string mes) { string t; switch (TransferEncoding) { case "base64": t = DecodeMessage(mes, new FromBase64Transform()); break; case "quoted-printable": t = DecodeMessage(mes, new FromQuotedPrintableTransform()); break; default: t = mes; break; } return t; } /// <summary> /// Подготовка тела сообщения. /// </summary> /// <returns></returns> internal string PreparedBody() { return PreparedString(_message); } /// <summary> /// Декодируем сообщение. /// </summary> /// <param name="message">Текст сообщения.</param> /// <param name="transform">Тип трансформации.</param> /// <returns></returns> string DecodeMessage(string message, ICryptoTransform transform) { MemoryStream tf = new MemoryStream(); CryptoStream cs = new CryptoStream(tf, transform, CryptoStreamMode.Write); // конвертируем строки в массив байтов Encoding enc = Encoding.ASCII; byte [] b = enc.GetBytes(message); cs.Write(b, 0, b.Length); cs.Close(); string t = Utils.GetEncoding(Charset).GetString(tf.ToArray()); tf.Close(); return t; } /// <summary> /// Конструктор. /// </summary> /// <param name="parent">Родительский провайдер.</param> /// <param name="message">Текст, содержащий сообщение.</param> internal Common(Provider parent, string message) { if (parent == null) { throw new ArgumentNullException("parent"); } if (message == String.Empty) { throw new ArgumentException("empty string", "message"); } int end = FillHeaders(message); _size = message.Length; // исключаем заголовок из тела сообщения _message = message.Substring(end); _pop3 = parent; } /// <summary> /// Выбираем все заголовки и заполняем массив. /// </summary> /// <returns></returns> internal int FillHeaders(string message) { int start = 0; //message.IndexOf(CRLF) + CRLF.Length; //пропускаем 2 байта int headerend = message.IndexOf(DCRLF); string headers = message.Substring(start, headerend - start); GetHeaders(headers); // пропускаем секцию заголовков headerend += DCRLF.Length; return headerend; } /// <summary> /// Заполнение <see cref="Mime"/> массива. /// </summary> /// <returns></returns> protected bool MultipartMixed() { string b = GetBoundary(); if (b == String.Empty) return false; int s = _message.IndexOf(b); if (s < 0) { throw new ParseException("Can't find beginning MIME boundary: " + b); } ArrayList tmimes = new ArrayList(); while(true) { s += b.Length + CRLF.Length; int e = _message.IndexOf(b, s); if (e < 0) { if (_message.IndexOf(MIMEE, s - CRLF.Length, MIMEE.Length) < 0) { throw new ParseException("Неправильный MIME"); } break; } tmimes.Add(new Mime(_pop3, _message.Substring(s, e - s - CRLF.Length))); s = e; } ChildMimes = (Mime [])tmimes.ToArray(typeof(Mime)); return true; } /// <summary> /// Попытка извлечения значения 'boundary' из <see cref="ContentType"/>. /// </summary> /// <returns></returns> protected string GetBoundary() { Regex r = new Regex("boundary=[\\\"]?([^\\r\\\"]+)"); if (ContentType == null) { return String.Empty; } Match m = r.Match(ContentType); if (m.Success) { return "--" + m.Groups[1].ToString(); } else { return String.Empty; } } /// <summary> /// Все заголовки в нижнем регистре. /// </summary> /// <param name="top">Заголовок</param> void GetHeaders(string top) { Regex line = new Regex(@"\r\n(?![\t\x20])"); string [] col = line.Split(top); foreach (string s in col) { string [] fields = s.Split(new Char[] {':'}, 2); // Console.WriteLine(fields[0] + "}={" + fields[1] + "}"); if (fields.Length < 2) continue; fields[0] = fields[0].ToLower(); // перевод в нижний регистр fields[1] = fields[1].TrimStart(' '); // удаление ненужных пробелов if (Headers.ContainsKey(fields[0])) { object oldv = Headers[fields[0]]; ArrayList al = oldv as ArrayList; if (al == null) { al = new ArrayList(); al.Add(oldv); Headers[fields[0]] = al; } al.Add(fields[1]); } else { Headers.Add(fields[0].ToLower(), fields[1]); } } } #region Common headers public string Charset { get { Regex r = new Regex(@"charset=[""'\s]([^""'\s]+)"); Match m = r.Match(ContentType); if (m.Success) return m.Groups[1].Value; else return ""; } } protected string TransferEncoding { get { return ((string)Headers["content-transfer-encoding"]).ToLower(); } } /// <summary> /// Содержит тип текущей <see cref="Mime"/> секции или <see cref="Message"/>. /// </summary> public string ContentType { get { return (string)Headers["content-type"]; } } #endregion } }Листинг 3.14.
Класс Message.cs
namespace Mail { using System; using System.Text; using System.Text.RegularExpressions; using System.Collections; using System.Diagnostics; using Mail.Providers; /// <summary> /// Класс, который описывает сообщение, полученное с сервера. /// </summary> public class Message : Common, IDisposable { string _body; // Тип тела сообщения. BodyTypes _body_type = BodyTypes.Unknown; // Массив вложений. AttachDescriptor [] _attaches = null; /// <summary> /// Номер сообщения. /// </summary> public uint Index; /// <summary> /// Создание нового сообщения. /// </summary> /// <param name="parent">Ссылка на провайдер.</param> /// <param name="message">Текст сообщения, которое необходимо проанализировать.</param> /// <param name="index">Номер сообщения.</param> public Message(Provider parent, string message, uint index) : base(parent, message) { // Если индекс сообщения меньше нуля, то генерируется исключение типа ArgumentOutOfRangeException if (index < 1) { throw new ArgumentOutOfRangeException("index"); } Index = index; ParseContentType(); } /// <summary> /// Вложенные файлы. /// </summary> public AttachDescriptor [] Attachments { get { if (_attaches == null) { ArrayList al = new ArrayList(); GetAllAttachments(ChildMimes, al); _attaches = (AttachDescriptor [])al.ToArray(typeof(AttachDescriptor)); } return _attaches; } } /// <summary> /// Получение всех вложений. /// </summary> /// <param name="mimes"></param> void GetAllAttachments(Mime [] mimes, ArrayList al) { foreach (Mime m in mimes) { if (m.ChildMimes.Length == 0) { if (m._attach != null) al.Add(m._attach); } else { GetAllAttachments(m.ChildMimes, al); } } } // Анализ типа сообщения. void ParseContentType() { if (ContentType == null) { throw new ParseException("Определение типа сообщения (Content-Type пуст)"); } string type; int i = ContentType.IndexOf(";"); if (i < 0) { type = ContentType; } else { type = ContentType.Substring(0, i); } // В зависимости от типа сообщения анализируем текст и выбираем вложения. switch(type) { case "multipart/mixed": MultipartMixed(); break; case "multipart/alternative": MultipartMixed(); break; case "multipart/related": MultipartMixed(); break; case "text/html": _body = _message; _body_type = BodyTypes.HTML; break; case "text/plain": _body = _message; _body_type = BodyTypes.Text; break; } } /// <summary> /// Анализирует строку для получения e-mail. /// </summary> /// <param name="mail">Строка с адресом</param> /// <returns>адрес типа [mail@host.com], [mail@localhost] или [host@123.123.123.123]</returns> public string ExtractEmailFromAddress(string mail) { // mail@(ip)|(host) Regex ex = new Regex(@"([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|(([a-zA-Z0-9\-]+\.?)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)"); Match m = ex.Match(mail); if (!m.Success) { throw new ParseException("email не найден."); } return m.ToString(); } public void Dispose() { foreach(AttachDescriptor ad in Attachments) { ad.Close(); } _attaches = null; _body = null; _message = null; Headers = null; ChildMimes = null; GC.SuppressFinalize(this); } /// <summary> /// Перегруженный метод ToString. Возвращает информацию о сообщении. /// </summary> /// <returns></returns> public override string ToString() { StringBuilder sb = new StringBuilder(); sb.AppendFormat("Size: {0}b\r\n", GetSize()); sb.AppendFormat("From: '{0}', email: '{1}'\r\n", From, FromEmail); sb.AppendFormat("Subject: '{0}'\r\n", Subject); if (Attachments.Length > 0) { sb.Append("Attachments:\r\n"); foreach(AttachDescriptor ad in Attachments) { sb.Append("\tName: " + ad.Name + " Size: " + ad.Size + "\r\n"); } } return sb.ToString(); } // /// <summary> /// Возможные типы тела сообщения. /// </summary> public enum BodyTypes { Unknown, HTML, Text } /// <summary> /// Возвращение тела сообщения из MIME. /// </summary> /// <param name="type">Тип тела сообщения.</param> /// <param name="mimes">MIME</param> /// <returns></returns> string GetBodyFromMime(BodyTypes type, Mime [] mimes) { foreach (Mime m in mimes) { if (m.ChildMimes.Length == 0) { switch(type) { case BodyTypes.HTML: if (m.ContentType.IndexOf("text/html") > -1) { return m.PreparedBody(); } break; case BodyTypes.Text: if (m.ContentType.IndexOf("text/plain") > -1) { return m.PreparedBody(); } break; } } else { string r = GetBodyFromMime(type, m.ChildMimes); if (r != "") return r; } } return ""; } /// <summary> /// Открытый метод, возвращающий тело сообщения. /// </summary> /// <param name="type">Тип тела сообщения.</param> /// <returns></returns> public string GetBody(BodyTypes type) { if (_body_type == BodyTypes.Unknown) return GetBodyFromMime(type, ChildMimes); else return PreparedString(_body); } /// <summary> /// Возвращение тела сообщения. /// </summary> /// <returns></returns> public string Text { get { string text; if (_body_type == BodyTypes.Unknown) { text = GetBodyFromMime(BodyTypes.Text, ChildMimes); if (text == null || text.Trim() == "") text = Utils.ExtractTextFromHtml(GetBodyFromMime(BodyTypes.HTML, ChildMimes)); } else { text = PreparedString(_body); if (_body_type == BodyTypes.HTML) text = Utils.ExtractTextFromHtml(text); } return text.Trim(); } } #region Common headers /// <summary> /// Организация. /// </summary> public string Organization { get { return (string)Headers["organization"]; } } /// <summary> /// Копии письма. /// </summary> public string CC { get { return (string)Headers["cc"]; } } /// <summary> /// Дата сообщения. /// </summary> public string Date { get { return (string)Headers["date"]; } } /// <summary> /// Адрес отправителя. /// </summary> public string ReturnPath { get { return (string)Headers["return-path"]; } } /// <summary> /// Адрес отправителя. /// </summary> public string From { get { return (string)Headers["from"]; } } /// <summary> /// От кого. /// </summary> public string FromEmail { get { return ExtractEmailFromAddress((string)Headers["from"]); } } /// <summary> /// Кому /// </summary> public string To { get { return (string)Headers["to"]; } } /// <summary> /// Тема /// </summary> public string Subject { get { return Utils.WordDecoder((string)Headers["subject"]); } } /// <summary> /// Повтор /// </summary> public string ReplyTo { get { return (string)Headers["reply-to"]; } } #endregion } }Листинг 3.15.
Класс Mime.cs
//#define _DEBUG namespace Mail { using System; using System.Diagnostics; using System.Text; using System.IO; using System.Text.RegularExpressions; using System.Security.Cryptography; using Mail.Providers; public class Mime : Common { #region DEBUG FileStream GetDebugStream() { return new FileStream(@"C:\trace_mimes.log", FileMode.Append); } [Conditional("_DEBUG")] void Trace(string str) { FileStream fs = GetDebugStream(); byte [] b = Encoding.ASCII.GetBytes(str); fs.Write(b, 0, b.Length); fs.Close(); } #endregion internal AttachDescriptor _attach = null; /// <summary> /// Конструктор. /// </summary> /// <param name="pm">Провайдер.</param> /// <param name="message">Текст сообщения.</param> internal Mime(Provider pm, string message) : base(pm, message) { // если MIME не содержит MultipartMixed, то осуществляется попытка проверки на наличие вложений if (!MultipartMixed()) { FindAttachment(); } } /// <summary> /// Определение вложения сообщения. /// </summary> void FindAttachment() { // Если вложения нет, возвращаемся назад if (ContentDisposition == null) { return; } string [] cd = ContentDisposition.Split(new char [] {';'}, 2); switch(cd[0].ToLower()) { case "attachment": ExtractAttachment(cd[1]); break; case "inline": throw new CoreException("не реализовано"); default: throw new ParseException("Неизвестный ContentDisposition:" + cd[0]); } } /// <summary> /// Получение имени вложенного файла. /// </summary> /// <param name="filename"></param> /// <returns></returns> string GetAttachmentFilename(string filename) { Regex r = new Regex("filename=[\\\"]?([^\\r\\\"]+)"); Match m = r.Match(filename); if (!m.Success) { return String.Empty; } return Utils.WordDecoder(m.Groups[1].ToString()); } /// <summary> /// Извлечение прикрепленных файлов из сообщения. /// </summary> /// <param name="filename">Название временного файла.</param> void ExtractAttachment(string filename) { _attach = new AttachDescriptor(GetAttachmentFilename(filename), _pop3.TempDirectory); switch (TransferEncoding) { case "base64": _attach.DecodeFile(_message, new FromBase64Transform()); break; case "quoted-printable": _attach.DecodeFile(_message, new FromQuotedPrintableTransform()); break; default: Debug.WriteLine("Неизвестный тип кодировки."); break; } } #region Common headers /// <summary> /// Возвращение заголовка content-disposition, сообщающего о вложении. /// </summary> string ContentDisposition { get { return (string)Headers["content-disposition"]; } } #endregion } }Листинг 3.16.
Отправка сообщений — проект SendMail
Основной листинг MailSender.cs:
using System; using System.Web.Mail; namespace Mail { /// <summary> /// Класс, отвечающий за отправку почты. /// </summary> /// <example> /// MailSender mailSender = new MailSender("smtp.someserver.com"); /// MailMessage message = new MailMessage(); /// message.From = "from@someserver.com"; /// message.To = "to@someserver.com"; /// message.Subject = "subject"; /// message.Body = "body text"; /// message.BodyFormat = MailFormat.Text; /// mailSender.Send(message); /// </example> public class MailSender { private string _server; /// <summary> /// Конструктор. /// </summary> /// <param name="server">SMTP-сервер.</param> public MailSender(string server) { this._server = server; } /// <summary> /// Отправка почты. /// </summary> /// <param name="message">Письмо.</param> public void Send(MailMessage message) { // Инициализируем сервер отправки сообщений. SmtpMail.SmtpServer = this._server; // Отправляем сообщение. SmtpMail.Send(message); } /// <summary> /// Отправка почты с паролем. /// </summary> /// <param name="message">Письмо.</param> /// <param name="password">Пароль пользователя.</param> public void Send(MailMessage message, string password) { // Добавляем к сообщению имя пользователя и пароль на тот случай, // когда сервер исходящей почты требует аутентификацию. message.Fields.Add("http://schemas.microsoft.com/cdo/configuration/smtpauthenticate", 1); message.Fields.Add("http://schemas.microsoft.com/cdo/configuration/sendusername", message.From); message.Fields.Add("http://schemas.microsoft.com/cdo/configuration/sendpassword", password); // Отправляем сообщение. this.Send(message); } } }Листинг 3.17.
Интерфейс программы Ballet — проект MailApplication.
Создание новой учетной записи. Форма-контейнер Мастера
Форма CreateUserWizard представляет собой родительский контейнер для помещения в нее форм — шагов Мастера (см. рис. 3.25)
using System; using System.Drawing; using System.Collections; using System.ComponentModel; using System.Windows.Forms; namespace MailApplication { /// <summary> /// Summary description for CreateUserWizard. /// </summary> public class CreateUserWizard : System.Windows.Forms.Form { /// <summary> /// Required designer variable. /// </summary> private System.ComponentModel.Container components = null; public CreateUserWizard() { // // Required for Windows Form Designer support // InitializeComponent(); // // TODO: Add any constructor code after InitializeComponent call // } /// <summary> /// Clean up any resources being used. /// </summary> protected override void Dispose( bool disposing ) { if( disposing ) { if(components != null) { components.Dispose(); } } base.Dispose( disposing ); } #region Windows Form Designer generated code /// <summary> /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// </summary> private void InitializeComponent() { System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(CreateUserWizard)); // // CreateUserWizard // this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); this.ClientSize = new System.Drawing.Size(392, 266); this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); this.IsMdiContainer = true; this.Name = "CreateUserWizard"; this.StartPosition = System.Windows.Forms.FormStartPosition.CenterScreen; this.Text = "Создание новый учетной записи"; this.Load += new System.EventHandler(this.CreateUserWizard_Load); } #endregion private void CreateUserWizard_Load(object sender, System.EventArgs e) { UserIdentity identity = new UserIdentity(); CUWStep1 step1 = new CUWStep1(identity); step1.MdiParent = this; step1.Show(); } } }Листинг 3.18.
Первый шаг Мастера. Форма CUWStep1.cs
Значения свойства Name элементов управления этой формы приведены на рис. 3.27:
Полный листинг формы:
using System; using System.Drawing; using System.Collections; using System.ComponentModel; using System.Windows.Forms; namespace MailApplication { /// <summary> /// Summary description for CUWStep1. /// </summary> public class CUWStep1 : System.Windows.Forms.Form { private UserIdentity identity; private System.Windows.Forms.Label lblEmail; private System.Windows.Forms.TextBox txbEmail; private System.Windows.Forms.Label lblMailSample; private System.Windows.Forms.Label lblAliasSample; private System.Windows.Forms.TextBox txbAlias; private System.Windows.Forms.Label lblAlias; private System.Windows.Forms.Button btnNext; /// <summary> /// Required designer variable. /// </summary> private System.ComponentModel.Container components = null; public CUWStep1(UserIdentity identity) { InitializeComponent(); this.identity = identity; } /// <summary> /// Clean up any resources being used. /// </summary> protected override void Dispose( bool disposing ) { if( disposing ) { if(components != null) { components.Dispose(); } } base.Dispose( disposing ); } #region Windows Form Designer generated code /// <summary> /// Required method for Designer support — do not modify /// the contents of this method with the code editor. /// </summary> private void InitializeComponent() { System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(CUWStep1)); this.lblEmail = new System.Windows.Forms.Label(); this.txbEmail = new System.Windows.Forms.TextBox(); this.lblMailSample = new System.Windows.Forms.Label(); this.lblAliasSample = new System.Windows.Forms.Label(); this.txbAlias = new System.Windows.Forms.TextBox(); this.lblAlias = new System.Windows.Forms.Label(); this.btnNext = new System.Windows.Forms.Button(); this.SuspendLayout(); // // lblEmail // this.lblEmail.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.lblEmail.Location = new System.Drawing.Point(24, 16); this.lblEmail.Name = "lblEmail"; this.lblEmail.Size = new System.Drawing.Size(240, 23); this.lblEmail.TabIndex = 0; this.lblEmail.Text = "Введите адрес электронной почты"; this.lblEmail.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; // // txbEmail // this.txbEmail.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.txbEmail.Location = new System.Drawing.Point(24, 48); this.txbEmail.Name = "txbEmail"; this.txbEmail.Size = new System.Drawing.Size(240, 20); this.txbEmail.TabIndex = 1; this.txbEmail.Text = ""; // // lblMailSample // this.lblMailSample.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.lblMailSample.ForeColor = System.Drawing.SystemColors.AppWorkspace; this.lblMailSample.Location = new System.Drawing.Point(24, 72); this.lblMailSample.Name = "lblMailSample"; this.lblMailSample.Size = new System.Drawing.Size(240, 23); this.lblMailSample.TabIndex = 2; this.lblMailSample.Text = "Например, address@mail.com"; this.lblMailSample.TextAlign = System.Drawing.ContentAlignment.TopRight; // // lblAliasSample // this.lblAliasSample.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.lblAliasSample.ForeColor = System.Drawing.SystemColors.AppWorkspace; this.lblAliasSample.Location = new System.Drawing.Point(26, 160); this.lblAliasSample.Name = "lblAliasSample"; this.lblAliasSample.Size = new System.Drawing.Size(240, 23); this.lblAliasSample.TabIndex = 5; this.lblAliasSample.Text = "Например, Иван Васильевич"; this.lblAliasSample.TextAlign = System.Drawing.ContentAlignment.TopRight; // // txbAlias // this.txbAlias.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.txbAlias.Location = new System.Drawing.Point(26, 136); this.txbAlias.Name = "txbAlias"; this.txbAlias.Size = new System.Drawing.Size(240, 20); this.txbAlias.TabIndex = 2; this.txbAlias.Text = ""; // // lblAlias // this.lblAlias.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.lblAlias.Location = new System.Drawing.Point(26, 104); this.lblAlias.Name = "lblAlias"; this.lblAlias.Size = new System.Drawing.Size(240, 23); this.lblAlias.TabIndex = 3; this.lblAlias.Text = "Введите ваше имя "; this.lblAlias.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; // // btnNext // this.btnNext.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.btnNext.Location = new System.Drawing.Point(192, 192); this.btnNext.Name = "btnNext"; this.btnNext.TabIndex = 3; this.btnNext.Text = "Далее"; this.btnNext.Click += new System.EventHandler(this.btnNext_Click); // // CUWStep1 // this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); this.ClientSize = new System.Drawing.Size(292, 238); this.ControlBox = false; this.Controls.Add(this.btnNext); this.Controls.Add(this.lblAliasSample); this.Controls.Add(this.txbAlias); this.Controls.Add(this.txbEmail); this.Controls.Add(this.lblAlias); this.Controls.Add(this.lblMailSample); this.Controls.Add(this.lblEmail); this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); this.Name = "CUWStep1"; this.Text = "Шаг 1 из 3"; this.WindowState = System.Windows.Forms.FormWindowState.Maximized; this.ResumeLayout(false); } #endregion private void btnNext_Click(object sender, System.EventArgs e) { if(txbEmail.Text == "") { MessageBox.Show("Введите адрес электронной почты."); return; } else { identity.Alias = txbAlias.Text; identity.Mail = txbEmail.Text; CUWStep2 step2 = new CUWStep2(this.identity); step2.MdiParent = this.MdiParent; this.Close(); step2.Show(); } } } }Листинг 3.19.
Второй шаг Мастера. Форма CUWStep2.cs
Значения свойства Name элементов управления этой формы приведены на рис. 3.28.
Полный листинг формы:
using System; using System.Drawing; using System.Collections; using System.ComponentModel; using System.Windows.Forms; namespace MailApplication { /// <summary> /// Summary description for CUWStep2. /// </summary> public class CUWStep2 : System.Windows.Forms.Form { private UserIdentity identity; private System.Windows.Forms.Label lblPop3Sample; private System.Windows.Forms.TextBox txbPop3; private System.Windows.Forms.Label lblPop3; private System.Windows.Forms.Label lblPop3PortSample; private System.Windows.Forms.TextBox txbPop3Port; private System.Windows.Forms.Label lblPop3Port; private System.Windows.Forms.Button btnNext; /// <summary> /// Required designer variable. /// </summary> private System.ComponentModel.Container components = null; public CUWStep2(UserIdentity identity) { InitializeComponent(); this.identity = identity; } /// <summary> /// Clean up any resources being used. /// </summary> protected override void Dispose( bool disposing ) { if( disposing ) { if(components != null) { components.Dispose(); } } base.Dispose( disposing ); } #region Windows Form Designer generated code /// <summary> /// Required method for Designer support — do not modify /// the contents of this method with the code editor. /// </summary> private void InitializeComponent() { System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(CUWStep2)); this.lblPop3Sample = new System.Windows.Forms.Label(); this.txbPop3 = new System.Windows.Forms.TextBox(); this.lblPop3 = new System.Windows.Forms.Label(); this.lblPop3PortSample = new System.Windows.Forms.Label(); this.txbPop3Port = new System.Windows.Forms.TextBox(); this.lblPop3Port = new System.Windows.Forms.Label(); this.btnNext = new System.Windows.Forms.Button(); this.SuspendLayout(); // // lblPop3Sample // this.lblPop3Sample.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.lblPop3Sample.ForeColor = System.Drawing.SystemColors.AppWorkspace; this.lblPop3Sample.Location = new System.Drawing.Point(26, 64); this.lblPop3Sample.Name = "lblPop3Sample"; this.lblPop3Sample.Size = new System.Drawing.Size(240, 23); this.lblPop3Sample.TabIndex = 5; this.lblPop3Sample.Text = "Например, pop3.mail.com"; this.lblPop3Sample.TextAlign = System.Drawing.ContentAlignment.TopRight; // // txbPop3 // this.txbPop3.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.txbPop3.Location = new System.Drawing.Point(26, 40); this.txbPop3.Name = "txbPop3"; this.txbPop3.Size = new System.Drawing.Size(240, 20); this.txbPop3.TabIndex = 4; this.txbPop3.Text = ""; // // lblPop3 // this.lblPop3.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.lblPop3.Location = new System.Drawing.Point(26, 8); this.lblPop3.Name = "lblPop3"; this.lblPop3.Size = new System.Drawing.Size(240, 23); this.lblPop3.TabIndex = 3; this.lblPop3.Text = "Введите адрес сервера POP3:"; this.lblPop3.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; // // lblPop3PortSample // this.lblPop3PortSample.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.lblPop3PortSample.ForeColor = System.Drawing.SystemColors.AppWorkspace; this.lblPop3PortSample.Location = new System.Drawing.Point(26, 160); this.lblPop3PortSample.Name = "lblPop3PortSample"; this.lblPop3PortSample.Size = new System.Drawing.Size(240, 23); this.lblPop3PortSample.TabIndex = 8; this.lblPop3PortSample.Text = "Например, 110"; this.lblPop3PortSample.TextAlign = System.Drawing.ContentAlignment.TopRight; // // txbPop3Port // this.txbPop3Port.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.txbPop3Port.Location = new System.Drawing.Point(26, 136); this.txbPop3Port.Name = "txbPop3Port"; this.txbPop3Port.Size = new System.Drawing.Size(240, 20); this.txbPop3Port.TabIndex = 7; this.txbPop3Port.Text = "110"; // // lblPop3Port // this.lblPop3Port.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.lblPop3Port.Location = new System.Drawing.Point(26, 104); this.lblPop3Port.Name = "lblPop3Port"; this.lblPop3Port.Size = new System.Drawing.Size(240, 23); this.lblPop3Port.TabIndex = 6; this.lblPop3Port.Text = "Укажите почтовый порт:"; this.lblPop3Port.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; // // btnNext // this.btnNext.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.btnNext.Location = new System.Drawing.Point(192, 200); this.btnNext.Name = "btnNext"; this.btnNext.TabIndex = 9; this.btnNext.Text = "Далее"; this.btnNext.Click += new System.EventHandler(this.btnNext_Click); // // CUWStep2 // this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); this.ClientSize = new System.Drawing.Size(292, 238); this.Controls.Add(this.btnNext); this.Controls.Add(this.lblPop3PortSample); this.Controls.Add(this.txbPop3Port); this.Controls.Add(this.lblPop3Port); this.Controls.Add(this.lblPop3Sample); this.Controls.Add(this.txbPop3); this.Controls.Add(this.lblPop3); this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedDialog; this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); this.Name = "CUWStep2"; this.Text = "Шаг 2 из 3"; this.WindowState = System.Windows.Forms.FormWindowState.Maximized; this.ResumeLayout(false); } #endregion private void btnNext_Click(object sender, System.EventArgs e) { if(txbPop3.Text == "") { MessageBox.Show("Введите адрес сервера POP3"); } else { this.identity.Pop3 = txbPop3.Text; try { //Преобразовываем введенное значение в тип Int32 this.identity.Pop3Port = Int32.Parse(txbPop3Port.Text); CUWStep3 step3 = new CUWStep3(this.identity); step3.MdiParent = this.MdiParent; this.Close(); step3.Show(); } catch(Exception) { MessageBox.Show("Значение порта должно быть числом"); } } } } }Листинг 3.20.
Третий шаг Мастера. Форма CUWStep3.cs
Значения свойства Name элементов управления этой формы приведены на рис. 3.29.
Полный листинг формы:
using System; using System.Drawing; using System.Collections; using System.ComponentModel; using System.Windows.Forms; using System.Threading; using System.Security.Principal; namespace MailApplication { /// <summary> /// Summary description for CUWStep3. /// </summary> public class CUWStep3 : System.Windows.Forms.Form { private UserIdentity identity; private System.Windows.Forms.Label lblSmtpSample; private System.Windows.Forms.TextBox txbSmtp; private System.Windows.Forms.Label lblSmtp; private System.Windows.Forms.Button btnFinish; /// <summary> /// Required designer variable. /// </summary> private System.ComponentModel.Container components = null; public CUWStep3(UserIdentity identity) { InitializeComponent(); this.identity = identity; } /// <summary> /// Clean up any resources being used. /// </summary> protected override void Dispose( bool disposing ) { if( disposing ) { if(components != null) { components.Dispose(); } } base.Dispose( disposing ); } #region Windows Form Designer generated code /// <summary> /// Required method for Designer support — do not modify /// the contents of this method with the code editor. /// </summary> private void InitializeComponent() { System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(CUWStep3)); this.lblSmtpSample = new System.Windows.Forms.Label(); this.txbSmtp = new System.Windows.Forms.TextBox(); this.lblSmtp = new System.Windows.Forms.Label(); this.btnFinish = new System.Windows.Forms.Button(); this.SuspendLayout(); // // lblSmtpSample // this.lblSmtpSample.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.lblSmtpSample.ForeColor = System.Drawing.SystemColors.AppWorkspace; this.lblSmtpSample.Location = new System.Drawing.Point(26, 72); this.lblSmtpSample.Name = "lblSmtpSample"; this.lblSmtpSample.Size = new System.Drawing.Size(240, 23); this.lblSmtpSample.TabIndex = 8; this.lblSmtpSample.Text = "Например, smtp.mail.com"; this.lblSmtpSample.TextAlign = System.Drawing.ContentAlignment.TopRight; // // txbSmtp // this.txbSmtp.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.txbSmtp.Location = new System.Drawing.Point(26, 48); this.txbSmtp.Name = "txbSmtp"; this.txbSmtp.Size = new System.Drawing.Size(240, 20); this.txbSmtp.TabIndex = 7; this.txbSmtp.Text = ""; // // lblSmtp // this.lblSmtp.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left) | System.Windows.Forms.AnchorStyles.Right))); this.lblSmtp.Location = new System.Drawing.Point(26, 16); this.lblSmtp.Name = "lblSmtp"; this.lblSmtp.Size = new System.Drawing.Size(240, 23); this.lblSmtp.TabIndex = 6; this.lblSmtp.Text = "Введите адрес SMTP-сервера:"; this.lblSmtp.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; // // btnFinish // this.btnFinish.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right))); this.btnFinish.Location = new System.Drawing.Point(200, 208); this.btnFinish.Name = "btnFinish"; this.btnFinish.TabIndex = 9; this.btnFinish.Text = "Готово"; this.btnFinish.Click += new System.EventHandler(this.btnFinish_Click); // // CUWStep3 // this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); this.ClientSize = new System.Drawing.Size(292, 266); this.Controls.Add(this.btnFinish); this.Controls.Add(this.lblSmtpSample); this.Controls.Add(this.txbSmtp); this.Controls.Add(this.lblSmtp); this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); this.Name = "CUWStep3"; this.Text = "Шаг 3 из 3"; this.WindowState = System.Windows.Forms.FormWindowState.Maximized; this.ResumeLayout(false); } #endregion private void btnFinish_Click(object sender, System.EventArgs e) { if(txbSmtp.Text != "") { this.identity.Smtp = txbSmtp.Text; //Закрываем текущую форму this.Close(); Thread.CurrentPrincipal = new GenericPrincipal(this.identity, new string[]{"user"}); this.identity.Dispose(); //Закрываем родительскую форму CreateUserWizard Form.ActiveForm.Close(); } else { MessageBox.Show("Введите адрес сервера SMTP"); } } } }Листинг 3.21.
Главная форма mainForm.cs
Главная форма программы представляет собой контейнер для других форм и поэтому содержит сравнительно мало элементов управления. Значения свойства Name элементов управления приведены на рис. 3.30.
Полный листинг формы:
using System; using System.Drawing; using System.Collections; using System.ComponentModel; using System.Windows.Forms; using System.Data; using System.Threading; using System.Security.Principal; namespace MailApplication { /// <summary> /// Summary description for Form1. /// </summary> public class mainForm : System.Windows.Forms.Form { private System.Windows.Forms.MainMenu mainMenu; private System.Windows.Forms.MenuItem itemFile; private System.Windows.Forms.MenuItem itemUsers; private System.Windows.Forms.MenuItem itemNewUser; private System.Windows.Forms.MenuItem itemExit; private System.Windows.Forms.MenuItem itemEvent; private System.Windows.Forms.MenuItem itemGet; private System.Windows.Forms.MenuItem itemSend; private System.Windows.Forms.MenuItem itemSetting; /// <summary> /// Required designer variable. /// </summary> private System.ComponentModel.Container components = null; public mainForm() { // // Required for Windows Form Designer support // InitializeComponent(); // // TODO: Add any constructor code after InitializeComponent call // } /// <summary> /// Clean up any resources being used. /// </summary> protected override void Dispose( bool disposing ) { if( disposing ) { if (components != null) { components.Dispose(); } } base.Dispose( disposing ); } #region Windows Form Designer generated code /// <summary> /// Required method for Designer support — do not modify /// the contents of this method with the code editor. /// </summary> private void InitializeComponent() { System.Resources.ResourceManager resources = new System.Resources.ResourceManager(typeof(mainForm)); this.mainMenu = new System.Windows.Forms.MainMenu(); this.itemFile = new System.Windows.Forms.MenuItem(); this.itemNewUser = new System.Windows.Forms.MenuItem(); this.itemUsers = new System.Windows.Forms.MenuItem(); this.itemExit = new System.Windows.Forms.MenuItem(); this.itemEvent = new System.Windows.Forms.MenuItem(); this.itemGet = new System.Windows.Forms.MenuItem(); this.itemSend = new System.Windows.Forms.MenuItem(); this.itemSetting = new System.Windows.Forms.MenuItem(); // // mainMenu // this.mainMenu.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { this.itemFile, this.itemEvent}); // // itemFile // this.itemFile.Index = 0; this.itemFile.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { this.itemNewUser, this.itemUsers, this.itemExit}); this.itemFile.Text = "Файл"; // // itemNewUser // this.itemNewUser.Index = 0; this.itemNewUser.Shortcut = System.Windows.Forms.Shortcut.CtrlN; this.itemNewUser.Text = "Новый пользователь"; this.itemNewUser.Click += new System.EventHandler(this.itemNewUser_Click); // // itemUsers // this.itemUsers.Index = 1; this.itemUsers.Shortcut = System.Windows.Forms.Shortcut.CtrlL; this.itemUsers.Text = "Смена пользователя"; this.itemUsers.Click += new System.EventHandler(this.itemUsers_Click); // // itemExit // this.itemExit.Index = 2; this.itemExit.Shortcut = System.Windows.Forms.Shortcut.AltF4; this.itemExit.Text = "Выход"; this.itemExit.Click += new System.EventHandler(this.itemExit_Click); // // itemEvent // this.itemEvent.Enabled = false; this.itemEvent.Index = 1; this.itemEvent.MenuItems.AddRange(new System.Windows.Forms.MenuItem[] { this.itemGet, this.itemSend, this.itemSetting}); this.itemEvent.Text = "Действия"; // // itemGet // this.itemGet.Index = 0; this.itemGet.Shortcut = System.Windows.Forms.Shortcut.CtrlG; this.itemGet.Text = "Получить почту"; this.itemGet.Click += new System.EventHandler(this.itemGet_Click); // // itemSend // this.itemSend.Index = 1; this.itemSend.Shortcut = System.Windows.Forms.Shortcut.CtrlS; this.itemSend.Text = "Отправить письмо"; this.itemSend.Click += new System.EventHandler(this.itemSend_Click); // // itemSetting // this.itemSetting.Index = 2; this.itemSetting.Shortcut = System.Windows.Forms.Shortcut.CtrlO; this.itemSetting.Text = "Настройки"; this.itemSetting.Visible = false; // // mainForm // this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); this.ClientSize = new System.Drawing.Size(792, 545); this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon"))); this.IsMdiContainer = true; this.Menu = this.mainMenu; this.Name = "mainForm"; this.Text = "Ballet"; this.Closing += new System.ComponentModel.CancelEventHandler(this.mainForm_Closing); this.Load += new System.EventHandler(this.itemUsers_Click); } #endregion /// <summary> /// The main entry point for the application. /// </summary> [STAThread] static void Main() { Application.Run(new mainForm()); } private void itemExit_Click(object sender, System.EventArgs e) { this.Close(); } private void itemUsers_Click(object sender, System.EventArgs e) { selectUser select = new selectUser(); if(select.ShowDialog() != DialogResult.OK) //Запускаем главную форму. return; if(Thread.CurrentPrincipal.Identity is UserIdentity) ((UserIdentity)Thread.CurrentPrincipal.Identity).Dispose(); string userName = select.lstViewUsers.SelectedItems[0].Text; UserIdentity identity = new UserIdentity(userName); Thread.CurrentPrincipal = new GenericPrincipal(identity, new string[]{"user"}); //Вызываем метод ActivateEventItem this.ActivateEventItem(); } private void ActivateEventItem() { //Включаем доступность пункта меню "Действия". this.itemEvent.Enabled = true; } private void itemNewUser_Click(object sender, System.EventArgs e) { //Создаем экземпляр wizard формы CreateUserWizard CreateUserWizard wizard = new CreateUserWizard(); //Показываем форму: wizard.ShowDialog(); if(Thread.CurrentPrincipal != null) this.ActivateEventItem(); } private void mainForm_Closing(object sender, System.ComponentModel.CancelEventArgs e) { if(Thread.CurrentPrincipal.Identity is UserIdentity) ((UserIdentity)Thread.CurrentPrincipal.Identity).Dispose(); } private void itemSend_Click(object sender, System.EventArgs e) { PasswordPromt pass = new PasswordPromt(); if(pass.ShowDialog() != DialogResult.OK) return; SendMessage send = new SendMessage(); send.MdiParent = this; send.Show(); } private void itemGet_Click(object sender, System.EventArgs e) { PasswordPromt pass = new PasswordPromt(); if(pass.ShowDialog() != DialogResult.OK) return; MessageList list = new MessageList(); list.MdiParent = this; list.Show(); } } }Листинг 3.22.