aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--HOWTO23
-rw-r--r--INSTALL29
-rw-r--r--Makefile17
-rw-r--r--README14
-rw-r--r--TODO12
-rw-r--r--examples/README.example31
-rw-r--r--examples/articletest.accepted20
-rw-r--r--examples/articletest.denied19
-rw-r--r--examples/mail16
-rw-r--r--examples/whitelist.example14
-rw-r--r--mail2news.py320
-rw-r--r--mail2news.py.withtab319
-rw-r--r--news2mail.py299
-rw-r--r--pyginfo.py26
-rwxr-xr-xpygm2n223
-rwxr-xr-xpygn2m214
-rw-r--r--whitelist.py129
-rw-r--r--wlp/C/Makefile43
-rw-r--r--wlp/C/commands.l75
-rw-r--r--wlp/C/commands.y110
-rw-r--r--wlp/C/macro.h44
-rw-r--r--wlp/C/structs.c164
-rw-r--r--wlp/C/structs.h35
-rw-r--r--wlp/C/test.c113
-rw-r--r--wlp/C/wlp.c183
-rw-r--r--wlp/C/yytest.c25
-rw-r--r--wlp/Makefile42
-rw-r--r--wlp/README12
-rw-r--r--wlp/module/Makefile.pre.in310
-rw-r--r--wlp/module/Makefile.pre.in.OLD304
-rw-r--r--wlp/module/Setup.in88
-rwxr-xr-xwlp/module/makesetup261
-rw-r--r--wlp/module/patch13
-rwxr-xr-xwlp_test31
34 files changed, 3578 insertions, 0 deletions
diff --git a/HOWTO b/HOWTO
new file mode 100644
index 0000000..12f1a6b
--- /dev/null
+++ b/HOWTO
@@ -0,0 +1,23 @@
+MUST BE FINISHED!
+
+
+It is a (very) small HOWTO to make pyg working properly.
+
+pygm2n:
+
+Pre: a fully working MTA (ie postfix) where you can run procmail. A
+new server (local or remote) where you can create groups.
+
+Create a user, ie mailgate, set its procmail as:
+
+:0 bhc:
+| pygm2n -n local.test
+
+you can use -a your@address and -s nntphost if local.test is moderated,
+or nntphost isn't localhost
+
+Create local.test (if it doen't exist).
+
+Now any mail you will write to mailgate user, will be sent to the
+server. Read local.test on localhost (or nntphost), you will see
+message.
diff --git a/INSTALL b/INSTALL
new file mode 100644
index 0000000..599a64d
--- /dev/null
+++ b/INSTALL
@@ -0,0 +1,29 @@
+For debian user:
+
+Make package as usual:
+
+$ dpkg-buildpackage -uc -us -rfakeroot
+and install .deb file made.
+
+
+
+
+For non debian user only:
+
+Simply run make:
+
+$ make
+
+and install file where you want:
+Something like:
+
+$ install -m 0755 -d /usr/local/lib/pyg
+to create /usr/local/lib/pyg with right permissions
+
+$ make install DESTDIR=/usr/local
+to install file in /usr/local as basedir
+/usr/local/sbin pygs (pyg frontend)
+/usr/local/lib/pyg *.py *.so (module classes)
+
+You may install manually documentation and examples in examples/ dir in
+/usr/local/share/doc or where you wish.
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..e37e417
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,17 @@
+WLPDIR=wlp
+
+CSRCDIR=$(WLPDIR)/C
+MODULEDIR=$(WLPDIR)/module
+BINDIR=$(WLPDIR)
+
+bin:
+ $(MAKE) -C $(WLPDIR)
+
+install:
+ install pygm2n pygn2m $(DESTDIR)/usr/bin
+ install *.py $(DESTDIR)/usr/lib/pyg
+ install *.so $(DESTDIR)/usr/lib/pyg
+
+clean:
+ -$(MAKE) -C $(WLPDIR) clean
+ -rm *.pyc *.so
diff --git a/README b/README
new file mode 100644
index 0000000..4eed9d9
--- /dev/null
+++ b/README
@@ -0,0 +1,14 @@
+Pyg is a news to mail and mail to news gateway.
+It is under devel.
+
+List of file:
+
+mail2news.py mail to news python class module
+news2mail.py news to mail python class module
+pyginfo.py info about pygs python class module
+pygm2n mail to news gateway frontend
+pygn2m news to mail gateway frontend
+whitelist.py whitelist managing python class module
+wlp_test test script to test yout whitelist file
+wlp C backend for whitelist parser (wlp) directory
+examples documentation and exaples directory
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..469ee36
--- /dev/null
+++ b/TODO
@@ -0,0 +1,12 @@
+pygm2n:
+
+Handle better socket errors (try: in sendemail)
+Let choose if remove (let server generate it), regenerete or leave Message-ID
+Post to many server (server list)? maybe.
+reads NNTPHOST environ var to set default host.
+
+
+both:
+
+try: for open() in readfile()
+finish to write HOWTO
diff --git a/examples/README.example b/examples/README.example
new file mode 100644
index 0000000..5dea2fe
--- /dev/null
+++ b/examples/README.example
@@ -0,0 +1,31 @@
+News2Mail:
+
+Using whitelist.example you can try to post articletest.accepted and
+articletest.denied.
+The first one will be accepted by pygs, second one rejected
+
+try to type something like (as normal user):
+
+$ pygn2m -TVt your@local.address -s your@local.address -e your@local.address \
+ -w /usr/share/doc/pyg/example/whitelist.example -l /tmp/pyg.log \
+ < /usr/share/doc/pyg/example/one_article_example
+
+It will reject to post articletest.denied because there are no 'From:' command
+in any section of whitelist.example.
+While it will post articletest.accepted because in the third section
+there is "From: = 'kame@inwind.it'" command.
+
+using -T option will only test, without opening a connection to your
+MTA. -V will change in verbose mode. see manpage for more info.
+
+
+
+Mail2News:
+
+/usr/share/doc/pyg/example/mail is a simple mail in unix mbox format,
+you can use it to test m2n functionality.
+
+$ pygm2n -TVn local.news.group < /usr/share/doc/pyg/example/mail
+
+format a news article to be posted to local.news.group newsgroup. Since
+-TV is present, it doen't open any connection.
diff --git a/examples/articletest.accepted b/examples/articletest.accepted
new file mode 100644
index 0000000..9c06457
--- /dev/null
+++ b/examples/articletest.accepted
@@ -0,0 +1,20 @@
+Path: pyg.server.tld!gateway
+From: pyg@pyg.server.tld (PYG)
+Newsgroups: local.moderated
+Subject: pyg's article test
+Date: 10 Jun 2000 23:20:47 +0200
+Organization: Debian GNU/Linux
+Lines: 8
+Sender: mailgate@localhost
+Approved: mailgate@localhost
+Reply-To: pyg@localhost
+NNTP-Posting-Host: pyg.server.tld
+Mime-Version: 1.0
+Content-Type: text/plain; charset=US-ASCII
+Content-Transfer-Encoding: 7bit
+X-Trace: pyg.server.tld 960672047 927 192.168.1.2 (10 Jun 2000 21:20:47 GMT)
+Xref: pyg.server.tld local.moderated:4
+
+test gateway
+
+.
diff --git a/examples/articletest.denied b/examples/articletest.denied
new file mode 100644
index 0000000..7383eb3
--- /dev/null
+++ b/examples/articletest.denied
@@ -0,0 +1,19 @@
+Path: pyg.server.tld!gateway
+From: pyg@localhost (PYG)
+Newsgroups: local.moderated
+Subject: pyg's article test
+Date: 10 Jun 2000 23:20:47 +0200
+Organization: Debian GNU/Linux
+Lines: 8
+Sender: mailgate@pyg.server.tld
+Approved: mailgate@localhost
+NNTP-Posting-Host: pyg.server.tld
+Mime-Version: 1.0
+Content-Type: text/plain; charset=US-ASCII
+Content-Transfer-Encoding: 7bit
+X-Trace: pyg.server.tld 960672047 927 192.168.1.2 (10 Jun 2000 21:20:47 GMT)
+Xref: pyg.server.tld local.moderated:4
+
+test gateway
+
+.
diff --git a/examples/mail b/examples/mail
new file mode 100644
index 0000000..6db6362
--- /dev/null
+++ b/examples/mail
@@ -0,0 +1,16 @@
+From pyg@localhost Sun Oct 1 16:40:41 2000
+Return-Path: <pyg@localhost>
+Received: by pyg.server.tld (Postfix, from userid 1000)
+ id 096A91838A; Sun, 1 Oct 2000 16:40:40 +0200 (CEST)
+Date: Sun, 1 Feb 2002 16:40:40 +0200
+From: Pyg <pyg@localhost.com>
+To: User <user@localhost.com>
+X-Multiline:
+ this header probably broke RFC, but is frequent.
+Subject: test
+Message-ID: <20001001164040.Aa8326@localhost>
+Mime-Version: 1.0
+Content-Type: text/plain; charset=us-ascii
+User-Agent: Mutt/1.2.5i
+
+one line test
diff --git a/examples/whitelist.example b/examples/whitelist.example
new file mode 100644
index 0000000..9f74108
--- /dev/null
+++ b/examples/whitelist.example
@@ -0,0 +1,14 @@
+<kame@innocent.com> {
+ From: = 'ME' Sender: = "Cosimo" Reply-to = "me"
+}
+
+<alfarano@students.cs.unibo.it> {
+ From: = 'Cosimo Alfarano'
+ X-Firstname: = 'Cosimo'
+}
+
+<kame@innocent.com> {
+ From: = 'kame@inwind.it'
+ Reply-to: = "KA"
+ Sender: = "Kalfa"
+}
diff --git a/mail2news.py b/mail2news.py
new file mode 100644
index 0000000..d340432
--- /dev/null
+++ b/mail2news.py
@@ -0,0 +1,320 @@
+"""Mail to news gateway script. Copyright 2000 Cosimo Alfarano
+
+Author: Cosimo Alfarano
+Date: September 16 2000
+
+mail2news.py - Copyright 2000 by Cosimo Alfarano <Alfarano@Students.CS.UniBo.It>
+You can use this software under the terms of the GPL. If we meet some day,
+and you think this stuff is worth it, you can buy me a beer in return.
+
+Thanks to md for this useful formula. Beer is beer.
+
+Gets news email and sends it via SMTP.
+
+class mail2news is hopefully conform to rfc850.
+
+"""
+
+import sys
+from os import unlink, getpid
+from socket import gethostbyaddr, gethostname
+import string
+from re import findall
+import time
+import nntplib
+import pyginfo
+import tempfile
+
+class mail2news:
+ """news to mail gateway class"""
+
+
+ reader = None # mode reader
+# newsgroups = None # Newsgroups: local.test,local.moderated...
+# approved = None # Approved: kame@aragorn.lorien.org
+ newsserver = 'localhost' # no comment :)
+ port = 119
+ user = None
+ password = None
+
+ hostname = gethostbyaddr(gethostname())[0]
+
+ heads_dict, smtpheads, nntpheads = {}, {}, {}
+ email, headers, body = [], [], []
+
+
+ def readfile(self):
+
+ for line in sys.stdin.readlines():
+ self.email.append(line)
+
+ if(len(self.email) == 1 and self.email[0][0] == '/'):
+ file = self.email[0][:-1]
+ del self.email[0]
+ for line in open(file,'r').readlines():
+ self.email.append(line)
+
+ return 1
+
+
+ def parseemail(self):
+ """get news email from file or stdin and separate heads from body
+
+ REMEBER: headers value has '\n' as last char.
+ Use string[:-1] to ignore newline.
+ """
+
+ try:
+ body = 0 # are we in body or in headers?
+
+ for line in self.email:
+ if not body and len(line) == 1:
+ body = 1 # starts email body section
+
+ if not body:
+ try:
+ # if it is a multi-line header like Received:
+ if not line[0] in [' ','\t']:
+ try:
+ head, value = string.split(line, ' ', 1)
+ except string.index_error:
+ value = ''
+ self.smtpheads[head] = value
+ else:
+ self.smtpheads[head] = '%s%s' % \
+ (self.smtpheads[head], line)
+ except (string.index_error), message:
+ print 'line: %s' % line
+ print '(probably missing couple "Header: value" in %s)' % line
+ sys.exit(1)
+
+ elif len(line) > 0 and body:
+ self.body.append(line)
+
+ except (string.index_error), message:
+ print message
+ sys.exit(1)
+
+ return self.smtpheads, self.body
+
+ def puthead(self, dict, list, key):
+ """private, transform dict entries in list entries
+ Appends key of dict to list, deleting it from dict.
+ """
+
+ if dict.has_key(key):
+ list.append(key + ' ' + dict.get(key))
+ del dict[key]
+ else:
+ return 0
+ return 1
+
+ def sortheads(self):
+ """make list sorted by heads: From: To: Subject: first, others, X-*, X-Resent-* last"""
+
+ set = ('Newsgroups:','From:','To:','X-To:','Cc:','Subject:','Date:','Approved:','References:','Message-Id:') # put at top
+
+ for k in set:
+ self.puthead(self.heads_dict,self.headers,k)
+
+ for k in self.heads_dict.keys():
+ if k[:2] != 'X-' and k[:9] != 'X-Resent-' and k not in set:
+ self.puthead(self.heads_dict,self.headers,k)
+
+ for k in self.heads_dict.keys():
+ if k[:2] == 'X-':
+ self.puthead(self.heads_dict,self.headers,k)
+
+ for k in self.heads_dict.keys():
+ if k[:9] == 'X-Resent-':
+ self.puthead(self.heads_dict,self.headers,k)
+
+ return self.headers
+
+
+ def mergeheads(self):
+ """make a unique headers dictionary from NNTP and SMTP
+ single headers dictionaries."""
+
+ self.heads_dict = {}
+
+ try:
+ for header in self.smtpheads.keys(): # fill it w/ smtp old heads
+ self.heads_dict[header] = self.smtpheads[header]
+
+ for header in self.nntpheads.keys(): # and replace them w/ nntp new heads
+ self.heads_dict[header] = self.nntpheads[header]
+
+ except KeyError, message:
+ print message
+
+ return self.heads_dict
+
+ def addheads(self):
+ """add new header like X-Gateway:
+ """
+
+ info = pyginfo.pygsinfo()
+
+ try:
+ self.heads_dict['X-Gateway:'] = info.PROGNAME + ' ' + \
+ info.PROGDESC + ' - Mail to News\n'
+
+# it is nntpheads stuff
+# if(self.newsgroups):
+# self.heads_dict['Newsgroups:'] = self.newsgroups
+
+# if(self.approved):
+# self.heads_dict['Approved:'] = self.approved
+
+ except KeyError, message:
+ print message
+
+ return self.heads_dict
+
+ def renameheads(self):
+ """rename headers such as Resent-*: to X-Resent-*:
+
+ headers renamed are useless or not rfc 977/850 copliant
+ handles References/In-Reply-To headers
+ """
+ try:
+
+### test
+# if(post):
+# if(self.heads_dict.has_key(post)):
+# self.heads_dict['X-Original-' + post] = self.heads_dict[post]
+#
+# self.heads_dict[post] = self.heads_dict[pre]
+# del(self.heads_dict[pre])
+#
+# else:
+# if(pre[0:2] == 'X-' and self.heads_dict.has_key(pre)):
+# self.heads_dict['X-Original-' + pre] = self.heads_dict[pre]
+# elif(not pre[0:2] == 'X-' and self.heads_dict.has_key('X-' + pre)):
+# self.heads_dict['X-' + pre] = self.heads_dict[pre]
+# del(self.heads_dict[pre])
+### end test
+
+ for key in self.heads_dict.keys():
+ if(key[:7] in ['Resent-']):
+ if(self.heads_dict.has_key('X-' + key)):
+ self.heads_dict[ 'X-Original-' + key ] = self.heads_dict['X-' + key]
+ self.heads_dict[ 'X-' + key ] = self.heads_dict[key]
+ del self.heads_dict[key]
+
+
+ # In rfc822 References: is considered, but many MUA doen't put it.
+ if(not self.heads_dict.has_key('References:') and self.heads_dict.has_key('In-Reply-To:')):
+ print self.heads_dict['In-Reply-To:']
+
+ # some MUA uses msgid without '<' '>'
+# ref = findall('([^\s<>\']+@[^\s<>;:\']+)', \
+ # but I prefer use RFC standards
+ ref = findall('(<[^<>]+@[^<>]+>)', \
+ self.heads_dict['In-Reply-To:'])
+
+ # if found, keep first element that seems a Msg-ID.
+ if(ref and len(ref)):
+ self.heads_dict['References:'] = '%s\n' % ref[0]
+
+# if(self.heads_dict.has_key('To:')):
+# self.heads_dict['X-To:'] = self.heads_dict['To:']
+# del self.heads_dict['To:']
+
+ except KeyError, message:
+ print message
+
+ return self.heads_dict
+
+
+ def removeheads(self, heads = None):
+ """remove headers like Xref: Path: Lines:
+ """
+
+ try:
+ # removing some others useless headers .... (From is not From:)
+
+ rmheads = ['Received:', 'From', 'NNTP-Posting-Host:', \
+ 'X-Trace:', 'X-Compliants-To:', 'NNTP-Posting-Date:']
+ if(heads):
+ rmheads.append(heads)
+
+ for head in rmheads:
+ if self.heads_dict.has_key(head):
+ del self.heads_dict[head]
+
+# if self.heads_dict.has_key('From'): # neither 'From ' nor 'From:'
+# del self.heads_dict['From']
+
+# if self.heads_dict.has_key('NNTP-Posting-Host:'): # neither 'From ' nor 'From:'
+# del self.heads_dict['']
+
+
+# if self.heads_dict.has_key('Lines:'):
+# del self.heads_dict['Lines:']
+
+ # it is usually set by INN, if ng is moderated...
+# if self.heads_dict.has_key('Sender:'):
+# del self.heads_dict['Sender:']
+
+
+ if self.heads_dict.has_key('Message-id:'):
+ self.heads_dict['Message-Id:'] = self.heads_dict['Message-id:']
+ del(self.heads_dict['Message-id:'])
+
+ if self.heads_dict.has_key('Message-ID:'):
+ self.heads_dict['Message-Id:'] = self.heads_dict['Message-ID:']
+ del(self.heads_dict['Message-ID:'])
+
+ # If message-id is not present, I generate it
+ if not self.heads_dict.has_key('Message-Id:'):
+ msgid = '<pyg.%d@tuchailepuppapera.org>\n' % (getpid())
+ self.heads_dict['Message-Id:'] = msgid
+
+ except KeyError, message:
+ print message
+
+ return self.heads_dict
+
+ def sendemail(self):
+ """Talk to NNTP server and try to send email."""
+ try:
+ msglist = []
+
+ n = nntplib.NNTP(self.newsserver, self.port, self.user, self.password)
+
+ if(self.reader):
+ n.putline('mode reader')
+ resp = n.getline()
+ print resp
+
+ resp = n.shortcmd('POST')
+
+ # sett RFC977 2.4.2
+ if resp[0] <> '3':
+ raise n.error_reply, str(resp)
+
+ for line in self.headers:
+ if not line:
+ break
+ if line[-1] == '\n':
+ line = line[:-1]
+ if line[:1] == '.':
+ line = '.' + line
+ n.putline(line)
+
+ for line in self.body:
+ if not line:
+ break
+ if line[-1] == '\n':
+ line = line[:-1]
+ if line[:1] == '.':
+ line = '.' + line
+ n.putline(line)
+
+ n.putline('.')
+ n.quit()
+ return None
+ except (nntplib.error_reply, nntplib.error_temp, nntplib.error_perm, nntplib.error_proto, nntplib.error_data), message:
+ return 'NNTP: ' + str(message)
diff --git a/mail2news.py.withtab b/mail2news.py.withtab
new file mode 100644
index 0000000..8b80e0c
--- /dev/null
+++ b/mail2news.py.withtab
@@ -0,0 +1,319 @@
+"""Mail to news gateway script. Copyright 2000 Cosimo Alfarano
+
+Author: Cosimo Alfarano
+Date: September 16 2000
+
+mail2news.py - Copyright 2000 by Cosimo Alfarano <Alfarano@Students.CS.UniBo.It>
+You can use this software under the terms of the GPL. If we meet some day,
+and you think this stuff is worth it, you can buy me a beer in return.
+
+Thanks to md for this useful formula. Beer is beer.
+
+Gets news email and sends it via SMTP.
+
+class mail2news is hopefully conform to rfc850.
+
+"""
+
+import sys
+from os import unlink, getpid
+from socket import gethostbyaddr, gethostname
+import string
+from re import findall
+import time
+import nntplib
+import pyginfo
+import tempfile
+
+class mail2news:
+ """news to mail gateway class"""
+
+
+ reader = None # mode reader
+# newsgroups = None # Newsgroups: local.test,local.moderated...
+# approved = None # Approved: kame@aragorn.lorien.org
+ newsserver = 'localhost' # no comment :)
+ port = 119
+ user = None
+ password = None
+
+ hostname = gethostbyaddr(gethostname())[0]
+
+ heads_dict, smtpheads, nntpheads = {}, {}, {}
+ email, headers, body = [], [], []
+
+
+ def readfile(self):
+
+ for line in sys.stdin.readlines():
+ self.email.append(line)
+
+ if(len(self.email) == 1 and self.email[0][0] == '/'):
+ file = self.email[0][:-1]
+ del self.email[0]
+ for line in open(file,'r').readlines():
+ self.email.append(line)
+
+ return 1
+
+
+ def parseemail(self):
+ """get news email from file or stdin and separate heads from body
+
+ REMEBER: headers value has '\n' as last char.
+ Use string[:-1] to ignore newline.
+ """
+
+ try:
+ body = 0 # are we in body or in headers?
+
+ for line in self.email:
+ if not body and len(line) == 1:
+ body = 1 # starts email body section
+
+ if not body:
+ try:
+ # if it is a multi-line header like Received:
+ if not line[0] in [' ','\t']:
+ try:
+ head, value = string.split(line, ' ', 1)
+ except string.index_error:
+ value = ''
+ self.smtpheads[head] = value
+ else:
+ self.smtpheads[head] = '%s%s' % \
+ (self.smtpheads[head], line)
+ except (string.index_error), message:
+ print 'line: %s' % line
+ print '(probably missing couple "Header: value" in %s)' % line
+ sys.exit(1)
+
+ elif len(line) > 0 and body:
+ self.body.append(line)
+
+ except (string.index_error), message:
+ print message
+ sys.exit(1)
+
+ return self.smtpheads, self.body
+
+ def puthead(self, dict, list, key):
+ """private, transform dict entries in list entries
+ Appends key of dict to list, deleting it from dict.
+ """
+
+ if dict.has_key(key):
+ list.append(key + ' ' + dict.get(key))
+ del dict[key]
+ else:
+ return 0
+ return 1
+
+ def sortheads(self):
+ """make list sorted by heads: From: To: Subject: first, others, X-*, X-Resent-* last"""
+
+ set = ('Newsgroups:','From:','To:','X-To:','Cc:','Subject:','Date:','Approved:','References:','Message-Id:') # put at top
+
+ for k in set:
+ self.puthead(self.heads_dict,self.headers,k)
+
+ for k in self.heads_dict.keys():
+ if k[:2] != 'X-' and k[:9] != 'X-Resent-' and k not in set:
+ self.puthead(self.heads_dict,self.headers,k)
+
+ for k in self.heads_dict.keys():
+ if k[:2] == 'X-':
+ self.puthead(self.heads_dict,self.headers,k)
+
+ for k in self.heads_dict.keys():
+ if k[:9] == 'X-Resent-':
+ self.puthead(self.heads_dict,self.headers,k)
+
+ return self.headers
+
+
+ def mergeheads(self):
+ """make a unique headers dictionary from NNTP and SMTP
+ single headers dictionaries."""
+
+ self.heads_dict = {}
+
+ try:
+ for header in self.smtpheads.keys(): # fill it w/ smtp old heads
+ self.heads_dict[header] = self.smtpheads[header]
+
+ for header in self.nntpheads.keys(): # and replace them w/ nntp new heads
+ self.heads_dict[header] = self.nntpheads[header]
+
+ except KeyError, message:
+ print message
+
+ return self.heads_dict
+
+ def addheads(self):
+ """add new header like X-Gateway:
+ """
+
+ info = pyginfo.pygsinfo()
+
+ try:
+ self.heads_dict['X-Gateway:'] = info.PROGNAME + ' ' + \
+ info.PROGDESC + ' - Mail to News\n'
+
+# it is nntpheads stuff
+# if(self.newsgroups):
+# self.heads_dict['Newsgroups:'] = self.newsgroups
+
+# if(self.approved):
+# self.heads_dict['Approved:'] = self.approved
+
+ except KeyError, message:
+ print message
+
+ return self.heads_dict
+
+ def renameheads(self):
+ """rename headers such as Resent-*: to X-Resent-*:
+
+ headers renamed are useless or not rfc 977/850 copliant
+ handles References/In-Reply-To headers
+ """
+ try:
+
+### test
+# if(post):
+# if(self.heads_dict.has_key(post)):
+# self.heads_dict['X-Original-' + post] = self.heads_dict[post]
+#
+# self.heads_dict[post] = self.heads_dict[pre]
+# del(self.heads_dict[pre])
+#
+# else:
+# if(pre[0:2] == 'X-' and self.heads_dict.has_key(pre)):
+# self.heads_dict['X-Original-' + pre] = self.heads_dict[pre]
+# elif(not pre[0:2] == 'X-' and self.heads_dict.has_key('X-' + pre)):
+# self.heads_dict['X-' + pre] = self.heads_dict[pre]
+# del(self.heads_dict[pre])
+### end test
+
+ for key in self.heads_dict.keys():
+ if(key[:7] in ['Resent-']):
+ if(self.heads_dict.has_key('X-' + key)):
+ self.heads_dict[ 'X-Original-' + key ] = self.heads_dict['X-' + key]
+ self.heads_dict[ 'X-' + key ] = self.heads_dict[key]
+ del self.heads_dict[key]
+
+
+ # In rfc822 References: is considered, but many MUA doen't put it.
+ if(not self.heads_dict.has_key('References:') and self.heads_dict.has_key('In-Reply-To:')):
+ print self.heads_dict['In-Reply-To:']
+
+ # some MUA uses msgid without '<' '>'
+# ref = findall('([^\s<>\']+@[^\s<>;:\']+)', \
+ # but I prefer use RFC standards
+ ref = findall('(<[^<>]+@[^<>]+>)', \
+ self.heads_dict['In-Reply-To:'])
+
+ # if found, keep first element that seems a Msg-ID.
+ if(ref and len(ref)):
+ self.heads_dict['References:'] = '%s\n' % ref[0]
+
+# if(self.heads_dict.has_key('To:')):
+# self.heads_dict['X-To:'] = self.heads_dict['To:']
+# del self.heads_dict['To:']
+
+ except KeyError, message:
+ print message
+
+ return self.heads_dict
+
+
+ def removeheads(self, heads = None):
+ """remove headers like Xref: Path: Lines:
+ """
+
+ try:
+ # removing some others useless headers .... (From is not From:)
+
+ rmheads = ['Received:','From','NNTP-Posting-Host:','X-Trace']
+ if(heads):
+ rmheads.append(heads)
+
+ for head in rmheads:
+ if self.heads_dict.has_key(head):
+ del self.heads_dict[head]
+
+# if self.heads_dict.has_key('From'): # neither 'From ' nor 'From:'
+# del self.heads_dict['From']
+
+# if self.heads_dict.has_key('NNTP-Posting-Host:'): # neither 'From ' nor 'From:'
+# del self.heads_dict['']
+
+
+# if self.heads_dict.has_key('Lines:'):
+# del self.heads_dict['Lines:']
+
+ # it is usually set by INN, if ng is moderated...
+# if self.heads_dict.has_key('Sender:'):
+# del self.heads_dict['Sender:']
+
+
+ if self.heads_dict.has_key('Message-id:'):
+ self.heads_dict['Message-Id:'] = self.heads_dict['Message-id:']
+ del(self.heads_dict['Message-id:'])
+
+ if self.heads_dict.has_key('Message-ID:'):
+ self.heads_dict['Message-Id:'] = self.heads_dict['Message-ID:']
+ del(self.heads_dict['Message-ID:'])
+
+ # If message-id is not present, I generate it
+ if not self.heads_dict.has_key('Message-Id:'):
+ msgid = '<pyg.%d@tuchailepuppapera.org>\n' % (getpid())
+ self.heads_dict['Message-Id:'] = msgid
+
+ except KeyError, message:
+ print message
+
+ return self.heads_dict
+
+ def sendemail(self):
+ """Talk to NNTP server and try to send email."""
+ try:
+ msglist = []
+
+ n = nntplib.NNTP(self.newsserver, self.port, self.user, self.password)
+
+ if(self.reader):
+ n.putline('mode reader')
+ resp = n.getline()
+ print resp
+
+ resp = n.shortcmd('POST')
+
+ # sett RFC977 2.4.2
+ if resp[0] <> '3':
+ raise n.error_reply, str(resp)
+
+ for line in self.headers:
+ if not line:
+ break
+ if line[-1] == '\n':
+ line = line[:-1]
+ if line[:1] == '.':
+ line = '.' + line
+ n.putline(line)
+
+ for line in self.body:
+ if not line:
+ break
+ if line[-1] == '\n':
+ line = line[:-1]
+ if line[:1] == '.':
+ line = '.' + line
+ n.putline(line)
+
+ n.putline('.')
+ n.quit()
+ return None
+ except (nntplib.error_reply, nntplib.error_temp, nntplib.error_perm, nntplib.error_proto, nntplib.error_data), message:
+ return 'NNTP: ' + str(message)
diff --git a/news2mail.py b/news2mail.py
new file mode 100644
index 0000000..73808b3
--- /dev/null
+++ b/news2mail.py
@@ -0,0 +1,299 @@
+"""News to mail gateway script. Copyright 2000 Cosimo Alfarano
+
+Author: Cosimo Alfarano
+Date: June 11 2000
+
+news2mail.py - Copyright 2000 by Cosimo Alfarano <Alfarano@Students.CS.UniBo.It>
+You can use this software under the terms of the GPL. If we meet some day,
+and you think this stuff is worth it, you can buy me a beer in return.
+
+Thanks to md for this useful formula. Beer is beer.
+
+
+Gets news article and sends it via SMTP.
+
+class news2mail is hopefully conform to rfc822.
+
+normal (what pygs does) operations flow is:
+1) reads from stdin NNTP article (readfile)
+2) divide headers and body (parsearticle)
+3) merges NNTP and SMTP heads into a unique heads
+4) adds, renames and removes some heads
+5) sorts remaining headers starting at top with Received: From: To: Subject:
+ Date:, normal headers ending with X-* and Resent-* headers.
+
+"""
+
+import sys
+import smtplib
+import string
+from re import compile
+#import getopt
+import time
+#import rfc822
+from socket import gethostbyaddr, gethostname
+import tempfile
+import pyginfo
+
+class news2mail:
+ """news to mail gateway class"""
+
+ TMPFILE = tempfile.mktemp()
+ wlfile = None
+ logfile = None
+
+ sender = ''
+ rcpt = ''
+ envelope = ''
+
+ smtpserver = 'localhost'
+
+ hostname = gethostbyaddr(gethostname())[0]
+
+ heads_dict, smtpheads, nntpheads = {}, {}, {}
+ article, headers, body = [], [], []
+
+ debug = 1
+
+ def readfile(self):
+
+ for line in sys.stdin.readlines():
+ self.article.append(line)
+
+ if (len(self.article) == 1 and self.article[0][0] == '/'):
+ file = self.article[0][:-1]
+ del self.article[0]
+ for line in open(file,'r').readlines():
+ self.article.append(line)
+
+
+ def parsearticle(self):
+ """get news article from file or stdin and separate heads from body
+
+ REMEBER: headers value has '\n' as last char.
+ Use string[:-1] to ignore newline.
+ """
+
+ try:
+ body = 0 # are we in body or in headers?
+
+# voidline = compile('^$') # I need '\n', ^$ matches anything
+# spaceending = compile('\s*\n$')
+
+ for line in self.article:
+ if not body and len(line) == 1:
+ body = 1 # starts article body section
+
+ if not body:
+ try:
+ head, value = string.split(line, ' ', 1)
+ self.nntpheads[head] = value
+ except (string.index_error), message:
+ print 'string error: %s' % message
+ print '(probably missing couple "Header: value" in %s)' % line
+ sys.exit(1)
+
+ elif len(line) > 0 and body:
+ self.body.append(line)
+
+ return self.nntpheads, self.body
+
+# except (re.error, string.index_error), message:
+ except (string.index_error), message:
+ print message
+ sys.exit(1)
+
+
+ def puthead(self, dict, list, key):
+ """private, x-form dict entries in list entries"""
+
+ if dict.has_key(key):
+ list.append(key + ' ' + dict.get(key))
+ else:
+ return 0
+ return 1
+
+ def sortheads(self):
+ """make list sorting heads, Received: From: To: Subject: first, others, X-*, Resent-* last"""
+
+ set = ('Received:','From:','To:','Subject:','Date:') # put at top
+
+ for k in set:
+ self.puthead(self.heads_dict,self.headers,k)
+
+ for k in self.heads_dict.keys():
+ if k[:2] != 'X-' and k[:7] != 'Resent-' and k not in set:
+ self.puthead(self.heads_dict,self.headers,k)
+
+ for k in self.heads_dict.keys():
+ if k[:2] == 'X-':
+ self.puthead(self.heads_dict,self.headers,k)
+
+ for k in self.heads_dict.keys():
+ if k[:7] == 'Resent-':
+ self.puthead(self.heads_dict,self.headers,k)
+
+ return self.headers
+
+
+ def mergeheads(self):
+ """make a unique headers dictionary from NNTP and SMTP
+ single headers dictionaries."""
+
+ self.heads_dict = {}
+
+
+ try:
+ for header in self.nntpheads.keys(): # fill it w/ nntp old heads
+ self.heads_dict[header] = self.nntpheads[header]
+
+ for header in self.smtpheads.keys(): # and replace them w/ smtp new heads
+ self.heads_dict[header] = self.smtpheads[header]
+
+ except KeyError, message:
+ print message
+
+ return self.heads_dict
+
+ def addheads(self):
+ """add new header like X-Gateway: Received:
+ """
+
+ info = pyginfo.pygsinfo()
+
+ try:
+ self.heads_dict['X-Gateway:'] = info.PROGNAME + ' ' + \
+ info.__doc__ + '\n'
+
+ ##self.heads_dict['X-Gateway:'] = '%s %s\n' % (info.PROGNAME, info.__doc__)
+
+ # to make Received: header
+ t = time.ctime(time.time())
+
+ if time.daylight:
+ tzone = time.tzname[1]
+ else:
+ tzone = time.tzname[0]
+
+ # An exemple from debian-italian:
+ # Received: from murphy.debian.org (murphy.debian.org [216.234.231.6])
+ # by smv04.iname.net (8.9.3/8.9.1SMV2) with SMTP id JAA26407
+ # for <kame.primo@innocent.com> sent by
+ # <debian-italian-request@lists.debian.org
+
+ tmp = 'from GATEWAY by ' + self.hostname + \
+ ' with ' + info.PROGNAME + \
+ '\n\tfor <' + self.rcpt + '> ; ' + \
+ t + ' (' + tzone +')\n'
+
+ self.heads_dict['Received:'] = tmp
+ except KeyError, message:
+ print message
+
+ return self.heads_dict
+
+ def renameheads(self):
+ """rename headers such as Newsgroups: to X-Newsgroups:
+
+ headers renamed are useless or not rfc 822 copliant
+ """
+ try:
+ if self.heads_dict.has_key('Newsgroups:'):
+ self.heads_dict['X-Newsgroups:'] = self.heads_dict['Newsgroups:']
+ del self.heads_dict['Newsgroups:']
+
+ if self.heads_dict.has_key('NNTP-Posting-Host:'):
+ self.heads_dict['X-NNTP-Posting-Host:'] = self.heads_dict['NNTP-Posting-Host:']
+ del self.heads_dict['NNTP-Posting-Host:']
+ except KeyError, message:
+ print message
+
+ return self.heads_dict
+
+
+ def removeheads(self):
+ """remove headers like Xref: Path: Lines:
+ """
+
+ try:
+ # removing some others useless headers ....
+
+ if self.heads_dict.has_key('Approved:'):
+ del self.heads_dict['Approved:']
+
+ if self.heads_dict.has_key('From'): # neither 'From ' nor 'From:'
+ del self.heads_dict['From']
+
+ if self.heads_dict.has_key('Xref:'):
+ del self.heads_dict['Xref:']
+
+ if self.heads_dict.has_key('Path:'):
+ del self.heads_dict['Path:']
+
+ if self.heads_dict.has_key('Lines:'):
+ del self.heads_dict['Lines:']
+
+ # it is usually set by INN, if ng is moderated...
+ if self.heads_dict.has_key('Sender:'):
+ del self.heads_dict['Sender:']
+
+
+ if self.heads_dict.has_key('Message-id:'):
+ self.heads_dict['Message-Id:'] = self.heads_dict['Message-id']
+ del(self.heads_dict['Message-id'])
+
+ if self.heads_dict.has_key('Message-ID:'):
+ self.heads_dict['Message-Id:'] = self.heads_dict['Message-ID']
+ del(self.heads_dict['Message-ID'])
+
+ # If message-id is not present, I generate it
+ if not self.heads_dict.has_key('Message-Id:'):
+ # It should put a real user@domain
+ msgid = 'pyg@puppapera.org'
+
+ except KeyError, message:
+ print message
+
+ return self.heads_dict
+
+ def sendarticle(self):
+ """Talk to SMTP server and try to send email."""
+ try:
+ msglist = []
+
+ s = smtplib.SMTP(self.smtpserver)
+
+ # put real locahost domain name.
+ s.helo(self.hostname)
+ if s.helo_resp is None and s.ehlo_resp is None:
+ print 'No helo resp'
+ sys.exit(1)
+
+ resp = s.mail(self.envelope)
+ if resp[0] != 250:
+ print 'SMTP error during MAIL cmd: %s %s' % (resp[0], resp[1])
+ print 'envelope %s gave problem?' % self.envelope
+ sys.exit(1)
+ resp = s.rcpt(self.rcpt)
+ if resp[0] != 250:
+ print 'SMTP error during MAIL cmd: %s %s' % (resp[0], resp[1])
+ sys.exit(1)
+
+
+ msglist.append(string.join(self.headers,''))
+
+ msglist.append(string.join(self.body,''))
+ msg = string.join(msglist,'')
+
+ s.data(msg)
+ s.quit()
+
+ return 1
+
+ except (smtplib.SMTPException), messaggio:
+ print messaggio
+ sys.exit(1)
+
+
+
+
diff --git a/pyginfo.py b/pyginfo.py
new file mode 100644
index 0000000..a9a0bfa
--- /dev/null
+++ b/pyginfo.py
@@ -0,0 +1,26 @@
+"""News to mail gateway script. Copyright 2000 Cosimo Alfarano
+
+Author: Cosimo Alfarano
+Date: June 11 2000
+
+pyginfo.py - Copyright 2000 by Cosimo Alfarano <Alfarano@Students.CS.UniBo.It>
+You can use this software under the terms of the GPL. If we meet some day,
+and you think this stuff is worth it, you can buy me a beer in return.
+
+Thanks to md for this useful formula. Beer is beer.
+
+
+Gets news article and sends it via SMTP.
+"""
+
+
+class pygsinfo:
+ """The Python Gateway Script: news2mail mail2news gateway"""
+
+ PROGNAME = 'pyg'
+ PROGDESC= 'The Python Gateway'
+
+ MAJOR = '0'
+ MINOR = '7b'
+ VERSION = MAJOR + '.' + MINOR
+
diff --git a/pygm2n b/pygm2n
new file mode 100755
index 0000000..428ca5b
--- /dev/null
+++ b/pygm2n
@@ -0,0 +1,223 @@
+#!/usr/bin/env python
+
+"""News to mail gateway script. Copyright 2000 Cosimo Alfarano
+
+Author: Cosimo Alfarano
+Date: June 11 2000
+
+pygs - Copyright 2000 by Cosimo Alfarano <Alfarano@Students.CS.UniBo.It>
+You can use this software under the terms of the GPL. If we meet some day,
+and you think this stuff is worth it, you can buy me a beer in return.
+
+Thanks to md for this useful formula. Beer is beer.
+
+Gets news article and sends it via SMTP.
+"""
+
+import sys, os
+import getopt
+from string import split
+
+sys.path.append('/usr/lib/pyg')
+
+import pyginfo
+import mail2news
+
+
+def parse_cmdline(gw):
+ """Parses cmdline with getopt. and returns a dictionary with
+ smtp new header
+ """
+
+ opt, arg = None, None
+ test, verbose = 0, 0
+# retnull = (None, None)
+ retnull = None
+
+ retval = { 'test': 0,
+ 'verbose': 0 }
+
+ try:
+ opt, arg = getopt.getopt(sys.argv[1:],"a:s:n:u:p:P:hvVTM")
+ except (getopt.error), message:
+ print '%s: %s\n' % (sys.argv[0], message)
+ sys.exit(1)
+
+ if len(sys.argv) == 1 or opt == []:
+ gw.smtpheads = None
+ return retnull
+
+ for i in range(len(opt)):
+ if opt[i][0] == '-h':
+ gw.nntpheads = None
+ return retnull
+ elif opt[i][0] == '-v':
+ gw.nntpheads = None
+ return retnull
+ elif opt[i][0] == '-n':
+ gw.nntpheads['Newsgroups:'] = opt[i][1] + '\n'
+ elif opt[i][0] == '-a':
+ gw.nntpheads['Approved:'] = opt[i][1] + '\n'
+ elif opt[i][0] == '-s':
+ gw.newsserver = opt[i][1]
+ elif opt[i][0] == '-P':
+ gw.port = int(opt[i][1])
+# elif opt[i][0] == '-d':
+# gw.debug = 1
+ elif opt[i][0] == '-u':
+ gw.user = opt[i][1]
+ elif opt[i][0] == '-p':
+ gw.password = opt[i][1]
+ elif opt[i][0] == '-T':
+ retval['test'] = 1
+ elif opt[i][0] == '-V':
+ retval['verbose'] = 1
+ elif opt[i][0] == '-M':
+ gw.reader = 1
+
+ if not gw.nntpheads.has_key('Newsgroups:'):
+ print 'Error: Missing Newsgroups\n'
+ return retnull
+
+
+# By rfc822 [Resent-]Sender: should be ever set, unless == From:
+# (not this case). Should be a human, while [Resent-]From: may be a program.
+
+# if gw.rcpt == '' or gw.sender == '':
+# print 'missing command line option'
+# gw.smtpheads = None
+# return retnull
+
+# if gw.envelope == '' and gw.sender != '':
+# gw.smtpheads['Resent-From:'] = gw.sender + '\n'
+# gw.envelope = gw.sender
+# elif gw.envelope == -1:
+# gw.smtpheads = None
+# return retnull
+
+ sys.argv[1:] = arg
+
+# return (test, verbose)
+ return retval
+
+
+def usage():
+ i = pyginfo.pygsinfo()
+
+ print '%s version %s - Copyright 2000 Cosimo Alfarano' % (i.PROGNAME, i.VERSION)
+ print i.PROGDESC + ' - Mail to News'
+ print
+ print 'usage: %s -n newsgroup [-h] [-a approver] [-n newsgroup] [-T] [-V]' % split(sys.argv[0],'/')[-1]
+ print '-n newsgroup[s] (specified as comma separated without spaces list)'
+ print '-u user | -p passwword (for auth to newsserver)'
+ print '-a address of moderator/approver'
+ print '-s servername'
+# print '-d for debug'
+ print '-h or -v for this info'
+ print '-T for test mode (not send article via NNTP)'
+ print '-V for verbose output (usefull with -T option for debugging)'
+
+
+
+
+
+
+
+
+
+
+
+
+"""main is structured in 4 phases:
+ 1) check and set pyg's internal variables
+ 2) check whitelist for users' permission
+ 3) format rfc 822 headers from input article
+ 4) open smtp connection and send e-mail
+"""
+
+
+try:
+
+ """phase 1:
+ check and set pyg's internal variables
+ """
+
+ m2n = mail2news.mail2news()
+ owner = None
+
+ opt = parse_cmdline(m2n)
+ if(opt == None):
+ usage()
+ sys.exit(0)
+
+
+ # check if m2n has some file prefercences set on commandline
+# if(m2n.wlfile == None):
+# wl = os.environ['HOME'] + '/pyg.whitelist'
+# else:
+# wl = m2n.wlfile
+#
+# if(m2n.logfile == None):
+# log = os.environ['HOME'] + '/pyg.log'
+# else:
+# log = m2n.logfile
+
+
+# wl = whitelist.whitelist(wl,log)
+
+ # reads stdin and parses article separating head from body
+ m2n.readfile()
+ m2n.parseemail()
+
+
+
+# for line in m2n.email:
+# print line[:-1]
+
+# for line in m2n.smtpheads.keys():
+# print line
+# print m2n.smtpheads[line][:-1]
+
+ """phase 2:
+ check whitelist for user's permission
+ """
+
+ # make a first check of From: address
+# owner = wl.checkfrom(m2n.nntpheads['From:'])
+# if(owner == None):
+# if(sys.stdin.isatty()==1 or test or verbose):
+# print ('"%s" is not in whitelist!' % (m2n.nntpheads['From:'][:-1]))
+# else:
+# wl.logmsg(m2n.nntpheads,wl.DENY)
+# sys.exit(1)
+
+ """phase 3:
+ format rfc 822 headers from input article
+ """
+
+ m2n.mergeheads() # make unique dict from NNTP and SMTP dicts
+
+ m2n.addheads() # add some important heads
+ m2n.renameheads() # rename useless heads
+ m2n.removeheads() # remove other heads
+
+ m2n.sortheads() # sort remaining heads :)
+
+ if(opt['verbose']):
+ for line in m2n.headers:
+ print line[:-1]
+
+ """phase 4:
+ open smtp connection and send e-mail
+ """
+
+ if(len(m2n.headers) > 0 and len(m2n.body) > 0):
+# wl.logmsg(m2n.heads_dict,wl.ACCEPT,owner)
+ if(not opt['test']):
+ resp = m2n.sendemail()
+ if resp:
+ print resp
+
+except KeyboardInterrupt:
+ print 'Keyboard Interrupt'
+ sys.exit(0)
diff --git a/pygn2m b/pygn2m
new file mode 100755
index 0000000..d093756
--- /dev/null
+++ b/pygn2m
@@ -0,0 +1,214 @@
+#!/usr/bin/env python
+
+"""News to mail gateway script. Copyright 2000 Cosimo Alfarano
+
+Author: Cosimo Alfarano
+Date: June 11 2000
+
+pygs - Copyright 2000 by Cosimo Alfarano <Alfarano@Students.CS.UniBo.It>
+You can use this software under the terms of the GPL. If we meet some day,
+and you think this stuff is worth it, you can buy me a beer in return.
+
+Thanks to md for this useful formula. Beer is beer.
+
+Gets news article from stdin and sends it via SMTP.
+"""
+
+import sys, os
+import getopt
+from string import split
+
+sys.path.append('/usr/lib/pyg')
+
+import pyginfo
+import whitelist
+import news2mail
+#import mail2news
+
+
+def parse_cmdline(gw):
+ """Parses cmdline with getopt.
+ set a dictionary with smtp new header in gw parameter (gw.smtpheads)
+ return (test,verbose) boolean tuple
+ """
+
+ opt, arg = None, None
+ test, verbose = 0, 0
+ retnull = (None, None)
+
+ try:
+ opt, arg = getopt.getopt(sys.argv[1:],"H:t:s:e:w:l:hdvVT")
+ except (getopt.error), message:
+ print '%s: %s\n' % (sys.argv[0], message)
+ sys.exit(1)
+
+ if len(sys.argv) == 1 or opt == []:
+ gw.smtpheads = None
+ return retnull
+
+ for i in range(len(opt)):
+ if opt[i][0] == '-h':
+ gw.smtpheads = None
+ return retnull
+ elif opt[i][0] == '-v':
+ gw.smtpheads = None
+ return retnull
+ elif opt[i][0] == '-H':
+ gw.smtpserver = opt[i][1]
+ elif opt[i][0] == '-s':
+ gw.smtpheads['Resent-Sender:'] = opt[i][1] + '\n'
+ gw.sender = opt[i][1]
+ elif opt[i][0] == '-t' or opt[i][0] == '-r':
+ gw.smtpheads['To:'] = opt[i][1] + '\n'
+ gw.rcpt = opt[i][1]
+ elif opt[i][0] == '-e':
+ gw.smtpheads['Resent-From:'] = opt[i][1] + '\n' #envelope
+ gw.envelope = opt[i][1]
+ elif opt[i][0] == '-w':
+ gw.wlfile = opt[i][1]
+ elif opt[i][0] == '-l':
+ gw.logfile = opt[i][1]
+ elif opt[i][0] == '-d':
+ gw.debug = 1
+ elif opt[i][0] == '-T':
+ test = 1
+ elif opt[i][0] == '-V':
+ verbose = 1
+
+# By rfc822 [Resent-]Sender: should be ever set, unless == From:
+# (not this case). Should be a human, while [Resent-]From: may be a program.
+
+ if gw.rcpt == '' or gw.sender == '':
+ print 'missing command line option'
+ gw.smtpheads = None
+ return retnull
+
+ if gw.envelope == '' and gw.sender != '':
+ gw.smtpheads['Resent-From:'] = gw.sender + '\n'
+ gw.envelope = gw.sender
+ elif gw.envelope == -1:
+ gw.smtpheads = None
+ return retnull
+
+ sys.argv[1:] = arg
+
+ return (test, verbose)
+
+
+def usage():
+ i = pyginfo.pygsinfo()
+
+ print '%s version %s - Copyright 2000 Cosimo Alfarano' % (i.PROGNAME, i.VERSION)
+ print i.__doc__
+ print
+ print 'usage: %s [-h] [-d] [-T] [-V] [-H smtphost] [-l logfile] [-w whitelist] -t recipient@... -s sender@... [-e envelope@...]' % split(sys.argv[0],'/')[-1]
+ print '-t -s recipient, sender are necessary'
+ print '-e envelope [default: same of sender]'
+ print '-T for test mode (not send article via SMTP)'
+ print '-V for verbose output'
+ print '-d for debug'
+ print '-h or -v for this info'
+
+
+
+
+
+
+
+
+"""main is structured in 4 phases:
+ 1) check and set pyg's internal variables
+ 2) check whitelist for users' permission
+ 3) format rfc 822 headers from input article
+ 4) open smtp connection and send e-mail
+"""
+
+
+try:
+
+ """phase 1:
+ check and set pyg's internal variables
+ """
+
+ n2m = news2mail.news2mail()
+ owner = None
+
+ # it returns only test, other parms are set directly in the actual parameter
+ (test, verbose) = parse_cmdline(n2m)
+ if (test, verbose) == (None, None):
+ usage()
+ sys.exit(0)
+
+
+ # check if n2m has some file prefercences set on commandline
+ if(n2m.wlfile == None):
+ wl = os.environ['HOME'] + '/pyg.whitelist'
+ else:
+ wl = n2m.wlfile
+
+ if(n2m.logfile == None):
+ log = os.environ['HOME'] + '/pyg.log'
+ else:
+ log = n2m.logfile
+
+# print 'using %s %s\n' % (wl,log)
+
+ wl = whitelist.whitelist(wl,log)
+
+ # reads stdin and parses article separating head from body
+ n2m.readfile()
+ n2m.parsearticle()
+
+
+ """phase 2:
+ check whitelist for user's permission
+ """
+
+ # make a first check of From: address
+ owner = wl.checkfrom(n2m.nntpheads['From:'])
+ if(owner == None):
+ if(sys.stdin.isatty()==1 or test):
+ print ('"%s" is not in whitelist!' % (n2m.nntpheads['From:'][:-1]))
+ else:
+ wl.logmsg(n2m.nntpheads,wl.DENY)
+
+ # if verbose, I want to print out headers, so I can't
+ # exit now.
+ if(not verbose):
+ sys.exit(1)
+
+ """phase 3:
+ format rfc 822 headers from input article
+ """
+
+ n2m.mergeheads() # make unique dict from NNTP and SMTP dicts
+
+ n2m.addheads() # add some important heads
+ n2m.renameheads() # rename useless heads
+ n2m.removeheads() # remove other heads
+
+ n2m.sortheads() # sort remaining heads :)
+
+ # prints formatted email message only (without send) if user wants
+ if(verbose):
+ for line in n2m.headers:
+ print line[:-1]
+
+ if(owner == None):
+ sys.exit(1)
+
+
+ """phase 4:
+ open smtp connection and send e-mail
+ """
+
+ if len(n2m.headers) > 0:
+ wl.logmsg(n2m.heads_dict,wl.ACCEPT,owner)
+ if(not test):
+ n2m.sendarticle()
+ else:
+ print 'Error: No Headers!!!'
+
+except KeyboardInterrupt:
+ print 'Keyboard Interrupt'
+ sys.exit(1)
diff --git a/whitelist.py b/whitelist.py
new file mode 100644
index 0000000..7eb88cd
--- /dev/null
+++ b/whitelist.py
@@ -0,0 +1,129 @@
+"""News to mail gateway script. Copyright 2000 Cosimo Alfarano
+
+Author: Cosimo Alfarano
+Date: June 11 2000
+
+whitelist.py - Copyright 2000 by Cosimo Alfarano <Alfarano@Students.CS.UniBo.It>
+You can use this software under the terms of the GPL. If we meet some day,
+and you think this stuff is worth it, you can buy me a beer in return.
+
+Thanks to md for this useful formula. Beer is beer.
+
+whitelist manage a list of trusted user.
+"""
+
+import sys
+import string
+import time
+import fcntl
+
+import pyginfo
+import wlp
+
+
+class whitelist:
+ """whitelist handling class
+
+ Do you really want anyone can post? Ah ah ah.
+ """
+
+ wl = {}
+ debug = None
+ log = None # filedescriptor
+
+ # constants
+ DENY = 0
+ ACCEPT = 1
+
+ def __init__(self, wlfile='wl.pyg', logfile='pyg.log', debug=0):
+
+ self.debug = debug
+
+ try:
+ wlp.setfilebyname(wlfile)
+ except (Exception), (errno,message):
+ print 'Opening %s: %s (errno %d)' % (wlfile,message,errno)
+ sys.exit(0)
+
+ # dict is a { ownername : {variable: value}} dictionary of dictionaries
+ self.wl = wlp.mkdict()
+
+# print 'owner: option = value'
+# for owner in self.wl.keys():
+# for option in self.wl[owner].keys():
+# print '%s: %s = %s' % (owner,option,self.wl[owner][option])
+
+ try:
+ self.log = open(logfile, 'a')
+ self.lock()
+ except (Exception), message:
+ print '%s\nAre you authorized to use this program? ' % message
+ sys.exit(1)
+
+ def lock(self):
+ fcntl.flock(self.log.fileno(),fcntl.LOCK_EX)
+
+ # to unlock fd locked, usually fd are unlocked after process exit()
+ def unlock(self):
+ fcntl.flock(self.log.fileno(),fcntl.LOCK_UN)
+
+ def checkfrom(self, fromhead):
+ """have you permission to be here, sir?"""
+
+ for owner in self.wl.keys():
+# if(self.wl[owner]['From:'] == fromhead[:-1]): # remove '\n'
+ if(string.find(fromhead[:-1],self.wl[owner]['From:']) >= 0):
+ return owner
+ else:
+ return None
+
+
+ def log(self, string):
+ """Captain Diary, Astral Date 962555394 from epoch.
+ it rawly write a line in logfile. Remeber to indent it, if you
+ like.
+ """
+
+ self.log.write(string + '\n')
+
+ def logmsg(self, heads, ok=DENY,owner=None):
+ """who are walking through my gate?
+ log
+ """
+
+ ltime = time.ctime(time.time())
+
+ if time.daylight:
+ tzone = time.tzname[1]
+ else:
+ tzone = time.tzname[0]
+
+ if(ok == self.ACCEPT):
+ self.log.write('Permission Accorded ')
+ else:
+ self.log.write('Permission Denied ')
+
+ self.log.write('at %s (%s)\n' % (ltime,tzone))
+ if(owner != None):
+ self.log.write('\tWLOwner: ' + owner + '\n')
+ self.log.write('\tFrom: ' + heads.get('From:','NOT PRESENT\n'))
+ self.log.write('\tSubject: ' + heads.get('Subject:','NOT PRESENT\n'))
+ self.log.write('\tSender: ' + heads.get('Sender:','NOT PRESENT\n'))
+ self.log.write('\tDate: ' + heads.get('Date:','NOT PRESENT\n'))
+
+ # some client create Message-Id other Message-ID.
+ if(heads.has_key('Message-ID:')):
+ self.log.write('\tMessage-ID: ' + heads.get('Message-ID:'))
+ else:
+ self.log.write('\tMessage-Id: ' + heads.get('Message-Id:','NOT PRESENT\n'))
+
+ # X-Newsgroups: and To: are present if user is trusted, else
+ # Newsgroup: exists since no changes on nntp headers are done.
+ if(heads.has_key('X-Newsgroups:')):
+ self.log.write('\tTo: ' + heads.get('To:','NOT PRESENT\n'))
+ self.log.write('\tX-Newsgroups: ' + heads.get('X-Newsgroups:','NOT PRESENT\n'))
+ else:
+ self.log.write('\tNewsgroups: ' + heads.get('Newsgroups:','NOT PRESENT\n'))
+
+
+ self.log.write('\n')
diff --git a/wlp/C/Makefile b/wlp/C/Makefile
new file mode 100644
index 0000000..6bc8fc3
--- /dev/null
+++ b/wlp/C/Makefile
@@ -0,0 +1,43 @@
+CC=gcc
+AR=ar
+FLEX=flex
+YACC=bison
+
+CCOPTS=-Wall -ansi
+CCSHARED=-fPIC
+AROPTS=-rs
+FLEXOPTS=
+YACCOPTS=-d
+
+SRCDIR=.
+BINDIR=.
+
+OBJFILE=structs.o commands.tab.o lex.yy.o
+
+all: archive bin
+
+# archive file for python module
+archive: structs bison flex /usr/lib/libfl.a macro.h structs.h commands.tab.h
+ $(AR) $(AROPTS) $(BINDIR)/wlp.a $(OBJFILE) \
+ /usr/lib/libfl.a
+
+# binary (executable) file for testing
+executable: bin
+
+bin: structs bison flex /usr/lib/libfl.a macro.h structs.h commands.tab.h
+ $(CC) $(CCSHARED) $(CCOPTS) $(OBJFILE) \
+ yytest.c /usr/lib/libfl.a -o ./yytest
+
+flex:
+ $(FLEX) $(FLEXOPTS) commands.l
+ $(CC) $(CCSHARED) -c lex.yy.c -o lex.yy.o
+
+bison:
+ $(YACC) $(YACCOPTS) -d commands.y -b commands
+ $(CC) $(CCSHARED) -c commands.tab.c -o commands.tab.o
+
+structs:
+ $(CC) $(CCSHARED) $(CCOPTS) -c structs.c -o structs.o
+
+clean:
+ -rm $(OBJFILE) lex.yy.c commands.tab.h commands.tab.c wlp.a yytest
diff --git a/wlp/C/commands.l b/wlp/C/commands.l
new file mode 100644
index 0000000..8f0f28e
--- /dev/null
+++ b/wlp/C/commands.l
@@ -0,0 +1,75 @@
+%{
+/* Lex analyzer for bison grammar */
+
+#include "commands.tab.h"
+/*#define DEBUG*/
+#include "macro.h"
+%}
+
+OWNER "<"[a-zA-Z0-9_.+-]+@[a-zA-Z0-9._-]+">"
+VAL ['`"][a-zA-Z0-9@_+.<>() -]+['`"]
+VAR [a-zA-Z0-9_<>-]+[:]?
+
+%option noyywrap
+
+%%
+
+
+
+
+{OWNER} {
+ DBG("OWNER %s\n",yytext);
+ yylval.text=yytext;
+ return(OWNERID);
+ }
+
+
+{VAL} {
+ DBG("VAL %s\n",yytext);
+ yylval.text=yytext;
+ return(VALID);
+ }
+
+{VAR} {
+ DBG("VAR %s\n",yytext);
+ yylval.text=yytext;
+ return(VARID);
+ }
+
+
+"{" |
+"}" |
+"=" {
+ yylval.text=yytext;
+ return(*yytext);
+ }
+
+
+"#"[^\n]* |
+"\n" |
+[[:space:]] ; /* comments 'til EOL and strip all spaces and \n */
+
+
+"." {
+ DBG("NOTSTR %s\n",yytext);
+ yylval.text=yytext;
+ return(ERROR);
+ }
+
+
+%%
+
+#include "structs.h"
+
+extern struct wlp_list_t *list;
+
+int parse(FILE *file)
+{
+ struct wlp_node_t *tmp;
+ int count;
+ yyin=file;
+
+ DBG("go!\n");
+ yyparse();
+ DBG("EOF found\n");
+}
diff --git a/wlp/C/commands.y b/wlp/C/commands.y
new file mode 100644
index 0000000..8b720d7
--- /dev/null
+++ b/wlp/C/commands.y
@@ -0,0 +1,110 @@
+
+%{
+/*#define YYSTYPE char**/
+/*#define DEBUG*/
+#include "macro.h"
+%}
+
+%union {
+ char *text;
+ char c;
+}
+
+%token <text> VARID
+%token <text> VALID
+%token <text> OWNERID
+
+%token ERROR
+%token EOFTOK
+
+
+%{
+char left[80], right[80], owner[80];
+char type = 0; /*unused*/
+%}
+
+%%
+
+
+block:
+ blockstatement
+ | block blockstatement
+ ;
+
+blockstatement:
+ owner '{' commandline '}'
+ ;
+
+commandline:
+ command | commandline command
+ ;
+
+command:
+ varpart '=' valpart { found(left,right,owner); }
+ ;
+
+owner:
+ OWNERID {
+ DBG("Owner %s\n",$1);
+ strncpy(owner,$1,strlen($1)+1);
+ }
+ ;
+
+varpart:
+ VARID {
+ DBG("Left %s\n",$1);
+ strncpy(left,$1,strlen($1)+1);
+ }
+ ;
+
+valpart:
+ VALID {
+ DBG("Right %s\n",$1);
+ strncpy(right,$1,strlen($1)+1);
+ }
+ ;
+
+%%
+
+#include <ctype.h>
+#include <stdio.h>
+#include "structs.h"
+
+extern struct wlp_list_t *list;
+
+int yyerror (char *s) /* Called by yyparse on error */
+{
+ printf ("error: %s\n", s);
+ return 1;
+}
+
+int found(const char* left, const char* right, const char *owner)
+{
+ static struct wlp_node_t *node;
+
+ /* alloc node with non-empty fields (ie alloc them too)*/
+ node = wlpn_alloc(FALSE);
+ if(!node) {
+ DBG("wlpn_alloc in found returned NULL\n");
+ }
+
+ strncpy(node->right,right,strlen(right));
+ strncpy(node->left,left,strlen(left));
+ strncpy(node->owner,owner,strlen(owner));
+
+ #ifndef WITHQUOTES
+ /* remove quotes of value part */
+ node->right += 1;
+ node->right[strlen(node->right)-1] = '\0';
+ #endif
+ #ifndef WITHANGBRACKETS
+ /* remove angle brackets of owner part */
+ node->owner += 1;
+ node->owner[strlen(node->owner)-1] = '\0';
+ #endif
+
+ if(!list)
+ list = wlpl_init(node);
+ else
+ wlpn_add(list,node);
+}
diff --git a/wlp/C/macro.h b/wlp/C/macro.h
new file mode 100644
index 0000000..303b3c6
--- /dev/null
+++ b/wlp/C/macro.h
@@ -0,0 +1,44 @@
+/*
+ * macro.h - Copyright 2000, 2001 Cosimo Alfarano <Alfarano@CS.UniBo.It>
+ * You can use this software under the terms of the GPL. If we meet some day,
+ * and you think this stuff is worth it, you can buy me a beer in return.
+ *
+ * Thanks to md for this useful formula. Beer is beer.
+ */
+
+
+#ifndef _macro_h_
+#define _macro_h_
+
+#define LINELEN 2048
+#define TRUE 1
+#define FALSE 0
+
+/*
+#define WITHQUOTES
+#define WITHANGBRACKETS
+*/
+
+#define ERR(a,b...) fprintf(stderr, a, ## b)
+
+/* Define it for debug info on stderr (better if in .c module ...) */
+/*
+#ifndef DEBUG
+ #define DEBUG
+#endif
+*/
+
+
+#ifdef DEBUG
+ #define DBG(a...) fprintf(stderr, ## a)
+ /* for a verbose debug*/
+ #define VDBG(a,b...) fprintf(stderr, "%s(): " a, __FUNCTION__ , ## b)
+#else
+ #define DBG(a...)
+ #define VDBG(a...)
+#endif
+
+
+#endif
+
+/* EOF */
diff --git a/wlp/C/structs.c b/wlp/C/structs.c
new file mode 100644
index 0000000..8c33443
--- /dev/null
+++ b/wlp/C/structs.c
@@ -0,0 +1,164 @@
+/*
+ * structs.c - Copyright 2000 by Cosimo Alfarano <Alfarano@CS.UniBo.It>
+ * You can use this software under the terms of the GPL. If we meet some day,
+ * and you think this stuff is worth it, you can buy me a beer in return.
+ *
+ * Thanks to md for this useful formula. Beer is beer.
+ */
+
+
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <errno.h>
+
+#include "structs.h"
+#include "macro.h"
+
+struct wlp_node_t *wlpn_add(struct wlp_list_t *list,struct wlp_node_t *node)
+{
+ struct wlp_node_t *ret;
+
+ if(node) {
+ node->next = list->head;
+ node->prev = list->tail;
+
+ list->tail->next = node;
+ list->head->prev = node;
+
+ list->tail = node;
+
+ list->count++;
+
+ ret = node;
+ } else {
+ DBG("cannot add %s %s to list. NULL pointer?\n",
+ node->left,node->right);
+ ret = NULL;
+ }
+
+ return ret;
+}
+
+void wlpn_free(struct wlp_node_t *node)
+{
+ free(node->left);
+ free(node->right);
+ free(node->owner);
+ free(node);
+}
+
+
+struct wlp_node_t *wlpn_alloc(const char empty)
+{
+ static struct wlp_node_t *node;
+
+ node = calloc(sizeof(struct wlp_node_t),1);
+
+ if (!node) {
+ perror("wlpn_create malloc");
+
+ /* calloc set *node to zero, it I don't want alloc anything,
+ leave it untouched, else alloc fields */
+ } else if (!empty) {
+ node->left = calloc(LINELEN+1,1);
+ if (!node->left) {
+ perror("wlpn_create malloc (left)");
+ free(node);
+ node = NULL;
+ }
+
+ /*if node is NULL, previous calloc returned error...*/
+ if(node && !(node->right = calloc(LINELEN+1,1))) {
+ perror("wlpn_create malloc (right)");
+ free(node);
+ node = NULL;
+ }
+
+ if(node && !(node->owner = calloc(LINELEN+1,1))) {
+ perror("wlpn_create malloc (owner)");
+ free(node);
+ node = NULL;
+ }
+ }
+ return node;
+}
+
+struct wlp_list_t *wlpl_init(struct wlp_node_t *node)
+{
+ static struct wlp_list_t *list;
+
+ list = malloc(sizeof(struct wlp_list_t));
+
+ if (list) {
+ list->head = node;
+ list->tail = list->head;
+
+ list->head->next = list->head;
+ list->head->prev = list->head;
+
+ list->count=1;
+ } else {
+ perror("wlpl_init malloc");
+ return NULL;
+ }
+
+ return list;
+}
+
+
+struct wlp_node_t *wlpn_searchowner(struct wlp_list_t *mbl,const char *owner)
+{
+ struct wlp_node_t *ret;
+
+ DBG("searching for %s\n",owner);
+
+ if(!mbl)
+ ret = NULL;
+ else {
+ int found = FALSE;
+ ret = mbl->head;
+
+ do {
+ if(!strcmp(owner,ret->owner)) {
+ DBG("found!\n");
+ found = TRUE;
+ } else {
+ DBG("not found: %s\n",ret->onwer);
+ ret = ret->next;
+ }
+ } while(ret != mbl->head && !found);
+
+ if(!found)
+ ret = NULL;
+ }
+
+ DBG("%s\n", (ret)?ret->owner:"not found");
+
+ return ret;
+}
+
+
+struct wlp_node_t *wlpn_extract(struct wlp_list_t *list,struct wlp_node_t *node)
+{
+ struct wlp_node_t *ret;
+
+ if(list && node) {
+ node->prev->next = node->next;
+ node->next->prev = node->prev;
+
+ if(list->tail == node)
+ list->tail = node->prev;
+ if(list->head == node)
+ list->head = node->next;
+
+ list->count--;
+
+ ret = node;
+ } else {
+ DBG("wlpn_extract: list addr %l and node %l (one is NULL)\n",list,addr)
+ ret = NULL;
+ }
+
+ return ret;
+}
diff --git a/wlp/C/structs.h b/wlp/C/structs.h
new file mode 100644
index 0000000..92036a7
--- /dev/null
+++ b/wlp/C/structs.h
@@ -0,0 +1,35 @@
+/*
+ * structs.h - Copyright 2000, 2001 by Cosimo Alfarano <Alfarano@CS.UniBo.It>
+ * You can use this software under the terms of the GPL. If we meet some day,
+ * and you think this stuff is worth it, you can buy me a beer in return.
+ *
+ * Thanks to md for this useful formula. Beer is beer.
+ */
+
+#ifndef _structs_h_
+#define _structs_h_
+
+typedef struct wlp_node_t {
+ char *left,*right;
+ char *owner;
+ char type; /* unused */
+ struct wlp_node_t *next, *prev;
+} wlp_node_t;
+
+typedef struct wlp_list_t {
+ int count;
+ struct wlp_node_t *head, *tail;
+} wlp_list_t;
+
+
+/* white list parser data structure manipulation */
+struct wlp_list_t *wlpl_init(struct wlp_node_t *node);
+struct wlp_node_t *wlpn_alloc(const char empty);
+void wlpn_free(struct wlp_node_t *node);
+struct wlp_node_t *wlpn_add(struct wlp_list_t *wlpl,struct wlp_node_t *wlpn);
+struct wlp_node_t *wlpn_extract(struct wlp_list_t *wlpl,struct wlp_node_t *wlpn);
+/*struct wlp_node_t *wlpn_search(struct wlp_list_t *wlpl,const char id);*/
+
+#endif /* _structs_h_ */
+
+/* EOF */
diff --git a/wlp/C/test.c b/wlp/C/test.c
new file mode 100644
index 0000000..47717b5
--- /dev/null
+++ b/wlp/C/test.c
@@ -0,0 +1,113 @@
+#include <python2.1/Python.h> /* should be modified to be pythonX.Y */
+#include <stdio.h>
+#include <unistd.h>
+
+#include "structs.h"
+#include "macro.h"
+
+/* first declare static functions */
+
+struct wlp_list_t *list;
+
+static FILE *fd = NULL;
+
+static PyObject *node2dict(struct wlp_node_t *node);
+
+static PyObject *wlp_setfilebyname(PyObject *self, PyObject *args) {
+ char *file;
+
+ DBG("setfilebyname\n");
+ if (!PyArg_ParseTuple(args, "s", &file))
+ return NULL;
+
+ fd = fopen(file,"r");
+
+ return Py_None;
+}
+
+static PyObject *wlp_setfilebyfd(PyObject *self, PyObject *args) {
+ PyObject *file = NULL;
+
+ if (!PyArg_ParseTuple(args, "O", &file))
+ return NULL;
+
+ if(!file)
+ return NULL;
+
+ if(!PyFile_Check(file))
+ return NULL;
+
+ fd = PyFile_AsFile(file);
+
+ return Py_None;
+
+}
+
+
+
+static PyObject *wlp_mklist(PyObject *self, PyObject *args) {
+ struct wlp_node_t *tmp;
+ int count;
+
+ PyObject *pylist = NULL;
+
+ DBG("a\n");
+ parse(fd);
+
+ DBG("count %d\n"list->count);
+ pylist = PyList_New(0);
+
+ DBG("a\n");
+ if(!pylist)
+ return NULL;
+
+ DBG("a\n");
+ if(list)
+ for(tmp = list->head, count=0;
+ tmp != list->head || count == 0;
+ tmp = tmp->next, count++) {
+ DBG("FOUND(%d) '%s' ('%s': '%s')\n",count,tmp->owner,tmp->left,tmp->right);
+ if(PyList_Append(pylist,node2dict(tmp))==-1) {
+ DBG("List failed\n");
+ return NULL;
+ }
+ DBG("a\n");
+ }
+
+ return pylist;
+}
+
+
+static PyObject *node2dict(struct wlp_node_t *node) {
+ PyObject *dict = PyDict_New();
+
+ if(!dict)
+ return NULL;
+
+ PyDict_SetItem(dict,
+ Py_BuildValue("s","owner"),
+ Py_BuildValue("s",node->owner));
+
+ PyDict_SetItem(dict,
+ Py_BuildValue("s",node->left),
+ Py_BuildValue("s",node->right));
+
+ return dict;
+
+}
+
+/* second a table with methods/functions matching */
+
+static PyMethodDef wlp_methods[] = {
+ {"mklist", wlp_mklist, METH_VARARGS},
+ {"setfilebyname", wlp_setfilebyname, METH_VARARGS},
+ {"setfilebyfd", wlp_setfilebyfd, METH_VARARGS},
+ {NULL,NULL}
+};
+
+
+/* last the init function, the only one non-static */
+
+void initwlp() {
+ (void) Py_InitModule("wlp",wlp_methods);
+}
diff --git a/wlp/C/wlp.c b/wlp/C/wlp.c
new file mode 100644
index 0000000..8c0779d
--- /dev/null
+++ b/wlp/C/wlp.c
@@ -0,0 +1,183 @@
+/*
+ * wlp.c - Copyright 2000, 2001 by Cosimo Alfarano <Alfarano@CS.UniBo.It>
+ * You can use this software under the terms of the GPL. If we meet some day,
+ * and you think this stuff is worth it, you can buy me a beer in return.
+ *
+ * Thanks to md for this useful formula. Beer is beer.
+ */
+
+//#include <python/Python.h>
+#include <Python.h>
+#include <stdio.h>
+#include <unistd.h>
+
+#include "structs.h"
+#include "macro.h"
+
+
+static FILE *fd = NULL;
+
+struct wlp_list_t *list;
+
+static PyObject *node2dict(struct wlp_node_t *node);
+static PyObject *node2dict2(struct wlp_node_t *node);
+
+
+
+
+/*
+ * wlp_setfilebyname(): get FILE* fd from filename string.
+ */
+
+static PyObject *wlp_setfilebyname(PyObject *self, PyObject *args) {
+ char *file;
+
+
+ DBG("setfilebyname\n");
+ if (!PyArg_ParseTuple(args, "s", &file))
+ return NULL;
+
+ if(fd = fopen(file,"r")) {
+ return Py_None;
+ } else {
+ PyErr_SetFromErrno(PyExc_Exception);
+/*
+ PyErr_SetString(PyExc_Exception,
+ (errno<=sys_nerr-1)?
+ sys_errlist[errno]:
+ "Unknown Error on fopen() of confifuration file");
+*/
+ return NULL;
+ }
+}
+
+
+
+/*
+ * wlp_setfilebydf(): get FILE* fd from FileObject.
+ */
+
+static PyObject *wlp_setfilebyfd(PyObject *self, PyObject *args) {
+ PyObject *file = NULL;
+
+ if(!PyArg_ParseTuple(args, "O", &file))
+ return NULL;
+
+ if(!file)
+ return NULL;
+
+ if(!PyFile_Check(file))
+ return NULL;
+
+ fd = PyFile_AsFile(file);
+
+ return Py_None;
+}
+
+/*
+ * wlp_mkdict(): make a dictonary of the form
+ * {ownername: {var1: val1, var2: val2,...}}
+ */
+
+static PyObject *wlp_mkdict(PyObject *self, PyObject *args) {
+ PyObject *pydicttmp = NULL;
+ PyObject *pydict = PyDict_New();
+ struct wlp_node_t *tmp;
+ int count;
+
+ if(!pydict)
+ return NULL;
+
+ /* fopen()*/
+ if(fd)
+ parse(fd);
+ else
+ return Py_None;
+
+ if(list)
+ for(tmp = list->head, count = 0;
+ tmp != list->head || count == 0;
+ tmp = tmp->next, count++) {
+ DBG("FOUND(%d) '%s' ('%s': '%s')\n",count,tmp->owner,tmp->left,tmp->right);
+ pydicttmp = PyDict_GetItem(pydict,
+ PyString_FromString(tmp->owner));
+
+ if(!pydicttmp) {
+ DBG("%s: owner not found, create new item\n",
+ tmp->owner);
+ PyDict_SetItemString(pydict,
+ tmp->owner,
+ node2dict(tmp));
+ } else {
+ DBG("%s: owner found,appendig items\n",
+ tmp->owner);
+ PyDict_SetItemString(pydicttmp,
+ tmp->left,
+ Py_BuildValue("s",tmp->right));
+ PyDict_SetItemString(pydict,
+ tmp->owner,
+ pydicttmp);
+ }
+ }
+
+ return pydict;
+}
+
+/*
+ * node2dict(): transoform a wlp_node_t node in a python dictionary of the form
+ * { var: val }
+ * to be used by mkdict()
+ */
+
+static PyObject *node2dict(struct wlp_node_t *node) {
+ PyObject *dict = PyDict_New();
+
+ if(!dict)
+ dict = Py_None;
+ else {
+ PyDict_SetItem(dict,
+ Py_BuildValue("s",node->left),
+ Py_BuildValue("s",node->right));
+ }
+
+ return dict;
+
+}
+
+
+/*
+ * node2dict2(): transoform a wlp_node_t node in a python dictionary of the form
+ * { 'owner': ownername, var: val}
+ * it's currently unused (obsoleted)
+ */
+
+static PyObject *node2dict2(struct wlp_node_t *node) {
+ PyObject *dict = PyDict_New();
+
+ if(!dict)
+ dict = Py_None;
+ else {
+ PyDict_SetItem(dict,
+ Py_BuildValue("s","owner"),
+ Py_BuildValue("s",node->owner));
+
+ PyDict_SetItem(dict,
+ Py_BuildValue("s",node->left),
+ Py_BuildValue("s",node->right));
+ }
+
+ return dict;
+
+}
+
+static PyMethodDef wlp_methods[] = {
+ {"mkdict", wlp_mkdict, METH_VARARGS},
+ {"setfilebyname", wlp_setfilebyname, METH_VARARGS},
+ {"setfilebyfd", wlp_setfilebyfd, METH_VARARGS},
+ {NULL,NULL}
+};
+
+
+void initwlp() {
+ (void) Py_InitModule("wlp",wlp_methods);
+}
diff --git a/wlp/C/yytest.c b/wlp/C/yytest.c
new file mode 100644
index 0000000..74c6fe7
--- /dev/null
+++ b/wlp/C/yytest.c
@@ -0,0 +1,25 @@
+#include <stdio.h>
+
+#include "structs.h"
+#include "macro.h"
+
+
+
+int parse(FILE *file);
+
+struct wlp_list_t *list;
+
+int main(int argc,char **argv) {
+ struct wlp_node_t *tmp;
+ int count;
+
+ parse(NULL);
+
+ if(list)
+ for(tmp = list->head, count=0;
+ tmp != list->head || count == 0;
+ tmp = tmp->next, count++)
+ printf("FOUND(%d) '%s' '%s' '%s'\n",count,tmp->left,tmp->right,tmp->owner);
+
+ return(0);
+}
diff --git a/wlp/Makefile b/wlp/Makefile
new file mode 100644
index 0000000..4e180d1
--- /dev/null
+++ b/wlp/Makefile
@@ -0,0 +1,42 @@
+MODULEDIR=module
+CSRCDIR=C
+BINDIR=..
+
+# modules name without $(MODULEDIR)
+SOLIST=test.so
+
+
+
+all: bin
+
+bin: initmodule wlp makemodule
+ chmod 0644 $(MODULEDIR)/*.so
+ mv $(MODULEDIR)/*.so $(BINDIR)
+
+# Init Makefile & Co. file for building python module
+initmodule:
+ $(MAKE) -C $(MODULEDIR) -f Makefile.pre.in boot
+
+# The White List Parser Module
+wlp:
+ $(MAKE) -C $(CSRCDIR) archive
+
+# Really make python module as .so
+makemodule:
+ $(MAKE) -C $(MODULEDIR)
+
+
+
+clean: cleanmodule cleansrc
+ -rm $(BINDIR)/*.so
+
+cleansrc:
+ -$(MAKE) -C $(CSRCDIR) clean
+
+cleanmodule:
+ -$(MAKE) -C $(MODULEDIR) clean
+ -rm $(MODULEDIR)/Makefile.pre $(MODULEDIR)/Makefile
+ -rm $(MODULEDIR)/config.c
+ -rm $(MODULEDIR)/sedscript
+ -rm $(MODULEDIR)/Setup
+
diff --git a/wlp/README b/wlp/README
new file mode 100644
index 0000000..a2f97a0
--- /dev/null
+++ b/wlp/README
@@ -0,0 +1,12 @@
+To make wlp python module extension type 'make', it should be sufficient.
+If it doesn't work, please, send a bug report with full make output to
+author or package maintainer and/or (better) try manually to do this steps and
+reporting output of the one which give error via email:
+
+make -C module -f Makefile.pre.in boot # to initialiaze python module Makefile
+make -C src archive # to compile python .c extension
+make -C module # to really make .so python module
+
+Please, remeber to report full output.
+
+Cosimo Alfarano <alfarano@cs.unibo.it>
diff --git a/wlp/module/Makefile.pre.in b/wlp/module/Makefile.pre.in
new file mode 100644
index 0000000..05f108b
--- /dev/null
+++ b/wlp/module/Makefile.pre.in
@@ -0,0 +1,310 @@
+# Universal Unix Makefile for Python extensions
+# =============================================
+
+# Short Instructions
+# ------------------
+
+# 1. Build and install Python (1.5 or newer).
+# 2. "make -f Makefile.pre.in boot"
+# 3. "make"
+# You should now have a shared library.
+
+# Long Instructions
+# -----------------
+
+# Build *and install* the basic Python 1.5 distribution. See the
+# Python README for instructions. (This version of Makefile.pre.in
+# only withs with Python 1.5, alpha 3 or newer.)
+
+# Create a file Setup.in for your extension. This file follows the
+# format of the Modules/Setup.dist file; see the instructions there.
+# For a simple module called "spam" on file "spammodule.c", it can
+# contain a single line:
+# spam spammodule.c
+# You can build as many modules as you want in the same directory --
+# just have a separate line for each of them in the Setup.in file.
+
+# If you want to build your extension as a shared library, insert a
+# line containing just the string
+# *shared*
+# at the top of your Setup.in file.
+
+# Note that the build process copies Setup.in to Setup, and then works
+# with Setup. It doesn't overwrite Setup when Setup.in is changed, so
+# while you're in the process of debugging your Setup.in file, you may
+# want to edit Setup instead, and copy it back to Setup.in later.
+# (All this is done so you can distribute your extension easily and
+# someone else can select the modules they actually want to build by
+# commenting out lines in the Setup file, without editing the
+# original. Editing Setup is also used to specify nonstandard
+# locations for include or library files.)
+
+# Copy this file (Misc/Makefile.pre.in) to the directory containing
+# your extension.
+
+# Run "make -f Makefile.pre.in boot". This creates Makefile
+# (producing Makefile.pre and sedscript as intermediate files) and
+# config.c, incorporating the values for sys.prefix, sys.exec_prefix
+# and sys.version from the installed Python binary. For this to work,
+# the python binary must be on your path. If this fails, try
+# make -f Makefile.pre.in Makefile VERSION=1.5 installdir=<prefix>
+# where <prefix> is the prefix used to install Python for installdir
+# (and possibly similar for exec_installdir=<exec_prefix>).
+
+# Note: "make boot" implies "make clobber" -- it assumes that when you
+# bootstrap you may have changed platforms so it removes all previous
+# output files.
+
+# If you are building your extension as a shared library (your
+# Setup.in file starts with *shared*), run "make" or "make sharedmods"
+# to build the shared library files. If you are building a statically
+# linked Python binary (the only solution of your platform doesn't
+# support shared libraries, and sometimes handy if you want to
+# distribute or install the resulting Python binary), run "make
+# python".
+
+# Note: Each time you edit Makefile.pre.in or Setup, you must run
+# "make Makefile" before running "make".
+
+# Hint: if you want to use VPATH, you can start in an empty
+# subdirectory and say (e.g.):
+# make -f ../Makefile.pre.in boot srcdir=.. VPATH=..
+
+
+# === Bootstrap variables (edited through "make boot") ===
+
+# The prefix used by "make inclinstall libainstall" of core python
+installdir= /usr/local
+
+# The exec_prefix used by the same
+exec_installdir=$(installdir)
+
+# Source directory and VPATH in case you want to use VPATH.
+# (You will have to edit these two lines yourself -- there is no
+# automatic support as the Makefile is not generated by
+# config.status.)
+srcdir= .
+VPATH= .
+
+# === Variables that you may want to customize (rarely) ===
+
+# (Static) build target
+TARGET= python
+
+# Installed python binary (used only by boot target)
+PYTHON= python
+
+# Add more -I and -D options here
+CFLAGS= $(OPT) -I$(INCLUDEPY) -I$(EXECINCLUDEPY) $(DEFS)
+
+# These two variables can be set in Setup to merge extensions.
+# See example[23].
+BASELIB=
+BASESETUP=
+
+# === Variables set by makesetup ===
+
+MODOBJS= _MODOBJS_
+MODLIBS= _MODLIBS_
+
+# === Definitions added by makesetup ===
+
+# === Variables from configure (through sedscript) ===
+
+VERSION= @VERSION@
+CC= @CC@
+LINKCC= @LINKCC@
+SGI_ABI= @SGI_ABI@
+OPT= @OPT@
+LDFLAGS= @LDFLAGS@
+LDLAST= @LDLAST@
+DEFS= @DEFS@
+LIBS= @LIBS@
+LIBM= @LIBM@
+LIBC= @LIBC@
+RANLIB= @RANLIB@
+MACHDEP= @MACHDEP@
+SO= @SO@
+LDSHARED= @LDSHARED@
+CCSHARED= @CCSHARED@
+LINKFORSHARED= @LINKFORSHARED@
+CXX= @CXX@
+
+# Install prefix for architecture-independent files
+prefix= /usr/local
+
+# Install prefix for architecture-dependent files
+exec_prefix= $(prefix)
+
+# Uncomment the following two lines for AIX
+#LINKCC= $(LIBPL)/makexp_aix $(LIBPL)/python.exp "" $(LIBRARY); $(PURIFY) $(CC)
+#LDSHARED= $(LIBPL)/ld_so_aix $(CC) -bI:$(LIBPL)/python.exp
+
+# === Fixed definitions ===
+
+# Shell used by make (some versions default to the login shell, which is bad)
+SHELL= /bin/sh
+
+# Expanded directories
+BINDIR= $(exec_installdir)/bin
+LIBDIR= $(exec_prefix)/lib
+MANDIR= $(installdir)/share/man
+INCLUDEDIR= $(installdir)/include
+SCRIPTDIR= $(prefix)/lib
+
+# Detailed destination directories
+BINLIBDEST= $(LIBDIR)/python$(VERSION)
+LIBDEST= $(SCRIPTDIR)/python$(VERSION)
+INCLUDEPY= $(INCLUDEDIR)/python$(VERSION)
+EXECINCLUDEPY= $(exec_installdir)/include/python$(VERSION)
+LIBP= $(exec_installdir)/lib/python$(VERSION)
+DESTSHARED= $(BINLIBDEST)/site-packages
+
+LIBPL= $(LIBP)/config
+
+PYTHONLIBS= $(LIBPL)/libpython$(VERSION).a
+
+MAKESETUP= $(LIBPL)/makesetup
+MAKEFILE= $(LIBPL)/Makefile
+CONFIGC= $(LIBPL)/config.c
+CONFIGCIN= $(LIBPL)/config.c.in
+SETUP= $(LIBPL)/Setup.config $(LIBPL)/Setup.local $(LIBPL)/Setup
+
+SYSLIBS= $(LIBM) $(LIBC)
+
+ADDOBJS= $(LIBPL)/python.o config.o
+
+# Portable install script (configure doesn't always guess right)
+INSTALL= $(LIBPL)/install-sh -c
+# Shared libraries must be installed with executable mode on some systems;
+# rather than figuring out exactly which, we always give them executable mode.
+# Also, making them read-only seems to be a good idea...
+INSTALL_SHARED= ${INSTALL} -m 555
+
+# === Fixed rules ===
+
+# Default target. This builds shared libraries only
+default: sharedmods
+
+# Build everything
+all: static sharedmods
+
+# Build shared libraries from our extension modules
+sharedmods: $(SHAREDMODS)
+
+# Build a static Python binary containing our extension modules
+static: $(TARGET)
+$(TARGET): $(ADDOBJS) lib.a $(PYTHONLIBS) Makefile $(BASELIB)
+ $(LINKCC) $(LDFLAGS) $(LINKFORSHARED) \
+ $(ADDOBJS) lib.a $(PYTHONLIBS) \
+ $(LINKPATH) $(BASELIB) $(MODLIBS) $(LIBS) $(SYSLIBS) \
+ -o $(TARGET) $(LDLAST)
+
+install: sharedmods
+ if test ! -d $(DESTSHARED) ; then \
+ mkdir $(DESTSHARED) ; else true ; fi
+ -for i in X $(SHAREDMODS); do \
+ if test $$i != X; \
+ then $(INSTALL_SHARED) $$i $(DESTSHARED)/$$i; \
+ fi; \
+ done
+
+# Build the library containing our extension modules
+lib.a: $(MODOBJS)
+ -rm -f lib.a
+ ar cr lib.a $(MODOBJS)
+ -$(RANLIB) lib.a
+
+# This runs makesetup *twice* to use the BASESETUP definition from Setup
+config.c Makefile: Makefile.pre Setup $(BASESETUP) $(MAKESETUP)
+ $(MAKESETUP) \
+ -m Makefile.pre -c $(CONFIGCIN) Setup -n $(BASESETUP) $(SETUP)
+ $(MAKE) -f Makefile do-it-again
+
+# Internal target to run makesetup for the second time
+do-it-again:
+ $(MAKESETUP) \
+ -m Makefile.pre -c $(CONFIGCIN) Setup -n $(BASESETUP) $(SETUP)
+
+# Make config.o from the config.c created by makesetup
+config.o: config.c
+ $(CC) $(CFLAGS) -c config.c
+
+# Setup is copied from Setup.in *only* if it doesn't yet exist
+Setup:
+ cp $(srcdir)/Setup.in Setup
+
+# Make the intermediate Makefile.pre from Makefile.pre.in
+Makefile.pre: Makefile.pre.in sedscript
+ sed -f sedscript $(srcdir)/Makefile.pre.in >Makefile.pre
+
+# Shortcuts to make the sed arguments on one line
+P=prefix
+E=exec_prefix
+H=Generated automatically from Makefile.pre.in by sedscript.
+L=LINKFORSHARED
+
+# Make the sed script used to create Makefile.pre from Makefile.pre.in
+sedscript: $(MAKEFILE)
+ sed -n \
+ -e '1s/.*/1i\\/p' \
+ -e '2s%.*%# $H%p' \
+ -e '/^VERSION=/s/^VERSION=[ ]*\(.*\)/s%@VERSION[@]%\1%/p' \
+ -e '/^CC=/s/^CC=[ ]*\(.*\)/s%@CC[@]%\1%/p' \
+ -e '/^CXX=/s/^CXX=[ ]*\(.*\)/s%@CXX[@]%\1%/p' \
+ -e '/^LINKCC=/s/^LINKCC=[ ]*\(.*\)/s%@LINKCC[@]%\1%/p' \
+ -e '/^OPT=/s/^OPT=[ ]*\(.*\)/s%@OPT[@]%\1%/p' \
+ -e '/^LDFLAGS=/s/^LDFLAGS=[ ]*\(.*\)/s%@LDFLAGS[@]%\1%/p' \
+ -e '/^LDLAST=/s/^LDLAST=[ ]*\(.*\)/s%@LDLAST[@]%\1%/p' \
+ -e '/^DEFS=/s/^DEFS=[ ]*\(.*\)/s%@DEFS[@]%\1%/p' \
+ -e '/^LIBS=/s/^LIBS=[ ]*\(.*\)/s%@LIBS[@]%\1%/p' \
+ -e '/^LIBM=/s/^LIBM=[ ]*\(.*\)/s%@LIBM[@]%\1%/p' \
+ -e '/^LIBC=/s/^LIBC=[ ]*\(.*\)/s%@LIBC[@]%\1%/p' \
+ -e '/^RANLIB=/s/^RANLIB=[ ]*\(.*\)/s%@RANLIB[@]%\1%/p' \
+ -e '/^MACHDEP=/s/^MACHDEP=[ ]*\(.*\)/s%@MACHDEP[@]%\1%/p' \
+ -e '/^SO=/s/^SO=[ ]*\(.*\)/s%@SO[@]%\1%/p' \
+ -e '/^LDSHARED=/s/^LDSHARED=[ ]*\(.*\)/s%@LDSHARED[@]%\1%/p' \
+ -e '/^CCSHARED=/s/^CCSHARED=[ ]*\(.*\)/s%@CCSHARED[@]%\1%/p' \
+ -e '/^SGI_ABI=/s/^SGI_ABI=[ ]*\(.*\)/s%@SGI_ABI[@]%\1%/p' \
+ -e '/^$L=/s/^$L=[ ]*\(.*\)/s%@$L[@]%\1%/p' \
+ -e '/^$P=/s/^$P=\(.*\)/s%^$P=.*%$P=\1%/p' \
+ -e '/^$E=/s/^$E=\(.*\)/s%^$E=.*%$E=\1%/p' \
+ $(MAKEFILE) >sedscript
+ echo "/^installdir=/s%=.*%= $(installdir)%" >>sedscript
+ echo "/^exec_installdir=/s%=.*%=$(exec_installdir)%" >>sedscript
+ echo "/^srcdir=/s%=.*%= $(srcdir)%" >>sedscript
+ echo "/^VPATH=/s%=.*%= $(VPATH)%" >>sedscript
+ echo "/^LINKPATH=/s%=.*%= $(LINKPATH)%" >>sedscript
+ echo "/^BASELIB=/s%=.*%= $(BASELIB)%" >>sedscript
+ echo "/^BASESETUP=/s%=.*%= $(BASESETUP)%" >>sedscript
+ if grep 's%@DEFS' sedscript >/dev/null 2>&1; then \
+ :; \
+ else \
+ echo "s%@DEFS[@]%%" >>sedscript; \
+ fi
+
+
+# Bootstrap target
+boot: clobber
+ VERSION=`$(PYTHON) -c "import sys; print sys.version[:3]"`; \
+ installdir=`$(PYTHON) -c "import sys; print sys.prefix"`; \
+ exec_installdir=`$(PYTHON) -c "import sys; print sys.exec_prefix"`; \
+ $(MAKE) -f $(srcdir)/Makefile.pre.in VPATH=$(VPATH) srcdir=$(srcdir) \
+ VERSION=$$VERSION \
+ installdir=$$installdir \
+ exec_installdir=$$exec_installdir \
+ Makefile
+
+# Handy target to remove intermediate files and backups
+clean:
+ -rm -f *.o *~
+
+# Handy target to remove everything that is easily regenerated
+clobber: clean
+ -rm -f *.a tags TAGS config.c Makefile.pre $(TARGET) sedscript
+ -rm -f *.so *.sl so_locations
+
+
+# Handy target to remove everything you don't want to distribute
+distclean: clobber
+ -rm -f Makefile Setup
diff --git a/wlp/module/Makefile.pre.in.OLD b/wlp/module/Makefile.pre.in.OLD
new file mode 100644
index 0000000..4f3f2bd
--- /dev/null
+++ b/wlp/module/Makefile.pre.in.OLD
@@ -0,0 +1,304 @@
+# Universal Unix Makefile for Python extensions
+# =============================================
+
+# Short Instructions
+# ------------------
+
+# 1. Build and install Python (1.5 or newer).
+# 2. "make -f Makefile.pre.in boot"
+# 3. "make"
+# You should now have a shared library.
+
+# Long Instructions
+# -----------------
+
+# Build *and install* the basic Python 1.5 distribution. See the
+# Python README for instructions. (This version of Makefile.pre.in
+# only withs with Python 1.5, alpha 3 or newer.)
+
+# Create a file Setup.in for your extension. This file follows the
+# format of the Modules/Setup.dist file; see the instructions there.
+# For a simple module called "spam" on file "spammodule.c", it can
+# contain a single line:
+# spam spammodule.c
+# You can build as many modules as you want in the same directory --
+# just have a separate line for each of them in the Setup.in file.
+
+# If you want to build your extension as a shared library, insert a
+# line containing just the string
+# *shared*
+# at the top of your Setup.in file.
+
+# Note that the build process copies Setup.in to Setup, and then works
+# with Setup. It doesn't overwrite Setup when Setup.in is changed, so
+# while you're in the process of debugging your Setup.in file, you may
+# want to edit Setup instead, and copy it back to Setup.in later.
+# (All this is done so you can distribute your extension easily and
+# someone else can select the modules they actually want to build by
+# commenting out lines in the Setup file, without editing the
+# original. Editing Setup is also used to specify nonstandard
+# locations for include or library files.)
+
+# Copy this file (Misc/Makefile.pre.in) to the directory containing
+# your extension.
+
+# Run "make -f Makefile.pre.in boot". This creates Makefile
+# (producing Makefile.pre and sedscript as intermediate files) and
+# config.c, incorporating the values for sys.prefix, sys.exec_prefix
+# and sys.version from the installed Python binary. For this to work,
+# the python binary must be on your path. If this fails, try
+# make -f Makefile.pre.in Makefile VERSION=1.5 installdir=<prefix>
+# where <prefix> is the prefix used to install Python for installdir
+# (and possibly similar for exec_installdir=<exec_prefix>).
+
+# Note: "make boot" implies "make clobber" -- it assumes that when you
+# bootstrap you may have changed platforms so it removes all previous
+# output files.
+
+# If you are building your extension as a shared library (your
+# Setup.in file starts with *shared*), run "make" or "make sharedmods"
+# to build the shared library files. If you are building a statically
+# linked Python binary (the only solution of your platform doesn't
+# support shared libraries, and sometimes handy if you want to
+# distribute or install the resulting Python binary), run "make
+# python".
+
+# Note: Each time you edit Makefile.pre.in or Setup, you must run
+# "make Makefile" before running "make".
+
+# Hint: if you want to use VPATH, you can start in an empty
+# subdirectory and say (e.g.):
+# make -f ../Makefile.pre.in boot srcdir=.. VPATH=..
+
+
+# === Bootstrap variables (edited through "make boot") ===
+
+# The prefix used by "make inclinstall libainstall" of core python
+installdir= /usr/local
+
+# The exec_prefix used by the same
+exec_installdir=$(installdir)
+
+# Source directory and VPATH in case you want to use VPATH.
+# (You will have to edit these two lines yourself -- there is no
+# automatic support as the Makefile is not generated by
+# config.status.)
+srcdir= .
+VPATH= .
+
+# === Variables that you may want to customize (rarely) ===
+
+# (Static) build target
+TARGET= python
+
+# Installed python binary (used only by boot target)
+PYTHON= python
+
+# Add more -I and -D options here
+CFLAGS= $(OPT) -I$(INCLUDEPY) -I$(EXECINCLUDEPY) $(DEFS)
+
+# These two variables can be set in Setup to merge extensions.
+# See example[23].
+BASELIB=
+BASESETUP=
+
+# === Variables set by makesetup ===
+
+MODOBJS= _MODOBJS_
+MODLIBS= _MODLIBS_
+
+# === Definitions added by makesetup ===
+
+# === Variables from configure (through sedscript) ===
+
+VERSION= @VERSION@
+CC= @CC@
+LINKCC= @LINKCC@
+SGI_ABI= @SGI_ABI@
+OPT= @OPT@
+LDFLAGS= @LDFLAGS@
+LDLAST= @LDLAST@
+DEFS= @DEFS@
+LIBS= @LIBS@
+LIBM= @LIBM@
+LIBC= @LIBC@
+RANLIB= @RANLIB@
+MACHDEP= @MACHDEP@
+SO= @SO@
+LDSHARED= @LDSHARED@
+CCSHARED= @CCSHARED@
+LINKFORSHARED= @LINKFORSHARED@
+CXX= @CXX@
+
+# Install prefix for architecture-independent files
+prefix= /usr/local
+
+# Install prefix for architecture-dependent files
+exec_prefix= $(prefix)
+
+# Uncomment the following two lines for AIX
+#LINKCC= $(LIBPL)/makexp_aix $(LIBPL)/python.exp "" $(LIBRARY); $(PURIFY) $(CC)
+#LDSHARED= $(LIBPL)/ld_so_aix $(CC) -bI:$(LIBPL)/python.exp
+
+# === Fixed definitions ===
+
+# Shell used by make (some versions default to the login shell, which is bad)
+SHELL= /bin/sh
+
+# Expanded directories
+BINDIR= $(exec_installdir)/bin
+LIBDIR= $(exec_prefix)/lib
+MANDIR= $(installdir)/share/man
+INCLUDEDIR= $(installdir)/include
+SCRIPTDIR= $(prefix)/lib
+
+# Detailed destination directories
+BINLIBDEST= $(LIBDIR)/python$(VERSION)
+LIBDEST= $(SCRIPTDIR)/python$(VERSION)
+INCLUDEPY= $(INCLUDEDIR)/python$(VERSION)
+EXECINCLUDEPY= $(exec_installdir)/include/python$(VERSION)
+LIBP= $(exec_installdir)/lib/python$(VERSION)
+DESTSHARED= $(BINLIBDEST)/site-packages
+
+LIBPL= $(LIBP)/config
+
+PYTHONLIBS= $(LIBPL)/libpython$(VERSION).a
+
+MAKESETUP= $(LIBPL)/makesetup
+MAKEFILE= $(LIBPL)/Makefile
+CONFIGC= $(LIBPL)/config.c
+CONFIGCIN= $(LIBPL)/config.c.in
+SETUP= $(LIBPL)/Setup.config $(LIBPL)/Setup.local $(LIBPL)/Setup
+
+SYSLIBS= $(LIBM) $(LIBC)
+
+ADDOBJS= $(LIBPL)/python.o config.o
+
+# Portable install script (configure doesn't always guess right)
+INSTALL= $(LIBPL)/install-sh -c
+# Shared libraries must be installed with executable mode on some systems;
+# rather than figuring out exactly which, we always give them executable mode.
+# Also, making them read-only seems to be a good idea...
+INSTALL_SHARED= ${INSTALL} -m 555
+
+# === Fixed rules ===
+
+# Default target. This builds shared libraries only
+default: sharedmods
+
+# Build everything
+all: static sharedmods
+
+# Build shared libraries from our extension modules
+sharedmods: $(SHAREDMODS)
+
+# Build a static Python binary containing our extension modules
+static: $(TARGET)
+$(TARGET): $(ADDOBJS) lib.a $(PYTHONLIBS) Makefile $(BASELIB)
+ $(LINKCC) $(LDFLAGS) $(LINKFORSHARED) \
+ $(ADDOBJS) lib.a $(PYTHONLIBS) \
+ $(LINKPATH) $(BASELIB) $(MODLIBS) $(LIBS) $(SYSLIBS) \
+ -o $(TARGET) $(LDLAST)
+
+install: sharedmods
+ if test ! -d $(DESTSHARED) ; then \
+ mkdir $(DESTSHARED) ; else true ; fi
+ -for i in X $(SHAREDMODS); do \
+ if test $$i != X; \
+ then $(INSTALL_SHARED) $$i $(DESTSHARED)/$$i; \
+ fi; \
+ done
+
+# Build the library containing our extension modules
+lib.a: $(MODOBJS)
+ -rm -f lib.a
+ ar cr lib.a $(MODOBJS)
+ -$(RANLIB) lib.a
+
+# This runs makesetup *twice* to use the BASESETUP definition from Setup
+config.c Makefile: Makefile.pre Setup $(BASESETUP) $(MAKESETUP)
+ $(MAKESETUP) \
+ -m Makefile.pre -c $(CONFIGCIN) Setup -n $(BASESETUP) $(SETUP)
+ $(MAKE) -f Makefile do-it-again
+
+# Internal target to run makesetup for the second time
+do-it-again:
+ $(MAKESETUP) \
+ -m Makefile.pre -c $(CONFIGCIN) Setup -n $(BASESETUP) $(SETUP)
+
+# Make config.o from the config.c created by makesetup
+config.o: config.c
+ $(CC) $(CFLAGS) -c config.c
+
+# Setup is copied from Setup.in *only* if it doesn't yet exist
+Setup:
+ cp $(srcdir)/Setup.in Setup
+
+# Make the intermediate Makefile.pre from Makefile.pre.in
+Makefile.pre: Makefile.pre.in sedscript
+ sed -f sedscript $(srcdir)/Makefile.pre.in >Makefile.pre
+
+# Shortcuts to make the sed arguments on one line
+P=prefix
+E=exec_prefix
+H=Generated automatically from Makefile.pre.in by sedscript.
+L=LINKFORSHARED
+
+# Make the sed script used to create Makefile.pre from Makefile.pre.in
+sedscript: $(MAKEFILE)
+ sed -n \
+ -e '1s/.*/1i\\/p' \
+ -e '2s%.*%# $H%p' \
+ -e '/^VERSION=/s/^VERSION=[ ]*\(.*\)/s%@VERSION[@]%\1%/p' \
+ -e '/^CC=/s/^CC=[ ]*\(.*\)/s%@CC[@]%\1%/p' \
+ -e '/^CXX=/s/^CXX=[ ]*\(.*\)/s%@CXX[@]%\1%/p' \
+ -e '/^LINKCC=/s/^LINKCC=[ ]*\(.*\)/s%@LINKCC[@]%\1%/p' \
+ -e '/^OPT=/s/^OPT=[ ]*\(.*\)/s%@OPT[@]%\1%/p' \
+ -e '/^LDFLAGS=/s/^LDFLAGS=[ ]*\(.*\)/s%@LDFLAGS[@]%\1%/p' \
+ -e '/^LDLAST=/s/^LDLAST=[ ]*\(.*\)/s%@LDLAST[@]%\1%/p' \
+ -e '/^DEFS=/s/^DEFS=[ ]*\(.*\)/s%@DEFS[@]%\1%/p' \
+ -e '/^LIBS=/s/^LIBS=[ ]*\(.*\)/s%@LIBS[@]%\1%/p' \
+ -e '/^LIBM=/s/^LIBM=[ ]*\(.*\)/s%@LIBM[@]%\1%/p' \
+ -e '/^LIBC=/s/^LIBC=[ ]*\(.*\)/s%@LIBC[@]%\1%/p' \
+ -e '/^RANLIB=/s/^RANLIB=[ ]*\(.*\)/s%@RANLIB[@]%\1%/p' \
+ -e '/^MACHDEP=/s/^MACHDEP=[ ]*\(.*\)/s%@MACHDEP[@]%\1%/p' \
+ -e '/^SO=/s/^SO=[ ]*\(.*\)/s%@SO[@]%\1%/p' \
+ -e '/^LDSHARED=/s/^LDSHARED=[ ]*\(.*\)/s%@LDSHARED[@]%\1%/p' \
+ -e '/^CCSHARED=/s/^CCSHARED=[ ]*\(.*\)/s%@CCSHARED[@]%\1%/p' \
+ -e '/^SGI_ABI=/s/^SGI_ABI=[ ]*\(.*\)/s%@SGI_ABI[@]%\1%/p' \
+ -e '/^$L=/s/^$L=[ ]*\(.*\)/s%@$L[@]%\1%/p' \
+ -e '/^$P=/s/^$P=\(.*\)/s%^$P=.*%$P=\1%/p' \
+ -e '/^$E=/s/^$E=\(.*\)/s%^$E=.*%$E=\1%/p' \
+ $(MAKEFILE) >sedscript
+ echo "/^installdir=/s%=.*%= $(installdir)%" >>sedscript
+ echo "/^exec_installdir=/s%=.*%=$(exec_installdir)%" >>sedscript
+ echo "/^srcdir=/s%=.*%= $(srcdir)%" >>sedscript
+ echo "/^VPATH=/s%=.*%= $(VPATH)%" >>sedscript
+ echo "/^LINKPATH=/s%=.*%= $(LINKPATH)%" >>sedscript
+ echo "/^BASELIB=/s%=.*%= $(BASELIB)%" >>sedscript
+ echo "/^BASESETUP=/s%=.*%= $(BASESETUP)%" >>sedscript
+
+# Bootstrap target
+boot: clobber
+ VERSION=`$(PYTHON) -c "import sys; print sys.version[:3]"`; \
+ installdir=`$(PYTHON) -c "import sys; print sys.prefix"`; \
+ exec_installdir=`$(PYTHON) -c "import sys; print sys.exec_prefix"`; \
+ $(MAKE) -f $(srcdir)/Makefile.pre.in VPATH=$(VPATH) srcdir=$(srcdir) \
+ VERSION=$$VERSION \
+ installdir=$$installdir \
+ exec_installdir=$$exec_installdir \
+ Makefile
+
+# Handy target to remove intermediate files and backups
+clean:
+ -rm -f *.o *~
+
+# Handy target to remove everything that is easily regenerated
+clobber: clean
+ -rm -f *.a tags TAGS config.c Makefile.pre $(TARGET) sedscript
+ -rm -f *.so *.sl so_locations
+
+
+# Handy target to remove everything you don't want to distribute
+distclean: clobber
+ -rm -f Makefile Setup
diff --git a/wlp/module/Setup.in b/wlp/module/Setup.in
new file mode 100644
index 0000000..18cce4d
--- /dev/null
+++ b/wlp/module/Setup.in
@@ -0,0 +1,88 @@
+# -*- makefile -*-
+# The file Setup is used by the makesetup script to construct the files
+# Makefile and config.c, from Makefile.pre and config.c.in,
+# respectively. The file Setup itself is initially copied from
+# Setup.in; once it exists it will not be overwritten, so you can edit
+# Setup to your heart's content. Note that Makefile.pre is created
+# from Makefile.pre.in by the toplevel configure script.
+
+# (VPATH notes: Setup and Makefile.pre are in the build directory, as
+# are Makefile and config.c; the *.in files are in the source
+# directory.)
+
+# Each line in this file describes one or more optional modules.
+# Comment out lines to suppress modules.
+# Lines have the following structure:
+#
+# <module> ... [<sourcefile> ...] [<cpparg> ...] [<library> ...]
+
+# <sourcefile> is anything ending in .c (.C, .cc, .c++ are C++ files)
+# <cpparg> is anything starting with -I, -D, -U or -C
+# <library> is anything ending in .a or beginning with -l or -L
+# <module> is anything else but should be a valid Python
+# identifier (letters, digits, underscores, beginning with non-digit)
+#
+# (As the makesetup script changes, it may recognize some other
+# arguments as well, e.g. *.so and *.sl as libraries. See the big
+# case statement in the makesetup script.)
+#
+# Lines can also have the form
+#
+# <name> = <value>
+#
+# which defines a Make variable definition inserted into Makefile.in
+#
+# Finally, if a line contains just the word "*shared*" (without the
+# quotes but with the stars), then the following modules will not be
+# included in the config.c file, nor in the list of objects to be
+# added to the library archive, and their linker options won't be
+# added to the linker options, but rules to create their .o files and
+# their shared libraries will still be added to the Makefile, and
+# their names will be collected in the Make variable SHAREDMODS. This
+# is used to build modules as shared libraries. (They can be
+# installed using "make sharedinstall", which is implied by the
+# toplevel "make install" target.) (For compatibility,
+# *noconfig* has the same effect as *shared*.)
+#
+# In addition, *static* reverses this effect (negating a previous
+# *shared* line).
+
+# NOTE: As a standard policy, as many modules as can be supported by a
+# platform should be present. The distribution comes with all modules
+# enabled that are supported by most platforms and don't require you
+# to ftp sources from elsewhere.
+
+*static*
+# Some special rules to define PYTHONPATH.
+# Edit the definitions below to indicate which options you are using.
+# Don't add any whitespace or comments!
+
+# Directories where library files get installed.
+# DESTLIB is for Python modules; MACHDESTLIB for shared libraries.
+DESTLIB=$(LIBDEST)
+MACHDESTLIB=$(BINLIBDEST)
+
+# NOTE: all the paths are now relative to the prefix that is computed
+# at run time!
+
+# Standard path -- don't edit.
+# No leading colon since this is the first entry.
+# Empty since this is now just the runtime prefix.
+DESTPATH=
+
+# Site specific path components -- should begin with : if non-empty
+SITEPATH=
+
+# Standard path components for test modules
+TESTPATH=
+
+# Path components for machine- or system-dependent modules and shared libraries
+MACHDEPPATH=:plat-$(MACHDEP)
+
+COREPYTHONPATH=$(DESTPATH)$(SITEPATH)$(MACHDEPPATH)$(STDWINPATH)$(TKPATH)
+PYTHONPATH=$(COREPYTHONPATH)
+
+*shared*
+
+WLPSRCDIR=../C
+wlp $(WLPSRCDIR)/wlp.c $(WLPSRCDIR)/wlp.a
diff --git a/wlp/module/makesetup b/wlp/module/makesetup
new file mode 100755
index 0000000..0fefcff
--- /dev/null
+++ b/wlp/module/makesetup
@@ -0,0 +1,261 @@
+#! /bin/sh
+
+# Convert templates into Makefile and config.c, based on the module
+# definitions found in the file Setup.
+#
+# Usage: makesetup [-s dir] [-c file] [-m file] [Setup] ... [-n [Setup] ...]
+#
+# Options:
+# -s directory: alternative source directory (default derived from $0)
+# -c file: alternative config.c template (default $srcdir/config.c.in)
+# -c -: don't write config.c
+# -m file: alternative Makefile template (default ./Makefile.pre)
+# -m -: don't write Makefile
+#
+# Remaining arguments are one or more Setup files (default ./Setup).
+# Setup files after a -n option are used for their variables, modules
+# and libraries but not for their .o files.
+#
+# See Setup.in for a description of the format of the Setup file.
+#
+# The following edits are made:
+#
+# Copying config.c.in to config.c:
+# - insert an identifying comment at the start
+# - for each <module> mentioned in Setup before *noconfig*:
+# + insert 'extern void init<module>();' before MARKER 1
+# + insert '{"<module>", initmodule},' before MARKER 2
+#
+# Copying Makefile.pre to Makefile:
+# - insert an identifying comment at the start
+# - replace _MODOBJS_ by the list of objects from Setup (except for
+# Setup files after a -n option)
+# - replace _MODLIBS_ by the list of libraries from Setup
+# - for each object file mentioned in Setup, append a rule
+# '<file>.o: <file>.c; <build commands>' to the end of the Makefile
+# - for each module mentioned in Setup, append a rule
+# which creates a shared library version to the end of the Makefile
+# - for each variable definition found in Setup, insert the definition
+# before the comment 'Definitions added by makesetup'
+
+# Loop over command line options
+usage='
+usage: makesetup [-s srcdir] [-c config.c.in] [-m Makefile.pre]
+ [Setup] ... [-n [Setup] ...]'
+srcdir=''
+config=''
+makepre=''
+noobjects=''
+doconfig=yes
+while :
+do
+ case $1 in
+ -s) shift; srcdir=$1; shift;;
+ -c) shift; config=$1; shift;;
+ -m) shift; makepre=$1; shift;;
+ --) shift; break;;
+ -n) noobjects=yes;;
+ -*) echo "$usage" 1>&2; exit 2;;
+ *) break;;
+ esac
+done
+
+# Set default srcdir and config if not set by command line
+# (Not all systems have dirname)
+case $srcdir in
+'') case $0 in
+ */*) srcdir=`echo $0 | sed 's,/[^/]*$,,'`;;
+ *) srcdir=.;;
+ esac;;
+esac
+case $config in
+'') config=$srcdir/config.c.in;;
+esac
+case $makepre in
+'') makepre=Makefile.pre;;
+esac
+
+# Newline for sed i and a commands
+NL='\
+'
+
+# Main loop
+for i in ${*-Setup}
+do
+ case $i in
+ -n) echo '*noobjects*';;
+ *) echo '*doconfig*'; cat "$i";;
+ esac
+done |
+sed -e 's/[ ]*#.*//' -e '/^[ ]*$/d' |
+(
+ rulesf="@rules.$$"
+ trap 'rm -f $rulesf' 0 1 2 3
+ echo "
+# Rules appended by makedepend
+" >$rulesf
+ DEFS=
+ MODS=
+ SHAREDMODS=
+ OBJS=
+ LIBS=
+ LOCALLIBS=
+ BASELIBS=
+ while read line
+ do
+ # Output DEFS in reverse order so first definition overrides
+ case $line in
+ *=*) DEFS="$line$NL$DEFS"; continue;;
+ 'include '*) DEFS="$line$NL$DEFS"; continue;;
+ '*noobjects*')
+ case $noobjects in
+ yes) ;;
+ *) LOCALLIBS=$LIBS; LIBS=;;
+ esac
+ noobjects=yes;
+ continue;;
+ '*doconfig*') doconfig=yes; continue;;
+ '*static*') doconfig=yes; continue;;
+ '*noconfig*') doconfig=no; continue;;
+ '*shared*') doconfig=no; continue;;
+ esac
+ srcs=
+ cpps=
+ libs=
+ mods=
+ skip=
+ for arg in $line
+ do
+ case $skip in
+ libs) libs="$libs $arg"; skip=; continue;;
+ cpps) cpps="$cpps $arg"; skip=; continue;;
+ srcs) srcs="$srcs $arg"; skip=; continue;;
+ esac
+ case $arg in
+ -[IDUC]*) cpps="$cpps $arg";;
+ -Xlinker) libs="$libs $arg"; skip=libs;;
+ -[A-Zl]*) libs="$libs $arg";;
+ *.a) libs="$libs $arg";;
+ *.so) libs="$libs $arg";;
+ *.sl) libs="$libs $arg";;
+ /*.o) libs="$libs $arg";;
+ *.o) srcs="$srcs `basename $arg .o`.c";;
+ *.[cC]) srcs="$srcs $arg";;
+ *.cc) srcs="$srcs $arg";;
+ *.c++) srcs="$srcs $arg";;
+ *.cxx) srcs="$srcs $arg";;
+ *.cpp) srcs="$srcs $arg";;
+ \$*) libs="$libs $arg"
+ cpps="$cpps $arg";;
+ *.*) echo 1>&2 "bad word $arg in $line"
+ exit 1;;
+ -u) skip=libs; libs="$libs -u";;
+ [a-zA-Z_]*) mods="$mods $arg";;
+ *) echo 1>&2 "bad word $arg in $line"
+ exit 1;;
+ esac
+ done
+ case $doconfig in
+ yes)
+ LIBS="$LIBS $libs"
+ MODS="$MODS $mods"
+ ;;
+ esac
+ case $noobjects in
+ yes) continue;;
+ esac
+ objs=''
+ for src in $srcs
+ do
+ case $src in
+ *.c) obj=`basename $src .c`.o; cc='$(CC)';;
+ *.cc) obj=`basename $src .cc`.o; cc='$(CCC)';;
+ *.c++) obj=`basename $src .c++`.o; cc='$(CCC)';;
+ *.C) obj=`basename $src .C`.o; cc='$(CCC)';;
+ *.cxx) obj=`basename $src .cxx`.o; cc='$(CCC)';;
+ *.cpp) obj=`basename $src .cpp`.o; cc='$(CCC)';;
+ *) continue;;
+ esac
+ objs="$objs $obj"
+ case $src in
+ glmodule.c) ;;
+ /*) ;;
+ *) src='$(srcdir)/'$src;;
+ esac
+ case $doconfig in
+ no) cc="$cc \$(CCSHARED)";;
+ esac
+ rule="$obj: $src; $cc $cpps \$(CFLAGS) -c $src"
+ echo "$rule" >>$rulesf
+ done
+ case $doconfig in
+ yes) OBJS="$OBJS $objs";;
+ esac
+ for mod in $mods
+ do
+ case $objs in
+ *$mod.o*) base=$mod;;
+ *) base=${mod}module;;
+ esac
+ file="$base\$(SO)"
+ case $doconfig in
+ no) SHAREDMODS="$SHAREDMODS $file";;
+ esac
+ rule="$file: $objs"
+ rule="$rule; \$(LDSHARED) $objs $libs -o $file"
+ echo "$rule" >>$rulesf
+ done
+ done
+
+ case $SHAREDMODS in
+ '') ;;
+ *) DEFS="SHAREDMODS=$SHAREDMODS$NL$DEFS";;
+ esac
+
+ case $noobjects in
+ yes) BASELIBS=$LIBS;;
+ *) LOCALLIBS=$LIBS;;
+ esac
+ LIBS='$(LOCALMODLIBS) $(BASEMODLIBS)'
+ DEFS="BASEMODLIBS=$BASELIBS$NL$DEFS"
+ DEFS="LOCALMODLIBS=$LOCALLIBS$NL$DEFS"
+
+ EXTDECLS=
+ INITBITS=
+ for mod in $MODS
+ do
+ EXTDECLS="${EXTDECLS}extern void init$mod();$NL"
+ INITBITS="${INITBITS} {\"$mod\", init$mod},$NL"
+ done
+
+
+ case $config in
+ -) ;;
+ *) sed -e "
+ 1i$NL/* Generated automatically from $config by makesetup. */
+ /MARKER 1/i$NL$EXTDECLS
+
+ /MARKER 2/i$NL$INITBITS
+
+ " $config >config.c
+ ;;
+ esac
+
+ case $makepre in
+ -) ;;
+ *) sedf="@sed.in.$$"
+ trap 'rm -f $sedf' 0 1 2 3
+ echo "1i\\" >$sedf
+ str="# Generated automatically from $makepre by makesetup."
+ echo "$str" >>$sedf
+ echo "s%_MODOBJS_%$OBJS%" >>$sedf
+ echo "s%_MODLIBS_%$LIBS%" >>$sedf
+ echo "/Definitions added by makesetup/a$NL$NL$DEFS" >>$sedf
+ sed -f $sedf $makepre >Makefile
+ cat $rulesf >>Makefile
+ rm -f $sedf
+ ;;
+ esac
+
+ rm -f $rulesf
+)
diff --git a/wlp/module/patch b/wlp/module/patch
new file mode 100644
index 0000000..bc798fa
--- /dev/null
+++ b/wlp/module/patch
@@ -0,0 +1,13 @@
+diff -ru pyg-0.9.6-old/wlp/module/Makefile.pre.in pyg-0.9.6/wlp/module/Makefile.pre.in
+--- pyg-0.9.6-old/wlp/module/Makefile.pre.in 2003-11-04 08:49:29.000000000 -0800
++++ pyg-0.9.6/wlp/module/Makefile.pre.in 2003-11-04 09:25:16.000000000 -0800
+@@ -278,6 +278,9 @@
+ echo "/^LINKPATH=/s%=.*%= $(LINKPATH)%" >>sedscript
+ echo "/^BASELIB=/s%=.*%= $(BASELIB)%" >>sedscript
+ echo "/^BASESETUP=/s%=.*%= $(BASESETUP)%" >>sedscript
++ if ! grep 's%@DEFS' sedscript >/dev/null 2>&1; then \
++ echo "s%@DEFS[@]%%" >>sedscript; \
++ fi
+
+ # Bootstrap target
+ boot: clobber
diff --git a/wlp_test b/wlp_test
new file mode 100755
index 0000000..5ccea1c
--- /dev/null
+++ b/wlp_test
@@ -0,0 +1,31 @@
+#!/usr/bin/python
+
+# Script to test if wlp.so works. It should parse confile without errors.
+
+import sys
+import wlp
+
+if(len(sys.argv) == 1):
+ wlp.setfilebyname('./pyg.wl')
+else:
+ wlp.setfilebyname(sys.argv[1])
+
+# dict is a { ownername : {variable: value}} dictionary of dictionaries
+dict = wlp.mkdict()
+
+try:
+ print 'owner: option = value'
+
+ for owner in dict.keys():
+ options = dict[owner]
+ for option in options.keys():
+ print '%s: %s = %s' % (owner,option,options[option])
+except (Exception), message:
+ print message
+
+
+for k in dict.keys():
+ if(dict[k]['From:'] == 'Cosimo Alfarano'):
+ print '%s has %s' % (k,dict[k]['From:'])
+
+sys.exit(0)