readding files

git-svn-id: https://linkchecker.svn.sourceforge.net/svnroot/linkchecker/trunk/linkchecker@192 e7d03fd6-7b0d-0410-9947-9c21f3af8025
This commit is contained in:
calvin 2000-11-09 12:05:12 +00:00
parent 27ae52dd56
commit 40f7cd55ca
9 changed files with 1875 additions and 0 deletions

View file

@ -7,3 +7,4 @@ MANIFEST
VERSION
LinkCheckerConf.py
locale
Packages.gz

34
debian/postinst vendored Executable file
View file

@ -0,0 +1,34 @@
#! /bin/sh
#
# Written 1998 by Gregor Hoffleit <flight@debian.org>.
# used by Bastian Kleineidam for LinkChecker
set -e
DIRLIST="/usr/lib/python1.5/site-packages/linkcheck"
FILELIST="CSV.py LinkCheckerConf.py StringUtil.py fcgi.py fintl.py
http11lib.py httpslib.py robotparser2.py sz_fcgi.py util1.py"
SITEPACKAGES="/usr/lib/python1.5/site-packages"
COMMAND="'import sys,py_compile;py_compile.compile(sys.argv[1])'"
case "$1" in
configure|abort-upgrade|abort-remove|abort-deconfigure)
for i in $DIRLIST; do
python -O /usr/lib/python1.5/compileall.py -q $i
python /usr/lib/python1.5/compileall.py -q $i
done
# use /bin/sh -c, otherwise I get a SyntaxError from Python
for i in $FILELIST; do
/bin/sh -c "python -O -c $COMMAND $SITEPACKAGES/$i"
/bin/sh -c "python -c $COMMAND $SITEPACKAGES/$i"
done
;;
*)
echo "postinst called with unknown argument \`$1'" >&2
exit 1
;;
esac
#DEBHELPER#
exit 0

18
debian/prerm vendored Executable file
View file

@ -0,0 +1,18 @@
#! /bin/sh
#
# Written 1998 by Gregor Hoffleit <flight@debian.org>.
# used by Bastian Kleineidam for LinkChecker
set -e
PACKAGE=linkchecker
dpkg --listfiles $PACKAGE |
awk '$0~/\.py$/ {print $0"c\n" $0"o"}' |
xargs rm -f >&2
rmdir /usr/lib/python1.5/site-packages/linkcheck 2>/dev/null || true
#DEBHELPER#
exit 0

208
fintl.py Normal file
View file

@ -0,0 +1,208 @@
## vim:ts=4:et:nowrap
"""i18n (multiple language) support. Reads .mo files from GNU gettext msgfmt
If you want to prepare your Python programs for i18n you could simply
add the following lines to the top of a BASIC_MAIN module of your py-program:
try:
import fintl
gettext = fintl.gettext
fintl.bindtextdomain(YOUR_PROGRAM, YOUR_LOCALEDIR)
fintl.textdomain(YOUR_PROGRAM)
except ImportError:
def gettext(msg):
return msg
_ = gettext
and/or also add the following to the top of any module containing messages:
import BASIC_MAIN
_ = BASIC_MAIN.gettext
Now you could use _("....") everywhere instead of "...." for message texts.
Once you have written your internationalized program, you can use
the suite of utility programs contained in the GNU gettext package to aid
the translation into other languages.
You ARE NOT REQUIRED to release the sourcecode of your program, since
linking of your program against GPL code is avoided by this module.
Although it is possible to use the GNU gettext library by using the
*intl.so* module written by Martin von Löwis if this is available. But it is
not required to use it in the first place.
"""
# Copyright 1999 by <mailto: pf@artcom-gmbh.de> (Peter Funk)
#
# All Rights Reserved
#
# Permission to use, copy, modify, and distribute this software and its
# documentation for any purpose and without fee is hereby granted,
# provided that the above copyright notice appear in all copies.
# ArtCom GmbH AND Peter Funk DISCLAIMS ALL WARRANTIES WITH REGARD TO
# THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
# AND FITNESS, IN NO EVENT SHALL ArtCom GmBH or Peter Funk BE LIABLE
# FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN
# AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING
# OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
_default_localedir = '/usr/share/locale'
_default_domain = 'python'
# check out, if Martin v. Löwis 'intl' module interface to the GNU gettext
# library is available and use it only, if it is available:
try:
from intl import *
except ImportError:
# now do what the gettext library provides in pure Python:
error = 'fintl.error'
# some globals preserving state:
_languages = []
_default_mo = None # This is default message outfile used by 'gettext'
_loaded_mos = {} # This is a dictionary of loaded message output files
# some small little helper routines:
def _check_env():
"""examine language enviroment variables and return list of languages"""
# TODO: This should somehow try to find out locale information on
# Non-unix platforms like WinXX and MacOS. Suggestions welcome!
languages = []
import os, string
for envvar in ('LANGUAGE', 'LC_ALL', 'LC_MESSAGES', 'LANG'):
if os.environ.has_key(envvar):
languages = string.split(os.environ[envvar], ':')
break
# use locale 'C' as default fallback:
if 'C' not in _languages:
languages.append('C')
return languages
# Utility function used to decode binary .mo file header and seek tables:
def _decode_Word(bin):
# This assumes little endian (intel, vax) byte order.
return ord(bin[0]) + (ord(bin[1]) << 8) + \
(ord(bin[2]) << 16) + (ord(bin[3]) << 24)
# Now the methods designed to be used from outside:
def gettext(message):
"""return localized version of a 'message' string"""
if _default_mo is None:
textdomain()
return _default_mo.gettext(message)
_ = gettext
def dgettext(domain, message):
"""like gettext but looks up 'message' in a special 'domain'"""
# This may useful for larger software systems
if not _loaded_mos.has_key(domain):
raise error, "No '" + domain + "' message domain"
return _loaded_mos[domain].gettext(message)
class _MoDict:
"""read a .mo file into a python dictionary"""
__MO_MAGIC = 0x950412de # Magic number of .mo files
def __init__(self, domain=_default_domain, localedir=_default_localedir):
global _languages
self.catalog = {}
self.domain = domain
self.localedir = localedir
# delayed access to environment variables:
if not _languages:
_languages = _check_env()
for self.lang in _languages:
if self.lang == 'C':
return
mo_filename = "%s//%s/LC_MESSAGES/%s.mo" % (
localedir, self.lang, domain)
try:
buffer = open(mo_filename, "rb").read()
break
except IOError:
pass
else:
return # assume C locale
# Decode the header of the .mo file (5 little endian 32 bit words):
if _decode_Word(buffer[:4]) != self.__MO_MAGIC :
raise error, '%s seems not be a valid .mo file' % mo_filename
self.mo_version = _decode_Word(buffer[4:8])
num_messages = _decode_Word(buffer[8:12])
master_index = _decode_Word(buffer[12:16])
transl_index = _decode_Word(buffer[16:20])
buf_len = len(buffer)
# now put all messages from the .mo file buffer in the catalog dict:
for i in xrange(0, num_messages):
start_master= _decode_Word(buffer[master_index+4:master_index+8])
end_master = start_master + \
_decode_Word(buffer[master_index:master_index+4])
start_transl= _decode_Word(buffer[transl_index+4:transl_index+8])
end_transl = start_transl + \
_decode_Word(buffer[transl_index:transl_index+4])
if end_master <= buf_len and end_transl <= buf_len:
self.catalog[buffer[start_master:end_master]]=\
buffer[start_transl:end_transl]
else:
raise error, ".mo file '%s' is corrupt" % mo_filename
# advance to the next entry in seek tables:
master_index= master_index + 8
transl_index= transl_index + 8
def gettext(self, message):
"""return the translation of a given message"""
try:
return self.catalog[message]
except KeyError:
return message
# _MoDict instances may be also accessed using mo[msg] or mo(msg):
__getitem = gettext
__call__ = gettext
def textdomain(domain=_default_domain):
"""Sets the 'domain' to be used by this program. Defaults to 'python'"""
global _default_mo
if not _loaded_mos.has_key(domain):
_loaded_mos[domain] = _MoDict(domain)
_default_mo = _loaded_mos[domain]
def bindtextdomain(domain, localedir=_default_localedir):
global _default_mo
if not _loaded_mos.has_key(domain):
_loaded_mos[domain] = _MoDict(domain, localedir)
if _default_mo is not None:
_default_mo = _loaded_mos[domain]
def translator(domain=_default_domain, localedir=_default_localedir):
"""returns a gettext compatible function object
which is bound to the domain given as parameter"""
pass # TODO implement this
def _testdriver(argv):
message = ""
domain = _default_domain
localedir = _default_localedir
if len(argv) > 1:
message = argv[1]
if len(argv) > 2:
domain = argv[2]
if len(argv) > 3:
localedir = argv[3]
# now perform some testing of this module:
bindtextdomain(domain, localedir)
textdomain(domain)
info = gettext('') # this is where special info is often stored
if info:
print ".mo file for domain %s in %s contains:" % (domain, localedir)
print info
else:
print ".mo file contains no info"
if message:
print "Translation of '"+ message+ "' is '"+ _(message)+ "'"
else:
for msg in ("Cancel", "No", "OK", "Quit", "Yes"):
print "Translation of '"+ msg + "' is '"+ _(msg)+ "'"
if __name__ == '__main__':
import sys
if len(sys.argv) > 1 and (sys.argv[1] == "-h" or sys.argv[1] == "-?"):
print "Usage :", sys.argv[0], "[ MESSAGE [ DOMAIN [ LOCALEDIR ]]]"
_testdriver(sys.argv)

394
http11lib.py Normal file
View file

@ -0,0 +1,394 @@
#
# HTTP/1.1 client library
#
# Copyright (C) 1998-1999 Guido van Rossum. All Rights Reserved.
# Written by Greg Stein. Given to Guido. Licensed using the Python license.
#
# This module is maintained by Greg and is available at:
# http://www.lyra.org/greg/python/httplib.py
#
# Since this isn't in the Python distribution yet, we'll use the CVS ID
# for tracking:
# $Id$
#
# Modified by Bastian Kleineidam to squish a bug.
import socket,string,mimetools,httplib
error = __name__ + '.error'
HTTP_PORT = 80
class HTTPResponse(mimetools.Message):
def __init__(self, fp, version, errcode):
mimetools.Message.__init__(self, fp, 0)
if version == 'HTTP/1.0':
self.version = 10
elif version[:7] == 'HTTP/1.':
self.version = 11 # use HTTP/1.1 code for HTTP/1.x where x>=1
else:
raise error, 'unknown HTTP protocol'
# are we using the chunked-style of transfer encoding?
tr_enc = self.getheader('transfer-encoding')
if tr_enc:
if string.lower(tr_enc) != 'chunked':
raise error, 'unknown transfer-encoding'
self.chunked = 1
self.chunk_left = None
else:
self.chunked = 0
# will the connection close at the end of the response?
conn = self.getheader('connection')
if conn:
conn = string.lower(conn)
# a "Connection: close" will always close the connection. if we
# don't see that and this is not HTTP/1.1, then the connection will
# close unless we see a Keep-Alive header.
self.will_close = string.find(conn, 'close') != -1 or \
( self.version != 11 and \
not self.getheader('keep-alive') )
else:
# for HTTP/1.1, the connection will always remain open
# otherwise, it will remain open IFF we see a Keep-Alive header
self.will_close = self.version != 11 and \
not self.getheader('keep-alive')
# do we have a Content-Length?
# NOTE: RFC 2616, S4.4, #3 states we ignore this if tr_enc is "chunked"
length = self.getheader('content-length')
if length and not self.chunked:
self.length = int(length)
else:
self.length = None
# does the body have a fixed length? (of zero)
if (errcode == 204 or # No Content
errcode == 304 or # Not Modified
100 <= errcode < 200): # 1xx codes
self.length = 0
# if the connection remains open, and we aren't using chunked, and
# a content-length was not provided, then assume that the connection
# WILL close.
if not self.will_close and \
not self.chunked and \
self.length is None:
self.will_close = 1
def close(self):
if self.fp:
self.fp.close()
self.fp = None
def isclosed(self):
# NOTE: it is possible that we will not ever call self.close(). This
# case occurs when will_close is TRUE, length is None, and we
# read up to the last byte, but NOT past it.
#
# IMPLIES: if will_close is FALSE, then self.close() will ALWAYS be
# called, meaning self.isclosed() is meaningful.
return self.fp is None
def read(self, amt=None):
if not self.fp:
return ''
if self.chunked:
chunk_left = self.chunk_left
value = ''
while 1:
if not chunk_left:
line = self.fp.readline()
i = string.find(line, ';')
if i >= 0:
line = line[:i] # strip chunk-extensions
chunk_left = string.atoi(line, 16)
if chunk_left == 0:
break
if not amt:
value = value + self.fp.read(chunk_left)
elif amt < chunk_left:
value = value + self.fp.read(amt)
self.chunk_left = chunk_left - amt
return value
elif amt == chunk_left:
value = value + self.fp.read(amt)
self.fp.read(2) # toss the CRLF at the end of the chunk
self.chunk_left = None
return value
else:
value = value + self.fp.read(chunk_left)
amt = amt - chunk_left
# we read the whole chunk, get another
self.fp.read(2) # toss the CRLF at the end of the chunk
chunk_left = None
# read and discard trailer up to the CRLF terminator
### note: we shouldn't have any trailers!
while 1:
line = self.fp.readline()
if line == '\r\n':
break
# we read everything; close the "file"
self.close()
return value
elif not amt:
# unbounded read
if self.will_close:
s = self.fp.read()
else:
s = self.fp.read(self.length)
self.close() # we read everything
return s
if self.length is not None:
if amt > self.length:
# clip the read to the "end of response"
amt = self.length
self.length = self.length - amt
s = self.fp.read(amt)
# close our "file" if we know we should
### I'm not sure about the len(s) < amt part; we should be safe because
### we shouldn't be using non-blocking sockets
if self.length == 0 or len(s) < amt:
self.close()
return s
class HTTPConnection:
_http_vsn = 11
_http_vsn_str = 'HTTP/1.1'
response_class = HTTPResponse
def __init__(self, host, port=None):
self.sock = None
self.response = None
self._set_hostport(host, port)
def _set_hostport(self, host, port):
if port is None:
i = string.find(host, ':')
if i >= 0:
port = int(host[i+1:])
host = host[:i]
else:
port = HTTP_PORT
self.host = host
self.port = port
def connect(self):
"""Connect to the host and port specified in __init__."""
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
self.sock.connect((self.host, self.port))
def close(self):
"""Close the connection to the HTTP server."""
if self.sock:
self.sock.close() # close it manually... there may be other refs
self.sock = None
if self.response:
self.response.close()
self.response = None
def send(self, str):
"""Send `str' to the server."""
if not self.sock:
self.connect()
# send the data to the server. if we get a broken pipe, then close
# the socket. we want to reconnect when somebody tries to send again.
#
# NOTE: we DO propagate the error, though, because we cannot simply
# ignore the error... the caller will know if they can retry.
try:
self.sock.send(str)
except socket.error, v:
if v[0] == 32: # Broken pipe
self.close()
raise
def putrequest(self, method, url='/'):
"""Send a request to the server.
`method' specifies an HTTP request method, e.g. 'GET'.
`url' specifies the object being requested, e.g.
'/index.html'.
"""
if self.response:
if not self.response.isclosed():
### implies half-duplex!
raise error, 'prior response has not been fully handled'
self.response = None
if not url:
url = '/'
str = '%s %s %s\r\n' % (method, url, self._http_vsn_str)
try:
self.send(str)
except socket.error, v:
if v[0] != 32: # Broken pipe
raise
# try one more time (the socket was closed; this will reopen)
self.send(str)
#self.putheader('Host', self.host)
if self._http_vsn == 11:
# Issue some standard headers for better HTTP/1.1 compliance
# note: we are assuming that clients will not attempt to set these
# headers since *this* library must deal with the consequences.
# this also means that when the supporting libraries are
# updated to recognize other forms, then this code should be
# changed (removed or updated).
# we only want a Content-Encoding of "identity" since we don't
# support encodings such as x-gzip or x-deflate.
self.putheader('Accept-Encoding', 'identity')
# we can accept "chunked" Transfer-Encodings, but no others
# NOTE: no TE header implies *only* "chunked"
#self.putheader('TE', 'chunked')
# if TE is supplied in the header, then it must appear in a
# Connection header.
#self.putheader('Connection', 'TE')
else:
# For HTTP/1.0, the server will assume "not chunked"
pass
def putheader(self, header, value):
"""Send a request header line to the server.
For example: h.putheader('Accept', 'text/html')
"""
str = '%s: %s\r\n' % (header, value)
self.send(str)
def endheaders(self):
"""Indicate that the last header line has been sent to the server."""
self.send('\r\n')
def request(self, method, url='/', body=None, headers={}):
"""Send a complete request to the server."""
self.putrequest(method, url)
if body:
self.putheader('Content-Length', str(len(body)))
for hdr, value in headers.items():
self.putheader(hdr, value)
self.endheaders()
if body:
self.send(body)
def getreply(self):
"""Get a reply from the server.
Returns a tuple consisting of:
- server response code (e.g. '200' if all goes well)
- server response string corresponding to response code
- any RFC822 headers in the response from the server
"""
file = self.sock.makefile('rb')
line = file.readline()
try:
[ver, code, msg] = string.split(line, None, 2)
except ValueError:
try:
[ver, code] = string.split(line, None, 1)
msg = ""
except ValueError:
self.close()
return -1, line, file
if ver[:5] != 'HTTP/':
self.close()
return -1, line, file
errcode = int(code)
errmsg = string.strip(msg)
response = self.response_class(file, ver, errcode)
if response.will_close:
# this effectively passes the connection to the response
self.close()
else:
# remember this, so we can tell when it is complete
self.response = response
return errcode, errmsg, response
class HTTP(HTTPConnection):
"Compatibility class with httplib.py from 1.5."
_http_vsn = 10
_http_vsn_str = 'HTTP/1.0'
def __init__(self, host='', port=None):
"Provide a default host, since the superclass requires one."
# Note that we may pass an empty string as the host; this will throw
# an error when we attempt to connect. Presumably, the client code
# will call connect before then, with a proper host.
HTTPConnection.__init__(self, host, port)
self.debuglevel=0
def connect(self, host=None, port=None):
"Accept arguments to set the host/port, since the superclass doesn't."
if host:
self._set_hostport(host, port)
HTTPConnection.connect(self)
def set_debuglevel(self, debuglevel):
self.debuglevel=debuglevel
def getfile(self):
"Provide a getfile, since the superclass' use of HTTP/1.1 prevents it."
return self.file
def putheader(self, header, *values):
"The superclass allows only one value argument."
HTTPConnection.putheader(self, header, string.joinfields(values,'\r\n\t'))
def getreply(self):
"Compensate for an instance attribute shuffling."
errcode, errmsg, response = HTTPConnection.getreply(self)
if errcode == -1:
self.file = response # response is the "file" when errcode==-1
self.headers = None
return -1, errmsg, None
self.headers = response
self.file = response.fp
return errcode, errmsg, response
def _test():
h = HTTP('www.siemens.de')
h.putrequest("GET")
h.putheader("Host", 'www.siemens.de')
h.endheaders()
status,text,reply = h.getreply()
print status,text,reply
if __name__=='__main__':
_test()

170
httpslib.py Normal file
View file

@ -0,0 +1,170 @@
# @(#)httpslib.py 1.1 VMS-99/01/30 https support
import ssl,httplib,string,socket,mimetools
HTTP_PREF = 'HTTP/'
HTTPS_PORT = 443
class HTTPS(httplib.HTTP):
def connect (self, host, port = 0):
"""Connect to a host on a given port.
Note: This method is automatically invoked by __init__,
if a host is specified during instantiation.
"""
if not port:
i = string.find(host, ':')
if i >= 0:
host, port = host[:i], host[i+1:]
try: port = string.atoi(port)
except string.atoi_error:
raise socket.error, "nonnumeric port"
if not port: port = HTTPS_PORT
self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
if self.debuglevel > 0: print 'connect:', (host, port)
self.sock.connect(host, port)
self.ssl = ssl.ssl(self.sock.fileno())
def send (self, str):
if self.debuglevel > 0: print 'send:', `str`
self.ssl.write(str,len(str))
def makefile (self, mode='r', bufsize=-1):
return _fileobject(self.sock,self.ssl,mode,bufsize)
def getreply (self):
self.file = self.makefile('rb')
# self.sock = None
line = self.file.readline()
if self.debuglevel > 0: print 'reply:',`line`
try:
[ver,code,msg] = string.split(line,None,2)
except ValueError:
try:
[ver,code] = string.split(line,None,1)
msg = ""
except ValueError:
ver = ""
if ver[:len(HTTP_PREF)] != HTTP_PREF:
self.headers = None
return -1, line, self.headers
self.headers = mimetools.Message(self.file,0)
return string.atoi(code), string.strip(msg), self.headers
def close (self):
if self.file:
self.file.close()
self.file = self.sock = self.ssl = None
class _fileobject:
def __init__ (self, sock, ssl, mode, bufsize):
import string
self._sock = sock
self._ssl = ssl
self._mode = mode
if bufsize < 0:
bufsize = 512
self._rbufsize = max(1,bufsize)
self._wbufsize = bufsize
self._wbuf = self._rbuf = ""
def close (self):
try:
if self._sock:
self.flush()
finally:
self._sock = None
def __del__ (self):
self.close()
def flush (self):
if self._wbuf:
self._sock.write(self._wbuf,len(self._wbuf))
self._wbuf = ""
def fileno (self):
return self._sock.fileno()
def write (self, data):
self._wbuf = self._wbuf + data
if self._wbufsize == 1:
if '\n' in data:
self.flush()
else:
if len(self._wbuf) >= self._wbufsize:
self.flush()
def writelines (self, lst):
filter(self._sock.send,lst)
self.flush()
def read (self, n=-1):
if n >= 0:
while len(self._rbuf) < n:
new = self._ssl.read(self._rbufsize)
if not new: break
self._rbuf = self._rbuf + new
data,self._rbuf = self._rbuf[:n],self._rbuf[n:]
return data
while 1:
new = self._ssl.read(self._rbufsize)
if not new: break
self._rbuf = self._rbuf + new
data,self._rbuf = self._rbuf,""
return data
def readline (self):
data = ""
i = string.find(self._rbuf,'\n')
while i < 0:
new = self._ssl.read(self._rbufsize)
if not new: break
i = string.find(new,'\n')
if i >= 0: i = i + len(self._rbuf)
self._rbuf = self._rbuf + new
if i < 0: i = len(self._rbuf)
else: i = i+1
data,self._rbuf = self._rbuf[:i],self._rbuf[i:]
return data
def readlines (self):
l = []
while 1:
line = self.readline()
if not line: break
l.append(line)
return l
def _test():
import sys
import getopt
opts, args = getopt.getopt(sys.argv[1:], 'd')
dl = 0
for o, a in opts:
if o == '-d': dl = dl + 1
if args[0:]: host = args[0]
if args[1:]: selector = args[1]
h = HTTPS()
host = 'synergy.as.cmu.edu'
selector = '/~geek/'
# host = 'tls.cryptsoft.com'
# selector = '/'
h.set_debuglevel(dl)
h.connect(host)
h.putrequest('GET', selector)
h.endheaders()
errcode, errmsg, headers = h.getreply()
print 'errcode =', errcode
print 'errmsg =', errmsg
print "\tHEADERS:"
if headers:
for header in headers.headers: print string.strip(header)
print "\tTEXT:"
print h.getfile().read()
if __name__ == '__main__':
_test()

189
po/msgfmt.py Executable file
View file

@ -0,0 +1,189 @@
#!/usr/bin/env python
# Written by Martin v. Löwis <loewis@informatik.hu-berlin.de>
"""Generate binary message catalog from textual translation description.
This program converts a textual Uniforum-style message catalog (.po file) into
a binary GNU catalog (.mo file). This is essentially the same function as the
GNU msgfmt program, however, it is a simpler implementation.
Usage: msgfmt.py [OPTIONS] filename.po
Options:
-h
--help
Print this message and exit.
-V
--version
Display version information and exit.
"""
import sys, getopt, struct, array, string
__version__ = "1.0"
MESSAGES = {}
def usage(code, msg=''):
sys.stderr.write(__doc__)
if msg:
sys.stderr.write(msg)
sys.exit(code)
def add(id, str, fuzzy):
"Add a non-fuzzy translation to the dictionary."
global MESSAGES
if not fuzzy and str:
MESSAGES[id] = str
def generate():
"Return the generated output."
global MESSAGES
keys = MESSAGES.keys()
# the keys are sorted in the .mo file
keys.sort()
offsets = []
ids = strs = ''
for id in keys:
# For each string, we need size and file offset. Each string is NUL
# terminated; the NUL does not count into the size.
offsets.append((len(ids), len(id), len(strs), len(MESSAGES[id])))
ids = ids + id + '\0'
strs = strs + MESSAGES[id] + '\0'
output = ''
# The header is 7 32-bit unsigned integers. We don't use hash tables, so
# the keys start right after the index tables.
# translated string.
keystart = 7*4+16*len(keys)
# and the values start after the keys
valuestart = keystart + len(ids)
koffsets = []
voffsets = []
# The string table first has the list of keys, then the list of values.
# Each entry has first the size of the string, then the file offset.
for o1, l1, o2, l2 in offsets:
koffsets = koffsets + [l1, o1+keystart]
voffsets = voffsets + [l2, o2+valuestart]
offsets = koffsets + voffsets
output = struct.pack("iiiiiii",
0x950412de, # Magic
0, # Version
len(keys), # # of entries
7*4, # start of key index
7*4+len(keys)*8, # start of value index
0, 0) # size and offset of hash table
output = output + array.array("i", offsets).tostring()
output = output + ids
output = output + strs
return output
def make(filename):
ID = 1
STR = 2
# Compute .mo name from .po name
if filename[-3:] == '.po':
infile = filename
outfile = filename[:-2] + 'mo'
else:
infile = filename + '.po'
outfile = filename + '.mo'
try:
lines = open(infile).readlines()
except IOError, msg:
sys.stderr.write(msg)
sys.exit(1)
section = None
fuzzy = 0
# Parse the catalog
lno = 0
for l in lines:
lno = lno + 1
# If we get a comment line after a msgstr, this is a new entry
if l[0] == '#' and section == STR:
add(msgid, msgstr, fuzzy)
section = None
fuzzy = 0
# Record a fuzzy mark
if l[:2] == '#,' and string.find(l, 'fuzzy') != -1:
fuzzy = 1
# Skip comments
if l[0] == '#':
continue
# Now we are in a msgid section, output previous section
if l[:5] == 'msgid':
if section == STR:
add(msgid, msgstr, fuzzy)
section = ID
l = l[5:]
msgid = msgstr = ''
# Now we are in a msgstr section
elif l[:6] == 'msgstr':
section = STR
l = l[6:]
# Skip empty lines
l = string.strip(l)
if not l:
continue
# XXX: Does this always follow Python escape semantics?
l = eval(l)
if section == ID:
msgid = msgid + l
elif section == STR:
msgstr = msgstr + l
else:
sys.stderr.write('Syntax error on %s:%d\n'
'before: %s\n' % (infile, lno, l))
sys.exit(1)
# Add last entry
if section == STR:
add(msgid, msgstr, fuzzy)
# Compute output
output = generate()
# Save output
try:
open(outfile,"wb").write(output)
except IOError,msg:
sys.stderr.write(msg)
def main():
try:
opts, args = getopt.getopt(sys.argv[1:], 'hV', ['help','version'])
except getopt.error, msg:
usage(1, msg)
# parse options
for opt, arg in opts:
if opt in ('-h', '--help'):
usage(0)
elif opt in ('-V', '--version'):
sys.stderr.write("msgfmt.py %s" % __version__)
sys.exit(0)
# do it
if not args:
sys.stderr.write('No input file given\n')
sys.stderr.write("Try `msgfmt --help' for more information.\n")
return
for filename in args:
make(filename)
if __name__ == '__main__':
main()

446
po/pygettext.py Executable file
View file

@ -0,0 +1,446 @@
#!/usr/bin/env python
# Originally written by Barry Warsaw <bwarsaw@python.org>
#
# minimally patched to make it even more xgettext compatible
# by Peter Funk <pf@artcom-gmbh.de>
# for selftesting
try:
import fintl
_ = fintl.gettext
except ImportError:
def _(s): return s
__doc__ = _("""pygettext -- Python equivalent of xgettext(1)
Many systems (Solaris, Linux, Gnu) provide extensive tools that ease the
internationalization of C programs. Most of these tools are independent of
the programming language and can be used from within Python programs. Martin
von Loewis' work[1] helps considerably in this regard.
There's one problem though; xgettext is the program that scans source code
looking for message strings, but it groks only C (or C++). Python introduces
a few wrinkles, such as dual quoting characters, triple quoted strings, and
raw strings. xgettext understands none of this.
Enter pygettext, which uses Python's standard tokenize module to scan Python
source code, generating .pot files identical to what GNU xgettext[2] generates
for C and C++ code. From there, the standard GNU tools can be used.
A word about marking Python strings as candidates for translation. GNU
xgettext recognizes the following keywords: gettext, dgettext, dcgettext, and
gettext_noop. But those can be a lot of text to include all over your code.
C and C++ have a trick: they use the C preprocessor. Most internationalized C
source includes a #define for gettext() to _() so that what has to be written
in the source is much less. Thus these are both translatable strings:
gettext("Translatable String")
_("Translatable String")
Python of course has no preprocessor so this doesn't work so well. Thus,
pygettext searches only for _() by default, but see the -k/--keyword flag
below for how to augment this.
[1] http://www.python.org/workshops/1997-10/proceedings/loewis.html
[2] http://www.gnu.org/software/gettext/gettext.html
NOTE: pygettext attempts to be option and feature compatible with GNU xgettext
where ever possible. However some options are still missing or are not fully
implemented. Also, xgettext's use of command line switches with option
arguments is broken, and in these cases, pygettext just defines additional
switches.
Usage: pygettext [options] inputfile ...
Options:
-a
--extract-all
Extract all strings
-d name
--default-domain=name
Rename the default output file from messages.pot to name.pot
-E
--escape
replace non-ASCII characters with octal escape sequences.
-h
--help
print this help message and exit
-k word
--keyword=word
Keywords to look for in addition to the default set, which are:
%(DEFAULTKEYWORDS)s
You can have multiple -k flags on the command line.
-K
--no-default-keywords
Disable the default set of keywords (see above). Any keywords
explicitly added with the -k/--keyword option are still recognized.
--no-location
Do not write filename/lineno location comments.
-n
--add-location
Write filename/lineno location comments indicating where each
extracted string is found in the source. These lines appear before
each msgid. The style of comments is controlled by the -S/--style
option. This is the default.
-S stylename
--style stylename
Specify which style to use for location comments. Two styles are
supported:
Solaris # File: filename, line: line-number
GNU #: filename:line
The style name is case insensitive. GNU style is the default.
-o filename
--output=filename
Rename the default output file from messages.pot to filename. If
filename is `-' then the output is sent to standard out.
-p dir
--output-dir=dir
Output files will be placed in directory dir.
-v
--verbose
Print the names of the files being processed.
-V
--version
Print the version of pygettext and exit.
-w columns
--width=columns
Set width of output to columns.
-x filename
--exclude-file=filename
Specify a file that contains a list of strings that are not be
extracted from the input files. Each string to be excluded must
appear on a line by itself in the file.
If `inputfile' is -, standard input is read.
""")
import os, sys, time, getopt, tokenize, string
__version__ = '1.1'
default_keywords = ['_']
DEFAULTKEYWORDS = string.join(default_keywords, ', ')
EMPTYSTRING = ''
# The normal pot-file header. msgmerge and EMACS' po-mode work better if
# it's there.
pot_header = _('''\
# SOME DESCRIPTIVE TITLE.
# Copyright (C) YEAR ORGANIZATION
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\\n"
"PO-Revision-Date: %(time)s\\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n"
"Language-Team: LANGUAGE <LL@li.org>\\n"
"MIME-Version: 1.0\\n"
"Content-Type: text/plain; charset=CHARSET\\n"
"Content-Transfer-Encoding: ENCODING\\n"
"Generated-By: pygettext.py %(version)s\\n"
''')
def usage(code, msg=''):
print __doc__ % globals()
if msg:
print msg
sys.exit(code)
escapes = []
def make_escapes(pass_iso8859):
global escapes
if pass_iso8859:
# Allow iso-8859 characters to pass through so that e.g. 'msgid
# "Höhe"' would result not result in 'msgid "H\366he"'. Otherwise we
# escape any character outside the 32..126 range.
mod = 128
else:
mod = 256
for i in range(256):
if 32 <= (i % mod) <= 126:
escapes.append(chr(i))
else:
escapes.append("\\%03o" % i)
escapes[ord('\\')] = '\\\\'
escapes[ord('\t')] = '\\t'
escapes[ord('\r')] = '\\r'
escapes[ord('\n')] = '\\n'
escapes[ord('\"')] = '\\"'
def escape(s):
global escapes
s = list(s)
for i in range(len(s)):
s[i] = escapes[ord(s[i])]
return string.join(s, EMPTYSTRING)
def safe_eval(s):
# unwrap quotes, safely
return eval(s, {'__builtins__':{}}, {})
def normalize(s):
# This converts the various Python string types into a format that is
# appropriate for .po files, namely much closer to C style.
lines = string.split(s, '\n')
if len(lines) == 1:
s = '"' + escape(s) + '"'
else:
if not lines[-1]:
del lines[-1]
lines[-1] = lines[-1] + '\n'
for i in range(len(lines)):
lines[i] = escape(lines[i])
lineterm = '\\n"\n"'
s = '""\n"' + string.join(lines, lineterm) + '"'
return s
class TokenEater:
def __init__(self, options):
self.__options = options
self.__messages = {}
self.__state = self.__waiting
self.__data = []
self.__lineno = -1
def __call__(self, ttype, tstring, stup, etup, line):
# dispatch
self.__state(ttype, tstring, stup[0])
def __waiting(self, ttype, tstring, lineno):
if ttype == tokenize.NAME and tstring in self.__options.keywords:
self.__state = self.__keywordseen
def __keywordseen(self, ttype, tstring, lineno):
if ttype == tokenize.OP and tstring == '(':
self.__data = []
self.__lineno = lineno
self.__state = self.__openseen
else:
self.__state = self.__waiting
def __openseen(self, ttype, tstring, lineno):
if ttype == tokenize.OP and tstring == ')':
# We've seen the last of the translatable strings. Record the
# line number of the first line of the strings and update the list
# of messages seen. Reset state for the next batch. If there
# were no strings inside _(), then just ignore this entry.
if self.__data:
msg = string.join(self.__data, EMPTYSTRING)
if not msg in self.__options.toexclude:
entry = (self.__curfile, self.__lineno)
linenos = self.__messages.get(msg)
if linenos is None:
self.__messages[msg] = [entry]
else:
linenos.append(entry)
self.__state = self.__waiting
elif ttype == tokenize.STRING:
self.__data.append(safe_eval(tstring))
# TBD: should we warn if we seen anything else?
def set_filename(self, filename):
self.__curfile = filename
def write(self, fp):
options = self.__options
timestamp = time.ctime(time.time())
# common header
try:
sys.stdout = fp
# The time stamp in the header doesn't have the same format
# as that generated by xgettext...
print pot_header % {'time': timestamp, 'version': __version__}
for k, v in self.__messages.items():
if not options.writelocations:
pass
# location comments are different b/w Solaris and GNU:
elif options.locationstyle == options.SOLARIS:
for filename, lineno in v:
d = {'filename': filename, 'lineno': lineno}
print _('# File: %(filename)s, line: %(lineno)d') % d
elif options.locationstyle == options.GNU:
# fit as many locations on one line, as long as the
# resulting line length doesn't exceeds 'options.width'
locline = '#:'
for filename, lineno in v:
d = {'filename': filename, 'lineno': lineno}
s = _(' %(filename)s:%(lineno)d') % d
if len(locline) + len(s) <= options.width:
locline = locline + s
else:
print locline
locline = "#:" + s
if len(locline) > 2:
print locline
# TBD: sorting, normalizing
print 'msgid', normalize(k)
print 'msgstr ""\n'
finally:
sys.stdout = sys.__stdout__
def main():
global default_keywords
try:
opts, args = getopt.getopt(
sys.argv[1:],
'ad:Ehk:Kno:p:S:Vvw:x:',
['extract-all', 'default-domain=', 'escape', 'help',
'keyword=', 'no-default-keywords',
'add-location', 'no-location', 'output=', 'output-dir=',
'style=', 'verbose', 'version', 'width=', 'exclude-file=',
])
except getopt.error, msg:
usage(1, msg)
# for holding option values
class Options:
# constants
GNU = 1
SOLARIS = 2
# defaults
extractall = 0 # FIXME: currently this option has no effect at all.
escape = 0
keywords = []
outpath = ''
outfile = 'messages.pot'
writelocations = 1
locationstyle = GNU
verbose = 0
width = 78
excludefilename = ''
options = Options()
locations = {'gnu' : options.GNU,
'solaris' : options.SOLARIS,
}
# parse options
for opt, arg in opts:
if opt in ('-h', '--help'):
usage(0)
elif opt in ('-a', '--extract-all'):
options.extractall = 1
elif opt in ('-d', '--default-domain'):
options.outfile = arg + '.pot'
elif opt in ('-E', '--escape'):
options.escape = 1
elif opt in ('-k', '--keyword'):
options.keywords.append(arg)
elif opt in ('-K', '--no-default-keywords'):
default_keywords = []
elif opt in ('-n', '--add-location'):
options.writelocations = 1
elif opt in ('--no-location',):
options.writelocations = 0
elif opt in ('-S', '--style'):
options.locationstyle = locations.get(arg.lower())
if options.locationstyle is None:
usage(1, _('Invalid value for --style: %s') % arg)
elif opt in ('-o', '--output'):
options.outfile = arg
elif opt in ('-p', '--output-dir'):
options.outpath = arg
elif opt in ('-v', '--verbose'):
options.verbose = 1
elif opt in ('-V', '--version'):
print _('pygettext.py (xgettext for Python) %s') % __version__
sys.exit(0)
elif opt in ('-w', '--width'):
try:
options.width = int(arg)
except ValueError:
usage(1, _('--width argument must be an integer: %s') % arg)
elif opt in ('-x', '--exclude-file'):
options.excludefilename = arg
# calculate escapes
make_escapes(options.escape)
# calculate all keywords
options.keywords.extend(default_keywords)
# initialize list of strings to exclude
if options.excludefilename:
try:
fp = open(options.excludefilename)
options.toexclude = fp.readlines()
fp.close()
except IOError:
sys.stderr.write(_("Can't read --exclude-file: %s") %
options.excludefilename)
sys.exit(1)
else:
options.toexclude = []
# slurp through all the files
eater = TokenEater(options)
for filename in args:
if filename == '-':
if options.verbose:
print _('Reading standard input')
fp = sys.stdin
closep = 0
else:
if options.verbose:
print _('Working on %s') % filename
fp = open(filename)
closep = 1
try:
eater.set_filename(filename)
tokenize.tokenize(fp.readline, eater)
finally:
if closep:
fp.close()
# write the output
if options.outfile == '-':
fp = sys.stdout
closep = 0
else:
if options.outpath:
options.outfile = os.path.join(options.outpath, options.outfile)
fp = open(options.outfile, 'w')
closep = 1
try:
eater.write(fp)
finally:
if closep:
fp.close()
if __name__ == '__main__':
main()
# some more test strings
#_(u'a unicode string')

415
ssl.c Normal file
View file

@ -0,0 +1,415 @@
/* @(#)ssl.c 1.1 VMS-99/01/30 python wrapper for SSLeay https
*/
#include "Python.h"
#if defined(WITH_THREAD) && !defined(HAVE_GETHOSTBYNAME_R) &&\
!defined(MS_WINDOWS)
#include "thread.h"
#endif
#include <sys/types.h>
#ifndef MS_WINDOWS
#include <sys/socket.h>
#else
#include <winsock.h>
#endif
#if defined(PYOS_OS2)
#define INCL_DOS
#define INCL_DOSERRORS
#define INCL_NOPMAPI
#include <os2.h>
#endif
#include "ssl.h"
#include "err.h"
/*
some hacks to choose between K&R or ANSI style function
definitions. For NT to build this as an extension module (ie, DLL)
it must be compiled by the C++ compiler, as it takes the address of
a static data item exported from the main Python DLL.
*/
#ifdef MS_WINDOWS
#define FORCE_ANSI_FUNC_DEFS
#endif
#if defined(PYOS_OS2)
#define FORCE_ANSI_FUNC_DEFS
#endif
#ifdef FORCE_ANSI_FUNC_DEFS
#define BUILD_FUNC_DEF_1( fnname, arg1type, arg1name ) \
fnname( arg1type arg1name )
#define BUILD_FUNC_DEF_2( fnname, arg1type, arg1name, arg2type, arg2name ) \
fnname( arg1type arg1name, arg2type arg2name )
#else /* !FORCE_ANSI_FN_DEFS */
#define BUILD_FUNC_DEF_1( fnname, arg1type, arg1name ) \
fnname( arg1name ) \
arg1type arg1name;
#define BUILD_FUNC_DEF_2( fnname, arg1type, arg1name, arg2type, arg2name ) \
fnname( arg1name, arg2name ) \
arg1type arg1name; \
arg2type arg2name;
#endif /* !FORCE_ANSI_FN_DEFS */
/* Global variable holding the exception type for errors detected
by this module (but not argument type or memory errors, etc.). */
static PyObject *PySslError;
typedef struct {
PyObject_HEAD
int sock_fd;
PyObject *x_attr; /* attributes dictionary */
SSL_CTX *ctx;
SSL *ssl;
X509 *server_cert;
BIO *sbio;
char server[256];
char issuer[256];
} PySslObject;
staticforward PyTypeObject SSL_Type;
#define PySslObject_Check(v) ((v)->ob_type == &SSL_Type)
/*
* raise an error according to errno, return NULL
*/
static PyObject *
PySsl_errno ()
{
#ifdef MS_WINDOWS
if (WSAGetLastError()) {
PyObject *v = Py_BuildValue("(is)",WSAGetLastError(),"winsock error");
if (v) {
PyErr_SetObject(PySslError,v);
Py_DECREF(v);
}
return NULL;
}
#endif
return PyErr_SetFromErrno(PySslError);
}
/*
* format SSl error string
*/
static int
BUILD_FUNC_DEF_2 (PySsl_err_str, unsigned long, e, char *, buf)
{
unsigned long l = ERR_GET_LIB(e);
unsigned long f = ERR_GET_FUNC(e);
unsigned long r = ERR_GET_REASON(e);
char* ls = (char*)ERR_lib_error_string(e);
char* fs = (char*)ERR_func_error_string(e);
char* rs = (char*)ERR_reason_error_string(e);
char* bp = buf + 2; /* skip two initial blanks */
(void)strcpy(buf," none:"); /* initialize buffer */
bp += (ls) ? sprintf(bp,"%s:",ls) :
((l) ? sprintf(bp,"lib %lu:",l) : 0);
bp += (fs) ? sprintf(bp,"%s ",fs) :
((f) ? sprintf(bp,"func %lu:",f) : 0);
bp += (rs) ? sprintf(bp,"%s:",rs) :
((r) ? sprintf(bp,"reason(%lu):",r) : 0);
*bp-- = 0; /* suppress last divider (:) */
return (bp - buf);
}
/*
* report SSL core errors
*/
static PySslObject *
PySsl_errors ()
{
#define PY_SSL_ERR_MAX 256
unsigned long e;
char buf[2 * PY_SSL_ERR_MAX];
char *bf = buf;
while (((bf - buf) < PY_SSL_ERR_MAX) && (e = ERR_get_error()))
bf += PySsl_err_str(e,bf);
{
PyObject *v = Py_BuildValue("(sss)", "ssl","core",buf+2);
if (v != NULL) {
PyErr_SetObject(PySslError,v);
Py_DECREF(v);
}
}
return (NULL);
}
/*
* report SSL application layer errors
*/
static PySslObject *
BUILD_FUNC_DEF_2 (PySsl_app_errors, SSL *, s, int, ret)
{
int err = SSL_get_error(s,ret);
char *str;
switch (err) {
case SSL_ERROR_SSL:
return (PySsl_errors());
case SSL_ERROR_SYSCALL:
return ((PySslObject *)PySsl_errno());
case SSL_ERROR_ZERO_RETURN:
str = "End of data";
break;
case SSL_ERROR_WANT_READ:
str = "Want read";
break;
case SSL_ERROR_WANT_WRITE:
str = "Want write";
break;
case SSL_ERROR_WANT_X509_LOOKUP:
str = "Want x509 lookup";
break;
case SSL_ERROR_WANT_CONNECT:
str = "Want connect";
break;
default:
str = "Unknown";
break;
}
{
PyObject *v = Py_BuildValue("(sis)", "ssl",err, str);
if (v != NULL) {
PyErr_SetObject(PySslError,v);
Py_DECREF(v);
}
}
return (NULL);
}
/* ssl.read(len) method */
static PyObject *
BUILD_FUNC_DEF_2 (PySslObj_read, PySslObject *, self, PyObject *, args)
{
int len, n;
PyObject *buf;
if (!PyArg_ParseTuple(args,"i",&len))
return (NULL);
if (!(buf = PyString_FromStringAndSize((char *)0,len)))
return (NULL);
Py_BEGIN_ALLOW_THREADS
n = SSL_read(self->ssl,PyString_AsString(buf),len);
Py_END_ALLOW_THREADS
switch (SSL_get_error(self->ssl,n)) {
case SSL_ERROR_NONE: /* good return value */
break;
case SSL_ERROR_ZERO_RETURN:
case SSL_ERROR_SYSCALL:
if (!n) /* fix SSL_ERROR_SYCSALL errno=0 case */
break;
/* fall thru here */
default:
Py_DECREF(buf);
(void)PySsl_app_errors(self->ssl,n);
return (NULL);
}
if ((n != len) && (_PyString_Resize(&buf,n) < 0))
return (NULL);
return (buf);
}
/* ssl.write(data,len) method */
static PyObject *
BUILD_FUNC_DEF_2 (PySslObj_write, PySslObject *, self, PyObject *, args)
{
char *buf;
int len, n;
if (!PyArg_ParseTuple(args, "si", &buf, &len))
return NULL;
/* Note: flags are ignored */
Py_BEGIN_ALLOW_THREADS
n = SSL_write(self->ssl,buf,len);
Py_END_ALLOW_THREADS
if (n < 0)
return (PySsl_errno());
return (PyInt_FromLong((long)n));
}
/* ssl.server() method */
static PyObject *
BUILD_FUNC_DEF_2 (PySslObj_server, PySslObject *, self, PyObject *, args)
{
if (!PyArg_NoArgs(args))
return (NULL);
return (PyString_FromString(self->server));
}
/* ssl.issuer() method */
static PyObject *
BUILD_FUNC_DEF_2 (PySslObj_issuer, PySslObject *, self, PyObject *, args)
{
if (!PyArg_NoArgs(args))
return (NULL);
return (PyString_FromString(self->issuer));
}
/* SSL object methods */
static PyMethodDef PySslObj_methods[] = {
{"read", (PyCFunction)PySslObj_read,1},
{"write", (PyCFunction)PySslObj_write,1},
{"server", (PyCFunction)PySslObj_server},
{"issuer", (PyCFunction)PySslObj_issuer},
{ NULL, NULL}
};
static void
BUILD_FUNC_DEF_1 (PySsl_dealloc, PySslObject *, self)
{
if (self->server_cert) /* possible not to have one? */
X509_free(self->server_cert);
SSL_CTX_free(self->ctx);
SSL_free(self->ssl);
Py_XDECREF(self->x_attr);
PyMem_DEL(self);
}
static PyObject *
BUILD_FUNC_DEF_2 (PySsl_getattr, PySslObject *, self, char *, name)
{
return (Py_FindMethod(PySslObj_methods,(PyObject *)self,name));
}
staticforward PyTypeObject SSL_Type = {
PyObject_HEAD_INIT(&PyType_Type)
0, /*ob_size*/
"SSL", /*tp_name*/
sizeof(PySslObject), /*tp_basicsize*/
0, /*tp_itemsize*/
/* methods */
(destructor)PySsl_dealloc, /*tp_dealloc*/
0, /*tp_print*/
(getattrfunc)PySsl_getattr, /*tp_getattr*/
0, /*tp_setattr*/
0, /*tp_compare*/
0, /*tp_repr*/
0, /*tp_as_number*/
0, /*tp_as_sequence*/
0, /*tp_as_mapping*/
0, /*tp_hash*/
};
/*
* C function called for new object initialization
* Note: SSL protocol version 2, 3, or 2+3 set at compile time
*/
static PySslObject *
BUILD_FUNC_DEF_1 (newPySslObject, int, sock_fd)
{
PySslObject *self;
SSL_METHOD *meth;
int ret;
#if 0
meth=SSLv3_client_method();
meth=SSLv23_client_method();
#endif
meth=SSLv2_client_method();
if (!(self = PyObject_NEW(PySslObject,&SSL_Type))) /* create new object */
return (NULL);
(void)memset(self->server,0,sizeof(self->server));
(void)memset(self->issuer,0,sizeof(self->issuer));
self->x_attr = PyDict_New();
if (!(self->ctx = SSL_CTX_new(meth))) { /* set up context */
PyMem_DEL(self);
return (PySsl_errors());
}
#if 0 /* Note: set this for v23, Netscape server */
SSL_CTX_set_options(self->ctx,SSL_OP_ALL);
#endif
self->ssl = SSL_new(self->ctx); /* new ssl struct */
if (!(ret = SSL_set_fd(self->ssl,sock_fd))) { /* set the socket for SSL */
PyMem_DEL(self);
return (PySsl_app_errors(self->ssl,ret));
}
SSL_CTX_set_verify(self->ctx,SSL_VERIFY_NONE,NULL); /* set verify lvl */
SSL_set_connect_state(self->ssl);
if ((ret = SSL_connect(self->ssl)) < 0) { /* negotiate SSL connection */
PyMem_DEL(self);
return (PySsl_app_errors(self->ssl,ret));
}
self->ssl->debug = 1;
if ((self->server_cert = SSL_get_peer_certificate(self->ssl))) {
X509_NAME_oneline(X509_get_subject_name(self->server_cert),
self->server,sizeof(self->server));
X509_NAME_oneline(X509_get_issuer_name(self->server_cert),
self->issuer, sizeof(self->issuer));
}
self->x_attr = NULL;
self->sock_fd = sock_fd;
return (self);
}
/*
* Python function called for new object initialization
*/
static PyObject *
BUILD_FUNC_DEF_2 (PySsl_ssl_new, PyObject *, self, PyObject *, args)
{
int sock_fd;
if (!PyArg_ParseTuple(args, "i", &sock_fd))
return (NULL);
return ((PyObject *)newPySslObject(sock_fd));
}
/* List of functions exported by this module. */
static PyMethodDef PySsl_methods[] = {
{"ssl", (PyCFunction)PySsl_ssl_new, 1},
{NULL, NULL} /* sentinel */
};
/*
* Initialize this module, called when the first 'import ssl' is done
*/
void
initssl ()
{
PyObject *m, *d;
m = Py_InitModule("ssl", PySsl_methods);
d = PyModule_GetDict(m);
SSL_load_error_strings();
SSLeay_add_ssl_algorithms();
/* *** Python 1.5 ***
if (!(PySssl_Error = PyErr_NewException("ssl.error",NULL,NULL)))
return;
*/
if (!(PySslError = PyString_FromString("ssl.error")) ||
PyDict_SetItemString(d,"error",PySslError))
Py_FatalError("can't define ssl.error");
if (PyDict_SetItemString(d,"SSLType",(PyObject *)&SSL_Type))
return;
}