# bbsrouter.py  -  routing-engine for the vjbox (c) dg6vj - project
# version 0.1 (c) 1997 Hans-Peter Zorn, DG4IAD, all rights reserved

import vjbox
import string
import regex
import rfc822
from string import index

# the internal representation of the routing data (draft):
# a list of 2-tupels. each tupel consists of a bbstag-instance an a list of strings
# representing a neighbour-bbs
#
# then the reverse structure:
# a dictonary with an entry for each neighbour and a list of bbstag-instances.
#
# first we map() through the list and collect the neigbours we can send the message to.
# then we do a lookup in the neighbours{}-dictonary, if we are allowed to do so. 
#
#

class bbstag:
     def __init__(self,define):
       if define[0] is "!":
          self.negative=1
          _define=string.strip(define[1:])
       else:
          self.negative=0
          _define=string.strip(define)
       self.typ=_define[0]
       self.pattern=regex.compile(_define[1:],regex.casefold)

# this is a list of tuples like (<bbstag_instance>,["db0aa","db0ab","db0ac"])
tags=[]

# this is the mentioned dictionary, with the restrictions for each bbs...
neighbours={}

# our global configuration-directory
configuration={}

# we make it global...
global neighbours,tags,configuration

# program initialization....     
def initialize():
  # first we read the configuration-file into a dictionary
  cfdata=string.splitfields(string.join(open("bbsrouter.conf").readlines()),"\n")
  for line in cfdata:
    if string.strip(line)[0] is "#" : continue
    configuration[string.lower(string.split(line)[0])]=string.join(string.split(line)[1:])
  # next we open the forward-definitions-file
  routing_data=string.splitfields(string.join(open(configuration["definitions_file"]).readlines()),"\n")
  # now we parse it and build our tags[]-list and neighbours{}-dictonary
  for line in routing_data:
    if len(string.strip(line)) == 0 : continue
    if string.strip(line)[0] is "#" : continue
    try:
      left=line[:index(line,"->")-1]
      right=line[index(line,"->")+2:]
    except ValueError:
      try: 
        left=line[:index(line,"<-")-1]
        right=line[index(line,"<-")+2:]
      except ValueError:
        print "Syntaxerror in %s" % configuration["definitions"]
        continue
      alist=[]
      for tag in string.split(right):
        a=bbstag(tag)
        alist.append(a)
      neighbours[string.lower(left)]=alist
      continue
    a=bbstag(left)
    alist=[]
    for bbs in string.split(right):
      alist.append(bbs)
    tags.append((a,alist))


def head2dict(head):
   dict={}  
   for line in head:
       tmp=string.splitfields(line,":")
       dict[tmp[0]]=string.joinfields(tmp[1:],":")
   return dict  
     

def sammeln(x,y):
  if x not in y: y.append(x)
  return y

def match_tag(message,tag,bbs,send_to):
  my_address=string.splitfields(configuration["h-address"],".")
  [target,address]=string.splitfields(message["To"],"@")
  address=string.splitfields(address,".")
  my_address=string.splitfields(configuration["h-address"],".")
  for i in range(0,len(address)):
    if address[-i:-i+1] is my_address[-i:-i+1] : del address[i]
  if tag.typ == ">":
    if tag.pattern.match(target)>=len(target):
      for b in bbs:
        send_to = sammeln(b,send_to)
  elif tag.typ == "<":
    if tag.pattern.match(message["From"])>=len(message["From"]):
      for b in bbs:
        send_to = sammeln(b,send_to)
  elif tag.typ == "@":
    if tag.pattern.match(address[0])>=len(address[0]) :
      for b in bbs:
        send_to = sammeln(b,send_to)
  elif tag.typ == ".":
    if tag.pattern.match(address[len(address)-1])>=len(address[len(address)-1]):
      for b in bbs:
        send_to = sammeln(b,send_to)
  return send_to


# then we create a instance of class vj, get the new msg-ids and
# get the new mails....
def main():
  # log on to the server...
  serv=vjbox.vj(configuration["hostname"],
                string.atoi(configuration["port"]),
                configuration["login_call"])
  # get the bids of all new articles
  news = serv.newmail(0)
  # for each bid we do the following...
  for bid in news:
    # get the message-header
    data=serv.header(bid)
    # use python´s rfc822-module to parse it -hmm, doesnt work... too different
    m=head2dict(data)
    # this is the list, where we collect the results
    send_to=[]
    for tup in tags:
       send_to=match_tag(m,tup[0],tup[1],send_to)
    for bbs in send_to:
      try: 
        f=open(configuration["sfqueue_dir"]+bbs,"a") 
      except IOError:
        try:
	  f=open( configuration["sfqueue_dir"]+bbs,"w")
          print configuration["sfqueue_dir"]+bbs
        finally:
          pass
      f.write(bid+"\n")
      f.close 
  del serv

# here we go
initialize()
main()
  
       
          































