diff --git a/DNS/Base.py b/DNS/Base.py index 8b9d4efb..d9c03508 100644 --- a/DNS/Base.py +++ b/DNS/Base.py @@ -126,7 +126,6 @@ class DnsRequest: self.args=args def socketInit(self,a,b): - import socket self.s = socket.socket(a,b) def processUDPReply(self): diff --git a/DNS/Lib.py b/DNS/Lib.py index 4a0abd62..2b6361b5 100644 --- a/DNS/Lib.py +++ b/DNS/Lib.py @@ -11,8 +11,6 @@ # ------------------------------------------------------------------------ -import string - import DNS.Type import DNS.Class import DNS.Opcode @@ -38,10 +36,10 @@ def unpack32bit(s): def addr2bin(addr): if type(addr) == type(0): return addr - bytes = string.splitfields(addr, '.') + bytes = addr.split('.') if len(bytes) != 4: raise ValueError, 'bad IP address' n = 0 - for byte in bytes: n = n<<8 | string.atoi(byte) + for byte in bytes: n = n<<8 | int(byte) return n def bin2addr(n): @@ -77,21 +75,21 @@ class Packer: # Add a domain name to the buffer, possibly using pointers. # The case of the first occurrence of a name is preserved. # Redundant dots are ignored. - list = [] - for label in string.splitfields(name, '.'): + lst = [] + for label in name.split('.'): if label: if len(label) > 63: raise PackError, 'label too long' - list.append(label) + lst.append(label) keys = [] - for i in range(len(list)): - key = string.joinfields(list[i:], '.').upper() + for i in range(len(lst)): + key = '.'.join(lst[i:]).upper() keys.append(key) if self.index.has_key(key): pointer = self.index[key] break else: - i = len(list) + i = len(lst) pointer = None # Do it into temporaries first so exceptions don't # mess up self.index and self.buf @@ -99,18 +97,18 @@ class Packer: offset = len(self.buf) index = [] for j in range(i): - label = list[j] + label = lst[j] n = len(label) if offset + len(buf) < 0x3FFF: index.append((keys[j], offset + len(buf))) else: print 'DNS.Lib.Packer.addname:', print 'warning: pointer too big' - buf = buf + (chr(n) + label) + buf += chr(n) + label if pointer: - buf = buf + pack16bit(pointer | 0xC000) + buf += pack16bit(pointer | 0xC000) else: - buf = buf + '\0' + buf += '\0' self.buf = self.buf + buf for key, value in index: self.index[key] = value @@ -494,7 +492,7 @@ class DnsResult: h['opcode'],h['status'],h['id']) flags=filter(lambda x,h=h:h[x],('qr','aa','rd','ra','tc')) print ';; flags: %s; Ques: %d, Ans: %d, Auth: %d, Addit: %d'%( - string.join(flags),h['qdcount'],h['ancount'],h['nscount'], + ' '.join(flags),h['qdcount'],h['ancount'],h['nscount'], h['arcount']) print ';; QUESTIONS:' for q in self.questions: diff --git a/DNS/asyncore.py b/DNS/asyncore.py deleted file mode 100644 index 24fbf622..00000000 --- a/DNS/asyncore.py +++ /dev/null @@ -1,265 +0,0 @@ -# $Id$ -# Author: Sam Rushing - -# A simple unix version of the asynchronous socket support. -# There are lots of problems with this still - I only wrote it to show -# that it could be done, and for my own testing purposes. -# [960206: servtest, asynfing, asynhttp, and pop3demo work, asyndns doesn't.] -# [960321: servtest, asynfing, asynhttp, pop3demo, pop3_2 work] -import select -import socket -import sys - -# you need to generate ERRNO.py from Tools/scripts/h2py.py in the Python -# distribution. - -try: - import ERRNO -except ImportError: - raise ImportError,'you need to generate ERRNO.py from Tools/scripts/h2py.py in the Python distribution' - -# look what I can get away with... 8^) -socket.socket_map = {} - -ALL_EVENTS = [] - -DEFAULT_TIMEOUT = 30.0 - -loop_running = 0 - -stop_loop_exception = "stop running the select loop" - -# we want to select for read only those sockets -# to which we are already connected to, -OR- those -# sockets we are accepting on. -def readables (sock_fds): - sm = socket.socket_map - def readable_test (fd, sm=sm): - sock = sm[fd] - return sock.connected or sock.accepting - return filter (readable_test, sock_fds) - -# only those fd's we are 'write blocked' on, -OR- -# those sockets we are waiting for a connection on. -def writables (sock_fds): - sm = socket.socket_map - def writable_test (fd, sm=sm): - sock = sm[fd] - return sock.write_blocked or not sock.connected - return filter (writable_test, sock_fds) - -def loop(timeout=DEFAULT_TIMEOUT): - loop_running = 1 - try: - while 1: - sock_fds = socket.socket_map.keys() - - read_fds = readables (sock_fds) - write_fds = writables (sock_fds) - expt_fds = sock_fds[:] - - (read_fds, - write_fds, - expt_fds) = select.select (read_fds, - write_fds, - expt_fds, - timeout) - print read_fds,write_fds,expt_fds - try: - for x in expt_fds: - socket.socket_map[x].handle_expt_event() - for x in read_fds: - socket.socket_map[x].handle_read_event() - for x in write_fds: - socket.socket_map[x].handle_write_event() - except KeyError: - # handle_expt handle_read might remove as socket - # from the map by calling self.close(). - pass - except stop_loop_exception: - print 'loop stopped' - -class dispatcher: - def __init__ (self, sock=None): - self.debug = 0 - self.log_queue = [] - self.connected = 0 - self.accepting = 0 - self.write_blocked = 1 - if sock: - self.socket = sock - self.fileno = self.socket.fileno() - # I think it should inherit this anyway - self.socket.setblocking (0) - self.connected = 1 - self.add_channel() - - def add_channel (self, events=ALL_EVENTS): - self.log ('adding channel %s' % self) - socket.socket_map [self.fileno] = self - - def del_channel (self): - if socket.socket_map.has_key (self.fileno): - del socket.socket_map [self.fileno] - if not len(socket.socket_map.keys()): - raise stop_loop_exception - - def create_socket (self, family, type): - self.socket = socket.socket (family, type) - self.socket.setblocking(0) - self.fileno = self.socket.fileno() - self.add_channel() - - def bind (self, *args): - return apply (self.socket.bind, args) - - def go (self): - if not loop_running: - loop() - - def listen (self, num): - self.accepting = 1 - self.socket.listen (num) - - def accept (self): - return self.socket.accept() - - def connect (self, host, port): - try: - self.socket.connect (host, port) - except socket.error, why: - if type(why) == type(()) \ - and why[0] in (ERRNO.EINPROGRESS, ERRNO.EALREADY, ERRNO.EWOULDBLOCK): - return - else: - raise socket.error, why - self.connected = 1 - self.handle_connect() - - def send (self, data): - try: - result = self.socket.send (data) - if result != len(data): - self.write_blocked = 1 - else: - self.write_blocked = 0 - return result - except socket.error, why: - if type(why) == type(()) and why[0] == ERRNO.EWOULDBLOCK: - self.write_blocked = 1 - return 0 - else: - raise socket.error, why - return 0 - - def recv (self, buffer_size): - data = self.socket.recv (buffer_size) - if not data: - self.handle_close() - return '' - else: - return data - - def close (self): - self.socket.close() - self.del_channel() - - def shutdown (self, how): - self.socket.shutdown (how) - - def log (self, message): - #self.log_queue.append ('%s:%d %s' % - # (self.__class__.__name__, self.fileno, message)) - print 'log:', message - - def done (self): - self.print_log() - - def print_log (self): - for x in self.log_queue: - print x - - def handle_read_event (self): - # getting a read implies that we are connected - if not self.connected: - self.handle_connect() - self.connected = 1 - self.handle_read() - elif self.accepting: - if not self.connected: - self.connected = 1 - self.handle_accept() - else: - self.handle_read() - - def more_to_send (self, yesno=1): - self.write_blocked = yesno - - def handle_write_event (self): - # getting a read implies that we are connected - if not self.connected: - self.handle_connect() - self.connected = 1 - self.write_blocked = 0 - self.handle_write() - - def handle_expt_event (self): - self.handle_error() - - def handle_error (self, error=0): - self.close() - - def handle_read (self): - self.log ('unhandled FD_READ') - - def handle_write (self): - self.log ('unhandled FD_WRITE') - - def handle_connect (self): - self.log ('unhandled FD_CONNECT') - - def handle_oob (self): - self.log ('unhandled FD_OOB') - - def handle_accept (self): - self.log ('unhandled FD_ACCEPT') - - def handle_close (self): - self.log ('unhandled FD_CLOSE') - - def handle_disconnect (self, error): - self.log ('unexpected disconnect, error:%d' % error) - -# --------------------------------------------------------------------------- -# adds async send capability, useful for simple clients. -# --------------------------------------------------------------------------- - -class dispatcher_with_send (dispatcher): - def __init__ (self, sock=None): - dispatcher.__init__ (self, sock) - self.out_buffer = '' - - def initiate_send (self): - while self.out_buffer: - num_sent = 0 - num_sent = dispatcher.send (self, self.out_buffer[:512]) - self.out_buffer = self.out_buffer[num_sent:] - - def handle_write (self): - self.initiate_send() - - def send (self, data): - if self.debug: - self.log ('sending %s' % repr(data)) - self.out_buffer = data - self.initiate_send() - -# --------------------------------------------------------------------------- -# used a lot when debugging -# --------------------------------------------------------------------------- - -def close_all (): - for x in socket.socket_map.items(): - x[1].socket.close() - socket.socket_map = {} - diff --git a/DNS/lazy.py b/DNS/lazy.py index c807e279..664290e2 100644 --- a/DNS/lazy.py +++ b/DNS/lazy.py @@ -10,12 +10,12 @@ def revlookup(name): # this will only return one of any records returned. return Base.DnsRequest(b, qtype = 'ptr').req().answers[0]['data'] -def mxlookup(name): +def mxlookup(name, protocol="udp"): """ convenience routine for doing an MX lookup of a name. returns a sorted list of (preference, mail exchanger) records """ - a = Base.DnsRequest(name, qtype = 'mx').req().answers + a = Base.DnsRequest(name, qtype='mx', protocol=protocol).req().answers l = map(lambda x:x['data'], a) l.sort() return l diff --git a/Makefile b/Makefile index abc3eff1..e13e8812 100644 --- a/Makefile +++ b/Makefile @@ -79,3 +79,7 @@ onlinetest: .PHONY: locale locale: $(MAKE) -C po + +.PHONY: timeouttest +timeouttest: + ./$(PACKAGE) -DDD --timeout=2 mailto:calvin@cs.uni-sb.de diff --git a/debian/changelog b/debian/changelog index eec5b319..b3224e71 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,12 +1,19 @@ linkchecker (1.3.6) unstable; urgency=low * fix typo in Copyright blurb - * implement Proxy Authentication - * Opera Bookmark files (opera.adr) support - * support for socket timeouts + * implemented Proxy Authentication (untested) + * Opera Bookmark files (opera.adr) support, they get parsed + automatically like HTML files + * support for TCP socket timeouts with --timeout (untested) * replace string module functions with Python 2.x string methods + * use TCP for DNS MX mailhost lookup as default, not UDP as it seems + to hang forever (dont know why). This should fix bug #106393, but + only time will tell. + * updated DNS.init_dns_config with Windows-specific functions from + pydns.sf.net (only tested under Win2000 with DNS server settings + over DHCP) - -- Bastian Kleineidam Wed, 22 Aug 2001 15:52:18 +0200 + -- Bastian Kleineidam Wed, 22 Aug 2001 19:34:13 +0200 linkchecker (1.3.5) unstable; urgency=low diff --git a/linkcheck/FileUrlData.py b/linkcheck/FileUrlData.py index a6a54f15..2a85893d 100644 --- a/linkcheck/FileUrlData.py +++ b/linkcheck/FileUrlData.py @@ -66,7 +66,7 @@ class FileUrlData(UrlData): def isHtml(self): if html_re.search(self.url) or opera_re.search(self.url): return 1 - # try to read content (attention: could be a directory) + # try to read content (can fail, so catch error) try: return html_content_re.search(self.getContent()) or \ opera_content_re.search(self.getContent()) diff --git a/linkcheck/MailtoUrlData.py b/linkcheck/MailtoUrlData.py index 19cc5b94..6fcd9b3c 100644 --- a/linkcheck/MailtoUrlData.py +++ b/linkcheck/MailtoUrlData.py @@ -15,7 +15,7 @@ # along with this program; if not, write to the Free Software # Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -import os,re,string,DNS,sys,Config,cgi,urllib,linkcheck +import os, re, DNS, sys, Config, cgi, urllib, linkcheck from rfc822 import AddressList from HostCheckingUrlData import HostCheckingUrlData from smtplib import SMTP @@ -33,7 +33,7 @@ DNS.init_dns_resolver() class MailtoUrlData(HostCheckingUrlData): "Url link with mailto scheme" - + def buildUrl(self): HostCheckingUrlData.buildUrl(self) self.headers = {} @@ -53,6 +53,7 @@ class MailtoUrlData(HostCheckingUrlData): return self.urlName[7:mo.start()] return self.urlName[7:] + def checkConnection(self, config): """Verify a list of email adresses. If one adress fails, the whole list will fail. @@ -72,8 +73,11 @@ class MailtoUrlData(HostCheckingUrlData): value = "unknown reason" for name,mail in self.adresses: Config.debug(BRING_IT_ON, "checking mail address", mail) + Config.debug(HURT_ME_PLENTY, "splitting address") user,host = self._split_adress(mail) - mxrecords = DNS.mxlookup(host) + Config.debug(HURT_ME_PLENTY, "looking up MX mailhost") + mxrecords = DNS.mxlookup(host, protocol="tcp") + Config.debug(HURT_ME_PLENTY, "found mailhosts", mxrecords) if not len(mxrecords): self.setError(_("No mail host for %s found")%host) return @@ -82,9 +86,11 @@ class MailtoUrlData(HostCheckingUrlData): try: Config.debug(BRING_IT_ON, "SMTP check for", mxrecord) self.urlConnection = SMTP(mxrecord[1]) + Config.debug(HURT_ME_PLENTY, "SMTP connected!") smtpconnect = 1 self.urlConnection.helo() info = self.urlConnection.verify(user) + Config.debug(HURT_ME_PLENTY, "SMTP user info", info) if info[0]==250: self.setInfo(_("Verified adress: %s")%str(info[1])) except: @@ -102,7 +108,7 @@ class MailtoUrlData(HostCheckingUrlData): def _split_adress(self, adress): - split = string.split(adress, "@", 1) + split = adress.split("@", 1) if len(split)==2: if not split[1]: return (split[0], "localhost") diff --git a/linkchecker b/linkchecker index 558b9dad..8da45371 100755 --- a/linkchecker +++ b/linkchecker @@ -21,10 +21,10 @@ import sys if sys.version[:5] < "2.0": raise SystemExit, "This program requires Python 2.0 or later." +from linkcheck import timeoutsocket import getopt, re, os, urlparse, linkcheck from linkcheck import _,StringUtil,timeoutsocket - Usage = _("""USAGE\tlinkchecker [options] file-or-url... OPTIONS