my newsgroup base database. (test)

Netkiller chan.neo at gmail.com
Tue Jul 4 02:44:16 EDT 2006


#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
Project: Network News Transport Protocol Server Program
Description:
基于数据库的新闻组,实现BBS前端使用NNTP协议来访问贴子
Reference:
        NNTP协议: http://www.mibsoftware.com/userkt/0099.htm
         正则表达式:
http://wiki.woodpecker.org.cn/moin/RegExpInPython#head-2358765384844ed72f01658cbcde24613d941e9d

-------------------------------------------------------------------------
python-chinese
Post: send python-chinese at lists.python.cn
Subscribe: send subscribe to python-chinese-request at lists.python.cn
Unsubscribe: send unsubscribe to
python-chinese-request at lists.python.cn
Detail Info: http://python.cn/mailman/listinfo/python-chinese
-------------------------------------------------------------------------
"""

import sys
import socket
import threading
import time
import asyncore, asynchat
import string, StringIO, re
#from netkiller import *
#import testMessages
from messages import Messages

#print Messages.banner

class nntp_server (asyncore.dispatcher):

    channel_counter = 0

    def __init__ (self, host, port):
        asyncore.dispatcher.__init__ (self)
        self.create_socket (socket.AF_INET, socket.SOCK_STREAM)
        self.set_reuse_addr()
        self.there = (host, port)
        self.bind (self.there)
        self.listen (5)
    def handle_connect(self):
        pass
    def handle_accept (self):
        conn, addr = self.accept()
        nntp_receiver (self, (conn, addr))
    def handle_error(self):
        pass
    def handle_close (self):
        self.close()

class nntp_receiver (asynchat.async_chat):

    def __init__ (self, server, (conn, addr)):
        asynchat.async_chat.__init__ (self, conn)
        self.set_terminator ('\r\n')
        self.server = server
        self.server.channel_counter = self.server.channel_counter + 1
        self.id = self.server.channel_counter
        #self.sender = nntp_sender (self, server.there)
        #self.sender.id = self.id
        self.buffer = ''
        self.handle_connect()
        self.current_group = group_selected(None)
    def handle_connect (self):
        if self.connected :
            self.push(Messages.banner)

    def collect_incoming_data (self, data):
        self.buffer = self.buffer + data

    def found_terminator (self):
        data = self.buffer
        self.buffer = ''
        if self.get_terminator() == '\r\n':
            parse = self.isCommand(data)
            if parse:
                parse[0] = parse[0].lower()
                self.log('command:'+parse[0])
                usenet(self,parse,self.current_group)
                if parse[0] == 'post':
                    self.set_terminator ('.\r\n')
                if parse[0] == 'quit':
                    self.handle_close()
        else:
            usenet(self,['post',data],self.current_group)
            self.set_terminator ('\r\n')

        message = '<== (%d) %s' % (self.server.channel_counter,
repr(data))
        self.log(message)
        #self.log('current:'+self.current_group.get_group())
        #self.sender.push (data + '\n')
    def close_when_done():
        pass
    def handle_close (self):
        self.log('Closing')
        self.server.channel_counter = self.server.channel_counter - 1
        #self.sender.close()
        self.close()

    def isCommand(self,data):
        rcommand = (
            r'^mode [reader|stream]',
            r'^list$',r'^list
[active|active.times|newsgroups|subscriptions]',
            r'^xover [0-9]+-[0-9]+',
            r'^newgroups [0-9]+ [0-9]+ ',
            r'^group .+',
            r'^newgroups [0-9]+ [0-9]+ [a-zA-Z]',
            r'^head [0-9]+',
            r'^body [0-9]+',
            r'^article [0-9]+',
            r'^post$',r'^next$',r'^last$',
            r'^ihave$',r'^slave$',
            r'^help$',r'^quit$'
        )
        parse = []
        for command in rcommand:
            digs = re.compile(command,re.IGNORECASE)
            if digs.match(data):
                parse = data.split(' ')
                return parse
        self.push("500 command not recognized\r\n")
        return None
"""
class nntp_sender (asynchat.async_chat):

    def __init__ (self, receiver, address):
        asynchat.async_chat.__init__ (self)
        self.receiver = receiver
        self.set_terminator (None)
        self.create_socket (socket.AF_INET, socket.SOCK_STREAM)
        self.buffer = ''
        self.set_terminator ('\n')
        self.connect (address)

    def handle_connect (self):
        print 'Connected'

    def collect_incoming_data (self, data):
        self.buffer = self.buffer + data

    def found_terminator (self):
        data = self.buffer
        self.buffer = ''
        print '==> (%d) %s' % (self.id, repr(data))
        self.receiver.push (data + '\n')

    def handle_close (self):
        self.receiver.close()
        self.close()
"""
class group_selected:
    #current = None
    def __init__(self,value):
        self.set_group(value)
    def set_group(self,value):
        self.current = value
    def get_group(self):
        return self.current

class usenet:
    #threading.Thread
    conn = None
    addr = None
    buffer = None
    msg = None
    conn = None
    current_group = None
    HELP = """\
HELP \r\n
100 Legal commands \r\n
  authinfo user Name|pass Password \r\n
  article [MessageID|Number] \r\n
  body [MessageID|Number] \r\n
  check MessageID \r\n
  date \r\n
  group newsgroup \r\n
  head [MessageID|Number] \r\n
  help \r\n
  ihave \r\n
  last \r\n
  list [active|active.times|newsgroups|subscriptions] \r\n
  listgroup newsgroup \r\n
  mode stream \r\n
  mode reader \r\n
  newgroups yymmdd hhmmss [GMT] [<distributions>] \r\n
  newnews newsgroups yymmdd hhmmss [GMT] [<distributions>] \r\n
  next \r\n
  post \r\n
  slave \r\n
  stat [MessageID|Number] \r\n
  takethis MessageID \r\n
  xgtitle [group_pattern] \r\n
  xhdr header [range|MessageID] \r\n
  xover [range] \r\n
  xpat header range|MessageID pat [morepat...] \r\n
. \r\n"""

    def __init__(self, conn,command,current_group):
        self.conn = conn
        self.buffer = buffer
        self.msg = Messages()
        self.current_group = current_group
        command[0] = command[0].lower()
        self.commands(command)
    def welcome(self):
        self.conn.send(self.msg.banner)
    def commands(self, command):
        if not buffer: return True
        if command[0] == 'mode':
            self.conn.push(self.msg.banner)
        elif command[0] == 'list':
            lists = self.msg.list()
            length = str(len(lists))
            self.conn.send("215 list of newsgroups follows\r\n")
            for group in lists:
                self.conn.push(group+"\r\n")
            self.conn.push(".\r\n")
        elif command[0] == 'group':
            current = command[1]
            isNone = self.msg.group(current)
            if not isNone:
                Responses(self.conn,411)
            else:
                self.current_group.set_group(current)
                number,first,last,group = isNone
                self.conn.push("211 " +number+' '+first+' '+last+'
'+group+ " selected\r\n")
        elif command[0] == 'newgroups':
            #newgroups = self.msg.newgroups(950803,192708,'GMT')
            #length = len(newgroups)
            self.conn.push("231 list of new newsgroups follows.\r\n")
            #for name in newgroups:
            #    self.conn.push(name+"\r\n")
            self.conn.push(".\r\n")
        elif command[0] =='article':
            MessageID = command[1]
            text = self.msg.article(MessageID)
            self.conn.push("220 "+MessageID+"
<mailman.jobs at lists.mozilla.org> article retrieved - head and body
follows\r\n")
            self.conn.push(text)
            self.conn.push(".\r\n")
        elif command[0] =='head':
            MessageID = command[1]
            self.conn.push("221 "+MessageID+"
<mailman.jobs at lists.mozilla.org>\r\n")
            self.conn.push(".\r\n")
        elif command[0] =='body':
            MessageID = command[0]
            self.conn.push("222 "+MessageID+"
<mailman.jobs at lists.mozilla.org>\r\n")
            self.conn.push(".\r\n")
        elif command[0] == 'xover':
            if not self.current_group.get_group():
                Responses(self.conn,412)
                return
            xover = command[1]
            first, last = xover.split('-')
            xovers = self.msg.xover(first,last)
            #length = len(xovers)
            self.conn.push("224 xover information follows\r\n")
            """
            412 no newsgroup has been selected
            """
            for xover in xovers:
                self.conn.push( xover + "\r\n")
            self.conn.push(".\r\n")
        elif command[0] =='xhdr':
            xhdr = command[1]
            subject, range = xhdr.split(' ')
            first, last = range.split('-')
            self.msg.xhdr('subject',first,last)
            #length = len(xover_list)
            self.conn.push("221 "+subject+" field follows\r\n")
            for xo in xover_list:
                self.conn.send( xo + "\r\n")
            self.conn.send(".\r\n")
        elif command[0] == 'post':
            if len(command) == 1:
                self.conn.push("340 send article\r\n")
            elif len(command) == 2:
                data = command[1]
                self.msg.post(data)
                Responses(self.conn,240)
        elif command[0] == 'rset':
            self.conn.push("250 OK\r\n")
        elif command[0] =='help':
            self.conn.push(self.HELP)
        elif command[0] =='quit':
            self.conn.push("205 closing connection - goodbye!\r\n")
        return True

    def close(self):
        self.conn.close()
        self.buffer = None
        self.conn = None
        self.addr = None

class Responses:
    conn = None
    def __init__(self,conn,status):
        self.conn = conn
        if status == 205:
            pass
        elif status == 224:
            self.conn.push('224 Overview information follows\r\n')

        elif status == 240:
            self.conn.push('240 article posted ok\r\n')
        elif status == 340:
            self.conn.push('340 send article to be posted. End with
<CR-LF>.<CR-LF>\r\n')
        elif status == 411:
            self.conn.push('411 no such news group\r\n')
        elif status == 412:
            self.conn.push('412 No news group current selected\r\n')
        elif status == 420:
            self.conn.push('420 No article(s) selected\r\n')

        elif status == 440:
            self.conn.push('440 posting not allowed\r\n')
        elif status == 441:
            self.conn.push('441 posting failed\r\n')
        elif status == 502:
            self.conn.push('502 no permission\r\n')

def main():
    try:
        nntpd = nntp_server('127.0.0.1',119)
        asyncore.loop()
    except KeyboardInterrupt:
        print "Crtl+C pressed. Shutting down."


if __name__ == '__main__':
    main()




More information about the Python-list mailing list