From: jkeks
Newsgroups: email
Date: Mon, 10 May 2004 14:31:37 +0000 (UTC)
Subject: Альтернатива MIME::Parser и Email::Simple
MIME переделки
задумывался кто-нибудь окгда-нибудь о том, зачем в MIME придумали сложные
структуры данных ?
--a
--b
--b--
--c
--c--
--a
--a--
(это чтобы вы имели представление о чем я говорю)
В одном из FAQ валяется такая мысль, что мол кантора Netscape сильно усложнила
жизнь, когда сделала возможным внедрение в пиьсма этого стандарта MIME
т.е. много частей в одном.
На самом деле проблемма не сильно изменилась с тех времен, и сейчас я еще не
встречал концептуально правильных программ подходящщих к разбору структуры
писем, а значит все программы предоставляют КОРЯВЫЙ интерфейс к сложным
письмам.
А ведь непростые структуры появляются всего лишь на этапе, когда мы к письму
прикрепим атач.
А среднестатическое сложное письмо - это две части текст и html. Если к ним
прибавить аттач, то задача разбора станет уже необычной.
Как подходит к делу MIME::Parser ?
В документации упомянуто, что это средство способно работать с любыми сложными
структурами, однако единоразовый разбор письма почему-то парсит только первый
уровень письма (на нашем примере в результате мы получим parts --a, при этом
первая часть --a будет содержать нераспарсенные части --c и --b.
Получается что нам нужно самому выяснять нужно ли парсить дальше.
Меня как разработчика правильно-концептуального ядра и как в дальнейшем
прикладного программиста использующего данное ядро - такой расклад никак не
устраивает.
Я хочу чтобы я просто вызвал функцию и чтобы я получил список содержимого
письма в виде объекта или в виде сложной структуры или чего-то еще, неважно
чего но откуда можно достать любые данные письма, не обращаясь рекурсивно
каждый раз к ядру как только обнаружу очередную нераспарсенную часть.
Модуль Email::Simple подошел к проблемме абсолютно аналогично, вот и
собственно все самые известные обработчики MIME. Email::Simple правда имеет те
приемущества, что код парсера принципиально минимален, в сравнении с коровьей
лепешкой MIME::Parser. Однако Первый не решил проблемму рекурсивного вызова, и
единой структуры для всех частей письма.
Можно сказать - ну и правильно, нам это и не надо, ведь письма приходят в
более менее оговоренных стандартах, а значит атачи можно легко вытащить зная
заранее структуру и обращаясь сразу к нужным частям.
Глубокий маразм - скажу я вам. Раз уж ввели универсальный стандарт, так и
нужная правильна универсальная обработка.
Сам я подумал что надо бы самому накидать какой-нибудь простецкий модуль,
который бы скаляр в структуру разводил без понтов лишних. А как ?
В голову пришел красивый алгоритм, красивая структура.
И я уже было начал писать, как вдруг напоролся на проблемму:
Нужно создавать сложную структуру сопоставимую со структурой письма.
Объектную модель Perl я не стал использовать потому что незнаю ее.
А все должно было быть завязано на сложных структурах.
К тому же слава богу сам я уже не раз писал переборщики сложных структур,
поэтому впринципе это не проблемма, но все таки код перебора структуры - дело
небыстрое, нужно что-то более красивое.
И опять же концептуально правильное.
И после часа мучительных размышлений в голову пришла прекрасная мысль о том,
что ведь по сути не так важна структура писем, как простой доступ к
содержимому.Решение всплало само собой.. вся структура письма должна
раскрываться в линейную структуру, доступ к каждой части письма возможен через
простой цикл, без использования рекурсии. А Если возникнет необходимость в
анализе все-таки самой структуры, то тут можно прибегнуть к анализу
последовательностей частей.
Эта идея была положена в основу универсального парсера MIME, который входит в
сосотав ret WebOS, и является принципиально свободным от модулей данного
проекта, как и все сотальные модули данного проекта независимы.
В совокупности с остальными модулями проект теперь принял еще одно направление
парсинг MIME.
Ну и плюсом является то что в результате работы функции обработки письма
создается одна сложная линейная структура, которая в дальнейшем может быть
полностью вся созранена как одна запись в базу данных СУБД ret WebOS, которая
ставит под собой один из важнейших и важных задач: хранение сложных структур
(структура любой сложности может быть записана как одна единственная запись в
блоговой модели ret баз.
Становиться смешно, когда посмотрев на модуль MIME::Parser
затем смотришь на следующий кусок кода, который я написал в несколько
присядов:
sub ParseEmail
{
($msg)=@_;
$#main_structure=-1;
$main_structure[0]='';
push @stack,$msg;
# start stack working
while (scalar @stack>0)
{
$msg_process=pop @stack;
$msg_process =~ /(.*?($crlf))2(.*)/sm;
$head=$1;
$body=$3;
for (split /$crlf/, $head)
{
if (/^([^:]+):s*(.*)/)
{
$pos=$#main_structure;
$main_structure[$pos]{$1}=$2;
}
}
# found boundary Easiest way to get boundary in fucked MIME
$head =~ /s*boundary="?([^s"]+)"?/sm;
$boundary=$1;
# has we a boundary ?
if (length $boundary>4 and length $boundary<40)
{
# separate body to parts to stack
$tempo=-1;
@tempo=split (/--$boundary/, $body);
my $o=$#tempo;
for (my $i=1;$i<$o;$i++)
{push @stack,$tempo[$i];}
}
else
{
# save bady to massive
$pos++;
$main_structure[$pos]=$body;
}
}
}
Данный кусок парсит MIME, который ему передается в строке.
Причем из письма любой сложности получается сложная линейная структура, которую
можно всю перебрать в цикле!
Воощем все как написано выше.
Чего тут нету ?
Тут нет перекодировок, а для этого существуют готовые решения.
Возникла какая-то проблемма с парсингом сложных параметров таких как
Content-Type.Поэтому для параметров заголовка действует один
единственный алгоритм.
Заголовок: Текст
Где текст может содержать несколько параметров.
Я тут этого не учитывал (не считая boundary)
Вообще история с boundary оочень странная и я никак не пойму этот стандарт MIME,
зачем было разрешать вообще boundary писать как часть заголовка Content-Type,
а если уж на то пошло, то зачем было разрешать перед boundary указывать символ
crlf. Получается что все заголовки как заголовки начинаются исключительно с
новой строки, а тут не заголовок, а кусок от предидущего заголовка вдруг начался
с новой строки, вот и догадывайся где тут начало boundary а где начало
заголовка. Мало того Провел небольшой анализ писем.. и действительно
используются совершенно безбашенные врианты записи boundary
то в одной строке то в двух, то в кавычках то без, а уж какие символы
использованы для указания boundary - и вообще не стоит и писать.
Благо пробелов не видел.
Поэтому способ который приведен тут расчитан на то что в заголовке будет один
единственный указатель на boundary, поэтому соблюдение различных правил для нас
является перебором.Для специалистов тут уже действительно нужно взять RFC и
просто написать именно по нему.Мой же вариант будет работать в большинстве
случаев. А если что-то не так, то можно легко что-то изменить, ведь код
помещается на один листок формата А4 в читабельном виде. Изучайте - нехочу.
Можно сказать что это один из самых маленьких вариантов парсинга mIME с учетом
сложных структур и созданием таковых.
На сим завершаю лирику.
Пришла пора декодировать тело и заголовки и все сотальное.
Наши проделки: http://revda.biz
850 Прочтений • [Альтернатива MIME::Parser и Email::Simple (mime mail perl parser)] [08.05.2012] [Комментариев: 0]