Шрифт:
# Различные параметры, необходимые шлюзу между почтой и конференциями.
module Params
NEWS_SERVER = "usenet.fake1.org" # Имя новостного сервера.
NEWSGROUP = "comp.lang.ruby" # Зеркалируемая конференция.
LOOP_FLAG = "X-rubymirror: yes" # Чтобы избежать циклов.
LAST_NEWS_FILE = "/tmp/m2n/last_news" # Номер последнего прочитанного
# сообщения.
SMTP_SERVER = "localhost" # Имя хоста для исходящей почты.
MAIL_SENDER = "myself@fake2.org" # От чьего имени посылать почту.
# (Для списков, на которые подписываются, это должно быть имя
# зарегистрированного участника списка.)
mailing_list = "list@fake3.org" # Адрес списка рассылки.
end
Модуль
Params
содержит лишь константы, нужные обеим программам. Большая их часть не нуждается в объяснениях, упомянем лишь парочку. Во-первых, константа LAST_NEWS_FILE
содержит путь к файлу, в котором хранится идентификатор последнего прочитанного из конференции сообщения; эта «информация о состоянии» позволяет избежать дублирования или пропуска сообщений. Константа
LOOP_FLAG
определяет строку, которой помечаются сообщения, уже прошедшие через шлюз. Тем самым мы препятствуем возникновению бесконечной рекурсии, а заодно негодованию возмущенных обитателей сети, получивших тысячи копий одного и того же сообщения.
Возникает вопрос: «А как вообще почта поступает в программу
mail2news
?» Ведь она, похоже, читает из стандартного ввода. Автор рекомендует следующую настройку: сначала в файле .forward
программы sendmail
вся входящая почта перенаправляется на программу procmail
. Файл .procmail
конфигурируется так, чтобы извлекать сообщения, приходящие из списка рассылки, и по конвейеру направлять их программе mail2news
. Уточнить детали можно в документации, сопровождающей приложение RubyMirror (в архиве RAA). Если вы работаете не в UNIX, то придется изобрести собственную схему конфигурирования. Ну а все остальное расскажет сам код, приведенный в листингах 18.6 и 18.7.
Листинг 18.6. Перенаправление почты в конференцию
# mail2news: Принимает почтовое сообщение и отправляет
# его в конференцию.
require "nntp"
include NNTP
require "params"
# Прочитать сообщение, выделив из него заголовок и тело.
# Пропускаются только определенные заголовки.
HEADERS = %w{From Subject References Message-ID
Content-Type Content-Transfer-Encoding Date}
allowed_headers = Regexp.new(%{^(#{HEADERS.join("|")}):})
# Прочитать заголовок. Допускаются только некоторые заголовки.
# Добавить строки Newsgroups и X-rubymirror.
head = "Newsgroups: #{Params::NEWSGROUP}\n"
subject = "unknown"
while line = gets
exit if line /^#{Params::LOOP_FLAG}/о # Такого не должно быть!
break if line =~ /^s*$/
next if line =~ /^\s/
next unless line =~ allowed_headers
# Вырезать префикс [ruby-talk:nnnn] из темы, прежде чем
# отправлять в конференцию.
if line =~ /^Subject:\s*(.*)/
subject = $1
# Следующий код вырезает специальный номер ruby-talk
# из начала сообщения в списке рассылки, перед тем
# как отправлять его новостному серверу.
line.sub!(/\[ruby-talk:(\d+)\]\s*/, '')
subject = "[#$1] #{line}"
head << "X-ruby-talk: #$1\n"
end
head << line
end
head << "#{Params::LOOP_FLAG}\n"
body = ""
while line = gets
body << line
end
msg = head + "\n" + body
msg.gsub!(/\r?\n/, "\r\n")
nntp = NNTPIO.new(Params::NEWS_SERVER)
raise "Failed to connect" unless nntp.connect