python update, II of B

greg andruk meowing at banet.net
Thu Sep 23 04:21:56 UTC 1999


ctlinnd.8, README.python_hook, INND.py and filter_innd.py updates to
reflect the previous patch.

*** ../inn/doc/man/ctlinnd.8	Sat Sep 18 03:20:40 1999
--- doc/man/ctlinnd.8	Sun Sep 19 02:32:03 1999
***************
*** 476,482 ****
  file is reloaded.  If a Python method named ``filter_before_reload'' exists,
  it will be called prior to rereading
  .IR filter_innd.py .
! If a Python method named ``filter_after_reload'' exists, it will be called
  after
  .IR filter_innd.py .
  has been reloaded.  Reloading the Python filter does not enable filtering if
--- 476,482 ----
  file is reloaded.  If a Python method named ``filter_before_reload'' exists,
  it will be called prior to rereading
  .IR filter_innd.py .
! If a Python method named ``__init__'' exists, it will be called
  after
  .IR filter_innd.py .
  has been reloaded.  Reloading the Python filter does not enable filtering if
***************
*** 550,556 ****
--- 550,562 ----
  .BI shutdown " reason"
  The server is shut down, with the specified reason recorded in the log
  and sent to all open connections.
+ 
  It is a good idea to send a ``throttle'' command first.
+ 
+ If
+ .I <\-\-with\-python is specified at configure>
+ and a Python method named ``filter_close'' exists,
+ it will be called just before innd exits.
  .TP
  .BI signal " sig site"
  Signal
*** ../inn/samples/INN.py	Sat Sep 18 03:20:57 1999
--- samples/INN.py	Thu Sep 23 00:13:52 1999
***************
*** 2,10 ****
  # provided by innd.  It is not used by the server; it is only here so
  # that you can test your filter scripts before loading.
  
  def set_filter_hook(anObject):
-     from types import *
-     
      if type(anObject) == InstanceType:
          print "** set_filter_hook for " + repr(anObject)
      else:
--- 2,10 ----
  # provided by innd.  It is not used by the server; it is only here so
  # that you can test your filter scripts before loading.
  
+ from types import *
+ 
  def set_filter_hook(anObject):
      if type(anObject) == InstanceType:
          print "** set_filter_hook for " + repr(anObject)
      else:
***************
*** 12,34 ****
  
  def havehist(messageid):
      print "** havehist message id: " + messageid
-     pass
  
  def cancel(messageid):
      print "** cancel message id: " + messageid
-     pass
  
  def newsgroup(groupname):
      print "** newsgroup: " + messageid
  
- 
  def head(messageid):
      print "** head  message id: " + messageid
-     pass
  
  def article(messageid):
      print "** article message id: " + messageid
  
  def syslog(level, message):
      print "-- syslog level: %s message: %s" % (level, message)
- 
--- 12,29 ----
*** ../inn/samples/filter_innd.py	Sat Sep 18 03:20:57 1999
--- samples/filter_innd.py	Thu Sep 23 00:15:44 1999
***************
*** 6,11 ****
--- 6,38 ----
  # For details, see the file README.python_hook that came with INN.
  #
  
+ import re
+ from string import *
+ 
+ # This looks weird, but creating and interning these strings should
+ # let us get faster access to header keys (which innd also interns) by
+ # losing some strcmps under the covers.
+ Approved = intern("Approved");           Control = intern("Control")
+ Date = intern("Date");                   Distribution = intern("Distribution")
+ Expires = intern("Expires");             From = intern("From")
+ Lines = intern("Lines");                 Message_ID = intern("Message-ID")
+ Newsgroups = intern("Newsgroups");       Path = intern("Path")
+ Reply_To = intern("Reply-To");           Sender = intern("Sender")
+ Subject = intern("Subject");             Supersedes = intern("Supersedes")
+ Bytes = intern("Bytes");                 Also_Control = intern("Also-Control")
+ References = intern("References");       Xref = intern("Xref")
+ Keywords = intern("Keywords");           X_Trace = intern("X-Trace")
+ NNTP_Posting_Host = intern("NNTP-Posting-Host")
+ Followup_To = intern("Followup-To");     Organization = intern("Organization")
+ Content_Type = intern("Content-Type");   Content_Base = intern("Content-Base")
+ Content_Disposition = intern("Content-Disposition")
+ X_Newsreader = intern("X-Newsreader");   X_Mailer = intern("X-Mailer")
+ X_Newsposter = intern("X-Newsposter")
+ X_Cancelled_By = intern("X-Cancelled-By")
+ X_Canceled_By = intern("X-Canceled-By"); Cancel_Key = intern("Cancel-Key")
+ __BODY__ = intern("__BODY__");           __LINES__ = intern("__LINES__")
+ 
+ 
  class InndFilter:
      """Provide filtering callbacks to innd."""
  
***************
*** 13,35 ****
          """This runs every time the filter is loaded or reloaded.
  
          This is a good place to initialize variables and precompile
!         regular expressions, or maybe save stats and stuff.
  
          """
!         import re
  
!         self.re_none44 = re.compile('none\d+\.yet>')
!         self.re_meow = re.compile("Meow", re.M)
  
  
      def filter_art(self, art):
          """Decide whether to keep offered articles.
  
          art is a dictionary with a bunch of headers, the article's
!         body, and innd's reckoning of the line count.  Not all keys
!         will necessarily be defined, particularly for the headers.
  
!         Headers offered are the ones listed near the top of
          innd/art.c.  At this writing, they are:
  
              Approved, Control, Date, Distribution, Expires, From,
--- 40,98 ----
          """This runs every time the filter is loaded or reloaded.
  
          This is a good place to initialize variables and precompile
!         regular expressions, or maybe reload stats from disk.
!         """
!         self.re_newrmgroup = re.compile('(?:new|rm)group\s')
!         self.re_obsctl = re.compile('(?:sendsys|version|uuname)')
!         # msgid  pattern from a once-common spambot.
!         self.re_none44 = re.compile('none\d+\.yet>')
!         # There is a mad newgrouper who likes to meow.
!         self.re_meow = re.compile("^Meow\!", re.M)
!         # One of my silly addresses.
!         self.re_fluffymorph = re.compile("andruQ at myremarQ.coM", re.I)
! 
!     def filter_before_reload(self):
!         """Runs just before the filter gets reloaded.
  
+         You can use this method to save state information to be
+         restored by the __init__() method or down in the main module.
          """
!         syslog('notice', "filter_before_reload executing...")
  
!     def filter_close(self):
!         """Runs when innd exits.
  
+         You can use this method to save state information to be
+         restored by the __init__() method or down in the main module.
+         """
+         syslog('notice', "filter_close running, bye!")
+ 
+     def filter_messageid(self, msgid):
+         """Filter articles just by their message IDs.
+ 
+         This method interacts with the IHAVE and CHECK NNTP commands.
+         If you return a non-empty string here, the offered article
+         will be refused before you ever have to waste any bandwidth
+         looking at it.  This is not foolproof, so you should do your
+         ID checks both here and in filter_art.  (TAKETHIS does not
+         offer the ID for examination, and a TAKETHIS isn't always
+         preceded by a CHECK.)
+         """
+         return ""               # deactivate the samples.
+         
+         if self.re_none44.search(msgid):
+             return "But I don't like spam!"
+         if msgid[0:8] == '<cancel.':
+             return "I don't do cybercancels."
  
      def filter_art(self, art):
          """Decide whether to keep offered articles.
  
          art is a dictionary with a bunch of headers, the article's
!         body, and innd's reckoning of the line count.  Itens not
!         in the article will have a value of None.
  
!         The available headers are the ones listed near the top of
          innd/art.c.  At this writing, they are:
  
              Approved, Control, Date, Distribution, Expires, From,
***************
*** 40,81 ****
              Content-Disposition, X-Newsreader, X-Mailer, X-Newsposter,
              X-Cancelled-By, X-Canceled-By and Cancel-Key.
  
!         The body is the string in art['__BODY__'] and the INN-reckoned
!         line count is held in art['__LINES__'].  (The Lines: header is
!         often generated by the poster, and large differences can be a
!         good indication of a corrupt article.)
  
          If you want to keep an article, return None or "".  If you
          want to reject, return a non-empty string.  The rejection
          string will appear in transfer and posting response banners,
          and local posters will see them if their messages are
          rejected.
- 
          """
!         from string import *
! 
!         if art.has_key('Control') and self.re_meow.search(art['__BODY__']):
!             return "The fake tale meows again."
!         if find(art['From'], 'vszbr.zrbj') != -1:
!             return "UDP! UDP!!!!1!!@@2!!1! YOOOOO DEEEEE PEEEE!!"
  
! 
!     def filter_messageid(self, msgid):
!         """Filter articles just by their message IDs.
! 
!         This method interacts with the IHAVE and CHECK NNTP commands.
!         If you return a non-empty string here, the offered article
!         will be refused before you ever have to waste any bandwidth
!         looking at it.  This is not foolproof, so you should do your
!         ID checks both here and in filter_art.  (TAKETHIS does not
!         offer the ID for examination, and a TAKETHIS isn't always
!         preceded by a CHECK.)
!         
!         """
!         if self.re_none44.search(msgid):
!             return "But I don't like spam!"
!         if msgid[0:8] == '<cancel.':
!             return "I don't do cybercancels."
  
      def filter_mode(self, oldmode, newmode, reason):
          """Capture server events and do something useful.
--- 103,143 ----
              Content-Disposition, X-Newsreader, X-Mailer, X-Newsposter,
              X-Cancelled-By, X-Canceled-By and Cancel-Key.
  
!         The body is the buffer in art['__BODY__'] and the INN-reckoned
!         line count is held as an integer in art['__LINES__'].  (The
!         Lines: header is often generated by the poster, and large
!         differences can be a good indication of a corrupt article.)
  
          If you want to keep an article, return None or "".  If you
          want to reject, return a non-empty string.  The rejection
          string will appear in transfer and posting response banners,
          and local posters will see them if their messages are
          rejected.
          """
!         return ""               # deactivate the samples.
  
!         # catch bad IDs from articles fed with TAKETHIS but no CHECK.
!         idcheck = self.filter_messageid(art[Message_ID])
!         if idcheck:
!             return idcheck
! 
!         # There are some control messages we don't want to process or
!         # forward to other sites.
!         try:
!             if art[Control] is not None:
!                 if self.re_newrmgroup.match(art[Control]):
!                     if self.re_meow.search(art[__BODY__]):
!                         return "The fake tale meows again."
!                     if art[Distribution] == buffer('mxyzptlk'):
!                         return "Evil control message from the 10th dimension"
!                 if self.re_obsctl.match(art[Control]):
!                     return "Obsolete control message"
! 
!             # If you don't know, you don't want to know.
!             if self.re_fluffymorph.search(art[From]):
!                 return "No, you may NOT meow."
!         except:
!             syslog('n', str(sys.exc_info[1]))
  
      def filter_mode(self, oldmode, newmode, reason):
          """Capture server events and do something useful.
***************
*** 85,107 ****
          just left, and newmode is where we are going.  reason is
          usually just a comment string.
  
!         The possible values of newmode and oldmode are the three
!         strings 'running', 'paused' and 'throttled'.
! 
          """
!         if newmode == 'running':
!             syslog('notice', 'Happy birthday!')
!         elif newmode == 'throttled':
!             syslog('warn', "OUCH!")
!         elif newmode == 'paused':
!             syslog('n', '*yawn*')
!         
  
  
  """
  Okay, that's the end of our class definition.  What follows is the
  stuff you need to do to get it all working inside innd.
- 
  """
  
  # This import must succeed, or your filter won't work.  I'll repeat
--- 147,165 ----
          just left, and newmode is where we are going.  reason is
          usually just a comment string.
  
!         The possible values of newmode and oldmode are the four
!         strings 'running', 'paused', 'throttled' and 'unknown'.
!         Actually 'unknown' shouldn't happen, it's there in case
!         feeping creatures invade innd.
          """
!         syslog('notice', 'state change from %s to %s - %s'
!                % (oldmode, newmode, reason))
! 
  
  
  """
  Okay, that's the end of our class definition.  What follows is the
  stuff you need to do to get it all working inside innd.
  """
  
  # This import must succeed, or your filter won't work.  I'll repeat
***************
*** 131,136 ****
--- 189,195 ----
  
  #     If you want to do something special when the server first starts
  #     up, this is how to find out when it's time.
+ 
  if 'spamfilter' not in dir():
      syslog ('n', "First load, so I can do initialization stuff.")
      #  You could unpickle a saved hash here, so that your hard-earned
***************
*** 139,150 ****
      syslog ('NoTicE', "I'm just reloading, so skip the formalities.")
  
  
! #  Here is how we get our class on speaking terms with innd.  The hook
! #  is refreshed on every reload, so that you can change the methods on
! #  a running server.
  spamfilter = InndFilter()
  try:
      set_filter_hook(spamfilter)
      syslog('n', "spamfilter successfully hooked into INN")
  except Exception, errmsg:
      syslog('e', "Cannot obtain INN hook for spamfilter: %s" % errmsg[0])
--- 198,211 ----
      syslog ('NoTicE', "I'm just reloading, so skip the formalities.")
  
  
! #  Finally, here is how we get our class on speaking terms with innd.
! #  The hook is refreshed on every reload, so that you can change the
! #  methods on a running server.  Don't forget to test your changes
! #  before reloading!
  spamfilter = InndFilter()
  try:
      set_filter_hook(spamfilter)
      syslog('n', "spamfilter successfully hooked into INN")
  except Exception, errmsg:
      syslog('e', "Cannot obtain INN hook for spamfilter: %s" % errmsg[0])
+ 
*** ../inn/README.python_hook	Sat Sep 18 03:21:02 1999
--- README.python_hook	Wed Sep 22 23:10:07 1999
***************
*** 1,6 ****
  INN Python Filtering Support
  
! This is $Revision: 1.1 $, dated $Date: 1999/05/20 09:21:16 $.
  
      This file documents INN's built-in optional support for Python
      article filtering.  It is patterned after the TCL and Perl hooks
--- 1,6 ----
  INN Python Filtering Support
  
! This is $Revision: 1.1 $, dated $Date: 1999/09/19 07:30:07 $.
  
      This file documents INN's built-in optional support for Python
      article filtering.  It is patterned after the TCL and Perl hooks
***************
*** 8,14 ****
  
      For this filter to work successfully, you will need to have Python
      1.5.2 (the latest at this writing) installed.  You can obtain it
!     from <URL:http://www.python.org/>.
  
  
  NOTE TO RED HAT LINUX USERS:
--- 8,14 ----
  
      For this filter to work successfully, you will need to have Python
      1.5.2 (the latest at this writing) installed.  You can obtain it
!     from <URL:http://www.python.org>.
  
  
  NOTE TO RED HAT LINUX USERS:
***************
*** 19,35 ****
      kit from the above URL and build it yourself.  Be sure when
      installing Python on Red Hat, to run configure with
      '--prefix=/usr' so that there are no version conflicts with the
!     "factory" installation.
  
  
  INSTALLATION:
  
!     Once you have built and installed Python, you can ask INN to use
      it by adding the '--with-python' switch to your configure command.
  
      See the ctlinnd(8) manual page to learn how to enable, disable and
      reload Python filters on a running server ('ctlinnd mode',
!     'ctlinnd python y|n' and 'ctlinnd reload filter.python').
  
      Also, see the example filter_innd.py script in your filters
      directory for a demonstration of how to get all this working.
--- 19,36 ----
      kit from the above URL and build it yourself.  Be sure when
      installing Python on Red Hat, to run configure with
      '--prefix=/usr' so that there are no version conflicts with the
!     "factory" installation.  You can also find a selection of well
!     made RPMs at <URL:ftp://starship.python.net/pub/crew/andrich/>
  
  
  INSTALLATION:
  
!     Once you have built and installed Python, you can cause INN to use
      it by adding the '--with-python' switch to your configure command.
  
      See the ctlinnd(8) manual page to learn how to enable, disable and
      reload Python filters on a running server ('ctlinnd mode',
!     'ctlinnd python y|n', 'ctlinnd reload filter.python').
  
      Also, see the example filter_innd.py script in your filters
      directory for a demonstration of how to get all this working.
***************
*** 37,60 ****
  
  WRITING AN INND FILTER:
  
!     You need to create a filter_innd.py module in INN's bin/filters
!     directory.  A heavily-commented sample is provided that you can
!     use as a template for your own filter.  There is also an INN.py
!     module there which is not actually used by INN; it is just there
!     so you can test your module interactively.
  
      First, define a class containing the methods you want to provide
      to innd.  Methods innd will use if present are:
  
          __init__(self):
!             Not explicitly called by innd, but will be run whenever
!             the filter is (re)loaded.
  
          filter_art(self, art):
              art is a dictionary containing an article's headers and
              body.  This method is called every time innd receives an
!             article.  Not all keys need be present, but the following
!             can be defined:
              
                  Approved, Control, Date, Distribution, Expires, From,
                  Lines, Message-ID, Newsgroups, Path, Reply-To, Sender,
--- 38,72 ----
  
  WRITING AN INND FILTER:
  
!     You need to create a filter_innd.py module in INN's filter
!     directory (see the pathfilter setting in inn.conf).  A
!     heavily-commented sample is provided that you can use as a
!     template for your own filter.  There is also an INN.py module
!     there which is not actually used by INN; it is there so you
!     can test your module interactively.
  
      First, define a class containing the methods you want to provide
      to innd.  Methods innd will use if present are:
  
          __init__(self):
!             Not explicitly called by innd, but will run whenever the
!             filter module is (re)loaded.  This is a good place to
!             initialize constants or pick up where filter_before_reload
!             or filter_close left off.
! 
!         filter_before_reload(self):
!             This will execute any time a 'ctlinnd reload all' or
!             'ctlinnd reload filter.python' command is issued.  You can
!             use it to save statistics or reports for use after
!             reloading.
! 
!         filter_close(self):
!             This will run when a 'ctlinnd shutdown' command is received.
  
          filter_art(self, art):
              art is a dictionary containing an article's headers and
              body.  This method is called every time innd receives an
!             article.  The following can be defined.
              
                  Approved, Control, Date, Distribution, Expires, From,
                  Lines, Message-ID, Newsgroups, Path, Reply-To, Sender,
***************
*** 65,102 ****
                  X-Newsposter, X-Cancelled-By, X-Canceled-By,
                  Cancel-Key, __LINES__, __BODY__
  
!             __BODY__ is a string containing the article's entire body,
!             and __LINES__ is an int holding innd's reckoning of the
!             number of lines in the article.  All the other elements
!             will be strings with the contents of the same-named
!             article headers.
  
!             If you want to accept an article, return nothing, or an
!             empty string.  To reject, return a non-empty string.  The
              rejection strings will be shown to local clients and your
              peers, so keep that in mind when phrasing your rejection
              responses.
  
          filter_messageid(self, msgid):
!             msgid is a string containing the ID of an article being
!             offered by IHAVE or CHECK.  Like with filter_art(), the
!             message will be refused if you return a non-empty string.
!             If you use this feature, keep it light because it is
!             called at a rather busy place in innd's main loop.  Also,
!             do not rely on this function alone to reject by ID; you
!             should repeat the tests in filter_art() to catch articles
!             sent with TAKETHIS but no CHECK.
  
          filter_mode(self, oldmode, newmode, reason):
              When the operator issues a ctlinnd pause, throttle or go
              command, this function can be used to do something
!             sensible in accordance with the state change.  Stamp a
!             log file, save your state on throttle, etc.  oldmode and
              newmode will be strings containing one of the values in
!             ('running', 'throttled', 'paused') -- oldmode is the state
!             innd was in before ctlinnd was run, newmode is the state
!             innd will be in after the command finishes.  reason is the
!             comment string provided on the ctlinnd command line.
  
      To register your methods with innd, you need to create an instance
      of your class, import the built-in INN module, and pass the
--- 77,120 ----
                  X-Newsposter, X-Cancelled-By, X-Canceled-By,
                  Cancel-Key, __LINES__, __BODY__
  
!             All the above values will be buffer objects holding the
!             contents of the same named article headers, except for the
!             special __BODY__ and __LINES__ items.  Items not present
!             in the article will contain None.
! 
!             __BODY__ is a buffer object containing the article's
!             entire body, and __LINES__ is an int holding innd's
!             reckoning of the number of lines in the article.  All the
!             other elements will be buffers with the contents of the
!             same-named article headers.
  
!             If you want to accept an article, return None or an empty
!             string.  To reject, return a non-empty string.  The
              rejection strings will be shown to local clients and your
              peers, so keep that in mind when phrasing your rejection
              responses.
  
          filter_messageid(self, msgid):
!             msgid is a buffer object containing the ID of an article
!             being offered by IHAVE or CHECK.  Like with filter_art(),
!             the message will be refused if you return a non-empty
!             string.  If you use this feature, keep it light because it
!             is called at a rather busy place in innd's main loop.
!             Also, do not rely on this function alone to reject by ID;
!             you should repeat the tests in filter_art() to catch
!             articles sent with TAKETHIS but no CHECK.
  
          filter_mode(self, oldmode, newmode, reason):
              When the operator issues a ctlinnd pause, throttle or go
              command, this function can be used to do something
!             sensible in accordance with the state change.  Stamp a log
!             file, save your state on throttle, etc.  oldmode and
              newmode will be strings containing one of the values in
!             ('running', 'throttled', 'paused', 'unknown') -- oldmode
!             is the state innd was in before ctlinnd was run, newmode
!             is the state innd will be in after the command finishes.
!             reason is the comment string provided on the ctlinnd
!             command line.
  
      To register your methods with innd, you need to create an instance
      of your class, import the built-in INN module, and pass the
***************
*** 124,170 ****
      silently otherwise.
  
      Also, remember to try importing your module interactively before
!     loading it, to ensure there are no syntax or variable errors.  One
!     typo can ruin your whole filter.  A dummy INND.py module is
!     provided to facilitate testing outside the server.
  
      You can define as many or few of the methods listed above as you
      want in your filter class (it's fine to define more methods for
      your own use; innd won't use them but your filter can).  If you
!     *do* define these methods, GET THE PARAMETER COUNTS RIGHT.  There
!     are checks in innd to see if the methods exist and are callable,
!     but if you define one and get the parameter counts wrong, INND
!     WILL DIE.  You have been warned.  Be careful with your return
!     values, too.  the filter_art() and filter_messageid() methods have
!     to return strings, or nothing at all.  If you return something
      like an int, innd will *not* be happy.
  
  
  FUNCTIONS SUPPLIED BY THE BUILT-IN INN MODULE:
  
!     Not only can innd use your Python code, but your Python code can
!     use some of innd's features too.  Here is some sample Python code
!     to show what you get:
  
      import INN
  
!     # Python's native syslog module doesn't work inside innd, so the
!     # INN module provides a replacement.  The first parameter tells
!     # the Unix syslogger what severity to use; you can abbreviate down
!     # to one letter and it's case insensitive.  Available levels are
!     # (in increasing levels of seriousness) Debug, Info, Notice,
!     # Warning, Err, Crit, and Alert. (If you provide any other string,
!     # it will be defaulted to Notice.)  the second parameter is the
!     # message text.  The syslog entries will go to the same log files
!     # innd itself uses, with a 'python:' prefix.
!     syslog('warning', 'I will not by this record.  It is scratched.')
      animals = 'eels'
      vehicle = 'hovercraft'
      syslog('N', 'My %s is full of %s.' % (vehicle, animals))
  
      # Let's cancel an article!  This only deletes the message on the
      # local server; it doesn't send out a control message or anything
!     # scary like that.
      if INN.cancel('<meow$123.456 at solvangpastries.edu>'):
          canceled = "yup"
      else:
--- 142,229 ----
      silently otherwise.
  
      Also, remember to try importing your module interactively before
!     loading it, to ensure there are no obvious errors.  One typo can
!     ruin your whole filter.  A dummy INND.py module is provided to
!     facilitate testing outside the server.  To test, change into your
!     filter directory and use a command like:
! 
!         python -ic 'import INN, filter_innd'
  
      You can define as many or few of the methods listed above as you
      want in your filter class (it's fine to define more methods for
      your own use; innd won't use them but your filter can).  If you
!     *do* define the above methods, GET THE PARAMETER COUNTS RIGHT.
!     There are checks in innd to see if the methods exist and are
!     callable, but if you define one and get the parameter counts
!     wrong, INND WILL DIE.  You have been warned.  Be careful with your
!     return values, too.  The filter_art() and filter_messageid()
!     methods have to return strings, or None.  If you return something
      like an int, innd will *not* be happy.
  
  
+ WHAT'S THE DEAL WITH THESE BUFFER OBJECTS?
+ 
+     Buffer objects are cousins of strings, new in Python 1.5.2.  They
+     are supported, but at this writing you won't yet find much about
+     them in the Python documentation.  Using buffer objects may take
+     some getting used to, but we can create buffers much faster and
+     with less memory than strings.
+ 
+     For most of the operations you will perform in filters (like
+     re.search, string.find, md5.digest) you can treat buffers just
+     like strings, but there are a few important differences you should
+     know about:
+ 
+         # Make a string and a two buffers.
+         s = "abc"
+         b = buffer("def")
+         bs = buffer("abc")
+ 
+         s == bs          # - This is false because the types differ...
+         buffer(s) == bs  # - ...but this is true, the types now agree.
+         s == str(bs)     # - This is also true, but buffer() is faster.
+         s[:2] == bs[:2]  # - True.  Buffer slices are strings.
+ 
+         # While most string methods will take either a buffer or string,
+         # string.join insists on using only strings.
+         string.join([str(b), s], '.')   # returns 'def.abc'
+ 
+         e = s + b        # This raises a TypeError, but...
+ 
+         # ...these two both return the string 'abcdef'. The first one
+         # is faster -- choose buffer() over str() whenever you can.
+         e = buffer(s) + b
+         f = s + str(b)
+ 
+         g = b + '>'      # This is legal, returns the string 'def>'.
+ 
+ 
  FUNCTIONS SUPPLIED BY THE BUILT-IN INN MODULE:
  
!     Not only can innd use Python, but your filter can use some of
!     innd's features too.  Here is some sample Python code to show what
!     you get:
  
      import INN
  
!     # Python's native syslog module isn't compiled in by default,
!     # so the INN module provides a replacement.  The first parameter
!     # tells the Unix syslogger what severity to use; you can
!     # abbreviate down to one letter and it's case insensitive.
!     # Available levels are (in increasing levels of seriousness)
!     # Debug, Info, Notice, Warning, Err, Crit, and Alert. (If you
!     # provide any other string, it will be defaulted to Notice.)  The
!     # second parameter is the message text.  The syslog entries will
!     # go to the same log files innd itself uses, with a 'python:'
!     # prefix.
!     syslog('warning', 'I will not buy this record.  It is scratched.')
      animals = 'eels'
      vehicle = 'hovercraft'
      syslog('N', 'My %s is full of %s.' % (vehicle, animals))
  
      # Let's cancel an article!  This only deletes the message on the
      # local server; it doesn't send out a control message or anything
!     # scary like that.  Returns 1 if successful, else 0.
      if INN.cancel('<meow$123.456 at solvangpastries.edu>'):
          canceled = "yup"
      else:
***************
*** 174,189 ****
      # necessarily mean the article is on your spool; canceled and
      # expired articles hang around in history for a while, and
      # rejected articles will be in there if you have enabled
!     # remember_trash in inn.conf.
!     if INN.havehist('<z456$789.abc at isc.org'):
          comment = "*yawn* I've already seen this article."
      else:
          comment = 'Mmm, fresh news.'
  
      # Here we are running a local spam filter, so why eat all those
      # cancels?  We can add fake entries to history so they'll get
!     # refused.  Returns 1 on success, 0 on failure
!     canceled_id = "<meow$123.456 at isc.org>"
      if INN.addhist("<cancel." + canceled_id[1:]):
          thought = "Eat my dust, roadkill!"
      else:
--- 233,248 ----
      # necessarily mean the article is on your spool; canceled and
      # expired articles hang around in history for a while, and
      # rejected articles will be in there if you have enabled
!     # remember_trash in inn.conf. Returns 1 if found, else 0.
!     if INN.havehist('<z456$789.abc at isc.org>'):
          comment = "*yawn* I've already seen this article."
      else:
          comment = 'Mmm, fresh news.'
  
      # Here we are running a local spam filter, so why eat all those
      # cancels?  We can add fake entries to history so they'll get
!     # refused.  Returns 1 on success, 0 on failure.
!     canceled_id = buffer('<meow$123.456 at isc.org>')
      if INN.addhist("<cancel." + canceled_id[1:]):
          thought = "Eat my dust, roadkill!"
      else:
***************
*** 192,203 ****
      # We can look at the header or all of an article already on spool,
      # too.  Might be useful for long-memory despamming or
      # authentication things.  Each is returned (if present) as a
!     # string; otherwise you'll end up with an empty string.    
      artbody = INN.article('<foo$bar.baz at bungmunch.edu>')
      artheader = INN.head('<foo$bar.baz at bungmunch.edu>')
  
      # Finally, do you want to see if a given newsgroup is moderated or
!     # whatever?
      froupflag = INN.newsgroup('alt.fan.karl-malden.nose')
      if froupflag == '':
          moderated = 'no such newsgroup'
--- 251,263 ----
      # We can look at the header or all of an article already on spool,
      # too.  Might be useful for long-memory despamming or
      # authentication things.  Each is returned (if present) as a
!     # string object; otherwise you'll end up with an empty string.
      artbody = INN.article('<foo$bar.baz at bungmunch.edu>')
      artheader = INN.head('<foo$bar.baz at bungmunch.edu>')
  
      # Finally, do you want to see if a given newsgroup is moderated or
!     # whatever?  INN.newsgroup returns the last field of a group's
!     # entry in active as a string.
      froupflag = INN.newsgroup('alt.fan.karl-malden.nose')
      if froupflag == '':
          moderated = 'no such newsgroup'


More information about the inn-patches mailing list