|
При нажатии на Сумма в примере 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.



