#! /usr/bin/env ruby # Copyright (c) 2006 Robbert Haarman # # Permission is hereby granted, free of charge, to any person obtaining a # copy of this software and associated documentation files (the # "Software"), to deal in the Software without restriction, including # without limitation the rights to use, copy, modify, merge, publish, # distribute, sublicense, and/or sell copies of the Software, and to # permit persons to whom the Software is furnished to do so, subject to # the following conditions: # # The above copyright notice and this permission notice shall be included # in all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. # IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY # CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, # TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE # SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. require 'socket' ## Defaults nntp_port = 119 nntp_server = 'news.hnglo1.ov.home.nl' smtp_port = 25 #smtp_server = 'mail.tilbu1.nb.home.nl' smtp_server = 'mail.home.nl' sender = 'inglorion@inglorion.net' recipients = [] ## Convert line ends to CRLF (if necessary) def convert_to_crlf message message.gsub /([^\015])$/, "\\1\015" end ## Strip Bcc header def strip_bcc message message.gsub /^Bcc:.*\015\012/i, '' end ## Read and return a response from the server def read_response conn response = '' while true line = conn.gets response = response + line break if line =~ /^\d\d\d\s/ end response end ## Read server's response, and match it with the given regexp ## Return whether there was a match, and the response def expect regexp, conn response = read_response conn [response =~ regexp, response] end ## Send a request and verify the server's reply ## Returns whether the request was successful, and the reply def request message, regexp, conn conn.print message + "\015\012" expect regexp, conn end ## Try to send message from sender to recipients via server def post_mail message, sender, recipients, server, port = 25 conn = TCPSocket.new server, port ok, reply = expect /^220\s/, conn return [ok, reply] unless ok ok, reply = request 'EHLO ' + server, /^250\s/, conn return [ok, reply] unless ok ok, reply = request 'MAIL FROM: ' + sender, /^250\s/, conn return [ok, reply] unless ok recipients.each do |recipient| ok, reply = request 'RCPT TO: ' + recipient, /^250\s/, conn return [ok, reply] unless ok end ok, reply = request 'DATA', /^354\s/, conn return [ok, reply] unless ok ok, reply = request message + "\015\012.", /^250\s/, conn return [ok, reply] unless ok request 'QUIT', /^221\s/, conn conn.close [ok, reply] end ## Post a message to the news server def post_news message, server, port = 119 conn = TCPSocket.new server, port ok, reply = expect /^200\s/, conn return [ok, reply] unless ok conn.print "MODE READER\015\012" read_response conn ok, reply = request 'POST', /^340\s/, conn return [ok, reply] unless ok ok, reply = request message + "\015\012.", /^240\s/, conn return [ok, reply] unless ok request 'QUIT', /^205\s/, conn conn.close [ok, reply] end ## Parse command line i = 0 while i < ARGV.length if ARGV[i] == '-f' || ARGV[i] == '--from' i = i + 1 sender = ARGV[i] elsif ARGV[i] == '--nntp-port' i = i + 1 nntp_port = ARGV[i].to_i elsif ARGV[i] == '-n' || ARGV[i] == '--nntp-server' i = i + 1 nntp_server = ARGV[i] elsif ARGV[i] == '--smtp-port' i = i + 1 smtp_port = ARGV[i].to_i elsif ARGV[i] == '-s' || ARGV[i] == '--smtp-server' i = i + 1 smtp_server = ARGV[i] elsif ARGV[i] == '--' i = i + 1 recipients = recipients + ARGV[i..-1] break elsif ARGV[i] =~ /^-/ $stderr.puts 'Unknown option: ' + ARGV[i] exit 0x80 else recipients = recipients << ARGV[i] end i = i + 1 end ## Read message message = convert_to_crlf $stdin.read ## Split into headers and body headers, body = message.split "\015\012\015\012", 2 headers << "\015\012" ## Remove Bcc header headers = strip_bcc headers ## Reassemble message message = headers + "\015\012" + body ## Test if the message needs to be submitted as mail mail = recipients.length > 0 ## Test if the message needs to be submitted as news news = headers =~ /^Newsgroups: .+\015/ ## Exit status status = 0 ## Post message to mail server, if necessary if mail begin ok, reply = post_mail message, sender, recipients, smtp_server, smtp_port unless ok $stderr.puts "Mailing message failed." + "Server said:\n#{reply}" status = status | 1 end rescue SocketError, Errno::ECONNREFUSED => e $stdout.puts "Error connecting to " + "#{smtp_server}:#{smtp_port}:\n#{e}" status = status | 1 end end ## Post message to news server, if necessary if news begin ok, reply = post_news message, nntp_server, nntp_port unless ok $stderr.puts "Posting message to news server failed." + "Server said:\n#{reply}" status = status | 2 end rescue SocketError, Errno::ECONNREFUSED => e $stdout.puts "Error connecting to " + "#{nntp_server}:#{nntp_port}:\n#{e}" status = status | 2 end end exit status