Программизм
 
Программизм
На главную | Графомания | Программизм | Книги | Всячина | Скачать | Ъ?  

Скачивание почты через web-интерфейс

Многие из тех, кто работает в крупных компаниях, предпочитают получать личную почту не в рабочий ящик (типа vassily_pouppkine@bigcompany.com), а в специальный маленький личный ящичек, заведённый на одной из бесплатных почтовых служб.

Одно из главных достоинств этих служб в том, что для чтения почты совсем не обязательно иметь специальную почтовую программу — достаточно зайти на web-сайт почтовой службы броузером. Такой подход хорош, когда приходится читать почту из разных случайных мест — интернет-кафе, компьютеров знакомых и т.п. Если же почту читать из одного места, то пользоваться почтовой программой (например, The Bat!) гораздо удобнее.

Казалось бы, в чём проблема — все почтовые службы предоставляют доступ к ящикам по протоколам pop3/smtp! но я не случайно заговорил о «сотрудниках крупных компаний» — зачастую у них все сервисы, кроме http, перекрыты. Именно им призван помочь описанный здесь скрипт, сохраняющий письма с бесплатных ящиков на локальный диск.

Первое, что приходит на ум, — написать программу на Perl, открывающую http-соединение, скачивающую файл... Но много ли найдётся людей, у которых установлен Perl? Поэтому, чтобы программа была универсальной и доступной, писать её следует на чём-нибудь общедоступном. Например, на WSH.

Windows Scripting Host — революционная технология Microsoft, которая... На самом деле, это всего лишь интерфейс для интерпретаторов командных языков и их расширений. Входит в Windows 98/ME/2000/XP, а также в NT Option Pack. В комплект поставки входят интерпретаторы двух языков — JScript И VBScript. Первый — Microsoft’овская версия JavaScript, второй — нечто очень похожее с синтаксисом, напоминающим Visual Basic. Отличия этих языков крайне незначительны. Учебников по ним в сети море, поэтому на синтаксисе останавливаться не имеет смысла. Расширяются возможности языка при помощи ActiveX-объектов. Найти информацию о расширениях можно в MSDN или на сайте ScriptInfo. Искать дополнительные источники нужно, т.к. документация в MSDN не совсем полная.

Избрав в качестве исходного языка JScript, мы сразу убиваем ещё одного зайца: вместо формирования http-запросов будем использовать ActiveX-компонент Internet Explorer, который сам позаботится о том, чтобы сохранять cookies и данные форм.

Сразу предупреждаю, что приведённая здесь программа — первая, написанная мной на JScript. Возможно, на некоторых вещях я остановлюсь более подробно, чем надо — не судите строго. Возможно, некоторые вещи сделаны не оптимально — комментарии приветствуются.

Рассмотрим сценарий чтения почты:

  1. Открыть заглавную страницу почтовой службы.
  2. Ввести имя и пароль, отправить эту информацию на сервер.
  3. Перейти в папку «Входящие».
  4. Последовательно перебрать все письма в этой папке.
  5. Сохранить письма на диск.
  6. Удалить письма с сервера.

Чтобы письмо было удобнее читать, желательно сохранить его без рекламы спонсора, баннеров и прочего мусора. Для этого на Яndex’е, например, в каждом письме есть ссылка «версия для печати», а в web-интерфейсе почтовой службы net.ru — ссылка «undecoded letter», то есть готовое письмо в виде, пригодном для импорта в почтовую программу. Скрипт должен пройти по этой ссылке и сохранить письмо без мусора.

Итак, вот обещанный скрипт, а потом будут комментарии:

// константы для Internet Explorer
var navOpenInNewWindow = 1;
var navNoHistory = 2;
var navNoReadFromCache = 4;
var navNoWriteToCache = 8 ;

var READYSTATE_UNINITIALIZED = 0;
var READYSTATE_LOADING = 1;
var READYSTATE_LOADED = 2;
var READYSTATE_INTERACTIVE = 3;
var READYSTATE_COMPLETE = 4;


// hardsign - для проектов с хостингом на net.ru
var USER_NAME = "hardsign@hardsign.com";
var PASSWORD = "********";
var START_URL = "http://mail.hardsign.com/";
var C_USER_NAME = "Username";
var C_PASSWORD = "Password";
var INBOX = "InBox";
var SUBMIT = "login";
var MESSAGE = "Message\\.wssp\\?Mailbox=INBOX&MSG=[0-9]+$";
var PLAIN = "MessagePart/INBOX/[0-9]+-P\\.txt";
var DELETE = "href";
var DELETE_NAME = "Mailbox.wssp\\?Mailbox=INBOX&MSG=[0-9]+&Delete=";

// Яndex-почта
var USER_NAME = "hardsign";
var PASSWORD = "********";
var START_URL = "http://mail.yandex.ru/login";
var C_USER_NAME = "login";
var C_PASSWORD = "passwd";
var INBOX = "Входящие";
var SUBMIT = "submit";
var MESSAGE = "msg\\?mesid=[0-9]+&folder=[0-9]+";
var PLAIN = "msg\\?mesid=[0-9]+&printit=yes";
var DELETE = "button";
var DELETE_NAME = "delete";

// mail.ru
var USER_NAME = "hardsign";
var PASSWORD = "********";
var START_URL = "http://www.mail.ru/";
var C_USER_NAME = "Login";
var C_PASSWORD = "Password";
var INBOX = "ВХОДЯЩИЕ";
var SUBMIT = "";
var MESSAGE = "readmsg\\?id=[0-9]+";
var PLAIN = "readmsg\\?id=[0-9]+&template=printmsg\\.tmpl";
var DELETE = "href";
var DELETE_NAME = "movemsg\\?remove&id=[0-9]+";


var ie = WScript.CreateObject("InternetExplorer.Application");
ie.Visible = true;


function GoTo(url) {
  with (ie) {
    if (url!="") Navigate(url);
    while (ReadyState==READYSTATE_COMPLETE) 
      WScript.Sleep(10);
    while (ReadyState!=READYSTATE_COMPLETE) 
      WScript.Sleep(10);
  }
}


WScript.Echo("Logging in...");
GoTo(START_URL);
with (ie.Document) {
  all[C_USER_NAME].value = USER_NAME;
  all[C_PASSWORD].value = PASSWORD;
  if (SUBMIT!="") all[SUBMIT].click(); 
  else forms(0).submit();
}
GoTo("");

WScript.Echo("Searching for inbox...");
var href = "";
with (ie.Document) {
  for (i = 0; i<links.length; i++) {
    if (links(i).innerText==INBOX) {
      href = links(i).href;
      break;
    }
  }
}
if (href=="") {
  WScript.Echo("ERROR: inbox not found!");
  ie.Quit();
  WScript.Quit();
}
GoTo(href);

WScript.Echo("Reading messages...");
var regexp = new RegExp();
regexp.compile(MESSAGE.toUpperCase());
var letters = new Array();
with (ie.Document) {
  for (i = 0; i<links.length; i++) {
    if (regexp.test(links[i].href.toUpperCase())) {
      var found = false;
      for (j = 0; j<letters.length; j++)
        if (letters[j]==links[i].href) { 
          found = true; 
          break; 
        }
      if (!found) letters[letters.length] = links[i].href;
    }
  }
}


WScript.Echo(letters.length+" messages found!");
regexp.compile(PLAIN);
var fs = new ActiveXObject("Scripting.FileSystemObject");
var curDate = new Date();
regexp.compile(PLAIN.toUpperCase());
for (msg = 0; msg<letters.length; msg++) {
  WScript.Echo("  Transferring message #"+msg);
  GoTo(letters[msg]);
  with (ie.Document) {
    for (i = 0; i<links.length; i++) {
      if (regexp.test(links[i].href.toUpperCase())) {
        GoTo(links[i].href);
        if (charset!="windows-1251") {
          charset = "windows-1251";
          ie.Refresh();
          WScript.Sleep(100);
          while (readyState!="complete") 
            WScript.Sleep(100);
        }
        file = fs.OpenTextFile(
          msg+"-"+curDate.getTime()+".msg",
          2,
          true
        );
        try {
          file.Write(body.innerText);
          file.WriteLine();
          GoTo(letters[msg]); // ie.GoBack(); GoTo("");
          if (DELETE=="href") {
            var dregexp = new RegExp();
            dregexp.compile(DELETE_NAME.toUpperCase());
            for (j = 0; j<links.length; j++) 
              if (dregexp.test(links[j].href.toUpperCase())) {
                GoTo(links[j].href);
                break;
              }
          } else if (DELETE=="button") {
            var btn = all[DELETE_NAME];
            if (btn.length!=0) btn = btn[0];
            btn.click();
            GoTo("");
          }
        } catch (E) {
          WScript.Echo("  EXCEPTION: "+E.message);
        }
        break;
      }
    }
  }
}

ie.Quit();
WScript.Echo("Done!");

Чтобы начать работу, выберите один из блоков переменных, где задаются настройки скрипта — для mail.ru, Яndex’а или net.ru и впишите туда название своего почтового ящика и пароль. Если вы пытаетесь адаптировать скрипт для другой почтовой службы, то вот что надо записать в переменные:

  • USER_NAME — название вашего почтового ящика;
  • PASSWORD — пароль к вашему почтовому ящику;
  • START_URL — адрес страницы, с которой начинается работа с почтой;
  • C_USER_NAME — название элемента input, куда вводится имя пользователя;
  • C_PASSWORD — название элемента input, куда вводится пароль;
  • SUBMIT — название кнопки, на которую нужно нажать, чтобы отправить регистрационную форму на сервер. Если название оставить пустым, будет вызван метод forms(0).submit();
  • INBOX — название ящика с входящими сообщениями. Регистрозависимое!
  • MESSAGE — регулярное выражение, которому должны удовлетворять ссылки из ящика на письма;
  • PLAIN — регулярное выражение, которому должны удовлетворять ссылки из писем на их версии для печати.
  • DELETE — если для того, чтобы удалить письмо, надо из письма пройти по ссылке, впишите сюда href, если надать на кнопку — button. Если не хотите удалять письма с сервера, вставьте пустую строку.
  • DELETE_NAME — регулярное выражение, которому должны удовлетворять ссылки из писем на их удаление или имя кнопки, которую надо нажать.

Первым делом надо создать объект InternetExplorer.Application. Кстати, если не устанавливать ему свойство visible в true, то вся работа будет происходить незаметно для пользователя. Однако делать этого я бы не советовал.

Функция GoTo(), как несложно догадаться, открывает переданный ей URL. Сначала она ждёт, чтобы броузер начал скачивать документ, а затем ждёт полного окончания загрузки. Кстати, функция Sleep() в MSDN не описана, но, тем не менее, она есть и работает. Ставить задержку больше 10 миллисекунд не стоит, т.к. иногда переход происходит практически мгновенно. Но и совсем выкидывать Sleep() тоже не нужно — процессор надо освобождать.

Затем, как несложно догадаться, заполняем поля login и password, загружаем страницу с перечнем папок и ищем на ней папку с входящими сообщениями.

Ну, а дальше всё совсем просто. Собираем все ссылки, ведущие на письма, проходимся по ним, находим ссылку на версию для печати, переходим туда и сохраняем полученный текст.

Обратите внимание, что ссылки на письма проверяются на наличие дубликатов — в почтовой системе net.ru из ящика к письму ведут две ссылки. Естественно, сохраняется всё в несортированный массив, а поиск используется линейный — не те объёмы, чтобы огород городить.

В файл записывается body.innerText, а не body.innerHTML, ибо то, что получается при сохранении HTML, в почтовую программу импортировать невозможно. Впрочем, вам может больше понравиться именно HTML.

Если кодировка определена неправильно, то возможно, что Internet Explorer не сможет корректно сохранить текст в файл. В этом случае будет брошено исключение. Чтобы поймать его, применяется конструкция try .. catch, которая хорошо знакома программистам на Java, но в справочнике по JScript в MSDN не описана. Правда, в большинстве случаев изменение свойства Document.charset спасает ситуацию.

После сохранения письма скрипт возвращается на предыдущую страницу и удаляет письмо. Обратите внимание, что кнопка кликается не сама по себе — берётся первый элемент массива. Это помогает в тех случаях, когда на странице две кнопки с одинаковым именем, как, например, на Яndex’е.

В целом, как мне кажется, получилась приличная поделка. Если кому-то пригодится, буду рад. А ещё больше буду рад, если кого-то эта статья заставит почитать соответствующие мануалы.

Кстати, вероятно, похожими скриптами пользуются спаммеры, массово регистрирующие ящики на бесплатных службах типа nldftwkod@mail.ru и рассылающие с них всякий мусор. Однако против них придумали достаточно эффективную защиту — при регистрации надо ввести текст, нарисованный на картинке. Пример такой защиты можно найти на Hotmail и Bee Online.

22.01.2003

Бесплатные почтовые службы* (ссылки открываются в новом окне)


* В лучших традициях Домашней Страницы Васи Пупкина™, но удержаться я не мог, к тому же здесь это вроде как в тему...
Поиск
См. также

я попытаюсь по возможности просто рассказать о семействе алгоритмов Брезенхема, а также приведу готовый к использованию код на JavaScript... »»»

Очевидно, что char поместится в int. Во многих моделях памяти размер указателя также равен размеру int. Следовательно, структуру можно заменить массивом... »»»

архив с драйвером занимает около 1.4 M. Те файлы, которые нам необходимы, в неархивированном виде занимают около 900 K... »»»

Рекомендую

e.g.Orius’
Игорь Иртеньев
Вячеслав Шевченко

Copyright notice

ъ) Все материалы, размещённые на странице, являются неотъемлемой собственностью автора с вытекающими отсюда правами, как ©, так и (ъ). Некоммерческое их распространение всячески приветствуется, разумеется, при условии сохранения ссылки на оригинал. Что касается коммерческого использования — пишите письма, договориться можно всегда.

Удивительное рядом

lj userhardsign
Закладки Карта Королёва

Пишите письма

Счётчики

XPEHOMETP™ Рейтинг@Mail.ru