From c02a2878b2eaadaf779e02dec375c2f0db3adff7 Mon Sep 17 00:00:00 2001 From: Christian Neukirchen Date: Sun, 25 Sep 2016 21:04:58 +0200 Subject: contrib: add msuck and mblow for NNTP support --- contrib/mblow | 36 +++++++++++++++ contrib/msuck | 137 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 173 insertions(+) create mode 100755 contrib/mblow create mode 100755 contrib/msuck (limited to 'contrib') diff --git a/contrib/mblow b/contrib/mblow new file mode 100755 index 0000000..d151504 --- /dev/null +++ b/contrib/mblow @@ -0,0 +1,36 @@ +#!/usr/bin/ruby +# mblow - post an article via NNTP + +require 'socket' +require 'optparse' + +params = ARGV.getopts("s:") + +port = 119 +if params["s"] =~ /(.*):(.*)/ + params["s"] = $1 + port = Integer($2) +end + +SERVER = params["s"] || ENV["NNTPSERVER"] || "news" + +nntp = TCPSocket.new SERVER, port + +msg = nntp.gets +abort msg unless msg =~ /^200 / + +nntp.write "POST\r\n" +msg = nntp.gets + +abort msg unless msg =~ /^340 / + +while line = gets + line.chomp! + line.sub!(/\A\./, '..') + nntp.write(line + "\r\n") +end + +nntp.write(".\r\n") +msg = nntp.gets + +abort msg unless msg =~ /^240 / diff --git a/contrib/msuck b/contrib/msuck new file mode 100755 index 0000000..60b53e6 --- /dev/null +++ b/contrib/msuck @@ -0,0 +1,137 @@ +#!/usr/bin/ruby +# msuck - suck NNTP groups into Maildirs +# +# msuck [-s NNTPSERVER[:PORT]] [-d BASEDIR] [-l LIMIT] GROUPS... to fetch GROUPS +# msuck [-s NNTPSERVER[:PORT]] -L to list all groups + +require 'socket' +require 'fileutils' +require 'optparse' + +$delivery = 0 +HOST = Socket.gethostname +def genname(id) + $delivery += 1 + t = Time.now + "%d.M%06dP%dQ%d.%s,N=%d" % [t.tv_sec, t.tv_usec, $$, $delivery, HOST, id] +end + +params = ARGV.getopts("d:fl:s:L") +dir = params["d"] || '.' +LIMIT = if params["l"] + Integer(params["l"]) + else + 10 + end + +port = 119 +if params["s"] =~ /(.*):(.*)/ + params["s"] = $1 + port = Integer($2) +end + +SERVER = params["s"] || ENV["NNTPSERVER"] || "news" + +nntp = TCPSocket.new SERVER, port + +msg = nntp.gets +abort msg unless msg =~ /^20[01] / + +if params["L"] # list all groups + nntp.write("LIST NEWSGROUPS\r\n") + msg = nntp.gets + if msg !~ /^215 / + abort msg + end + + loop { + msg = nntp.gets + break if msg == ".\r\n" + puts msg + } + + exit +end + +STDOUT.sync = true + +ARGV.each { |group| + + FileUtils.mkdir_p(File.join(dir, group, "cur")) + FileUtils.mkdir_p(File.join(dir, group, "new")) + FileUtils.mkdir_p(File.join(dir, group, "tmp")) + + nntp.write("GROUP #{group}\r\n") + + msg = nntp.gets + unless msg =~ /^211 / + STDERR.puts msg + next + end + + _, number, low, high, _ = msg.split(" ", 5) + + number = number.to_i + low = low.to_i + high = high.to_i + + low = high - LIMIT + 1 if number > LIMIT - 1 + low = 1 if low <= 0 + + have = Dir.entries(File.join(dir, group, "cur")). + map { |f| $1.to_i if f =~ /N=(\d+)/ }.compact + + ourhigh = have.max + if ourhigh && low < ourhigh && !params["f"] + low = ourhigh + 1 + end + + next if low >= high + + printf "%s %d-%d ", group, low, high + + nntp.write("STAT #{low}\r\n") + msg = nntp.gets + _, num, mid, _ = msg.split(" ", 4) + + loop { + unless have.include? num.to_i + nntp.write("ARTICLE\r\n") + msg = nntp.gets + + if msg =~ /^220 / + _, num, mid, _ = msg.split(" ", 4) + + text = ["X-Msuck: nntp://#{SERVER}/#{group}/#{num}\n"] + loop { + msg = nntp.gets + break if msg == ".\r\n" + msg.sub!(/\A\./, "") + msg.sub!(/\r\n\z/, "\n") + text << msg + } + text = text.join + + name = genname(num) + + File.write(File.join(dir, group, "tmp", name), text) + File.rename(File.join(dir, group, "tmp", name), + File.join(dir, group, "cur", name + ":2,")) + print "." + else + STDERR.puts msg + end + else + print "=" + end + + nntp.write("NEXT\r\n") + msg = nntp.gets + if msg !~ /^223 / + break + end + _, num, mid, _ = msg.split(" ", 4) + } + + puts +} -- cgit 1.4.1