replacement for nntpxmit.py

lance@markv.com
Fri, 30 Jul 93 17:08:51 PDT

I got completely tired of nntpxmit dieing on my system so I thought
I would rewrite it in Python.. Thanks to the new nntplib.py file in the
0.9.9 lib directory I was able to toss out about 200 lines of code that
I had written and now have a nntpxmit.py file that works!!
Here it is for any who wish it.. please let me know of any bugs or
improvements..
Mind you there are almost NO comments in it.. have not had time to go
through it and probably won't have time now that it is working..

#! /usr2/local/bin/python

# This file reads the batch files created by NNTP and
# sends the messages to the remote site.

# The usage for this program is:
#
# nntpxmit Batch_dir News_dir

import sys
import strop
import posix
from nntplib import NNTP, error_temp, error_reply

False = 0
True = 1

#####
# Global locations to use
#####
NewsSpoolDir = ''
NewsBatchDir = ''
if len(sys.argv) != 3:
print 'Usage: ' + sys.argv[0] + ' NNTP_Batch_Dir NEWS_Directory'
raise SystemExit
NewsSpoolDir = sys.argv[2] + '/'
NewsBatchDir = sys.argv[1] + '/'
NewsBatchHost= ''

#####
# Codes returned from NNTP Server
#####
OK_NOPOST = 201
OK_CANPOST = 200
OK_XFERD = 235
CONT_XFER = 335
ERR_GOTIT = 435
ERR_XFERRJCT = 437
ERR_XFERFAIL = 436

#####
# Globals
#####
# Transfer Stats
Stats = {
'offered':0,
'accepted':0,
'rejected':0,
'failed':0
}

Debug = False
Report_Stats = True
ReQueue_fails = True

Debug_Stream = None

Requeue_Article_lst = []

#####
# Support Functions
#####

def reset_stats():
global Stats
Stats['offered'] = 0
Stats['accepted'] = 0
Stats['rejected'] = 0
Stats['failed'] = 0
return None

def print_stats(host):
global Stats
print ''
print 'Statistics for \'' + host + '\''
print '='*30
print 'Offered : ' + `Stats['offered']`
print 'Accepted : ' + `Stats['accepted']`
print 'Rejected : ' + `Stats['rejected']`
print 'Failed : ' + `Stats['failed']`
print ''
return None

def write_requeue(file_name, lst):
try:
fp = open(NewsBatchDir + file_name,'a+')
except IOError, msg:
print 'write_requeue(' + NewsBatchDir + file_name + ') failed: ' + msg
return None
if len(lst) == 0:
fp.close()
return None
for item in lst:
try:
fp.write(item[0] + ' ' + item[1] + '\n')
except IOError, msg:
print 'write_requeue(' + NewsBatchDir + file_name + ') failed: ' + msg
return None
return None

# This routine takes a file name and loads all the lines in the file
# into a list. This list contains 2 parts, ('filename','message id')
# This information is taked from a batch file
def load_batch(file_name):
try:
fp = open(file_name,'r')
except:
return None
list = []
list = fp.readlines()
for ndx in range(len(list)):
list_el = strop.strip(list[ndx])
l = len(list_el)
j = 0
while j < l and list_el[j] != ' ':
j = j + 1
fn = list_el[0:j]
msgid = list_el[j:]
list[ndx] = (strop.strip(fn),strop.strip(msgid))
try:
t = posix.unlink(file_name)
except:
pass
return list

# this will lock a directory
def lock_dir(dir_to_lock):
t_dir = posix.getcwd()
r = posix.chdir(dir_to_lock)
try:
r = open('.LCK'+`posix.getpid()`,'w')
except:
r = posix.chdir(t_dir)
return False
r.close()
try:
r = posix.link('.LCK'+`posix.getpid()`,'.LCKdir')
except:
r = posix.chdir(t_dir)
return False
r = posix.chdir(t_dir)
return True

# This will unlock the directory
def unlock_dir(dir_to_unlock):
t_dir = posix.getcwd()
r = posix.chdir(dir_to_unlock)
try:
r = posix.unlink('.LCKdir')
r = posix.unlink('.LCK'+`posix.getpid()`)
except:
return False
r = posix.chdir(t_dir)
return True

# This function returns 2 lists..
# 1: A list of all files in the directory that are NOT requeue files (! '~xxx')
# 2: A list of all files in the directory that are requeue files (~xxx)
# This function NEVER returns files that start as '.LCK' as these
# are lock files and Never need to be touched and it never returns
# files that start with '.' as these are hidden
def rtn_dirlist(dir_to_list):
requeue_lst = []
rtn_lst = []
try:
lst = posix.listdir(dir_to_list)
except:
return (None, None)
for i in range(len(lst)):
name = lst[i]
if name[0] == '.':
continue
if name[0] == '~':
r = requeue_lst.append(name)
continue
rtn_lst.append(name)
return (rtn_lst, requeue_lst)

def process_file(f_name):
global Requeue_Article_lst
count = -1
lst = load_batch(NewsBatchDir + f_name)
if len(lst):
reset_stats()
try:
if f_name[0] == '~':
host = f_name[1:]
else:
host = f_name
n = NNTP().init(host)
print 'NNTP welcomes with \'' + n.getwelcome() + '\''
except error_temp, msg:
print 'NNTP connect failed: ' + msg
for item in lst:
Requeue_Article_lst.append(item)
return None
for item in lst:
count = count + 1
try:
f = open(NewsSpoolDir + item[0],'r')
except IOError:
print 'opening of ' + NewsSpoolDir + item[0],
print ' failed: ' + msg
Stats['failed'] = Stats['failed'] + 1
continue
try:
Stats['offered'] = Stats['offered'] + 1
rtn = n.ihave(item[1],f)
Stats['accepted'] = Stats['accepted'] + 1
except error_temp,msg:
rtn_val = eval(msg[:3])
if rtn_val == ERR_XFERFAIL:
print 'Transfer failed: Requeuing ' + item[1]
Requeue_Article_lst.append(item)
Stats['failed'] = Stats['failed'] + 1
if rtn_val == ERR_GOTIT:
Stats['rejected'] = Stats['rejected'] + 1
except EOFError, msg:
print 'Connection Closed!! requeueing items left'
print 'Returned: ' + msg
print 'Requeuing ' + `eval(len(lst) - count)` + ' items.'
for items in lst[count:]:
Requeue_Article_lst.append(items)
return None
n.quit()
print_stats(host)
return None

# This is the main routine that runs everything
def main():
global Stats
global Requeue_Article_lst
if not lock_dir(NewsBatchDir):
print 'Could not lock \'' + NewsBatchDir + '\'.'
print 'Try again later.'
raise SystemExit
do_list, redo_list = rtn_dirlist(NewsBatchDir)
if redo_list != None and len(redo_list):
for f_name in redo_list:
process_file(f_name)
if len(Requeue_Article_lst):
write_requeue(f_name,Requeue_Article_lst)
Requeue_Article_lst = []
if do_list != None and len(do_list):
for f_name in do_list:
process_file(f_name)
if len(Requeue_Article_lst):
write_requeue('~'+f_name,Requeue_Article_lst)
Requeue_Article_lst = []
r = unlock_dir(NewsBatchDir)
return None

main()

--

Lance Ellinghouse lance@markv.com

1231 bit key fingerprint = 56 DA 31 0C 17 51 36 6A 4E D4 E0 11 D9 B8 06 0A 1024 bit key fingerprint = 66 2C 75 F2 E9 1C 32 84 3A E3 B0 5E 48 01 4C 37 You can recieve my Public Key by `finger lance@mark.com`