Какой самый популярный IM-клиент в России? Конечно же, аська.
А в США? Конечно, MSN. Даже те, кто сидят на маках (в смысле, компьютерах), пользуются этим мессенджером. И даже те, кто сидят на маках опийных, тоже пользуются майкрософтовской системой быстрых сообщений.

 

Как оно работает?

Из этого следует простой вывод — хочешь внедриться в спам-бизнес, затрагивающий цивилизованные страны (те, где у людей есть деньги) — изучай их ПО, знай их протоколы передачи данных.

Когда я впервые (это было довольно давно) решил разобраться с работой протокола Microsoft Messenger, то оказалось, что в интернете не так уж и много информации по этой теме. При этом сама Microsoft по ходу пьесы притворилась Буратино, или тем, из чего это существо сделано — я беседовал с сотрудниками компании, искал в интернете блоги программистов, работающих в MS, просил их поделиться знаниями. Все бесполезно.

На некоторое время я оставил попытки узнать про протокол, но через полгодика наткнулся на библиотеку MSNPSharp (http://code.google.com/p/msnp-sharp/). Долгое время эта библиотека лежала у меня на диске мертвым грузом, но вот недавно на работе мне пришлось писать модуль, который должен был рассылать сообщения на MSN-клиенты. Я тут же вспомнил про MSNPSharp, скачал последнюю версию и разобрался с ней в два счета.

 

Ползучая тварь

Точек приложения для этой библиотеки много — от легального софта до реализации различных противозаконных программулин, вроде спамеров и червяков. Ну, например, работающих вот так:

  1. Пытаемся разослать приглашения на общения;
  2. Если кто-то отзывается, то пытаемся заставить пользователя принять и запустить файл. В свое время таким же образом распространялись вирусы по почте, и вполне успешно;
  3. Если кто-то повелся и запустил файл, то этот файл рассылает себя дальше.

Еще один сценарий — написать программу, которая будет подбирать пароли к аккаунтам из списка по словарю. Если аккаунт взломан (а чем больше аккаунтов, тем проще найти ламера с примитивным паролем), то можно прочитать содержимое контактов и разослать файл от имени ламера. Такая рассылка отработает намного эффективнее, потому что MSN’у пока доверяют.

 

Асинхронная модель

Все в библиотеке крутится вокруг класса Messenger, который создается банально и без параметров:

Messenger messenger = new Messenger();

Класс работает с протоколом в асинхронном режиме. И за это разработчикам MSNPSharp однозначно нужно пожать руку. Дело в том, что если бы класс работал в синхронном режиме, то на нас свалилась бы куча проблем по асинхронизации. Некоторые команды выполняются очень долго. Например, в момент скачивания контактов класс может капитально заснуть на несколько секунд. Если выполнять операцию синхронно, то в спячку ушло бы все приложение, а так — только класс.

Просто вызывай нужную функцию, и жди, когда она сгенерит соответствующее событие. Событий у класса довольно много. Вот минимальный набор, который может пригодиться в реальной жизни:

  • NameserverProcessor.ConnectionEstablished — генерируется, когда соединение удачно установлено;
  • Nameserver.SignedIn — мы вошли в систему;
  • Nameserver.SignedOff — удачно вышли, прямо как Винни-Пух, у которого все прекрасно входит и выходит;
  • Nameserver.AuthenticationError — авторизация не прошла;
  • ConversationCreated — начато общение с удаленным клиентом.

Достаточно установить обработчик на каждое событие, и можно начинать соединение с сервером. Хотя подожди. Сначала нужно указать свои данные — те, с которыми мы подключаемся к серверу. У класса мессенджера есть свойство Credentials, которое имеет одноименный тип.

У конструктора класса Credentials есть два параметра — почтовый ящик и пароль в чистом и красивом виде. Итак, параметры учетной записи, с помощью которой мы будем подключаться к серверу сообщений, прописываем следующим образом:

messenger.Credentials = new Credentials(
"youaccount@hotmail.com", "qwerty");

Если ты подцепился на все нужные нам обработчики событий и указал учетную запись, можно запускать процесс коннекта к серверу методом Connect();.

 

Поболтаем

Разговоры между незнакомыми абонентами категорически запрещены, и этот запрет представляет собой реальное западло для хакера. Чтобы кого-то вызвать на серьезный и жесткий разговор, нужно сначала направить приглашение, и только если твой invite приняли, можно посылать сообщения. Такой протокол должен предотвращать бесконтрольные рассылки заразы, которые происходят в классической e-почте. Правда, теоретически вполне реально написать червя, который будет распространяться по алгоритму Морриса, ведь все хорошее новое — это хорошо забытое старое. Вспомним, как работал один из самых нашумевших червей. Для взлома аккаунтов он использовал подбор паролей по словарю, который брал из *nix-системы. Так как в те времена о безопасности мало думали даже специалисты, червь удачно ломал системы.

Сейчас о безопасности думают больше, но только специалисты и продвинутые пользователи. Ламеров на просторах нашей Сети все еще очень много, поэтому можно попробовать повторить взлом. Проникая на компьютер, можно попытаться взломать MSN-аккаунты банальным перебором всех почтовых ящиков, которые есть в адресной книге. Если что-то взломалось, то подключаемся от имени лохоюзера и рассылаем себя других лохоюзерам Сети. Известный факт — когда файлы приходят от друзей, то их запускают намного чаще. Итак, чтобы отправить кому-то сообщение, мы сначала должны пригласить его в свой список друзейтоварищей.

Все, что касается адресной книги MSN, находится в классе Nameserver мессенджера. Чтобы пригласить нового друга, вызываем метод AddNewContact сервиса ContactService. Запутался? Проще один раз показать, чем десять раз рассказать:

Messenger.Nameserver.ContactService.
AddNewContact("pamela_anderson@hotmail.com");

Теперь о том, как получить список контактов. Контакты находятся в свойстве ContactList, которое является достаточно серьезным классом. Если тебе нужны все контакты, то обращайся к коллекции All (ContactList.All).

Помимо этого можно увидеть следующие типы контактов:

  • Allowed — разрешенные контакты;
  • BlockedList — здесь мы можем увидеть юзеров, которых заблокировали.

Сам по себе список не синхронизируется с сервером, и сразу после подключения все списки контактов будут пустыми. Дело в том, что эта операция происходит довольно медленно. Если нужно забрать с сервера свои контакты, то можно изменить свойство AutoSynchronize на true:
messenger.Nameserver.AutoSynchronize = true;

Если же скорость старта тебя особенно не волнует, то изменение свойства AutoSynchronize можно поместить в обработчике события ConnectionEstablished. Это вполне логично — сразу после установки подключения синхронизировать контакты.

 

Общение

Когда мы вошли в систему, то есть произошло событие SignedIn, мы можем изменять состояние и начинать общаться. Чтобы показать, что ты в сети и готов к общению, измени свое состояние на online следующим образом:

messenger.Owner.Status = PresenceStatus.Online;

Разумеется, для спама и прочих сомнительных с точки зрения законности мероприятий статус значения не имеет — сообщения можно слать и при PresenceStatus.Busy. Лично мне кажется, что с психологической точки зрения занятость даже более предпочтительна — если собеседник занят, но отправляет тебе что-то, ты не будешь приставать к нему с лишними вопросами о том, что это и зачем.

Теперь сама отправка сообщения. Этот процесс чуть более запутан. Для этого нужно создать новое общение, за которое отвечает класс Conversation:

Conversation conversation =
messenger.CreateConversation();

Теперь просто дожидаемся, когда сработает событие ConversationCreated. А вот уже когда новое общение создано, мы должны найти в списке контактов человека, которому хотим отправить послание, и пригласить его на разговор.

Допустим, что messenger-аккаунт человека, которому мы хотим отправить сообщение, находится в строковой переменной MsnAccountTo:

private void messenger_ConversationCreated(
object sender, ConversationCreatedEventArgs e)
{
if (e.Initiator != null)
{
foreach (MSNPSharp.Contact
contact in messenger.ContactList.All)
{
if (contact.Mail == MsnAccountTo)
{
e.Conversation.ContactJoined +=
new EventHandler<ContactEventArgs>(
ContactJoined);
e.Conversation.Invite(contact);
return;
}
}
messenger.Nameserver.ContactService.AddNewContact
(MsnAccountTo);
}
}

Код банален — мы просто ищем контакт в списке всех, кого мы знаем. Если чей-то почтовый ящик совпадает с тем, кого мы хотим нежно и ласково полюбить, то вызываем этого человека на разговор. Созданная беседа покоится в свойстве Conversation второго параметра события.

Мы должны подписаться на событие ContactJoined этого класса общения, чтобы узнать, когда удаленный пользователь готов пообщаться:

e.Conversation.ContactJoined +=
new EventHandler<ContactEventArgs>(ContactJoined);

А приглашение на этот разговор делается вызовом метода Invite и указанием ящика бедолаги:

e.Conversation.Invite(contact);

Тут нужно быть внимательным и аккуратным. Событие ConversationCreated может вызываться несколько раз. Я не понял, с какого перепуга это происходит, но факт есть факт — приходится гасить повторяющуюся генерацию события. Это можно сделать, например, вводя дополнительную булеву переменную, которая будет устанавливаться при создании общения и гаситься после обработки события. Если переменная не установлена, то игнорировать событие.

Но и это еще не все. Теперь в недрах библиотеки снова начинается асинхронный для нас процесс, по завершению которого вызывается событие ContactJoined. И вот в нем мы уже можем отправить пользователю сообщение. Следующий пример показывает, как отправить простое текстовое послание:

private void ContactJoined(object sender,
ContactEventArgs e)
{
TextMessage message =
new TextMessage(currentmessage);
(sender as Conversation).SendTextMessage(message);
}

В первой строке мы подготавливаем текстовое сообщение к отправке. Оно должно иметь тип класса TextMessage. Конструктору этого класса мы банально передаем строку текста.
Так как событие генерирует класс Conversation, то первый параметр как раз на него и указывает, и мы можем его использовать. Например, для вызова метода SendTextMessage с целью непосредственной отправки сообщения.

На уже созданном классе Conversation и пришедшем на разговор удаленным клиентом, можно отсылать несколько сообщений подряд. Если пользователь не в сети, Conversation все равно будет создан.

 

Итого

Вот и все. Еще раз повторю, что MSN реально популярен в США — лишь однажды я видел контору, в которой использовали Skype, но при ближайшем рассмотрении оказалось, что большинство ее программистов сидят в Петербурге. На диске к журналу ты найдешь небольшой класс-помощник, который упрощает работу с библиотекой и сводит отправку сообщений к вызову всего одного метода, если не считать конструктора, который вызывается автоматом при инициализации объекта. В большинстве простых ситуаций этого класса будет достаточно.

Оставить мнение

Check Also

LUKS container vs Border Patrol Agent. Как уберечь свои данные, пересекая границу

Не секрет, что если ты собрался посетить такие страны как США или Великобританию то, прежд…