diff -Nru twisted-words-10.0.0/debian/changelog twisted-words-12.1.0/debian/changelog --- twisted-words-10.0.0/debian/changelog 2012-06-29 14:37:51.000000000 +0000 +++ twisted-words-12.1.0/debian/changelog 2012-06-29 14:00:19.000000000 +0000 @@ -1,3 +1,17 @@ +twisted-words (12.1.0-1~ppa1~lucid1) lucid; urgency=low + + * New upstream version. + * Rebuild package for use in PPA. + + -- Jessica McKellar Fri, 29 Jun 2012 10:00:02 -0400 + +twisted-words (12.0.0-1~ppa1~lucid1) lucid; urgency=low + + * New upstream version. + * Rebuild package for use in PPA. + + -- Jessica McKellar Sat, 18 Feb 2012 20:51:19 -0500 + twisted-words (10.0.0-2) unstable; urgency=low * Bump dependency on python-twisted-core from 9.0 to 10 diff -Nru twisted-words-10.0.0/debian/compat twisted-words-12.1.0/debian/compat --- twisted-words-10.0.0/debian/compat 2012-06-29 14:37:51.000000000 +0000 +++ twisted-words-12.1.0/debian/compat 2012-06-29 13:59:44.000000000 +0000 @@ -1 +1 @@ -5 +7 diff -Nru twisted-words-10.0.0/debian/control twisted-words-12.1.0/debian/control --- twisted-words-10.0.0/debian/control 2012-06-29 14:37:51.000000000 +0000 +++ twisted-words-12.1.0/debian/control 2012-06-29 13:59:59.000000000 +0000 @@ -3,16 +3,15 @@ Priority: optional Maintainer: Matthias Klose Uploaders: Free Ekanayaka -Build-Depends: debhelper (>= 5.0.37.1), python-central (>= 0.6.7), python-all, python-twisted-core (>= 10.0), patch +Build-Depends: debhelper (>=7.0.50~), python-central (>= 0.6.7), python-all, python-twisted-core (>= 12.1), patch XS-Python-Version: all -Standards-Version: 3.8.4 +Standards-Version: 3.9.2 Package: python-twisted-words Architecture: all -Depends: ${python:Depends}, python-twisted-core (>= 10.0), python-openssl, ${misc:Depends} +Depends: ${python:Depends}, python-twisted-core (>= 12.1), python-openssl, ${misc:Depends} Conflicts: python-twisted (<< 2.1), python2.3-twisted-words, python2.4-twisted-words Replaces: python-twisted (<< 2.1), python2.3-twisted-words, python2.4-twisted-words -XB-Python-Version: ${python:Versions} Description: Chat and Instant Messaging Twisted Words includes: - Low-level protocol implementations of OSCAR (AIM and ICQ), IRC, MSN, diff -Nru twisted-words-10.0.0/debian/python-twisted-words.menu twisted-words-12.1.0/debian/python-twisted-words.menu --- twisted-words-10.0.0/debian/python-twisted-words.menu 1970-01-01 00:00:00.000000000 +0000 +++ twisted-words-12.1.0/debian/python-twisted-words.menu 2012-06-29 13:59:44.000000000 +0000 @@ -0,0 +1,5 @@ +?package(python-twisted-words):\ + needs="x11"\ + section="Apps/Net"\ + title="Twisted Instance Messenger"\ + command="/usr/bin/im" diff -Nru twisted-words-10.0.0/debian/rules twisted-words-12.1.0/debian/rules --- twisted-words-10.0.0/debian/rules 2012-06-29 14:37:51.000000000 +0000 +++ twisted-words-12.1.0/debian/rules 2012-06-29 13:59:44.000000000 +0000 @@ -7,6 +7,8 @@ VER := $(shell /usr/bin/python -c 'import sys; print sys.version[:3]') build: build-stamp +build-arch: build-stamp +build-indep: build-stamp build-stamp: $(PYVERS:%=build-python%) touch $@ build-python%: @@ -25,7 +27,7 @@ install-prereq: build-stamp dh_testdir dh_testroot - dh_clean -k + dh_prep install-python%: install-prereq : # python-twisted-words diff -Nru twisted-words-10.0.0/debian/source/format twisted-words-12.1.0/debian/source/format --- twisted-words-10.0.0/debian/source/format 1970-01-01 00:00:00.000000000 +0000 +++ twisted-words-12.1.0/debian/source/format 2012-06-29 14:37:51.000000000 +0000 @@ -0,0 +1 @@ +3.0 (quilt) diff -Nru twisted-words-10.0.0/doc/examples/aimbot.py twisted-words-12.1.0/doc/examples/aimbot.py --- twisted-words-10.0.0/doc/examples/aimbot.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/doc/examples/aimbot.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,62 +0,0 @@ -#!/usr/bin/env python - -# Copyright (c) 2009 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -AIM echo bot. -""" - -from twisted.words.protocols import toc -from twisted.internet import reactor, protocol -import twisted.words.im.tocsupport as ts - -# account info -screenname = 'username' -password = 'password' - -class aimBot(toc.TOCClient): - """AOL Instant Messenger echo bot""" - - def gotConfig(self, mode, buddylist, permit, deny): - """called when the server sends us config info""" - global screename - - # add someone to our deny list? - self.add_deny([]) - - # add ourself to our buddy list - self.add_buddy([screenname]) - - # finish up the signon procedure - self.signon() - - def updateBuddy(self,username,online,evilness,signontime,idletime,userclass,away): - """called when a buddy changes state""" - print "status changed for",username - - def hearWarning(self, warnlvl, screenname): - """called when someone warns us""" - print screenname,"warned us" - - def hearError(self, errcode, *args): - """called when server sends error""" - print "recieved error:",errcode - - def hearMessage(self, username, message, autoreply): - """called when a message is recieved""" - - # remove the incoming message' html - msg = ts.dehtml(message) - - print "got message:",msg - - # construct the reply, and turn it into html - reply = ts.html("echo: %s" % msg) - - self.say(username, reply) - -cc = protocol.ClientCreator(reactor, aimBot, screenname, password) -cc.connectTCP("toc.oscar.aol.com", 9898) - -reactor.run() diff -Nru twisted-words-10.0.0/doc/examples/cursesclient.py twisted-words-12.1.0/doc/examples/cursesclient.py --- twisted-words-10.0.0/doc/examples/cursesclient.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/doc/examples/cursesclient.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,6 +1,6 @@ #!/usr/bin/env python -# Copyright (c) 2009 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ diff -Nru twisted-words-10.0.0/doc/examples/index.html twisted-words-12.1.0/doc/examples/index.html --- twisted-words-10.0.0/doc/examples/index.html 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/doc/examples/index.html 2012-06-04 08:46:26.000000000 +0000 @@ -13,7 +13,6 @@
  • ircLogBot.py - connects to an IRC server and logs all messages
  • minchat.py - log bot using twisted.im
  • -
  • aimbot.py - (AOL Instant Messaging)
  • msn_example.py
  • oscardemo.py
  • jabber_client.py
  • @@ -25,6 +24,6 @@

    Index

    - Version: 10.0.0 + Version: 12.1.0 \ No newline at end of file diff -Nru twisted-words-10.0.0/doc/examples/ircLogBot.py twisted-words-12.1.0/doc/examples/ircLogBot.py --- twisted-words-10.0.0/doc/examples/ircLogBot.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/doc/examples/ircLogBot.py 2011-10-05 01:11:53.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2009 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. @@ -126,13 +126,15 @@ A new protocol instance will be created each time we connect to the server. """ - # the class of the protocol to build when new connection is made - protocol = LogBot - def __init__(self, channel, filename): self.channel = channel self.filename = filename + def buildProtocol(self, addr): + p = LogBot() + p.factory = self + return p + def clientConnectionLost(self, connector, reason): """If we get disconnected, reconnect to server.""" connector.connect() diff -Nru twisted-words-10.0.0/doc/examples/jabber_client.py twisted-words-12.1.0/doc/examples/jabber_client.py --- twisted-words-10.0.0/doc/examples/jabber_client.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/doc/examples/jabber_client.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2009 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. # Originally written by Darryl Vandorp diff -Nru twisted-words-10.0.0/doc/examples/minchat.py twisted-words-12.1.0/doc/examples/minchat.py --- twisted-words-10.0.0/doc/examples/minchat.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/doc/examples/minchat.py 2012-04-02 18:54:43.000000000 +0000 @@ -1,18 +1,22 @@ #!/usr/bin/env python -# Copyright (c) 2001-2009 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ -A very simple twisted.im-based logbot. +A very simple twisted.words.im-based logbot. + +To run the script: +$ python minchat.py """ -from twisted.im import basechat, baseaccount +from twisted.words.im import basechat, baseaccount, ircsupport + # A list of account objects. We might as well create them at runtime, this is # supposed to be a Minimalist Implementation, after all. -from twisted.im import ircsupport + accounts = [ ircsupport.IRCAccount("IRC", 1, "Tooty", # nickname @@ -25,7 +29,8 @@ class AccountManager (baseaccount.AccountManager): - """This class is a minimal implementation of the Acccount Manager. + """ + This class is a minimal implementation of the Acccount Manager. Most implementations will show some screen that lets the user add and remove accounts, but we're not quite that sophisticated. @@ -42,17 +47,20 @@ class MinConversation(basechat.Conversation): - """This class is a minimal implementation of the abstract Conversation class. + """ + This class is a minimal implementation of the abstract Conversation class. This is all you need to override to receive one-on-one messages. """ def show(self): - """If you don't have a GUI, this is a no-op. + """ + If you don't have a GUI, this is a no-op. """ pass def hide(self): - """If you don't have a GUI, this is a no-op. + """ + If you don't have a GUI, this is a no-op. """ pass @@ -65,17 +73,20 @@ class MinGroupConversation(basechat.GroupConversation): - """This class is a minimal implementation of the abstract GroupConversation class. + """ + This class is a minimal implementation of the abstract GroupConversation class. This is all you need to override to listen in on a group conversaion. """ def show(self): - """If you don't have a GUI, this is a no-op. + """ + If you don't have a GUI, this is a no-op. """ pass def hide(self): - """If you don't have a GUI, this is a no-op. + """ + If you don't have a GUI, this is a no-op. """ pass @@ -98,9 +109,11 @@ def memberLeft(self, member): basechat.GroupConversation.memberLeft(self, member) print "-!- %s left %s" % (member, self.group.name) - + + class MinChat(basechat.ChatUI): - """This class is a minimal implementation of the abstract ChatUI class. + """ + This class is a minimal implementation of the abstract ChatUI class. There are only two methods that need overriding - and of those two, the only change that needs to be made is the default value of the Class @@ -118,6 +131,7 @@ return basechat.ChatUI.getConversation(self, person, Class, stayHidden) + if __name__ == "__main__": from twisted.internet import reactor diff -Nru twisted-words-10.0.0/doc/examples/msn_example.py twisted-words-12.1.0/doc/examples/msn_example.py --- twisted-words-10.0.0/doc/examples/msn_example.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/doc/examples/msn_example.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,6 +1,6 @@ #!/usr/bin/env python -# Copyright (c) 2001-2009 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. # Twisted Imports diff -Nru twisted-words-10.0.0/doc/examples/oscardemo.py twisted-words-12.1.0/doc/examples/oscardemo.py --- twisted-words-10.0.0/doc/examples/oscardemo.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/doc/examples/oscardemo.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,6 +1,6 @@ #!/usr/bin/env python -# Copyright (c) 2009 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. from twisted.words.protocols import oscar diff -Nru twisted-words-10.0.0/doc/examples/pb_client.py twisted-words-12.1.0/doc/examples/pb_client.py --- twisted-words-10.0.0/doc/examples/pb_client.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/doc/examples/pb_client.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,6 +1,6 @@ #!/usr/bin/env python -# Copyright (c) 2009 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ diff -Nru twisted-words-10.0.0/doc/examples/xmpp_client.py twisted-words-12.1.0/doc/examples/xmpp_client.py --- twisted-words-10.0.0/doc/examples/xmpp_client.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/doc/examples/xmpp_client.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2009 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. import sys diff -Nru twisted-words-10.0.0/doc/howto/im.html twisted-words-12.1.0/doc/howto/im.html --- twisted-words-10.0.0/doc/howto/im.html 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/doc/howto/im.html 2012-06-04 08:46:26.000000000 +0000 @@ -10,13 +10,6 @@
    -
    Note: Twisted IM and Twisted Words are both known to be in a state -of flux at the moment. Several of the APIs discussed here have fallen short of -their original goals and will be changing within the next few releases -of Twisted. The good news is that newer versions will be based on our -experiences with the current ones and will provide much more access to features -beyond plain-text chat message relaying in different protocols.
    -

    Twisted IM (Instance Messenger) is a multi-protocol chat framework, based on the Twisted framework we've all come to know and love. It's fairly simple and extensible in two directions - @@ -24,21 +17,9 @@ to add new front-ends.

    Code flow

    -

    Twisted IM is usually started from the file - twisted/scripts/im.py (maybe with a shell-script - wrapper or similar). Twisted currently comes with two - interfaces for Twisted IM - one written in GTK for Python - under Linux, and one written in Swing for Jython. - im.py picks an implementation and starts it - if - you want to write your own interface, you can modify - im.py to start it under appropriate - conditions.

    - -

    Once started, both interfaces behave in a very similar - fashion, so I won't be getting into differences here.

    AccountManager

    -

    Control flow starts at the relevant subclass of baseaccount.AccountManager. +

    The control flow starts at the relevant subclass of baseaccount.AccountManager. The AccountManager is responsible for, well, managing accounts - remembering what accounts are available, their settings, adding and removal of accounts, and making accounts @@ -46,7 +27,7 @@

    This would be a good place to start your interface, load a list of accounts from disk and tell them to login. Most of the - method names in AccountManager + method names in AccountManager are pretty self-explanatory, and your subclass can override whatever it wants, but you need to override __init__. Something like this:

    @@ -56,15 +37,17 @@ 3 4 5 -

    def __init__(self): - self.chatui = ... # Your subclass of basechat.ChatUI - self.accounts = ... # Load account list - for a in self.accounts: - a.logOn(self.chatui) +6 +

    ... + def __init__(self): + self.chatui = ... # Your subclass of basechat.ChatUI + self.accounts = ... # Load account list + for a in self.accounts: + a.logOn(self.chatui) - +

    ChatUI

    -

    Account objects talk to the user via a subclass of basechat.ChatUI. +

    Account objects talk to the user via a subclass of basechat.ChatUI. This class keeps track of all the various conversations that are currently active, so that when an account receives and incoming message, it can put that message in its correct @@ -82,7 +65,7 @@ routines is that they take a parameter, Class, which defaults to an abstract implementation of that class - for example, getConversation has a - Class parameter that defaults to basechat.Conversation which + Class parameter that defaults to basechat.Conversation which raises a lot of NotImplementedErrors. In your subclass, override the method with a new method whose Class parameter defaults to your own implementation of @@ -103,13 +86,13 @@ NotImplementedError.

    Accounts

    -

    An account is an instance of a subclass of basesupport.AbstractAccount. +

    An account is an instance of a subclass of basesupport.AbstractAccount. For more details and sample code, see the various - *support files in twisted.im.

    + *support files in twisted.words.im.

    Index

    - Version: 10.0.0 + Version: 12.1.0 \ No newline at end of file diff -Nru twisted-words-10.0.0/doc/howto/index.html twisted-words-12.1.0/doc/howto/index.html --- twisted-words-10.0.0/doc/howto/index.html 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/doc/howto/index.html 2012-06-04 08:46:26.000000000 +0000 @@ -17,6 +17,6 @@

    Index

    - Version: 10.0.0 + Version: 12.1.0 \ No newline at end of file diff -Nru twisted-words-10.0.0/doc/index.html twisted-words-12.1.0/doc/index.html --- twisted-words-10.0.0/doc/index.html 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/doc/index.html 2012-06-04 08:46:26.000000000 +0000 @@ -20,6 +20,6 @@

    Index

    - Version: 10.0.0 + Version: 12.1.0 \ No newline at end of file diff -Nru twisted-words-10.0.0/doc/man/im.1 twisted-words-12.1.0/doc/man/im.1 --- twisted-words-10.0.0/doc/man/im.1 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/doc/man/im.1 1970-01-01 00:00:00.000000000 +0000 @@ -1,16 +0,0 @@ -.TH IM "1" "July 2001" "" "" -.SH NAME -im \- run Instance Messenger, the Tkinter twisted.words client -.SH SYNOPSIS -.B im -.SH DESCRIPTION -Run Instance Messenger, the Tkinter twisted.words client -.SH AUTHOR -Written by Moshe Zadka, based on im's help messages -.SH "REPORTING BUGS" -To report a bug, visit \fIhttp://twistedmatrix.com/bugs/\fR -.SH COPYRIGHT -Copyright \(co 2000-2008 Twisted Matrix Laboratories. -.br -This is free software; see the source for copying conditions. There is NO -warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. diff -Nru twisted-words-10.0.0/doc/man/im-man.html twisted-words-12.1.0/doc/man/im-man.html --- twisted-words-10.0.0/doc/man/im-man.html 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/doc/man/im-man.html 1970-01-01 00:00:00.000000000 +0000 @@ -1,50 +0,0 @@ - - -Twisted Documentation: IM.1 - - - - -

    IM.1

    - - - -

    Index

    - Version: 10.0.0 - - \ No newline at end of file diff -Nru twisted-words-10.0.0/LICENSE twisted-words-12.1.0/LICENSE --- twisted-words-10.0.0/LICENSE 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/LICENSE 2012-02-11 13:47:35.000000000 +0000 @@ -1,4 +1,4 @@ -Copyright (c) 2001-2010 +Copyright (c) 2001-2012 Allen Short Andy Gayton Andrew Bennetts @@ -12,7 +12,7 @@ Donovan Preston Eric Mangold Eyal Lotem -Itamar Shtull-Trauring +Itamar Turner-Trauring James Knight Jason A. Mobarak Jean-Paul Calderone diff -Nru twisted-words-10.0.0/NEWS twisted-words-12.1.0/NEWS --- twisted-words-10.0.0/NEWS 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/NEWS 2012-06-04 08:27:07.000000000 +0000 @@ -1,6 +1,135 @@ Ticket numbers in this file can be looked up by visiting http://twistedmatrix.com/trac/ticket/ +Twisted Words 12.1.0 (2012-06-02) +================================= + +Bugfixes +-------- + - twisted.words.protocols.irc.DccChatFactory.buildProtocol now + returns the protocol object that it creates (#3179) + - twisted.words.im no longer offers an empty threat of a rewrite on + import. (#5598) + +Other +----- + - #5555, #5595 + + +Twisted Words 12.0.0 (2012-02-10) +================================= + +Improved Documentation +---------------------- + - twisted.words.im.basechat now has improved API documentation. + (#2458) + +Other +----- + - #5401 + + +Twisted Words 11.1.0 (2011-11-15) +================================= + +Features +-------- + - twisted.words.protocols.irc.IRCClient now uses a PING heartbeat as + a keepalive to avoid losing an IRC connection without being aware + of it. (#5047) + +Bugfixes +-------- + - twisted.words.protocols.irc.IRCClient now replies only once to + known CTCP queries per message and not at all to unknown CTCP + queries. (#5029) + - IRCClient.msg now determines a safe maximum command length, + drastically reducing the chance of relayed text being truncated on + the server side. (#5176) + +Deprecations and Removals +------------------------- + - twisted.words.protocols.irc.IRCClient.me was deprecated in Twisted + 9.0 and has been removed. Use IRCClient.describe instead. (#5059) + +Other +----- + - #5025, #5330 + + +Twisted Words 11.0.0 (2011-04-01) +================================= + +Features +-------- + - twisted.words.protocols.irc.IRCClient now has an invite method. + (#4820) + +Bugfixes +-------- + - twisted.words.protocols.irc.IRCClient.say is once again able to + send messages when using the default value for the length limit + argument. (#4758) + - twisted.words.protocols.jabber.jstrports is once again able to + parse jstrport description strings. (#4771) + - twisted.words.protocols.msn.NotificationClient now calls the + loginFailure callback when it is unable to connect to the Passport + server due to missing SSL dependencies. (#4801) + - twisted.words.protocols.jabber.xmpp_stringprep now always uses + Unicode version 3.2 for stringprep normalization. (#4850) + +Improved Documentation +---------------------- + - Removed the non-working AIM bot example, depending on the obsolete + twisted.words.protocols.toc functionality. (#4007) + - Outdated GUI-related information was removed from the IM howto. + (#4054) + +Deprecations and Removals +------------------------- + - Remove twisted.words.protocols.toc, that was largely non-working + and useless since AOL disabled TOC on their AIM network. (#4363) + +Other +----- + - #4733, #4902 + + +Twisted Words 10.2.0 (2010-11-29) +================================= + +Features +-------- + - twisted.words.protocols.irc.IRCClient.msg now enforces a maximum + length for messages, splitting up messages that are too long. + (#4416) + +Bugfixes +-------- + - twisted.words.protocols.irc.IRCClient no longer invokes privmsg() + in the default noticed() implementation. (#4419) + - twisted.words.im.ircsupport.IRCProto now sends the correct name in + the USER command. (#4641) + +Deprecations and Removals +------------------------- + - Remove twisted.words.im.proxyui and twisted.words.im.tap. (#1823) + + +Twisted Words 10.1.0 (2010-06-27) +================================= + +Bugfixes +-------- + - twisted.words.im.basechat.ChatUI now has a functional + contactChangedNick with unit tests. (#229) + - twisted.words.protocols.jabber.error.StanzaError now correctly sets + a default error type and code for the remote-server-timeout + condition (#4311) + - twisted.words.protocols.jabber.xmlstream.ListenAuthenticator now + uses unicode objects for session identifiers (#4345) + + Twisted Words 10.0.0 (2010-03-01) ================================= diff -Nru twisted-words-10.0.0/README twisted-words-12.1.0/README --- twisted-words-10.0.0/README 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/README 2012-06-02 07:04:01.000000000 +0000 @@ -1,4 +1,5 @@ -Twisted Words 10.0.0 +Twisted Words 12.1.0 Twisted Words depends on Twisted Core and Twisted Web. The Twisted Web -dependency is only necessary for MSN support. +dependency is only necessary for MSN support. MSN support also requires HTTPS, +and therefore pyOpenSSL (). diff -Nru twisted-words-10.0.0/setup.py twisted-words-12.1.0/setup.py --- twisted-words-10.0.0/setup.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/setup.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2008 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. import sys diff -Nru twisted-words-10.0.0/twisted/plugins/twisted_words.py twisted-words-12.1.0/twisted/plugins/twisted_words.py --- twisted-words-10.0.0/twisted/plugins/twisted_words.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/plugins/twisted_words.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. from zope.interface import classProvides @@ -8,11 +8,6 @@ from twisted.application.service import ServiceMaker from twisted.words import iwords -TwistedTOC = ServiceMaker( - "Twisted TOC Server", - "twisted.words.toctap", - "An AIM TOC service.", - "toc") NewTwistedWords = ServiceMaker( "New Twisted Words", diff -Nru twisted-words-10.0.0/twisted/words/ewords.py twisted-words-12.1.0/twisted/words/ewords.py --- twisted-words-10.0.0/twisted/words/ewords.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/ewords.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,5 +1,5 @@ # -*- test-case-name: twisted.words.test -*- -# Copyright (c) 2001-2005 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """Exception definitions for Words diff -Nru twisted-words-10.0.0/twisted/words/im/baseaccount.py twisted-words-12.1.0/twisted/words/im/baseaccount.py --- twisted-words-10.0.0/twisted/words/im/baseaccount.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/im/baseaccount.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,6 +1,6 @@ # -*- Python -*- # -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. # diff -Nru twisted-words-10.0.0/twisted/words/im/basechat.py twisted-words-12.1.0/twisted/words/im/basechat.py --- twisted-words-10.0.0/twisted/words/im/basechat.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/im/basechat.py 2011-11-28 03:50:30.000000000 +0000 @@ -1,17 +1,36 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. +# -*- test-case-name: twisted.words.test.test_basechat -*- +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. -# - -"""Base classes for Instance Messenger clients.""" +""" +Base classes for Instance Messenger clients. +""" from twisted.words.im.locals import OFFLINE, ONLINE, AWAY + class ContactsList: - """A GUI object that displays a contacts list""" + """ + A GUI object that displays a contacts list. + + @ivar chatui: The GUI chat client associated with this contacts list. + @type chatui: L{ChatUI} + + @ivar contacts: The contacts. + @type contacts: C{dict} mapping C{str} to a L{IPerson} + provider + + @ivar onlineContacts: The contacts who are currently online (have a status + that is not C{OFFLINE}). + @type onlineContacts: C{dict} mapping C{str} to a + L{IPerson} provider + + @ivar clients: The signed-on clients. + @type clients: C{list} of L{IClient} providers + """ def __init__(self, chatui): """ - @param chatui: ??? + @param chatui: The GUI chat client associated with this contacts list. @type chatui: L{ChatUI} """ self.chatui = chatui @@ -19,38 +38,60 @@ self.onlineContacts = {} self.clients = [] + def setContactStatus(self, person): - """Inform the user that a person's status has changed. + """ + Inform the user that a person's status has changed. - @type person: L{Person} + @param person: The person whose status has changed. + @type person: L{IPerson} provider """ if not self.contacts.has_key(person.name): self.contacts[person.name] = person if not self.onlineContacts.has_key(person.name) and \ - (person.status == ONLINE or person.status == AWAY): + (person.status == ONLINE or person.status == AWAY): self.onlineContacts[person.name] = person if self.onlineContacts.has_key(person.name) and \ - person.status == OFFLINE: + person.status == OFFLINE: del self.onlineContacts[person.name] + def registerAccountClient(self, client): - """Notify the user that an account client has been signed on to. + """ + Notify the user that an account client has been signed on to. - @type client: L{Client} + @param client: The client being added to your list of account clients. + @type client: L{IClient} provider """ if not client in self.clients: self.clients.append(client) + def unregisterAccountClient(self, client): - """Notify the user that an account client has been signed off - or disconnected from. + """ + Notify the user that an account client has been signed off or + disconnected from. - @type client: L{Client} + @param client: The client being removed from the list of account + clients. + @type client: L{IClient} provider """ if client in self.clients: self.clients.remove(client) + def contactChangedNick(self, person, newnick): + """ + Update your contact information to reflect a change to a contact's + nickname. + + @param person: The person in your contacts list whose nickname is + changing. + @type person: L{IPerson} provider + + @param newnick: The new nickname for this person. + @type newnick: C{str} + """ oldname = person.name if self.contacts.has_key(oldname): del self.contacts[oldname] @@ -61,173 +102,301 @@ self.onlineContacts[newnick] = person + class Conversation: - """A GUI window of a conversation with a specific person""" + """ + A GUI window of a conversation with a specific person. + + @ivar person: The person who you're having this conversation with. + @type person: L{IPerson} provider + + @ivar chatui: The GUI chat client associated with this conversation. + @type chatui: L{ChatUI} + """ def __init__(self, person, chatui): """ - @type person: L{Person} + @param person: The person who you're having this conversation with. + @type person: L{IPerson} provider + + @param chatui: The GUI chat client associated with this conversation. @type chatui: L{ChatUI} """ self.chatui = chatui self.person = person + def show(self): - """Displays the ConversationWindow""" + """ + Display the ConversationWindow. + """ raise NotImplementedError("Subclasses must implement this method") + def hide(self): - """Hides the ConversationWindow""" + """ + Hide the ConversationWindow. + """ raise NotImplementedError("Subclasses must implement this method") + def sendText(self, text): - """Sends text to the person with whom the user is conversing. + """ + Send text to the person with whom the user is conversing. - @returntype: L{Deferred} + @param text: The text to be sent. + @type text: C{str} """ self.person.sendMessage(text, None) + def showMessage(self, text, metadata=None): - """Display a message sent from the person with whom she is conversing + """ + Display a message sent from the person with whom the user is conversing. + + @param text: The sent message. + @type text: C{str} - @type text: string - @type metadata: dict + @param metadata: Metadata associated with this message. + @type metadata: C{dict} """ raise NotImplementedError("Subclasses must implement this method") + def contactChangedNick(self, person, newnick): - """Change a person's name. + """ + Change a person's name. + + @param person: The person whose nickname is changing. + @type person: L{IPerson} provider - @type person: L{Person} - @type newnick: string + @param newnick: The new nickname for this person. + @type newnick: C{str} """ self.person.name = newnick + class GroupConversation: - """A conversation with a group of people.""" + """ + A GUI window of a conversation with a group of people. + + @ivar chatui: The GUI chat client associated with this conversation. + @type chatui: L{ChatUI} + + @ivar group: The group of people that are having this conversation. + @type group: L{IGroup} provider + + @ivar members: The names of the people in this conversation. + @type members: C{list} of C{str} + """ def __init__(self, group, chatui): """ - @type group: L{Group} - @param chatui: ??? + @param chatui: The GUI chat client associated with this conversation. @type chatui: L{ChatUI} + + @param group: The group of people that are having this conversation. + @type group: L{IGroup} provider """ self.chatui = chatui self.group = group self.members = [] + def show(self): - """Displays the GroupConversationWindow.""" + """ + Display the GroupConversationWindow. + """ raise NotImplementedError("Subclasses must implement this method") + def hide(self): - """Hides the GroupConversationWindow.""" + """ + Hide the GroupConversationWindow. + """ raise NotImplementedError("Subclasses must implement this method") + def sendText(self, text): - """Sends text to the group. + """ + Send text to the group. - @type text: string - @returntype: L{Deferred} + @param: The text to be sent. + @type text: C{str} """ self.group.sendGroupMessage(text, None) + def showGroupMessage(self, sender, text, metadata=None): - """Displays to the user a message sent to this group from the given sender - @type sender: string (XXX: Not Person?) - @type text: string - @type metadata: dict + """ + Display to the user a message sent to this group from the given sender. + + @param sender: The person sending the message. + @type sender: C{str} + + @param text: The sent message. + @type text: C{str} + + @param metadata: Metadata associated with this message. + @type metadata: C{dict} """ raise NotImplementedError("Subclasses must implement this method") + def setGroupMembers(self, members): - """Sets the list of members in the group and displays it to the user + """ + Set the list of members in the group. + + @param members: The names of the people that will be in this group. + @type members: C{list} of C{str} """ self.members = members + def setTopic(self, topic, author): - """Displays the topic (from the server) for the group conversation window + """ + Change the topic for the group conversation window and display this + change to the user. + + @param topic: This group's topic. + @type topic: C{str} - @type topic: string - @type author: string (XXX: Not Person?) + @param author: The person changing the topic. + @type author: C{str} """ raise NotImplementedError("Subclasses must implement this method") + def memberJoined(self, member): - """Adds the given member to the list of members in the group conversation - and displays this to the user + """ + Add the given member to the list of members in the group conversation + and displays this to the user. - @type member: string (XXX: Not Person?) + @param member: The person joining the group conversation. + @type member: C{str} """ if not member in self.members: self.members.append(member) + def memberChangedNick(self, oldnick, newnick): - """Changes the oldnick in the list of members to newnick and displays this - change to the user + """ + Change the nickname for a member of the group conversation and displays + this change to the user. - @type oldnick: string - @type newnick: string + @param oldnick: The old nickname. + @type oldnick: C{str} + + @param newnick: The new nickname. + @type newnick: C{str} """ if oldnick in self.members: self.members.remove(oldnick) self.members.append(newnick) - #self.chatui.contactChangedNick(oldnick, newnick) + def memberLeft(self, member): - """Deletes the given member from the list of members in the group - conversation and displays the change to the user + """ + Delete the given member from the list of members in the group + conversation and displays the change to the user. - @type member: string + @param member: The person leaving the group conversation. + @type member: C{str} """ if member in self.members: self.members.remove(member) + class ChatUI: - """A GUI chat client""" + """ + A GUI chat client. + + @type conversations: C{dict} of L{Conversation} + @ivar conversations: A cache of all the direct windows. + + @type groupConversations: C{dict} of L{GroupConversation} + @ivar groupConversations: A cache of all the group windows. + + @type persons: C{dict} with keys that are a C{tuple} of (C{str}, + L{IAccount} provider) and values that are + L{IPerson} provider + @ivar persons: A cache of all the users associated with this client. + + @type groups: C{dict} with keys that are a C{tuple} of (C{str}, + L{IAccount} provider) and values that are + L{IGroup} provider + @ivar groups: A cache of all the groups associated with this client. + + @type onlineClients: C{list} of L{IClient} providers + @ivar onlineClients: A list of message sources currently online. + + @type contactsList: L{ContactsList} + @ivar contactsList: A contacts list. + """ def __init__(self): - self.conversations = {} # cache of all direct windows - self.groupConversations = {} # cache of all group windows - self.persons = {} # keys are (name, client) - self.groups = {} # cache of all groups - self.onlineClients = [] # list of message sources currently online + self.conversations = {} + self.groupConversations = {} + self.persons = {} + self.groups = {} + self.onlineClients = [] self.contactsList = ContactsList(self) + def registerAccountClient(self, client): - """Notifies user that an account has been signed on to. + """ + Notify the user that an account has been signed on to. - @type client: L{Client} - @returns: client, so that I may be used in a callback chain + @type client: L{IClient} provider + @param client: The client account for the person who has just signed on. + + @rtype client: L{IClient} provider + @return: The client, so that it may be used in a callback chain. """ - print "signing onto", client.accountName self.onlineClients.append(client) self.contactsList.registerAccountClient(client) return client + def unregisterAccountClient(self, client): - """Notifies user that an account has been signed off or disconnected + """ + Notify the user that an account has been signed off or disconnected. - @type client: L{Client} + @type client: L{IClient} provider + @param client: The client account for the person who has just signed + off. """ - print "signing off from", client.accountName self.onlineClients.remove(client) self.contactsList.unregisterAccountClient(client) + def getContactsList(self): """ - @returntype: L{ContactsList} + Get the contacts list associated with this chat window. + + @rtype: L{ContactsList} + @return: The contacts list associated with this chat window. """ return self.contactsList - def getConversation(self, person, Class=Conversation, stayHidden=0): - """For the given person object, returns the conversation window - or creates and returns a new conversation window if one does not exist. - - @type person: L{Person} - @type Class: L{Conversation} class - @type stayHidden: boolean - @returntype: L{Conversation} + def getConversation(self, person, Class=Conversation, stayHidden=False): + """ + For the given person object, return the conversation window or create + and return a new conversation window if one does not exist. + + @type person: L{IPerson} provider + @param person: The person whose conversation window we want to get. + + @type Class: L{IConversation} implementor + @param: The kind of conversation window we want. If the conversation + window for this person didn't already exist, create one of this type. + + @type stayHidden: C{bool} + @param stayHidden: Whether or not the conversation window should stay + hidden. + + @rtype: L{IConversation} provider + @return: The conversation window. """ conv = self.conversations.get(person) if not conv: @@ -239,15 +408,26 @@ conv.show() return conv - def getGroupConversation(self,group,Class=GroupConversation,stayHidden=0): - """For the given group object, returns the group conversation window or - creates and returns a new group conversation window if it doesn't exist - - @type group: L{Group} - @type Class: L{Conversation} class - @type stayHidden: boolean - @returntype: L{GroupConversation} + def getGroupConversation(self, group, Class=GroupConversation, + stayHidden=False): + """ + For the given group object, return the group conversation window or + create and return a new group conversation window if it doesn't exist. + + @type group: L{IGroup} provider + @param group: The group whose conversation window we want to get. + + @type Class: L{IConversation} implementor + @param: The kind of conversation window we want. If the conversation + window for this person didn't already exist, create one of this type. + + @type stayHidden: C{bool} + @param stayHidden: Whether or not the conversation window should stay + hidden. + + @rtype: L{IGroupConversation} provider + @return: The group conversation window. """ conv = self.groupConversations.get(group) if not conv: @@ -259,15 +439,21 @@ conv.show() return conv + def getPerson(self, name, client): - """For the given name and account client, returns the instance of the - AbstractPerson subclass, or creates and returns a new AbstractPerson - subclass of the type Class + """ + For the given name and account client, return an instance of a + L{IGroup} provider or create and return a new + instance of a L{IGroup} provider. + + @type name: C{str} + @param name: The name of the person of interest. - @type name: string - @type client: L{Client} + @type client: L{IClient} provider + @param client: The client account of interest. - @returntype: L{Person} + @rtype: L{IPerson} provider + @return: The person with that C{name}. """ account = client.account p = self.persons.get((name, account)) @@ -276,15 +462,21 @@ self.persons[name, account] = p return p + def getGroup(self, name, client): - """For the given name and account client, returns the instance of the - AbstractGroup subclass, or creates and returns a new AbstractGroup - subclass of the type Class + """ + For the given name and account client, return an instance of a + L{IGroup} provider or create and return a new instance + of a L{IGroup} provider. + + @type name: C{str} + @param name: The name of the group of interest. - @type name: string - @type client: L{Client} + @type client: L{IClient} provider + @param client: The client account of interest. - @returntype: L{Group} + @rtype: L{IGroup} provider + @return: The group with that C{name}. """ # I accept 'client' instead of 'account' in my signature for # backwards compatibility. (Groups changed to be Account-oriented @@ -296,21 +488,25 @@ self.groups[name, account] = g return g - def contactChangedNick(self, oldnick, newnick): - """For the given person, changes the person's name to newnick, and - tells the contact list and any conversation windows with that person - to change as well. - @type oldnick: string - @type newnick: string + def contactChangedNick(self, person, newnick): + """ + For the given C{person}, change the C{person}'s C{name} to C{newnick} + and tell the contact list and any conversation windows with that + C{person} to change as well. + + @type person: L{IPerson} provider + @param person: The person whose nickname will get changed. + + @type newnick: C{str} + @param newnick: The new C{name} C{person} will take. """ - if self.persons.has_key((person.name, person.account)): + oldnick = person.name + if self.persons.has_key((oldnick, person.account)): conv = self.conversations.get(person) if conv: conv.contactChangedNick(person, newnick) - self.contactsList.contactChangedNick(person, newnick) - - del self.persons[person.name, person.account] + del self.persons[oldnick, person.account] person.name = newnick self.persons[person.name, person.account] = person diff -Nru twisted-words-10.0.0/twisted/words/im/basesupport.py twisted-words-12.1.0/twisted/words/im/basesupport.py --- twisted-words-10.0.0/twisted/words/im/basesupport.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/im/basesupport.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. # diff -Nru twisted-words-10.0.0/twisted/words/im/__init__.py twisted-words-12.1.0/twisted/words/im/__init__.py --- twisted-words-10.0.0/twisted/words/im/__init__.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/im/__init__.py 2012-04-06 11:40:52.000000000 +0000 @@ -1,8 +1,6 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """Instance Messenger, Pan-protocol chat client.""" -import warnings -warnings.warn("twisted.im will be undergoing a rewrite at some point in the future.") diff -Nru twisted-words-10.0.0/twisted/words/im/interfaces.py twisted-words-12.1.0/twisted/words/im/interfaces.py --- twisted-words-10.0.0/twisted/words/im/interfaces.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/im/interfaces.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,5 +1,5 @@ # -*- Python -*- -# Copyright (c) 2008 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ diff -Nru twisted-words-10.0.0/twisted/words/im/ircsupport.py twisted-words-12.1.0/twisted/words/im/ircsupport.py --- twisted-words-10.0.0/twisted/words/im/ircsupport.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/im/ircsupport.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,8 +1,9 @@ -# Copyright (c) 2001-2009 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. - -"""IRC support for Instance Messenger.""" +""" +IRC support for Instance Messenger. +""" import string @@ -105,7 +106,8 @@ if self.account.password: self.sendLine("PASS :%s" % self.account.password) self.setNick(self.account.username) - self.sendLine("USER %s foo bar :Twisted-IM user" % (self.nickname,)) + self.sendLine("USER %s foo bar :Twisted-IM user" % ( + self.account.username,)) for channel in self.account.channels: self.joinGroup(channel) self.account._isOnline=1 diff -Nru twisted-words-10.0.0/twisted/words/im/locals.py twisted-words-12.1.0/twisted/words/im/locals.py --- twisted-words-10.0.0/twisted/words/im/locals.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/im/locals.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. diff -Nru twisted-words-10.0.0/twisted/words/im/pbsupport.py twisted-words-12.1.0/twisted/words/im/pbsupport.py --- twisted-words-10.0.0/twisted/words/im/pbsupport.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/im/pbsupport.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. diff -Nru twisted-words-10.0.0/twisted/words/im/proxyui.py twisted-words-12.1.0/twisted/words/im/proxyui.py --- twisted-words-10.0.0/twisted/words/im/proxyui.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/im/proxyui.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,24 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -from twisted.words.protocols.irc import IRC -from twisted.python import log -from twisted.internet.protocol import Factory - -class IRCUserInterface(IRC): - def connectionLost(self): - del self.factory.ircui - -class IRCUIFactory(Factory): - ircui = None - def buildProtocol(self): - if self.ircui: - log.msg("already logged in") - return None - i = IRCUserInterface() - i.factory = self - self.ircui = i - return i - diff -Nru twisted-words-10.0.0/twisted/words/im/tap.py twisted-words-12.1.0/twisted/words/im/tap.py --- twisted-words-10.0.0/twisted/words/im/tap.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/im/tap.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,15 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - -# - -from twisted.words.im.proxyui import IRCUIFactory -from twisted.python import usage - -class Options(usage.Options): - optParameters = [["ircport", "p", "6667", - "Port to start the IRC server on."]] - -def updateApplication(app, config): - factory = IRCUIFactory() - app.listenTCP(int(config.opts['ircport']), IRCUIFactory()) diff -Nru twisted-words-10.0.0/twisted/words/im/tocsupport.py twisted-words-12.1.0/twisted/words/im/tocsupport.py --- twisted-words-10.0.0/twisted/words/im/tocsupport.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/im/tocsupport.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,220 +0,0 @@ -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -"""TOC (i.e. AIM) support for Instance Messenger.""" - -# System Imports -import string, re -from zope.interface import implements - -# Twisted Imports -from twisted.words.protocols import toc -from twisted.words.im.locals import ONLINE, OFFLINE, AWAY -from twisted.internet import defer, reactor, protocol -from twisted.internet.defer import succeed - -# Sibling Imports -from twisted.words.im import basesupport, interfaces, locals - -def dehtml(text): - text=string.replace(text,"
    ","\n") - text=string.replace(text,"
    ","\n") - text=string.replace(text,"
    ","\n") # XXX make this a regexp - text=string.replace(text,"
    ","\n") - text=re.sub('<.*?>','',text) - text=string.replace(text,'>','>') - text=string.replace(text,'<','<') - text=string.replace(text,'&','&') - text=string.replace(text,' ',' ') - text=string.replace(text,'"','"') - return text - -def html(text): - text=string.replace(text,'"','"') - text=string.replace(text,'&','&') - text=string.replace(text,'<','<') - text=string.replace(text,'>','>') - text=string.replace(text,"\n","
    ") - return '%s'%text - -class TOCPerson(basesupport.AbstractPerson): - def isOnline(self): - return self.status != OFFLINE - - def getStatus(self): - return self.status - - def getIdleTime(self): - return str(self.idletime) - - def setStatusAndIdle(self, status, idletime): - if self.account.client is None: - raise locals.OfflineError - self.status = status - self.idletime = idletime - self.account.client.chat.getContactsList().setContactStatus(self) - - def sendMessage(self, text, meta=None): - if self.account.client is None: - raise locals.OfflineError - if meta: - if meta.get("style", None) == "emote": - text="* "+text+"* " - self.account.client.say(self.name,html(text)) - return succeed(text) - -class TOCGroup(basesupport.AbstractGroup): - implements(interfaces.IGroup) - def __init__(self, name, tocAccount): - basesupport.AbstractGroup.__init__(self, name, tocAccount) - self.roomID = self.client.roomID[self.name] - - def sendGroupMessage(self, text, meta=None): - if self.account.client is None: - raise locals.OfflineError - if meta: - if meta.get("style", None) == "emote": - text="* "+text+"* " - self.account.client.chat_say(self.roomID,html(text)) - return succeed(text) - - def leave(self): - if self.account.client is None: - raise locals.OfflineError - self.account.client.chat_leave(self.roomID) - - -class TOCProto(basesupport.AbstractClientMixin, toc.TOCClient): - def __init__(self, account, chatui, logonDeferred): - toc.TOCClient.__init__(self, account.username, account.password) - basesupport.AbstractClientMixin.__init__(self, account, chatui, - logonDeferred) - self.roomID = {} - self.roomIDreverse = {} - - def _debug(self, m): - pass #print '', repr(m) - - def getGroupConversation(self, name, hide=0): - return self.chat.getGroupConversation( - self.chat.getGroup(name, self), hide) - - def addContact(self, name): - self.add_buddy([name]) - if not self._buddylist.has_key('TwistedIM'): - self._buddylist['TwistedIM'] = [] - if name in self._buddylist['TwistedIM']: - # whoops, don't add again - return - self._buddylist['TwistedIM'].append(name) - self.set_config(self._config_mode, self._buddylist, self._permit, self._deny) - - def getPerson(self,name): - return self.chat.getPerson(name, self) - - def onLine(self): - self.account._isOnline = 1 - #print '$$!&*$&!(@$*& TOC ONLINE *!#@&$(!*%&' - - def gotConfig(self, mode, buddylist, permit, deny): - #print 'got toc config', repr(mode), repr(buddylist), repr(permit), repr(deny) - self._config_mode = mode - self._buddylist = buddylist - self._permit = permit - self._deny = deny - if permit: - self._debug('adding permit') - self.add_permit(permit) - if deny: - self._debug('adding deny') - self.add_deny(deny) - clist=[] - for k in buddylist.keys(): - self.add_buddy(buddylist[k]) - for name in buddylist[k]: - self.getPerson(name).setStatusAndIdle(OFFLINE, '--') - self.signon() - name = None - def tocNICK(self,data): - if not self.name: - print 'Waiting for second NICK', data - self.name=data[0] - self.accountName = '%s (TOC)' % self.name - self.chat.getContactsList() - else: - print 'reregistering...?', data - self.name=data[0] - # self.accountName = "%s (TOC)"%data[0] - if self._logonDeferred is not None: - self._logonDeferred.callback(self) - self._logonDeferred = None - - ### Error Messages - def hearError(self, code, args): - print '*** TOC ERROR ***', repr(code), repr(args) - def hearWarning(self, newamount, username): - print '*** TOC WARNING ***', repr(newamount), repr(username) - ### Buddy Messages - def hearMessage(self,username,message,autoreply): - if autoreply: - message=': '+message - self.chat.getConversation(self.getPerson(username) - ).showMessage(dehtml(message)) - def updateBuddy(self,username,online,evilness,signontime,idletime,userclass,away): - if away: - status=AWAY - elif online: - status=ONLINE - else: - status=OFFLINE - self.getPerson(username).setStatusAndIdle(status, idletime) - - ### Group Chat - def chatJoined(self, roomid, roomname, users): - self.roomID[roomname]=roomid - self.roomIDreverse[roomid]=roomname - self.getGroupConversation(roomname).setGroupMembers(users) - def chatUpdate(self,roomid,member,inroom): - group=self.roomIDreverse[roomid] - if inroom: - self.getGroupConversation(group).memberJoined(member) - else: - self.getGroupConversation(group).memberLeft(member) - def chatHearMessage(self, roomid, username, message): - if toc.normalize(username) == toc.normalize(self.name): - return # ignore the message - group=self.roomIDreverse[roomid] - self.getGroupConversation(group).showGroupMessage(username, dehtml(message)) - def chatHearWhisper(self, roomid, username, message): - print '*** user whispered *** ', roomid, username, message - def chatInvited(self, roomid, roomname, username, message): - print '*** user invited us to chat *** ',roomid, roomname, username, message - def chatLeft(self, roomid): - group=self.roomIDreverse[roomid] - self.getGroupConversation(group,1) - del self.roomID[group] - del self.roomIDreverse[roomid] - def rvousProposal(self,type,cookie,user,vip,port,**kw): - print '*** rendezvous. ***', type, cookie, user, vip, port, kw - def receiveBytes(self, user, file, chunk, sofar, total): - print '*** File transfer! ***', user, file, chunk, sofar, total - - def joinGroup(self,name): - self.chat_join(4,toc.normalize(name)) - -class TOCAccount(basesupport.AbstractAccount): - implements(interfaces.IAccount) - gatewayType = "AIM (TOC)" - - _groupFactory = TOCGroup - _personFactory = TOCPerson - - def _startLogOn(self, chatui): - logonDeferred = defer.Deferred() - cc = protocol.ClientCreator(reactor, TOCProto, self, chatui, - logonDeferred) - d = cc.connectTCP(self.host, self.port) - d.addErrback(logonDeferred.errback) - return logonDeferred - diff -Nru twisted-words-10.0.0/twisted/words/__init__.py twisted-words-12.1.0/twisted/words/__init__.py --- twisted-words-10.0.0/twisted/words/__init__.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/__init__.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,5 +1,5 @@ # -*- test-case-name: twisted.words.test -*- -# Copyright (c) 2001-2005 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. diff -Nru twisted-words-10.0.0/twisted/words/iwords.py twisted-words-12.1.0/twisted/words/iwords.py --- twisted-words-10.0.0/twisted/words/iwords.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/iwords.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,5 +1,5 @@ # -*- test-case-name: twisted.words.test -*- -# Copyright (c) 2001-2005 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. from zope.interface import Interface, Attribute, implements diff -Nru twisted-words-10.0.0/twisted/words/protocols/irc.py twisted-words-12.1.0/twisted/words/protocols/irc.py --- twisted-words-10.0.0/twisted/words/protocols/irc.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/protocols/irc.py 2012-03-14 05:06:21.000000000 +0000 @@ -1,5 +1,5 @@ # -*- test-case-name: twisted.words.test.test_irc -*- -# Copyright (c) 2001-2010 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -20,6 +20,9 @@ Test coverage needs to be better. +@var MAX_COMMAND_LENGTH: The maximum length of a command, as defined by RFC + 2812 section 2.3. + @author: Kevin Turner @see: RFC 1459: Internet Relay Chat Protocol @@ -31,12 +34,14 @@ import errno, os, random, re, stat, struct, sys, time, types, traceback import string, socket import warnings +import textwrap from os import path -from twisted.internet import reactor, protocol +from twisted.internet import reactor, protocol, task from twisted.persisted import styles from twisted.protocols import basic from twisted.python import log, reflect, text +from twisted.python.compat import set NUL = chr(0) CR = chr(015) @@ -44,6 +49,9 @@ LF = NL SPC = chr(040) +# This includes the CRLF terminator characters. +MAX_COMMAND_LENGTH = 512 + CHANNEL_PREFIXES = '&#!+' class IRCBadMessage(Exception): @@ -80,34 +88,26 @@ return prefix, command, args -def split(str, length = 80): - """I break a message into multiple lines. - - I prefer to break at whitespace near str[length]. I also break at \\n. - @returns: list of strings +def split(str, length=80): """ - if length <= 0: - raise ValueError("Length must be a number greater than zero") - r = [] - while len(str) > length: - w, n = str[:length].rfind(' '), str[:length].find('\n') - if w == -1 and n == -1: - line, str = str[:length], str[length:] - else: - if n == -1: - i = w - else: - i = n - if i == 0: # just skip the space or newline. don't append any output. - str = str[1:] - continue - line, str = str[:i], str[i+1:] - r.append(line) - if len(str): - r.extend(str.split('\n')) - return r + Split a string into multiple lines. + + Whitespace near C{str[length]} will be preferred as a breaking point. + C{"\\n"} will also be used as a breaking point. + + @param str: The string to split. + @type str: C{str} + + @param length: The maximum length which will be allowed for any string in + the result. + @type length: C{int} + @return: C{list} of C{str} + """ + return [chunk + for line in str.split('\n') + for chunk in textwrap.wrap(line, length)] def _intOrDefault(value, default=None): @@ -969,7 +969,8 @@ class IRCClient(basic.LineReceiver): - """Internet Relay Chat client protocol, with sprinkles. + """ + Internet Relay Chat client protocol, with sprinkles. In addition to providing an interface for an IRC client protocol, this class also contains reasonable implementations of many common @@ -981,11 +982,6 @@ does). - Add flood protection/rate limiting for my CTCP replies. - NickServ cooperation. (a mix-in?) - - Heartbeat. The transport may die in such a way that it does not realize - it is dead until it is written to. Sending something (like "PING - this.irc-host.net") during idle peroids would alleviate that. If - you're concerned with the stability of the host as well as that of the - transport, you might care to watch for the corresponding PONG. @ivar nickname: Nickname the client will use. @ivar password: Password used to log on to the server. May be C{None}. @@ -1037,7 +1033,23 @@ @type supported: L{ServerSupportedFeatures} @ivar supported: Available ISUPPORT features on the server + + @type hostname: C{str} + @ivar hostname: Host name of the IRC server the client is connected to. + Initially the host name is C{None} and later is set to the host name + from which the I{RPL_WELCOME} message is received. + + @type _heartbeat: L{task.LoopingCall} + @ivar _heartbeat: Looping call to perform the keepalive by calling + L{IRCClient._sendHeartbeat} every L{heartbeatInterval} seconds, or + C{None} if there is no heartbeat. + + @type heartbeatInterval: C{float} + @ivar heartbeatInterval: Interval, in seconds, to send I{PING} messages to + the server as a form of keepalive, defaults to 120 seconds. Use C{None} + to disable the heartbeat. """ + hostname = None motd = None nickname = 'irc' password = None @@ -1073,6 +1085,10 @@ _attemptedNick = '' erroneousNickFallback = 'defaultnick' + _heartbeat = None + heartbeatInterval = 120 + + def _reallySendLine(self, line): return basic.LineReceiver.sendLine(self, lowQuote(line) + '\r') @@ -1093,6 +1109,52 @@ self._queueEmptying = None + def connectionLost(self, reason): + basic.LineReceiver.connectionLost(self, reason) + self.stopHeartbeat() + + + def _createHeartbeat(self): + """ + Create the heartbeat L{LoopingCall}. + """ + return task.LoopingCall(self._sendHeartbeat) + + + def _sendHeartbeat(self): + """ + Send a I{PING} message to the IRC server as a form of keepalive. + """ + self.sendLine('PING ' + self.hostname) + + + def stopHeartbeat(self): + """ + Stop sending I{PING} messages to keep the connection to the server + alive. + + @since: 11.1 + """ + if self._heartbeat is not None: + self._heartbeat.stop() + self._heartbeat = None + + + def startHeartbeat(self): + """ + Start sending I{PING} messages every L{IRCClient.heartbeatInterval} + seconds to keep the connection to the server alive during periods of no + activity. + + @since: 11.1 + """ + self.stopHeartbeat() + if self.heartbeatInterval is None: + return + self._heartbeat = self._createHeartbeat() + self._heartbeat.start(self.heartbeatInterval, now=False) + + ### Interface level client->user output methods ### ### You'll want to override these. @@ -1100,21 +1162,24 @@ ### Methods relating to the server itself def created(self, when): - """Called with creation date information about the server, usually at logon. + """ + Called with creation date information about the server, usually at logon. @type when: C{str} @param when: A string describing when the server was created, probably. """ def yourHost(self, info): - """Called with daemon information about the server, usually at logon. + """ + Called with daemon information about the server, usually at logon. @type info: C{str} @param when: A string describing what software the server is running, probably. """ def myInfo(self, servername, version, umodes, cmodes): - """Called with information about the server, usually at logon. + """ + Called with information about the server, usually at logon. @type servername: C{str} @param servername: The hostname of this server. @@ -1130,7 +1195,8 @@ """ def luserClient(self, info): - """Called with information about the number of connections, usually at logon. + """ + Called with information about the number of connections, usually at logon. @type info: C{str} @param info: A description of the number of clients and servers @@ -1138,7 +1204,8 @@ """ def bounce(self, info): - """Called with information about where the client should reconnect. + """ + Called with information about where the client should reconnect. @type info: C{str} @param info: A plaintext description of the address that should be @@ -1146,7 +1213,8 @@ """ def isupport(self, options): - """Called with various information about what the server supports. + """ + Called with various information about what the server supports. @type options: C{list} of C{str} @param options: Descriptions of features or limits of the server, possibly @@ -1154,19 +1222,22 @@ """ def luserChannels(self, channels): - """Called with the number of channels existant on the server. + """ + Called with the number of channels existant on the server. @type channels: C{int} """ def luserOp(self, ops): - """Called with the number of ops logged on to the server. + """ + Called with the number of ops logged on to the server. @type ops: C{int} """ def luserMe(self, info): - """Called with information about the server connected to. + """ + Called with information about the server connected to. @type info: C{str} @param info: A plaintext string describing the number of users and servers @@ -1176,7 +1247,8 @@ ### Methods involving me directly def privmsg(self, user, channel, message): - """Called when I have a message from a user to me or a channel. + """ + Called when I have a message from a user to me or a channel. """ pass @@ -1196,12 +1268,13 @@ intact. """ + def noticed(self, user, channel, message): - """Called when I have a notice from a user to me or a channel. + """ + Called when I have a notice from a user to me or a channel. - By default, this is equivalent to IRCClient.privmsg, but if your - client makes any automated replies, you must override this! - From the RFC:: + If the client makes any automated replies, it must not do so in + response to a NOTICE message, per the RFC:: The difference between NOTICE and PRIVMSG is that automatic replies MUST NEVER be sent in response to a @@ -1209,10 +1282,11 @@ loops between clients automatically sending something in response to something it received. """ - self.privmsg(user, channel, message) + def modeChanged(self, user, channel, set, modes, args): - """Called when users or channel's modes are changed. + """ + Called when users or channel's modes are changed. @type user: C{str} @param user: The user and hostmask which instigated this change. @@ -1238,22 +1312,26 @@ """ def pong(self, user, secs): - """Called with the results of a CTCP PING query. + """ + Called with the results of a CTCP PING query. """ pass def signedOn(self): - """Called after sucessfully signing on to the server. + """ + Called after sucessfully signing on to the server. """ pass def kickedFrom(self, channel, kicker, message): - """Called when I am kicked from a channel. + """ + Called when I am kicked from a channel. """ pass def nickChanged(self, nick): - """Called when my nick has been changed. + """ + Called when my nick has been changed. """ self.nickname = nick @@ -1261,46 +1339,54 @@ ### Things I observe other people doing in a channel. def userJoined(self, user, channel): - """Called when I see another user joining a channel. + """ + Called when I see another user joining a channel. """ pass def userLeft(self, user, channel): - """Called when I see another user leaving a channel. + """ + Called when I see another user leaving a channel. """ pass def userQuit(self, user, quitMessage): - """Called when I see another user disconnect from the network. + """ + Called when I see another user disconnect from the network. """ pass def userKicked(self, kickee, channel, kicker, message): - """Called when I observe someone else being kicked from a channel. + """ + Called when I observe someone else being kicked from a channel. """ pass def action(self, user, channel, data): - """Called when I see a user perform an ACTION on a channel. + """ + Called when I see a user perform an ACTION on a channel. """ pass def topicUpdated(self, user, channel, newTopic): - """In channel, user changed the topic to newTopic. + """ + In channel, user changed the topic to newTopic. Also called when first joining a channel. """ pass def userRenamed(self, oldname, newname): - """A user changed their name from oldname to newname. + """ + A user changed their name from oldname to newname. """ pass ### Information from the server. def receivedMOTD(self, motd): - """I received a message-of-the-day banner from the server. + """ + I received a message-of-the-day banner from the server. motd is a list of strings, where each string was sent as a seperate message from the server. To display, you might want to use:: @@ -1369,6 +1455,23 @@ part = leave + + def invite(self, user, channel): + """ + Attempt to invite user to channel + + @type user: C{str} + @param user: The user to invite + @type channel: C{str} + @param channel: The channel to invite the user too + + @since: 11.0 + """ + if channel[0] not in CHANNEL_PREFIXES: + channel = '#' + channel + self.sendLine("INVITE %s %s" % (user, channel)) + + def topic(self, channel, topic=None): """ Attempt to set the topic of the given channel, or ask what it is. @@ -1391,6 +1494,7 @@ else: self.sendLine("TOPIC %s" % (channel,)) + def mode(self, chan, set, modes, limit = None, user = None, mask = None): """ Change the modes on a user or channel. @@ -1426,7 +1530,7 @@ self.sendLine(line) - def say(self, channel, message, length = None): + def say(self, channel, message, length=None): """ Send a message to a channel @@ -1448,40 +1552,64 @@ self.msg(channel, message, length) - def msg(self, user, message, length = None): - """Send a message to a user or channel. + def _safeMaximumLineLength(self, command): + """ + Estimate a safe maximum line length for the given command. + + This is done by assuming the maximum values for nickname length, + realname and hostname combined with the command that needs to be sent + and some guessing. A theoretical maximum value is used because it is + possible that our nickname, username or hostname changes (on the server + side) while the length is still being calculated. + """ + # :nickname!realname@hostname COMMAND ... + theoretical = ':%s!%s@%s %s' % ( + 'a' * self.supported.getFeature('NICKLEN'), + # This value is based on observation. + 'b' * 10, + # See . + 'c' * 63, + command) + # Fingers crossed. + fudge = 10 + return MAX_COMMAND_LENGTH - len(theoretical) - fudge + + + def msg(self, user, message, length=None): + """ + Send a message to a user or channel. + + The message will be split into multiple commands to the server if: + - The message contains any newline characters + - Any span between newline characters is longer than the given + line-length. + @param user: Username or channel name to which to direct the + message. @type user: C{str} - @param user: The username or channel name to which to direct the - message. + @param message: Text to send. @type message: C{str} - @param message: The text to send + @param length: Maximum number of octets to send in a single + command, including the IRC protocol framing. If C{None} is given + then L{IRCClient._safeMaximumLineLength} is used to determine a + value. @type length: C{int} - @param length: The maximum number of octets to send at a time. This - has the effect of turning a single call to msg() into multiple - commands to the server. This is useful when long messages may be - sent that would otherwise cause the server to kick us off or silently - truncate the text we are sending. If None is passed, the entire - message is always send in one command. """ - - fmt = "PRIVMSG %s :%%s" % (user,) + fmt = 'PRIVMSG %s :' % (user,) if length is None: - self.sendLine(fmt % (message,)) - else: - # NOTE: minimumLength really equals len(fmt) - 2 (for '%s') + n - # where n is how many bytes sendLine sends to end the line. - # n was magic numbered to 2, I think incorrectly - minimumLength = len(fmt) - if length <= minimumLength: - raise ValueError("Maximum length must exceed %d for message " - "to %s" % (minimumLength, user)) - lines = split(message, length - minimumLength) - map(lambda line, self=self, fmt=fmt: self.sendLine(fmt % line), - lines) + length = self._safeMaximumLineLength(fmt) + + # Account for the line terminator. + minimumLength = len(fmt) + 2 + if length <= minimumLength: + raise ValueError("Maximum length must exceed %d for message " + "to %s" % (minimumLength, user)) + for line in split(message, length - minimumLength): + self.sendLine(fmt + line) + def notice(self, user, message): """ @@ -1497,6 +1625,7 @@ """ self.sendLine("NOTICE %s :%s" % (user, message)) + def away(self, message=''): """ Mark this client as away. @@ -1507,7 +1636,6 @@ self.sendLine("AWAY :%s" % message) - def back(self): """ Clear the away status. @@ -1549,6 +1677,7 @@ self.username = nickname self.sendLine("USER %s %s %s :%s" % (self.username, hostname, servername, self.realname)) + def setNick(self, nickname): """ Set this client's nickname. @@ -1559,6 +1688,7 @@ self._attemptedNick = nickname self.sendLine("NICK %s" % nickname) + def quit(self, message = ''): """ Disconnect from the server @@ -1586,26 +1716,6 @@ self.ctcpMakeQuery(channel, [('ACTION', action)]) - def me(self, channel, action): - """ - Strike a pose. - - This function is deprecated since Twisted 9.0. Use describe(). - - @type channel: C{str} - @param channel: The name of the channel to have an action on. If it - has no prefix, C{'#'} will be prepended to it. - @type action: C{str} - @param action: The action to preform. - """ - warnings.warn("me() is deprecated since Twisted 9.0. Use IRCClient.describe().", - DeprecationWarning, stacklevel=2) - - if channel[0] not in CHANNEL_PREFIXES: - channel = '#' + channel - self.describe(channel, action) - - _pings = None _MAX_PINGRING = 12 @@ -1632,6 +1742,7 @@ for i in xrange(excess): del self._pings[byValue[i][1]] + def dccSend(self, user, file): if type(file) == types.StringType: file = open(file, 'r') @@ -1658,13 +1769,18 @@ self.ctcpMakeQuery(user, [('DCC', args)]) + def dccResume(self, user, fileName, port, resumePos): - """Send a DCC RESUME request to another user.""" + """ + Send a DCC RESUME request to another user. + """ self.ctcpMakeQuery(user, [ ('DCC', ['RESUME', fileName, port, resumePos])]) + def dccAcceptResume(self, user, fileName, port, resumePos): - """Send a DCC ACCEPT response to clients who have requested a resume. + """ + Send a DCC ACCEPT response to clients who have requested a resume. """ self.ctcpMakeQuery(user, [ ('DCC', ['ACCEPT', fileName, port, resumePos])]) @@ -1717,13 +1833,17 @@ """ raise IRCPasswordMismatch("Password Incorrect.") + def irc_RPL_WELCOME(self, prefix, params): """ Called when we have received the welcome from the server. """ + self.hostname = prefix self._registered = True self.nickname = self._attemptedNick self.signedOn() + self.startHeartbeat() + def irc_JOIN(self, prefix, params): """ @@ -1800,9 +1920,11 @@ channel = params[0] message = params[-1] - if not message: return # don't raise an exception if some idiot sends us a blank message + if not message: + # Don't raise an exception if we get blank message. + return - if message[0]==X_DELIM: + if message[0] == X_DELIM: m = ctcpExtract(message) if m['extended']: self.ctcpQuery(user, channel, m['extended']) @@ -1954,15 +2076,34 @@ ### Receiving a CTCP query from another party ### It is safe to leave these alone. + def ctcpQuery(self, user, channel, messages): - """Dispatch method for any CTCP queries received. """ - for m in messages: - method = getattr(self, "ctcpQuery_%s" % m[0], None) - if method: - method(user, channel, m[1]) - else: - self.ctcpUnknownQuery(user, channel, m[0], m[1]) + Dispatch method for any CTCP queries received. + + Duplicated CTCP queries are ignored and no dispatch is + made. Unrecognized CTCP queries invoke L{IRCClient.ctcpUnknownQuery}. + """ + seen = set() + for tag, data in messages: + method = getattr(self, 'ctcpQuery_%s' % tag, None) + if tag not in seen: + if method is not None: + method(user, channel, data) + else: + self.ctcpUnknownQuery(user, channel, tag, data) + seen.add(tag) + + + def ctcpUnknownQuery(self, user, channel, tag, data): + """ + Fallback handler for unrecognized CTCP queries. + + No CTCP I{ERRMSG} reply is made to remove a potential denial of service + avenue. + """ + log.msg('Unknown CTCP query from %r: %r %r' % (user, tag, data)) + def ctcpQuery_ACTION(self, user, channel, data): self.action(user, channel, data) @@ -2020,7 +2161,8 @@ self.ctcpMakeReply(nick, [('USERINFO', self.userinfo)]) def ctcpQuery_CLIENTINFO(self, user, channel, data): - """A master index of what CTCP tags this client knows. + """ + A master index of what CTCP tags this client knows. If no arguments are provided, respond with a list of known tags. If an argument is provided, provide human-readable help on @@ -2188,14 +2330,6 @@ # """ # raise NotImplementedError - def ctcpUnknownQuery(self, user, channel, tag, data): - nick = string.split(user,"!")[0] - self.ctcpMakeReply(nick, [('ERRMSG', - "%s %s: Unknown query '%s'" - % (tag, data, tag))]) - - log.msg("Unknown CTCP query from %s: %s %s\n" - % (user, tag, data)) def ctcpMakeReply(self, user, messages): """ @@ -2547,9 +2681,12 @@ self.client = client self.queryData = queryData + def buildProtocol(self, addr): p = self.protocol(client=self.client, queryData=self.queryData) p.factory = self + return p + def clientConnectionFailed(self, unused_connector, unused_reason): self.client.dcc_sessions.remove(self) @@ -2744,14 +2881,13 @@ X_DELIM = chr(001) def ctcpExtract(message): - """Extract CTCP data from a string. - - Returns a dictionary with two items: - - - C{'extended'}: a list of CTCP (tag, data) tuples - - C{'normal'}: a list of strings which were not inside a CTCP delimeter """ + Extract CTCP data from a string. + @return: A C{dict} containing two keys: + - C{'extended'}: A list of CTCP (tag, data) tuples. + - C{'normal'}: A list of strings which were not inside a CTCP delimiter. + """ extended_messages = [] normal_messages = [] retval = {'extended': extended_messages, diff -Nru twisted-words-10.0.0/twisted/words/protocols/jabber/client.py twisted-words-12.1.0/twisted/words/protocols/jabber/client.py --- twisted-words-10.0.0/twisted/words/protocols/jabber/client.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/protocols/jabber/client.py 2012-03-16 19:16:33.000000000 +0000 @@ -1,9 +1,8 @@ # -*- test-case-name: twisted.words.test.test_jabberclient -*- # -# Copyright (c) 2001-2009 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. -from twisted.internet import defer from twisted.words.xish import domish, xpath, utility from twisted.words.protocols.jabber import xmlstream, sasl, error from twisted.words.protocols.jabber.jid import JID @@ -37,7 +36,7 @@ @type xmlstream: L{xmlstream.XmlStream} @param xmlstream: XmlStream to use for transmission of this IQ - @type type: L{str} + @type type: C{str} @param type: IQ type identifier ('get' or 'set') """ @@ -59,7 +58,7 @@ Call this method to send this IQ request via the associated XmlStream. @param to: Jabber ID of the entity to send the request to - @type to: L{str} + @type to: C{str} @returns: Callback list for this IQ. Any callbacks added to this list will be fired when the result comes back. @@ -294,7 +293,7 @@ @param jid: Jabber ID to connect with. @type jid: L{jid.JID} @param password: password to authenticate with. - @type password: L{unicode} + @type password: C{unicode} @return: XML stream factory. @rtype: L{xmlstream.XmlStreamFactory} """ @@ -334,7 +333,7 @@ variable. @type jid: L{jid.JID} @ivar password: password to be used during SASL authentication. - @type password: L{unicode} + @type password: C{unicode} """ namespace = 'jabber:client' diff -Nru twisted-words-10.0.0/twisted/words/protocols/jabber/component.py twisted-words-12.1.0/twisted/words/protocols/jabber/component.py --- twisted-words-10.0.0/twisted/words/protocols/jabber/component.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/protocols/jabber/component.py 2012-03-16 19:16:33.000000000 +0000 @@ -1,6 +1,6 @@ # -*- test-case-name: twisted.words.test.test_jabbercomponent -*- # -# Copyright (c) 2001-2009 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -34,9 +34,9 @@ XML stream factory for external server-side components. @param componentid: JID of the component. - @type componentid: L{unicode} + @type componentid: C{unicode} @param password: password used to authenticate to the server. - @type password: L{str} + @type password: C{str} """ a = ConnectComponentAuthenticator(componentid, password) return xmlstream.XmlStreamFactory(a) @@ -84,10 +84,10 @@ def __init__(self, componentjid, password): """ - @type componentjid: L{str} + @type componentjid: C{str} @param componentjid: Jabber ID that this component wishes to bind to. - @type password: L{str} + @type password: C{str} @param password: Password/secret this component uses to authenticate. """ # Note that we are sending 'to' our desired component JID. diff -Nru twisted-words-10.0.0/twisted/words/protocols/jabber/error.py twisted-words-12.1.0/twisted/words/protocols/jabber/error.py --- twisted-words-10.0.0/twisted/words/protocols/jabber/error.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/protocols/jabber/error.py 2012-03-16 19:16:33.000000000 +0000 @@ -1,6 +1,6 @@ # -*- test-case-name: twisted.words.test.test_jabbererror -*- # -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -32,7 +32,7 @@ 'redirect': {'code': '302', 'type': 'modify'}, 'registration-required': {'code': '407', 'type': 'auth'}, 'remote-server-not-found': {'code': '404', 'type': 'cancel'}, - 'remove-server-timeout': {'code': '504', 'type': 'wait'}, + 'remote-server-timeout': {'code': '504', 'type': 'wait'}, 'resource-constraint': {'code': '500', 'type': 'wait'}, 'service-unavailable': {'code': '503', 'type': 'cancel'}, 'subscription-required': {'code': '407', 'type': 'auth'}, @@ -250,7 +250,7 @@ @return: Dictionary with extracted error information. If present, keys C{condition}, C{text}, C{textLang} have a string value, and C{appCondition} has an L{domish.Element} value. - @rtype: L{dict} + @rtype: C{dict} """ condition = None text = None diff -Nru twisted-words-10.0.0/twisted/words/protocols/jabber/ijabber.py twisted-words-12.1.0/twisted/words/protocols/jabber/ijabber.py --- twisted-words-10.0.0/twisted/words/protocols/jabber/ijabber.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/protocols/jabber/ijabber.py 2012-03-16 19:16:33.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -119,7 +119,7 @@ """ The XML stream has been closed. - Subsequent use of L{parent.send} will result in data being queued + Subsequent use of C{parent.send} will result in data being queued until a new connection has been established. @type reason: L{twisted.python.failure.Failure} @@ -170,7 +170,7 @@ Parent component has established a connection. At this point, authentication was succesful, and XML stanzas - can be exchanged over the XML stream L{xs}. This method can be used + can be exchanged over the XML stream C{xs}. This method can be used to setup observers for incoming stanzas. @param xs: XML Stream that represents the established connection. @@ -193,7 +193,7 @@ transport. At this point, no traffic has been exchanged over the XML stream. This - method can be used to change properties of the XML Stream (in L{xs}), + method can be used to change properties of the XML Stream (in C{xs}), the service manager or it's authenticator prior to stream initialization (including authentication). """ diff -Nru twisted-words-10.0.0/twisted/words/protocols/jabber/__init__.py twisted-words-12.1.0/twisted/words/protocols/jabber/__init__.py --- twisted-words-10.0.0/twisted/words/protocols/jabber/__init__.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/protocols/jabber/__init__.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,5 +1,5 @@ # -*- test-case-name: twisted.words.test -*- -# Copyright (c) 2001-2006 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. diff -Nru twisted-words-10.0.0/twisted/words/protocols/jabber/jid.py twisted-words-12.1.0/twisted/words/protocols/jabber/jid.py --- twisted-words-10.0.0/twisted/words/protocols/jabber/jid.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/protocols/jabber/jid.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,6 +1,6 @@ # -*- test-case-name: twisted.words.test.test_jabberjid -*- # -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ diff -Nru twisted-words-10.0.0/twisted/words/protocols/jabber/jstrports.py twisted-words-12.1.0/twisted/words/protocols/jabber/jstrports.py --- twisted-words-10.0.0/twisted/words/protocols/jabber/jstrports.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/protocols/jabber/jstrports.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,12 +1,12 @@ # -*- test-case-name: twisted.words.test -*- -# Copyright (c) 2001-2005 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ A temporary placeholder for client-capable strports, until we sufficient use cases get identified """ -from twisted.application import strports +from twisted.internet.endpoints import _parse def _parseTCPSSL(factory, domain, port): """ For the moment, parse TCP or SSL connections the same """ @@ -22,7 +22,7 @@ def parse(description, factory): - args, kw = strports._parse(description) + args, kw = _parse(description) return (args[0].upper(),) + _funcs[args[0]](factory, *args[1:], **kw) def client(description, factory): diff -Nru twisted-words-10.0.0/twisted/words/protocols/jabber/sasl_mechanisms.py twisted-words-12.1.0/twisted/words/protocols/jabber/sasl_mechanisms.py --- twisted-words-10.0.0/twisted/words/protocols/jabber/sasl_mechanisms.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/protocols/jabber/sasl_mechanisms.py 2012-03-16 19:16:33.000000000 +0000 @@ -1,6 +1,6 @@ # -*- test-case-name: twisted.words.test.test_jabbersaslmechanisms -*- # -# Copyright (c) 2001-2009 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -21,7 +21,7 @@ Get the initial client response, if defined for this mechanism. @return: initial client response string. - @rtype: L{str}. + @rtype: C{str}. """ @@ -30,9 +30,9 @@ Get the response to a server challenge. @param challenge: server challenge. - @type challenge: L{str}. + @type challenge: C{str}. @return: client response. - @rtype: L{str}. + @rtype: C{str}. """ @@ -122,7 +122,7 @@ Splits the challenge into a dictionary of directives with values. @return: challenge directives and their values. - @rtype: L{dict} of L{str} to L{str}. + @rtype: C{dict} of C{str} to C{str}. """ s = challenge paramDict = {} @@ -166,9 +166,9 @@ @param directives: dictionary of directives (names to their values). For certain directives, extra quotes are added, as needed. - @type directives: L{dict} of L{str} to L{str} + @type directives: C{dict} of C{str} to C{str} @return: message string. - @rtype: L{str}. + @rtype: C{str}. """ directive_list = [] @@ -189,7 +189,7 @@ Generate response-value. Creates a response to a challenge according to section 2.1.2.1 of - RFC 2831 using the L{charset}, L{realm} and L{nonce} directives + RFC 2831 using the C{charset}, C{realm} and C{nonce} directives from the challenge. """ diff -Nru twisted-words-10.0.0/twisted/words/protocols/jabber/sasl.py twisted-words-12.1.0/twisted/words/protocols/jabber/sasl.py --- twisted-words-10.0.0/twisted/words/protocols/jabber/sasl.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/protocols/jabber/sasl.py 2012-03-16 19:16:33.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2009 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -169,7 +169,7 @@ sent along. @param data: initial client response. - @type data: L{str} or L{None}. + @type data: C{str} or C{None}. """ auth = domish.Element((NS_XMPP_SASL, 'auth')) @@ -184,7 +184,7 @@ Send response to a challenge. @param data: client response. - @type data: L{str}. + @type data: C{str}. """ response = domish.Element((NS_XMPP_SASL, 'response')) diff -Nru twisted-words-10.0.0/twisted/words/protocols/jabber/xmlstream.py twisted-words-12.1.0/twisted/words/protocols/jabber/xmlstream.py --- twisted-words-10.0.0/twisted/words/protocols/jabber/xmlstream.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/protocols/jabber/xmlstream.py 2012-03-16 19:16:33.000000000 +0000 @@ -1,6 +1,6 @@ # -*- test-case-name: twisted.words.test.test_jabberxmlstream -*- # -# Copyright (c) 2001-2009 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -105,10 +105,10 @@ A stream is considered to have started when the start tag of the root element has been received. - This examines L{rootElement} to see if there is a version attribute. + This examines C{rootElement} to see if there is a version attribute. If absent, C{0.0} is assumed per RFC 3920. Subsequently, the minimum of the version from the received stream header and the - value stored in L{xmlstream} is taken and put back in {xmlstream}. + value stored in L{xmlstream} is taken and put back in L{xmlstream}. Extensions of this method can extract more information from the stream header and perform checks on them, optionally sending @@ -214,7 +214,7 @@ Called by the XmlStream when the stream has started. This extends L{Authenticator.streamStarted} to extract further stream - headers from L{rootElement}, optionally wait for stream features being + headers from C{rootElement}, optionally wait for stream features being received and then call C{initializeStream}. """ @@ -266,7 +266,7 @@ Called by the XmlStream when the stream has started. This extends L{Authenticator.streamStarted} to extract further - information from the stream headers from L{rootElement}. + information from the stream headers from C{rootElement}. """ Authenticator.streamStarted(self, rootElement) @@ -279,7 +279,7 @@ for prefix, uri in rootElement.localPrefixes.iteritems(): self.xmlstream.prefixes[uri] = prefix - self.xmlstream.sid = randbytes.secureRandom(8).encode('hex') + self.xmlstream.sid = unicode(randbytes.secureRandom(8).encode('hex')) @@ -299,10 +299,10 @@ of the connection. @cvar feature: tuple of (uri, name) of the stream feature root element. - @type feature: tuple of (L{str}, L{str}) + @type feature: tuple of (C{str}, C{str}) @ivar required: whether the stream feature is required to be advertized by the receiving entity. - @type required: L{bool} + @type required: C{bool} """ implements(ijabber.IInitiatingInitializer) @@ -320,7 +320,7 @@ Checks if the receiving entity advertizes the stream feature. If it does, the initialization is started. If it is not advertized, and the - C{required} instance variable is L{True}, it raises + C{required} instance variable is C{True}, it raises L{FeatureNotAdvertized}. Otherwise, the initialization silently succeeds. """ @@ -387,7 +387,7 @@ of initializers, so a proper exception L{TLSRequired} can be raised. @cvar wanted: indicates if TLS negotiation is wanted. - @type wanted: L{bool} + @type wanted: C{bool} """ feature = (NS_XMPP_TLS, 'starttls') @@ -455,25 +455,25 @@ receiving the stream header of the peer, it is set to the minimum of that value and the version on the received header. - @type version: (L{int}, L{int}) + @type version: (C{int}, C{int}) @ivar namespace: default namespace URI for stream - @type namespace: L{str} + @type namespace: C{unicode} @ivar thisEntity: JID of this entity @type thisEntity: L{JID} @ivar otherEntity: JID of the peer entity @type otherEntity: L{JID} @ivar sid: session identifier - @type sid: L{str} + @type sid: C{unicode} @ivar initiating: True if this is the initiating stream - @type initiating: L{bool} + @type initiating: C{bool} @ivar features: map of (uri, name) to stream features element received from the receiving entity. - @type features: L{dict} of (L{str}, L{str}) to L{domish.Element}. + @type features: C{dict} of (C{unicode}, C{unicode}) to L{domish.Element}. @ivar prefixes: map of URI to prefixes that are to appear on stream header. - @type prefixes: L{dict} of L{str} to L{str} + @type prefixes: C{dict} of C{unicode} to C{unicode} @ivar initializers: list of stream initializer objects - @type initializers: L{list} of objects that provide L{IInitializer} + @type initializers: C{list} of objects that provide L{IInitializer} @ivar authenticator: associated authenticator that uses C{initializers} to initialize the XML stream. """ @@ -778,7 +778,7 @@ @type xmlstream: L{xmlstream.XmlStream} @param xmlstream: XmlStream to use for transmission of this IQ - @type stanzaType: L{str} + @type stanzaType: C{str} @param stanzaType: IQ type identifier ('get' or 'set') """ domish.Element.__init__(self, (None, "iq")) @@ -947,7 +947,7 @@ L{XMPPHandler} itself, so this is not recursive. @ivar handlers: List of protocol handlers. - @type handlers: L{list} of objects providing + @type handlers: C{list} of objects providing L{IXMPPHandler} """ @@ -993,13 +993,13 @@ @ivar xmlstream: currently managed XML stream @type xmlstream: L{XmlStream} @ivar logTraffic: if true, log all traffic. - @type logTraffic: L{bool} + @type logTraffic: C{bool} @ivar _initialized: Whether the stream represented by L{xmlstream} has been initialized. This is used when caching outgoing stanzas. @type _initialized: C{bool} @ivar _packetQueue: internal buffer of unsent data. See L{send} for details. - @type _packetQueue: L{list} + @type _packetQueue: C{list} """ logTraffic = False @@ -1090,7 +1090,7 @@ """ - def _disconnected(self, _): + def _disconnected(self, reason): """ Called when the stream has been closed. @@ -1104,7 +1104,7 @@ # Notify all child services which implement # the IService interface for e in self: - e.connectionLost(None) + e.connectionLost(reason) def send(self, obj): @@ -1125,7 +1125,7 @@ __all__ = ['Authenticator', 'BaseFeatureInitiatingInitializer', - 'ConnectAuthenticator', 'ConnectionLost', 'FeatureNotAdvertized', + 'ConnectAuthenticator', 'FeatureNotAdvertized', 'INIT_FAILED_EVENT', 'IQ', 'ListenAuthenticator', 'NS_STREAMS', 'NS_XMPP_TLS', 'Reset', 'STREAM_AUTHD_EVENT', 'STREAM_CONNECTED_EVENT', 'STREAM_END_EVENT', 'STREAM_ERROR_EVENT', diff -Nru twisted-words-10.0.0/twisted/words/protocols/jabber/xmpp_stringprep.py twisted-words-12.1.0/twisted/words/protocols/jabber/xmpp_stringprep.py --- twisted-words-10.0.0/twisted/words/protocols/jabber/xmpp_stringprep.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/protocols/jabber/xmpp_stringprep.py 2012-03-16 19:16:33.000000000 +0000 @@ -1,6 +1,6 @@ # -*- test-case-name: twisted.words.test.test_jabberxmppstringprep -*- # -# Copyright (c) 2001-2005 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. import sys, warnings @@ -26,7 +26,12 @@ else: import stringprep - import unicodedata + # We require Unicode version 3.2. Python 2.5 and later provide this as + # a separate object. Before that the unicodedata module uses 3.2. + try: + from unicodedata import ucd_3_2_0 as unicodedata + except: + import unicodedata from encodings import idna crippled = False @@ -70,7 +75,7 @@ self.map = map_table_function class EmptyMappingTable: - + implements(IMappingTable) def __init__(self, in_table_function): @@ -128,7 +133,7 @@ for c in string: if stringprep.in_table_a1(c): raise UnicodeError, "Unassigned code point %s" % repr(c) - + def check_bidirectionals(self, string): found_LCat = False found_RandALCat = False @@ -152,21 +157,21 @@ This class implements preparing internationalized domain names using the rules defined in RFC 3491, section 4 (Conversion operations). - + We do not perform step 4 since we deal with unicode representations of domain names and do not convert from or to ASCII representations using - punycode encoding. When such a conversion is needed, the L{idna} standard + punycode encoding. When such a conversion is needed, the C{idna} standard library provides the C{ToUnicode()} and C{ToASCII()} functions. Note that - L{idna} itself assumes UseSTD3ASCIIRules to be false. - + C{idna} itself assumes UseSTD3ASCIIRules to be false. + The following steps are performed by C{prepare()}: - + - Split the domain name in labels at the dots (RFC 3490, 3.1) - Apply nameprep proper on each label (RFC 3491) - Enforce the restrictions on ASCII characters in host names by assuming STD3ASCIIRules to be true. (STD 3) - Rejoin the labels using the label separator U+002E (full stop). - + """ # Prohibited characters. @@ -218,7 +223,7 @@ resourceprep = Profile(normalize=False, check_unassigneds=False, check_bidi=False) - + else: C_11 = LookupTableFromFunction(stringprep.in_table_c11) C_12 = LookupTableFromFunction(stringprep.in_table_c12) diff -Nru twisted-words-10.0.0/twisted/words/protocols/msn.py twisted-words-12.1.0/twisted/words/protocols/msn.py --- twisted-words-10.0.0/twisted/words/protocols/msn.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/protocols/msn.py 2011-03-16 03:06:28.000000000 +0000 @@ -1,5 +1,5 @@ # -*- test-case-name: twisted.words.test -*- -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -78,7 +78,7 @@ from twisted.python import failure, log from twisted.python.hashlib import md5 from twisted.internet import reactor -from twisted.internet.defer import Deferred +from twisted.internet.defer import Deferred, execute from twisted.internet.protocol import ClientFactory try: from twisted.internet.ssl import ClientContextFactory @@ -125,6 +125,17 @@ CR = "\r" LF = "\n" + +class SSLRequired(Exception): + """ + This exception is raised when it is necessary to talk to a passport server + using SSL, but the necessary SSL dependencies are unavailable. + + @since: 11.0 + """ + + + def checkParamLen(num, expected, cmd, error=None): if error == None: error = "Invalid Number of Parameters for %s" % cmd @@ -160,11 +171,19 @@ p = '/' + p return h,p + def _login(userHandle, passwd, nexusServer, cached=0, authData=''): """ This function is used internally and should not ever be called directly. + + @raise SSLRequired: If there is no SSL support available. """ + if ClientContextFactory is None: + raise SSLRequired( + 'Connecting to the Passport server requires SSL, but SSL is ' + 'unavailable.') + cb = Deferred() def _cb(server, auth): loginFac = ClientFactory() @@ -824,7 +843,9 @@ elif params[2].upper() == "S": # we need to obtain auth from a passport server f = self.factory - d = _login(f.userHandle, f.password, f.passportServer, authData=params[3]) + d = execute( + _login, f.userHandle, f.password, f.passportServer, + authData=params[3]) d.addCallback(self._passportLogin) d.addErrback(self._passportError) @@ -839,9 +860,17 @@ elif result[0] == LOGIN_FAILURE: self.loginFailure(result[1]) + def _passportError(self, failure): + """ + Handle a problem logging in via the Passport server, passing on the + error as a string message to the C{loginFailure} callback. + """ + if failure.check(SSLRequired): + failure = failure.getErrorMessage() self.loginFailure("Exception while authenticating: %s" % failure) + def handle_CHG(self, params): checkParamLen(len(params), 3, 'CHG') id = int(params[0]) @@ -1078,13 +1107,14 @@ listVersion = self.factory.contacts.version self.syncList(listVersion).addCallback(self.listSynchronized) + def loginFailure(self, message): """ Called when the client fails to login. @param message: a message indicating the problem that was encountered """ - pass + def gotProfile(self, message): """ diff -Nru twisted-words-10.0.0/twisted/words/protocols/oscar.py twisted-words-12.1.0/twisted/words/protocols/oscar.py --- twisted-words-10.0.0/twisted/words/protocols/oscar.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/protocols/oscar.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,5 +1,5 @@ # -*- test-case-name: twisted.words.test -*- -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. diff -Nru twisted-words-10.0.0/twisted/words/protocols/toc.py twisted-words-12.1.0/twisted/words/protocols/toc.py --- twisted-words-10.0.0/twisted/words/protocols/toc.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/protocols/toc.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,1622 +0,0 @@ -# -*- test-case-name: twisted.words.test -*- -# Copyright (c) 2001-2005 Twisted Matrix Laboratories. -# See LICENSE for details. - -""" -Implements a AOL Instant Messenger TOC server and client, using the Twisted -framework. - -TODO: -info,dir: see how gaim connects for this...it may never work if it tries to -connect to the aim server automatically - -This module is deprecated. - -Maintainer: Paul Swartz -""" - -import warnings -warnings.warn( - "twisted.words.protocols.toc is deprecated since Twisted 9.0. " - "Use twisted.words.protocols.oscar instead.", - category=DeprecationWarning, - stacklevel=2) - - -# twisted imports -from twisted.internet import reactor, protocol -from twisted.python import log - -# base imports -import struct -import string -import time -import base64 -import os -import StringIO - -SIGNON,DATA,ERROR,SIGNOFF,KEEP_ALIVE=range(1,6) -PERMITALL,DENYALL,PERMITSOME,DENYSOME=range(1,5) - -DUMMY_CHECKSUM = -559038737 # 0xdeadbeef - -def quote(s): - rep=['\\','$','{','}','[',']','(',')','"'] - for r in rep: - s=string.replace(s,r,"\\"+r) - return "\""+s+"\"" - -def unquote(s): - if s=="": return "" - if s[0]!='"': return s - r=string.replace - s=s[1:-1] - s=r(s,"\\\\","\\") - s=r(s,"\\$","$") - s=r(s,"\\{","{") - s=r(s,"\\}","}") - s=r(s,"\\[","[") - s=r(s,"\\]","]") - s=r(s,"\\(","(") - s=r(s,"\\)",")") - s=r(s,"\\\"","\"") - return s - -def unquotebeg(s): - for i in range(1,len(s)): - if s[i]=='"' and s[i-1]!='\\': - q=unquote(s[:i+1]) - return [q,s[i+2:]] - -def unroast(pw): - roaststring="Tic/Toc" - pw=string.lower(pw[2:]) - r="" - count=0 - hex=["0","1","2","3","4","5","6","7","8","9","a","b","c","d","e","f"] - while pw: - st,pw=pw[:2],pw[2:] - value=(16*hex.index(st[0]))+hex.index(st[1]) - xor=ord(roaststring[count]) - count=(count+1)%len(roaststring) - r=r+chr(value^xor) - return r - -def roast(pw): - # contributed by jemfinch on #python - key="Tic/Toc" - ro="0x" - i=0 - ascii=map(ord,pw) - for c in ascii: - ro=ro+'%02x'%(c^ord(key[i%len(key)])) - i=i+1 - return string.lower(ro) - -def checksum(b): - return DUMMY_CHECKSUM # do it like gaim does, since the checksum - # formula doesn't work -## # used in file transfers -## check0 = check1 = 0x00ff -## for i in range(len(b)): -## if i%2: -## if ord(b[i])>check1: -## check1=check1+0x100 # wrap -## if check0==0: -## check0=0x00ff -## if check1==0x100: -## check1=check1-1 -## else: -## check0=check0-1 -## check1=check1-ord(b[i]) -## else: -## if ord(b[i])>check0: # wrap -## check0=check0+0x100 -## if check1==0: -## check1=0x00ff -## if check0==0x100: -## check0=check0-1 -## else: -## check1=check1-1 -## check0=check0-ord(b[i]) -## check0=check0 & 0xff -## check1=check1 & 0xff -## checksum=(long(check0)*0x1000000)+(long(check1)*0x10000) -## return checksum - -def checksum_file(f): - return DUMMY_CHECKSUM # do it like gaim does, since the checksum - # formula doesn't work -## check0=check1=0x00ff -## i=0 -## while 1: -## b=f.read() -## if not b: break -## for char in b: -## i=not i -## if i: -## if ord(char)>check1: -## check1=check1+0x100 # wrap -## if check0==0: -## check0=0x00ff -## if check1==0x100: -## check1=check1-1 -## else: -## check0=check0-1 -## check1=check1-ord(char) -## else: -## if ord(char)>check0: # wrap -## check0=check0+0x100 -## if check1==0: -## check1=0x00ff -## if check0==0x100: -## check0=check0-1 -## else: -## check1=check1-1 -## check0=check0-ord(char) -## check0=check0 & 0xff -## check1=check1 & 0xff -## checksum=(long(check0)*0x1000000)+(long(check1)*0x10000) -## return checksum - -def normalize(s): - s=string.lower(s) - s=string.replace(s," ","") - return s - - -class TOCParseError(ValueError): - pass - - -class TOC(protocol.Protocol): - users={} - - def connectionMade(self): - # initialization of protocol - self._buf="" - self._ourseqnum=0L - self._theirseqnum=0L - self._mode="Flapon" - self._onlyflaps=0 - self._laststatus={} # the last status for a user - self.username=None - self.permitmode=PERMITALL - self.permitlist=[] - self.denylist=[] - self.buddylist=[] - self.signontime=0 - self.idletime=0 - self.userinfo="
    " - self.userclass=" O" - self.away="" - self.saved=None - - def _debug(self,data): - log.msg(data) - - def connectionLost(self, reason): - self._debug("dropped connection from %s" % self.username) - try: - del self.factory.users[self.username] - except: - pass - for k in self.factory.chatroom.keys(): - try: - self.factory.chatroom[k].leave(self) - except TOCParseError: - pass - if self.saved: - self.factory.savedusers[self.username]=self.saved - self.updateUsers() - - def sendFlap(self,type,data): - """ - send a FLAP to the client - """ - send="*" - self._debug(data) - if type==DATA: - data=data+"\000" - length=len(data) - send=send+struct.pack("!BHH",type,self._ourseqnum,length) - send=send+data - self._ourseqnum=self._ourseqnum+1 - if self._ourseqnum>(256L**4): - self._ourseqnum=0 - self.transport.write(send) - - def dataReceived(self,data): - self._buf=self._buf+data - try: - func=getattr(self,"mode%s"%self._mode) - except: - return - self._mode=func() - if self._onlyflaps and self.isFlap(): self.dataReceived("") - - def isFlap(self): - """ - tests to see if a flap is actually on the buffer - """ - if self._buf=='': return 0 - if self._buf[0]!="*": return 0 - if len(self._buf)<6: return 0 - foo,type,seqnum,length=struct.unpack("!BBHH",self._buf[:6]) - if type not in range(1,6): return 0 - if len(self._buf)<6+length: return 0 - return 1 - - def readFlap(self): - """ - read the first FLAP off self._buf, raising errors if it isn't in the right form. - the FLAP is the basic TOC message format, and is logically equivilant to a packet in TCP - """ - if self._buf=='': return None - if self._buf[0]!="*": - raise TOCParseError - if len(self._buf)<6: return None - foo,type,seqnum,length=struct.unpack("!BBHH",self._buf[:6]) - if len(self._buf)<6+length: return None - data=self._buf[6:6+length] - self._buf=self._buf[6+length:] - if data and data[-1]=="\000": - data=data[:-1] - self._debug([type,data]) - return [type,data] - - #def modeWeb(self): - # try: - # line,rest=string.split(self._buf,"\n",1) - # get,username,http=string.split(line," ",2) - # except: - # return "Web" # not enough data - # foo,type,username=string.split(username,"/") - # if type=="info": - # user=self.factory.users[username] - # text="User Information for %sUsername: %s
    \nWarning Level: %s%
    \n Online Since: %s
    \nIdle Minutes: %s
    \n

    \n%s\n

    \n"%(user.saved.nick, user.saved.nick, user.saved.evilness, time.asctime(user.signontime), int((time.time()-user.idletime)/60), user.userinfo) - # self.transport.write("HTTP/1.1 200 OK\n") - # self.transport.write("Content-Type: text/html\n") - # self.transport.write("Content-Length: %s\n\n"%len(text)) - # self.transport.write(text) - # self.loseConnection() - - def modeFlapon(self): - #if self._buf[:3]=="GET": self.modeWeb() # TODO: get this working - if len(self._buf)<10: return "Flapon" # not enough bytes - flapon,self._buf=self._buf[:10],self._buf[10:] - if flapon!="FLAPON\r\n\r\n": - raise TOCParseError - self.sendFlap(SIGNON,"\000\000\000\001") - self._onlyflaps=1 - return "Signon" - - def modeSignon(self): - flap=self.readFlap() - if flap==None: - return "Signon" - if flap[0]!=SIGNON: raise TOCParseError - version,tlv,unlength=struct.unpack("!LHH",flap[1][:8]) - if version!=1 or tlv!=1 or unlength+8!=len(flap[1]): - raise TOCParseError - self.username=normalize(flap[1][8:]) - if self.username in self.factory.savedusers.keys(): - self.saved=self.factory.savedusers[self.username] - else: - self.saved=SavedUser() - self.saved.nick=self.username - return "TocSignon" - - def modeTocSignon(self): - flap=self.readFlap() - if flap==None: - return "TocSignon" - if flap[0]!=DATA: raise TOCParseError - data=string.split(flap[1]," ") - if data[0]!="toc_signon": raise TOCParseError - for i in data: - if not i:data.remove(i) - password=unroast(data[4]) - if not(self.authorize(data[1],int(data[2]),data[3],password)): - self.sendError(BAD_NICKNAME) - self.transport.loseConnection() - return - self.sendFlap(DATA,"SIGN_ON:TOC1.0") - self.sendFlap(DATA,"NICK:%s"%self.saved.nick) - self.sendFlap(DATA,"CONFIG:%s"%self.saved.config) - # sending user configuration goes here - return "Connected" - - def authorize(self,server,port,username,password): - if self.saved.password=="": - self.saved.password=password - return 1 - else: - return self.saved.password==password - - def modeConnected(self): - flap=self.readFlap() - while flap!=None: - if flap[0] not in [DATA,KEEP_ALIVE]: raise TOCParseError - flapdata=string.split(flap[1]," ",1) - tocname=flapdata[0][4:] - if len(flapdata)==2: - data=flapdata[1] - else: - data="" - func=getattr(self,"toc_"+tocname,None) - if func!=None: - func(data) - else: - self.toc_unknown(tocname,data) - flap=self.readFlap() - return "Connected" - - def toc_unknown(self,tocname,data): - self._debug("unknown! %s %s" % (tocname,data)) - - def toc_init_done(self,data): - """ - called when all the setup is done. - - toc_init_done - """ - self.signontime=int(time.time()) - self.factory.users[self.username]=self - self.updateUsers() - - def toc_add_permit(self,data): - """ - adds users to the permit list. if the list is null, then set the mode to DENYALL - """ - if data=="": - self.permitmode=DENYALL - self.permitlist=[] - self.denylist=[] - else: - self.permitmode=PERMITSOME - self.denylist=[] - users=string.split(data," ") - map(self.permitlist.append,users) - self.updateUsers() - - def toc_add_deny(self,data): - """ - adds users to the deny list. if the list is null, then set the mode to PERMITALL - """ - if data=="": - self.permitmode=PERMITALL - self.permitlist=[] - self.denylist=[] - else: - self.permitmode=DENYSOME - self.permitlist=[] - users=string.split(data," ") - map(self.denylist.append,users) - self.updateUsers() - - def toc_evil(self,data): - """ - warns a user. - - toc_evil - """ - username,nora=string.split(data," ") - if nora=="anon": - user="" - else: - user=self.saved.nick - if not(self.factory.users.has_key(username)): - self.sendError(CANT_WARN,username) - return - if self.factory.users[username].saved.evilness>=100: - self.sendError(CANT_WARN,username) - return - self.factory.users[username].evilFrom(user) - - def toc_add_buddy(self,data): - """ - adds users to the buddy list - - toc_add_buddy [] []... - """ - buddies=map(normalize,string.split(data," ")) - for b in buddies: - if b not in self.buddylist: - self.buddylist.append(b) - for buddy in buddies: - try: - buddy=self.factory.users[buddy] - except: - pass - else: - self.buddyUpdate(buddy) - - def toc_remove_buddy(self,data): - """ - removes users from the buddy list - - toc_remove_buddy [] []... - """ - buddies=string.split(data," ") - for buddy in buddies: - try: - self.buddylist.remove(normalize(buddy)) - except: pass - - def toc_send_im(self,data): - """ - incoming instant message - - toc_send_im [auto] - """ - username,data=string.split(data," ",1) - auto=0 - if data[-4:]=="auto": - auto=1 - data=data[:-5] - data=unquote(data) - if not(self.factory.users.has_key(username)): - self.sendError(NOT_AVAILABLE,username) - return - user=self.factory.users[username] - if not(self.canContact(user)): - self.sendError(NOT_AVAILABLE,username) - return - user.hearWhisper(self,data,auto) - - def toc_set_info(self,data): - """ - set the users information, retrivable with toc_get_info - - toc_set_info - """ - info=unquote(data) - self._userinfo=info - - def toc_set_idle(self,data): - """ - set/unset idle - - toc_set_idle - """ - seconds=int(data) - self.idletime=time.time()-seconds # time when they started being idle - self.updateUsers() - - def toc_set_away(self,data): - """ - set/unset away message - - toc_set_away [] - """ - away=unquote(data) - if not self.away and away: # setting an away message - self.away=away - self.userclass=self.userclass+'U' - self.updateUsers() - elif self.away and not away: # coming back - self.away="" - self.userclass=self.userclass[:2] - self.updateUsers() - else: - raise TOCParseError - - def toc_chat_join(self,data): - """ - joins the chat room. - - toc_chat_join - """ - exchange,name=string.split(data," ",1) - self.factory.getChatroom(int(exchange),unquote(name)).join(self) - - def toc_chat_invite(self,data): - """ - invite others to the room. - - toc_chat_invite []... - """ - id,data=string.split(data," ",1) - id=int(id) - message,data=unquotebeg(data) - buddies=string.split(data," ") - for b in buddies: - room=self.factory.chatroom[id] - bud=self.factory.users[b] - bud.chatInvite(room,self,message) - - def toc_chat_accept(self,data): - """ - accept an invitation. - - toc_chat_accept - """ - id=int(data) - self.factory.chatroom[id].join(self) - - def toc_chat_send(self,data): - """ - send a message to the chat room. - - toc_chat_send - """ - id,message=string.split(data," ",1) - id=int(id) - message=unquote(message) - self.factory.chatroom[id].say(self,message) - - def toc_chat_whisper(self,data): - id,user,message=string.split(data," ",2) - id=int(id) - room=self.factory.chatroom[id] - message=unquote(message) - self.factory.users[user].chatWhisper(room,self,message) - - def toc_chat_leave(self,data): - """ - leave the room. - - toc_chat_leave - """ - id=int(data) - self.factory.chatroom[id].leave(self) - - def toc_set_config(self,data): - """ - set the saved config. this gets send when you log in. - - toc_set_config - """ - self.saved.config=unquote(data) - - def toc_get_info(self,data): - """ - get the user info for a user - - toc_get_info - """ - if not self.factory.users.has_key(data): - self.sendError(901,data) - return - self.sendFlap(2,"GOTO_URL:TIC:info/%s"%data) - - def toc_format_nickname(self,data): - """ - change the format of your nickname. - - toc_format_nickname - """ - # XXX may not work - nick=unquote(data) - if normalize(nick)==self.username: - self.saved.nick=nick - self.sendFlap(2,"ADMIN_NICK_STATUS:0") - else: - self.sendError(BAD_INPUT) - - def toc_change_passwd(self,data): - orig,data=unquotebeg(data) - new=unquote(data) - if orig==self.saved.password: - self.saved.password=new - self.sendFlap(2,"ADMIN_PASSWD_STATUS:0") - else: - self.sendError(BAD_INPUT) - - def sendError(self,code,*varargs): - """ - send an error to the user. listing of error messages is below. - """ - send="ERROR:%s"%code - for v in varargs: - send=send+":"+v - self.sendFlap(DATA,send) - - def updateUsers(self): - """ - Update the users who have us on their buddylist. - Called when the user changes anything (idle,away) so people can get updates. - """ - for user in self.factory.users.values(): - if self.username in user.buddylist and self.canContact(user): - user.buddyUpdate(self) - - def getStatus(self,user): - if self.canContact(user): - if self in self.factory.users.values():ol='T' - else: ol='F' - idle=0 - if self.idletime: - idle=int((time.time()-self.idletime)/60) - return (self.saved.nick,ol,self.saved.evilness,self.signontime,idle,self.userclass) - else: - return (self.saved.nick,'F',0,0,0,self.userclass) - - def canContact(self,user): - if self.permitmode==PERMITALL: return 1 - elif self.permitmode==DENYALL: return 0 - elif self.permitmode==PERMITSOME: - if user.username in self.permitlist: return 1 - else: return 0 - elif self.permitmode==DENYSOME: - if user.username in self.denylist: return 0 - else: return 1 - else: - assert 0,"bad permitmode %s" % self.permitmode - - def buddyUpdate(self,user): - """ - Update the buddy. Called from updateUsers() - """ - if not self.canContact(user): return - status=user.getStatus(self) - if not self._laststatus.has_key(user): - self._laststatus[user]=() - if self._laststatus[user]!=status: - send="UPDATE_BUDDY:%s:%s:%s:%s:%s:%s"%status - self.sendFlap(DATA,send) - self._laststatus[user]=status - - def hearWhisper(self,user,data,auto=0): - """ - Called when you get an IM. If auto=1, it's an autoreply from an away message. - """ - if not self.canContact(user): return - if auto: auto='T' - else: auto='F' - send="IM_IN:%s:%s:%s"%(user.saved.nick,auto,data) - self.sendFlap(DATA,send) - - def evilFrom(self,user): - if user=="": - percent=0.03 - else: - percent=0.1 - self.saved.evilness=self.saved.evilness+int((100-self.saved.evilness)*percent) - self.sendFlap(2,"EVILED:%s:%s"%(self.saved.evilness,user)) - self.updateUsers() - - def chatJoin(self,room): - self.sendFlap(2,"CHAT_JOIN:%s:%s"%(room.id,room.name)) - f="CHAT_UPDATE_BUDDY:%s:T"%room.id - for u in room.users: - if u!=self: - u.chatUserUpdate(room,self) - f=f+":"+u.saved.nick - self.sendFlap(2,f) - - def chatInvite(self,room,user,message): - if not self.canContact(user): return - self.sendFlap(2,"CHAT_INVITE:%s:%s:%s:%s"%(room.name,room.id,user.saved.nick,message)) - - def chatUserUpdate(self,room,user): - if user in room.users: - inroom='T' - else: - inroom='F' - self.sendFlap(2,"CHAT_UPDATE_BUDDY:%s:%s:%s"%(room.id,inroom,user.saved.nick)) - - def chatMessage(self,room,user,message): - if not self.canContact(user): return - self.sendFlap(2,"CHAT_IN:%s:%s:F:%s"%(room.id,user.saved.nick,message)) - - def chatWhisper(self,room,user,message): - if not self.canContact(user): return - self.sendFlap(2,"CHAT_IN:%s:%s:T:%s"%(room.id,user.saved.nick,message)) - - def chatLeave(self,room): - self.sendFlap(2,"CHAT_LEFT:%s"%(room.id)) - - -class Chatroom: - def __init__(self,fac,exchange,name,id): - self.exchange=exchange - self.name=name - self.id=id - self.factory=fac - self.users=[] - - def join(self,user): - if user in self.users: - return - self.users.append(user) - user.chatJoin(self) - - def leave(self,user): - if user not in self.users: - raise TOCParseError - self.users.remove(user) - user.chatLeave(self) - for u in self.users: - u.chatUserUpdate(self,user) - if len(self.users)==0: - self.factory.remChatroom(self) - - def say(self,user,message): - for u in self.users: - u.chatMessage(self,user,message) - - -class SavedUser: - def __init__(self): - self.config="" - self.nick="" - self.password="" - self.evilness=0 - - -class TOCFactory(protocol.Factory): - def __init__(self): - self.users={} - self.savedusers={} - self.chatroom={} - self.chatroomid=0 - - def buildProtocol(self,addr): - p=TOC() - p.factory=self - return p - - def getChatroom(self,exchange,name): - for i in self.chatroom.values(): - if normalize(i.name)==normalize(name): - return i - self.chatroom[self.chatroomid]=Chatroom(self,exchange,name,self.chatroomid) - self.chatroomid=self.chatroomid+1 - return self.chatroom[self.chatroomid-1] - - def remChatroom(self,room): - id=room.id - del self.chatroom[id] - -MAXARGS={} -MAXARGS["CONFIG"]=0 -MAXARGS["NICK"]=0 -MAXARGS["IM_IN"]=2 -MAXARGS["UPDATE_BUDDY"]=5 -MAXARGS["ERROR"]=-1 -MAXARGS["EVILED"]=1 -MAXARGS["CHAT_JOIN"]=1 -MAXARGS["CHAT_IN"]=3 -MAXARGS["CHAT_UPDATE_BUDDY"]=-1 -MAXARGS["CHAT_INVITE"]=3 -MAXARGS["CHAT_LEFT"]=0 -MAXARGS["ADMIN_NICK_STATUS"]=0 -MAXARGS["ADMIN_PASSWD_STATUS"]=0 - - -class TOCClient(protocol.Protocol): - def __init__(self,username,password,authhost="login.oscar.aol.com",authport=5190): - - self.username=normalize(username) # our username - self._password=password # our password - self._mode="SendNick" # current mode - self._ourseqnum=19071 # current sequence number (for sendFlap) - self._authhost=authhost # authorization host - self._authport=authport # authorization port - self._online=0 # are we online? - self._buddies=[] # the current buddy list - self._privacymode=PERMITALL # current privacy mode - self._permitlist=[] # list of users on the permit list - self._roomnames={} # the names for each of the rooms we're in - self._receivedchatmembers={} # have we gotten who's in our room yet? - self._denylist=[] - self._cookies={} # for file transfers - self._buf='' # current data buffer - self._awaymessage='' - - def _debug(self,data): - log.msg(data) - - def sendFlap(self,type,data): - if type==DATA: - data=data+"\000" - length=len(data) - s="*" - s=s+struct.pack("!BHH",type,self._ourseqnum,length) - s=s+data - self._ourseqnum=self._ourseqnum+1 - if self._ourseqnum>(256*256+256): - self._ourseqnum=0 - self._debug(data) - self.transport.write(s) - - def isFlap(self): - """ - tests to see if a flap is actually on the buffer - """ - if self._buf=='': return 0 - if self._buf[0]!="*": return 0 - if len(self._buf)<6: return 0 - foo,type,seqnum,length=struct.unpack("!BBHH",self._buf[:6]) - if type not in range(1,6): return 0 - if len(self._buf)<6+length: return 0 - return 1 - - def readFlap(self): - if self._buf=='': return None - if self._buf[0]!="*": - raise TOCParseError - if len(self._buf)<6: return None - foo,type,seqnum,length=struct.unpack("!BBHH",self._buf[:6]) - if len(self._buf)<6+length: return None - data=self._buf[6:6+length] - self._buf=self._buf[6+length:] - if data and data[-1]=="\000": - data=data[:-1] - return [type,data] - - def connectionMade(self): - self._debug("connection made! %s" % self.transport) - self.transport.write("FLAPON\r\n\r\n") - - def connectionLost(self, reason): - self._debug("connection lost!") - self._online=0 - - def dataReceived(self,data): - self._buf=self._buf+data - while self.isFlap(): - flap=self.readFlap() - func=getattr(self,"mode%s"%self._mode) - func(flap) - - def modeSendNick(self,flap): - if flap!=[1,"\000\000\000\001"]: raise TOCParseError - s="\000\000\000\001\000\001"+struct.pack("!H",len(self.username))+self.username - self.sendFlap(1,s) - s="toc_signon %s %s %s %s english \"penguin\""%(self._authhost,\ - self._authport,self.username,roast(self._password)) - self.sendFlap(2,s) - self._mode="Data" - - def modeData(self,flap): - if not flap[1]: - return - if not ':' in flap[1]: - self._debug("bad SNAC:%s"%(flap[1])) - return - command,rest=string.split(flap[1],":",1) - if MAXARGS.has_key(command): - maxsplit=MAXARGS[command] - else: - maxsplit=-1 - if maxsplit==-1: - l=tuple(string.split(rest,":")) - elif maxsplit==0: - l=(rest,) - else: - l=tuple(string.split(rest,":",maxsplit)) - self._debug("%s %s"%(command,l)) - try: - func=getattr(self,"toc%s"%command) - self._debug("calling %s"%func) - except: - self._debug("calling %s"%self.tocUNKNOWN) - self.tocUNKNOWN(command,l) - return - func(l) - - def tocUNKNOWN(self,command,data): - pass - - def tocSIGN_ON(self,data): - if data!=("TOC1.0",): raise TOCParseError - self._debug("Whee, signed on!") - if self._buddies: self.add_buddy(self._buddies) - self._online=1 - self.onLine() - - def tocNICK(self,data): - """ - Handle a message that looks like:: - - NICK: - """ - self.username=data[0] - - def tocCONFIG(self,data): - """ - Handle a message that looks like:: - - CONFIG: - - Format of config data: - - - g: group. all users until next g or end of config are in this group - - b: buddy - - p: person on the permit list - - d: person on the deny list - - m: permit/deny mode (1: permit all, 2: deny all, 3: permit some, 4: deny some) - """ - data=data[0] - if data and data[0]=="{":data=data[1:-1] - lines=string.split(data,"\n") - buddylist={} - currentgroup="" - permit=[] - deny=[] - mode=1 - for l in lines: - if l: - code,data=l[0],l[2:] - if code=='g': # group - currentgroup=data - buddylist[currentgroup]=[] - elif code=='b': - buddylist[currentgroup].append(data) - elif code=='p': - permit.append(data) - elif code=='d': - deny.append(data) - elif code=='m': - mode=int(data) - self.gotConfig(mode,buddylist,permit,deny) - - def tocIM_IN(self,data): - """ - Handle a message that looks like:: - - IM_IN:::message - """ - user=data[0] - autoreply=(data[1]=='T') - message=data[2] - self.hearMessage(user,message,autoreply) - - def tocUPDATE_BUDDY(self,data): - """ - Handle a message that looks like:: - - UPDATE_BUDDY:::::: - """ - data=list(data) - online=(data[1]=='T') - if len(data[5])==2: - data[5]=data[5]+" " - away=(data[5][-1]=='U') - if data[5][-1]=='U': - data[5]=data[5][:-1] - self.updateBuddy(data[0],online,int(data[2]),int(data[3]),int(data[4]),data[5],away) - - def tocERROR(self,data): - """ - Handle a message that looks like:: - - ERROR:: - """ - code,args=data[0],data[1:] - self.hearError(int(code),args) - - def tocEVILED(self,data): - """ - Handle a message that looks like:: - - EVILED:: - """ - self.hearWarning(data[0],data[1]) - - def tocCHAT_JOIN(self,data): - """ - Handle a message that looks like:: - - CHAT_JOIN:: - """ - #self.chatJoined(int(data[0]),data[1]) - self._roomnames[int(data[0])]=data[1] - self._receivedchatmembers[int(data[0])]=0 - - def tocCHAT_UPDATE_BUDDY(self,data): - """ - Handle a message that looks like:: - - CHAT_UPDATE_BUDDY::::... - """ - roomid=int(data[0]) - inroom=(data[1]=='T') - if self._receivedchatmembers[roomid]: - for u in data[2:]: - self.chatUpdate(roomid,u,inroom) - else: - self._receivedchatmembers[roomid]=1 - self.chatJoined(roomid,self._roomnames[roomid],list(data[2:])) - - def tocCHAT_IN(self,data): - """ - Handle a message that looks like:: - - CHAT_IN:::: - - whisper isn't used - """ - whisper=(data[2]=='T') - if whisper: - self.chatHearWhisper(int(data[0]),data[1],data[3]) - else: - self.chatHearMessage(int(data[0]),data[1],data[3]) - - def tocCHAT_INVITE(self,data): - """ - Handle a message that looks like:: - - CHAT_INVITE:::: - """ - self.chatInvited(int(data[1]),data[0],data[2],data[3]) - - def tocCHAT_LEFT(self,data): - """ - Handle a message that looks like:: - - CHAT_LEFT: - """ - self.chatLeft(int(data[0])) - del self._receivedchatmembers[int(data[0])] - del self._roomnames[int(data[0])] - - def tocRVOUS_PROPOSE(self,data): - """ - Handle a message that looks like:: - - RVOUS_PROPOSE:::::::: - [:tlv tag1:tlv value1[:tlv tag2:tlv value2[:...]]] - """ - user,uid,cookie,seq,rip,pip,vip,port=data[:8] - cookie=base64.decodestring(cookie) - port=int(port) - tlvs={} - for i in range(8,len(data),2): - key=data[i] - value=base64.decodestring(data[i+1]) - tlvs[key]=value - name=UUIDS[uid] - try: - func=getattr(self,"toc%s"%name) - except: - self._debug("no function for UID %s" % uid) - return - func(user,cookie,seq,pip,vip,port,tlvs) - - def tocSEND_FILE(self,user,cookie,seq,pip,vip,port,tlvs): - if tlvs.has_key('12'): - description=tlvs['12'] - else: - description="" - subtype,numfiles,size=struct.unpack("!HHI",tlvs['10001'][:8]) - name=tlvs['10001'][8:-4] - while name[-1]=='\000': - name=name[:-1] - self._cookies[cookie]=[user,SEND_FILE_UID,pip,port,{'name':name}] - self.rvousProposal("send",cookie,user,vip,port,description=description, - name=name,files=numfiles,size=size) - - def tocGET_FILE(self,user,cookie,seq,pip,vip,port,tlvs): - return - # XXX add this back in - #reactor.clientTCP(pip,port,GetFileTransfer(self,cookie,os.path.expanduser("~"))) - #self.rvous_accept(user,cookie,GET_FILE_UID) - - def onLine(self): - """ - called when we are first online - """ - pass - - def gotConfig(self,mode,buddylist,permit,deny): - """ - called when we get a configuration from the server - mode := permit/deny mode - buddylist := current buddylist - permit := permit list - deny := deny list - """ - pass - - def hearError(self,code,args): - """ - called when an error is received - code := error code - args := misc. arguments (username, etc.) - """ - pass - - def hearWarning(self,newamount,username): - """ - called when we get warned - newamount := the current warning level - username := the user who warned us, or '' if it's anonymous - """ - pass - - def hearMessage(self,username,message,autoreply): - """ - called when you receive an IM - username := the user who the IM is from - message := the message - autoreply := true if the message is an autoreply from an away message - """ - pass - - def updateBuddy(self,username,online,evilness,signontime,idletime,userclass,away): - """ - called when a buddy changes state - username := the user whos state changed - online := true if the user is online - evilness := the users current warning level - signontime := the time the user signed on (UNIX epoch) - idletime := the time the user has been idle (minutes) - away := true if the user is away - userclass := the class of the user (generally " O") - """ - pass - - def chatJoined(self,roomid,roomname,users): - """ - we just joined a chat room - roomid := the AIM id for the room - roomname := the name for the room - users := a list of the users already in the room - """ - pass - - def chatUpdate(self,roomid,username,inroom): - """ - a user has joined the room - roomid := the AIM id for the room - username := the username - inroom := true if the user is in the room - """ - pass - - def chatHearMessage(self,roomid,username,message): - """ - a message was sent to the room - roomid := the AIM id for the room - username := the user who sent the message - message := the message - """ - pass - - def chatHearWhisper(self,roomid,username,message): - """ - someone whispered to us in a chatroom - roomid := the AIM for the room - username := the user who whispered to us - message := the message - """ - pass - - def chatInvited(self,roomid,roomname,username,message): - """ - we were invited to a chat room - roomid := the AIM id for the room - roomname := the name of the room - username := the user who invited us - message := the invite message - """ - pass - - def chatLeft(self,roomid): - """ - we left the room - roomid := the AIM id for the room - """ - pass - - def rvousProposal(self,type,cookie,user,vip,port,**kw): - """ - we were asked for a rondevouz - type := the type of rondevous. currently, one of ["send"] - cookie := the cookie. pass this to rvous_accept() - user := the user who asked us - vip := their verified_ip - port := the port they want us to conenct to - kw := misc. args - """ - pass #self.rvous_accept(cookie) - - def receiveBytes(self,user,file,chunk,sofar,total): - """ - we received part of a file from a file transfer - file := the name of the file - chunk := the chunk of data - sofar := how much data we've gotten so far - total := the total amount of data - """ - pass #print user,file,sofar,total - - def isaway(self): - """ - return our away status - """ - return len(self._awaymessage)>0 - - def set_config(self,mode,buddylist,permit,deny): - """ - set the server configuration - mode := permit mode - buddylist := buddy list - permit := permit list - deny := deny list - """ - s="m %s\n"%mode - for g in buddylist.keys(): - s=s+"g %s\n"%g - for u in buddylist[g]: - s=s+"b %s\n"%u - for p in permit: - s=s+"p %s\n"%p - for d in deny: - s=s+"d %s\n"%d - #s="{\n"+s+"\n}" - self.sendFlap(2,"toc_set_config %s"%quote(s)) - - def add_buddy(self,buddies): - s="" - if type(buddies)==type(""): buddies=[buddies] - for b in buddies: - s=s+" "+normalize(b) - self.sendFlap(2,"toc_add_buddy%s"%s) - - def del_buddy(self,buddies): - s="" - if type(buddies)==type(""): buddies=[buddies] - for b in buddies: - s=s+" "+b - self.sendFlap(2,"toc_remove_buddy%s"%s) - - def add_permit(self,users): - if type(users)==type(""): users=[users] - s="" - if self._privacymode!=PERMITSOME: - self._privacymode=PERMITSOME - self._permitlist=[] - for u in users: - u=normalize(u) - if u not in self._permitlist:self._permitlist.append(u) - s=s+" "+u - if not s: - self._privacymode=DENYALL - self._permitlist=[] - self._denylist=[] - self.sendFlap(2,"toc_add_permit"+s) - - def del_permit(self,users): - if type(users)==type(""): users=[users] - p=self._permitlist[:] - for u in users: - u=normalize(u) - if u in p: - p.remove(u) - self.add_permit([]) - self.add_permit(p) - - def add_deny(self,users): - if type(users)==type(""): users=[users] - s="" - if self._privacymode!=DENYSOME: - self._privacymode=DENYSOME - self._denylist=[] - for u in users: - u=normalize(u) - if u not in self._denylist:self._denylist.append(u) - s=s+" "+u - if not s: - self._privacymode=PERMITALL - self._permitlist=[] - self._denylist=[] - self.sendFlap(2,"toc_add_deny"+s) - - def del_deny(self,users): - if type(users)==type(""): users=[users] - d=self._denylist[:] - for u in users: - u=normalize(u) - if u in d: - d.remove(u) - self.add_deny([]) - if d: - self.add_deny(d) - - def signon(self): - """ - called to finish the setup, and signon to the network - """ - self.sendFlap(2,"toc_init_done") - self.sendFlap(2,"toc_set_caps %s" % (SEND_FILE_UID,)) # GET_FILE_UID) - - def say(self,user,message,autoreply=0): - """ - send a message - user := the user to send to - message := the message - autoreply := true if the message is an autoreply (good for away messages) - """ - if autoreply: a=" auto" - else: a='' - self.sendFlap(2,"toc_send_im %s %s%s"%(normalize(user),quote(message),a)) - - def idle(self,idletime=0): - """ - change idle state - idletime := the seconds that the user has been away, or 0 if they're back - """ - self.sendFlap(2,"toc_set_idle %s" % int(idletime)) - - def evil(self,user,anon=0): - """ - warn a user - user := the user to warn - anon := if true, an anonymous warning - """ - self.sendFlap(2,"toc_evil %s %s"%(normalize(user), (not anon and "anon") or "norm")) - - def away(self,message=''): - """ - change away state - message := the message, or '' to come back from awayness - """ - self._awaymessage=message - if message: - message=' '+quote(message) - self.sendFlap(2,"toc_set_away%s"%message) - - def chat_join(self,exchange,roomname): - """ - join a chat room - exchange := should almost always be 4 - roomname := room name - """ - roomname=string.replace(roomname," ","") - self.sendFlap(2,"toc_chat_join %s %s"%(int(exchange),roomname)) - - def chat_say(self,roomid,message): - """ - send a message to a chatroom - roomid := the AIM id for the room - message := the message to send - """ - self.sendFlap(2,"toc_chat_send %s %s"%(int(roomid),quote(message))) - - def chat_whisper(self,roomid,user,message): - """ - whisper to another user in a chatroom - roomid := the AIM id for the room - user := the user to whisper to - message := the message to send - """ - self.sendFlap(2,"toc_chat_whisper %s %s %s"%(int(roomid),normalize(user),quote(message))) - - def chat_leave(self,roomid): - """ - leave a chat room. - roomid := the AIM id for the room - """ - self.sendFlap(2,"toc_chat_leave %s" % int(roomid)) - - def chat_invite(self,roomid,usernames,message): - """ - invite a user[s] to the chat room - roomid := the AIM id for the room - usernames := either a string (one username) or a list (more than one) - message := the message to invite them with - """ - if type(usernames)==type(""): # a string, one username - users=usernames - else: - users="" - for u in usernames: - users=users+u+" " - users=users[:-1] - self.sendFlap(2,"toc_chat_invite %s %s %s" % (int(roomid),quote(message),users)) - - def chat_accept(self,roomid): - """ - accept an invite to a chat room - roomid := the AIM id for the room - """ - self.sendFlap(2,"toc_chat_accept %s"%int(roomid)) - - def rvous_accept(self,cookie): - user,uuid,pip,port,d=self._cookies[cookie] - self.sendFlap(2,"toc_rvous_accept %s %s %s" % (normalize(user), - cookie,uuid)) - if uuid==SEND_FILE_UID: - protocol.ClientCreator(reactor, SendFileTransfer,self,cookie,user,d["name"]).connectTCP(pip,port) - - def rvous_cancel(self,cookie): - user,uuid,pip,port,d=self._cookies[cookie] - self.sendFlap(2,"toc_rvous_accept %s %s %s" % (normalize(user), - cookie,uuid)) - del self._cookies[cookie] - - -class SendFileTransfer(protocol.Protocol): - header_fmt="!4s2H8s6H10I32s3c69s16s2H64s" - - def __init__(self,client,cookie,user,filename): - self.client=client - self.cookie=cookie - self.user=user - self.filename=filename - self.hdr=[0,0,0] - self.sofar=0 - - def dataReceived(self,data): - if not self.hdr[2]==0x202: - self.hdr=list(struct.unpack(self.header_fmt,data[:256])) - self.hdr[2]=0x202 - self.hdr[3]=self.cookie - self.hdr[4]=0 - self.hdr[5]=0 - self.transport.write(apply(struct.pack,[self.header_fmt]+self.hdr)) - data=data[256:] - if self.hdr[6]==1: - self.name=self.filename - else: - self.name=self.filename+self.hdr[-1] - while self.name[-1]=="\000": - self.name=self.name[:-1] - if not data: return - self.sofar=self.sofar+len(data) - self.client.receiveBytes(self.user,self.name,data,self.sofar,self.hdr[11]) - if self.sofar==self.hdr[11]: # end of this file - self.hdr[2]=0x204 - self.hdr[7]=self.hdr[7]-1 - self.hdr[9]=self.hdr[9]-1 - self.hdr[19]=DUMMY_CHECKSUM # XXX really calculate this - self.hdr[18]=self.hdr[18]+1 - self.hdr[21]="\000" - self.transport.write(apply(struct.pack,[self.header_fmt]+self.hdr)) - self.sofar=0 - if self.hdr[7]==0: - self.transport.loseConnection() - - -class GetFileTransfer(protocol.Protocol): - header_fmt="!4s 2H 8s 6H 10I 32s 3c 69s 16s 2H 64s" - def __init__(self,client,cookie,dir): - self.client=client - self.cookie=cookie - self.dir=dir - self.buf="" - - def connectionMade(self): - def func(f,path,names): - names.sort(lambda x,y:cmp(string.lower(x),string.lower(y))) - for n in names: - name=os.path.join(path,n) - lt=time.localtime(os.path.getmtime(name)) - size=os.path.getsize(name) - f[1]=f[1]+size - f.append("%02d/%02d/%4d %02d:%02d %8d %s" % - (lt[1],lt[2],lt[0],lt[3],lt[4],size,name[f[0]:])) - f=[len(self.dir)+1,0] - os.path.walk(self.dir,func,f) - size=f[1] - self.listing=string.join(f[2:],"\r\n")+"\r\n" - open("\\listing.txt","w").write(self.listing) - hdr=["OFT2",256,0x1108,self.cookie,0,0,len(f)-2,len(f)-2,1,1,size, - len(self.listing),os.path.getmtime(self.dir), - checksum(self.listing),0,0,0,0,0,0,"OFT_Windows ICBMFT V1.1 32", - "\002",chr(0x1a),chr(0x10),"","",0,0,""] - self.transport.write(apply(struct.pack,[self.header_fmt]+hdr)) - - def dataReceived(self,data): - self.buf=self.buf+data - while len(self.buf)>=256: - hdr=list(struct.unpack(self.header_fmt,self.buf[:256])) - self.buf=self.buf[256:] - if hdr[2]==0x1209: - self.file=StringIO.StringIO(self.listing) - self.transport.registerProducer(self,0) - elif hdr[2]==0x120b: pass - elif hdr[2]==0x120c: # file request - file=hdr[-1] - for k,v in [["\000",""],["\001",os.sep]]: - file=string.replace(file,k,v) - self.name=os.path.join(self.dir,file) - self.file=open(self.name,'rb') - hdr[2]=0x0101 - hdr[6]=hdr[7]=1 - hdr[10]=hdr[11]=os.path.getsize(self.name) - hdr[12]=os.path.getmtime(self.name) - hdr[13]=checksum_file(self.file) - self.file.seek(0) - hdr[18]=hdr[19]=0 - hdr[21]=chr(0x20) - self.transport.write(apply(struct.pack,[self.header_fmt]+hdr)) - log.msg("got file request for %s"%file,hex(hdr[13])) - elif hdr[2]==0x0202: - log.msg("sending file") - self.transport.registerProducer(self,0) - elif hdr[2]==0x0204: - log.msg("real checksum: %s"%hex(hdr[19])) - del self.file - elif hdr[2]==0x0205: # resume - already=hdr[18] - if already: - data=self.file.read(already) - else: - data="" - log.msg("restarting at %s"%already) - hdr[2]=0x0106 - hdr[19]=checksum(data) - self.transport.write(apply(struct.pack,[self.header_fmt]+hdr)) - elif hdr[2]==0x0207: - self.transport.registerProducer(self,0) - else: - log.msg("don't understand 0x%04x"%hdr[2]) - log.msg(hdr) - - def resumeProducing(self): - data=self.file.read(4096) - log.msg(len(data)) - if not data: - self.transport.unregisterProducer() - self.transport.write(data) - - def pauseProducing(self): pass - - def stopProducing(self): del self.file - -# UUIDs -SEND_FILE_UID = "09461343-4C7F-11D1-8222-444553540000" -GET_FILE_UID = "09461348-4C7F-11D1-8222-444553540000" -UUIDS={ - SEND_FILE_UID:"SEND_FILE", - GET_FILE_UID:"GET_FILE" -} - -# ERRORS -# general -NOT_AVAILABLE=901 -CANT_WARN=902 -MESSAGES_TOO_FAST=903 -# admin -BAD_INPUT=911 -BAD_ACCOUNT=912 -REQUEST_ERROR=913 -SERVICE_UNAVAILABLE=914 -# chat -NO_CHAT_IN=950 -# im and info -SEND_TOO_FAST=960 -MISSED_BIG_IM=961 -MISSED_FAST_IM=962 -# directory -DIR_FAILURE=970 -TOO_MANY_MATCHES=971 -NEED_MORE_QUALIFIERS=972 -DIR_UNAVAILABLE=973 -NO_EMAIL_LOOKUP=974 -KEYWORD_IGNORED=975 -NO_KEYWORDS=976 -BAD_LANGUAGE=977 -BAD_COUNTRY=978 -DIR_FAIL_UNKNOWN=979 -# authorization -BAD_NICKNAME=980 -SERVICE_TEMP_UNAVAILABLE=981 -WARNING_TOO_HIGH=982 -CONNECTING_TOO_QUICK=983 -UNKNOWN_SIGNON=989 - -STD_MESSAGE={} -STD_MESSAGE[NOT_AVAILABLE]="%s not currently available" -STD_MESSAGE[CANT_WARN]="Warning of %s not currently available" -STD_MESSAGE[MESSAGES_TOO_FAST]="A message has been dropped, you are exceeding the server speed limit" -STD_MESSAGE[BAD_INPUT]="Error validating input" -STD_MESSAGE[BAD_ACCOUNT]="Invalid account" -STD_MESSAGE[REQUEST_ERROR]="Error encountered while processing request" -STD_MESSAGE[SERVICE_UNAVAILABLE]="Service unavailable" -STD_MESSAGE[NO_CHAT_IN]="Chat in %s is unavailable" -STD_MESSAGE[SEND_TOO_FAST]="You are sending messages too fast to %s" -STD_MESSAGE[MISSED_BIG_IM]="You missed an IM from %s because it was too big" -STD_MESSAGE[MISSED_FAST_IM]="You missed an IM from %s because it was sent too fast" -# skipping directory for now -STD_MESSAGE[BAD_NICKNAME]="Incorrect nickname or password" -STD_MESSAGE[SERVICE_TEMP_UNAVAILABLE]="The service is temporarily unavailable" -STD_MESSAGE[WARNING_TOO_HIGH]="Your warning level is currently too high to sign on" -STD_MESSAGE[CONNECTING_TOO_QUICK]="You have been connecting and disconnecting too frequently. Wait 10 minutes and try again. If you continue to try, you will need to wait even longer." -STD_MESSAGE[UNKNOWN_SIGNON]="An unknown signon error has occurred %s" diff -Nru twisted-words-10.0.0/twisted/words/service.py twisted-words-12.1.0/twisted/words/service.py --- twisted-words-10.0.0/twisted/words/service.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/service.py 2011-03-14 06:46:24.000000000 +0000 @@ -1,5 +1,5 @@ # -*- test-case-name: twisted.words.test.test_service -*- -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -515,7 +515,7 @@ targetName = params[0].decode(self.encoding) except UnicodeDecodeError: self.sendMessage( - irc.ERR_NOSUCHNICK, targetName, + irc.ERR_NOSUCHNICK, params[0], ":No such nick/channel (could not decode your unicode!)") return @@ -546,7 +546,7 @@ groupName = params[0].decode(self.encoding) except UnicodeDecodeError: self.sendMessage( - irc.IRC_NOSUCHCHANNEL, params[0], + irc.ERR_NOSUCHCHANNEL, params[0], ":No such channel (could not decode your unicode!)") return diff -Nru twisted-words-10.0.0/twisted/words/tap.py twisted-words-12.1.0/twisted/words/tap.py --- twisted-words-10.0.0/twisted/words/tap.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/tap.py 2011-10-18 10:31:11.000000000 +0000 @@ -1,5 +1,5 @@ # -*- test-case-name: twisted.words.test.test_tap -*- -# Copyright (c) 2001-2005 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ Shiny new words service maker @@ -21,6 +21,8 @@ ('hostname', None, socket.gethostname(), 'Name of this server; purely an informative')] + compData = usage.Completions(multiUse=["group"]) + interfacePlugins = {} plg = None for plg in plugin.getPlugins(iwords.IProtocolPlugin): diff -Nru twisted-words-10.0.0/twisted/words/test/test_basechat.py twisted-words-12.1.0/twisted/words/test/test_basechat.py --- twisted-words-10.0.0/twisted/words/test/test_basechat.py 1970-01-01 00:00:00.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/test/test_basechat.py 2011-07-14 19:05:14.000000000 +0000 @@ -0,0 +1,68 @@ +# Copyright (c) Twisted Matrix Laboratories. +# See LICENSE for details. + +""" +Tests for L{twisted.words.im.basechat}. +""" + +from twisted.trial import unittest +from twisted.words.im import basechat, basesupport + + +class ChatUITests(unittest.TestCase): + """ + Tests for the L{basechat.ChatUI} chat client. + """ + def setUp(self): + self.ui = basechat.ChatUI() + self.account = basesupport.AbstractAccount("fooAccount", False, "foo", + "password", "host", "port") + self.person = basesupport.AbstractPerson("foo", self.account) + + + def test_contactChangedNickNoKey(self): + """ + L{basechat.ChatUI.contactChangedNick} on an + L{twisted.words.im.interfaces.IPerson} who doesn't have an account + associated with the L{basechat.ChatUI} instance has no effect. + """ + self.assertEqual(self.person.name, "foo") + self.assertEqual(self.person.account, self.account) + + self.ui.contactChangedNick(self.person, "bar") + self.assertEqual(self.person.name, "foo") + self.assertEqual(self.person.account, self.account) + + + def test_contactChangedNickNoConversation(self): + """ + L{basechat.ChatUI.contactChangedNick} changes the name for an + L{twisted.words.im.interfaces.IPerson}. + """ + self.ui.persons[self.person.name, self.person.account] = self.person + + self.assertEqual(self.person.name, "foo") + self.assertEqual(self.person.account, self.account) + + self.ui.contactChangedNick(self.person, "bar") + self.assertEqual(self.person.name, "bar") + self.assertEqual(self.person.account, self.account) + + + def test_contactChangedNickHasConversation(self): + """ + If an L{twisted.words.im.interfaces.IPerson} is in a + L{basechat.Conversation}, L{basechat.ChatUI.contactChangedNick} causes a + name change for that person in both the L{basechat.Conversation} and the + L{basechat.ChatUI}. + """ + self.ui.persons[self.person.name, self.person.account] = self.person + conversation = basechat.Conversation(self.person, self.ui) + self.ui.conversations[self.person] = conversation + + self.assertEqual(self.person.name, "foo") + self.assertEqual(self.person.account, self.account) + + self.ui.contactChangedNick(self.person, "bar") + self.assertEqual(self.person.name, "bar") + self.assertEqual(self.person.account, self.account) diff -Nru twisted-words-10.0.0/twisted/words/test/test_basesupport.py twisted-words-12.1.0/twisted/words/test/test_basesupport.py --- twisted-words-10.0.0/twisted/words/test/test_basesupport.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/test/test_basesupport.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2006 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. from twisted.trial import unittest diff -Nru twisted-words-10.0.0/twisted/words/test/test_domish.py twisted-words-12.1.0/twisted/words/test/test_domish.py --- twisted-words-10.0.0/twisted/words/test/test_domish.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/test/test_domish.py 2011-07-14 19:05:14.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -12,36 +12,36 @@ class DomishTestCase(unittest.TestCase): def testEscaping(self): s = "&<>'\"" - self.assertEquals(domish.escapeToXml(s), "&<>'\"") - self.assertEquals(domish.escapeToXml(s, 1), "&<>'"") + self.assertEqual(domish.escapeToXml(s), "&<>'\"") + self.assertEqual(domish.escapeToXml(s, 1), "&<>'"") def testNamespaceObject(self): ns = domish.Namespace("testns") - self.assertEquals(ns.foo, ("testns", "foo")) + self.assertEqual(ns.foo, ("testns", "foo")) def testElementInit(self): e = domish.Element((None, "foo")) - self.assertEquals(e.name, "foo") - self.assertEquals(e.uri, None) - self.assertEquals(e.defaultUri, None) - self.assertEquals(e.parent, None) + self.assertEqual(e.name, "foo") + self.assertEqual(e.uri, None) + self.assertEqual(e.defaultUri, None) + self.assertEqual(e.parent, None) e = domish.Element(("", "foo")) - self.assertEquals(e.name, "foo") - self.assertEquals(e.uri, "") - self.assertEquals(e.defaultUri, "") - self.assertEquals(e.parent, None) + self.assertEqual(e.name, "foo") + self.assertEqual(e.uri, "") + self.assertEqual(e.defaultUri, "") + self.assertEqual(e.parent, None) e = domish.Element(("testns", "foo")) - self.assertEquals(e.name, "foo") - self.assertEquals(e.uri, "testns") - self.assertEquals(e.defaultUri, "testns") - self.assertEquals(e.parent, None) + self.assertEqual(e.name, "foo") + self.assertEqual(e.uri, "testns") + self.assertEqual(e.defaultUri, "testns") + self.assertEqual(e.parent, None) e = domish.Element(("testns", "foo"), "test2ns") - self.assertEquals(e.name, "foo") - self.assertEquals(e.uri, "testns") - self.assertEquals(e.defaultUri, "test2ns") + self.assertEqual(e.name, "foo") + self.assertEqual(e.uri, "testns") + self.assertEqual(e.defaultUri, "test2ns") def testChildOps(self): e = domish.Element(("testns", "foo")) @@ -55,26 +55,26 @@ e.addContent("123") # Check content merging - self.assertEquals(e.children[-1], "abc123") + self.assertEqual(e.children[-1], "abc123") # Check str()/content extraction - self.assertEquals(str(e), "somecontent") + self.assertEqual(str(e), "somecontent") # Check direct child accessor - self.assertEquals(e.bar2, b2) + self.assertEqual(e.bar2, b2) e.bar2.addContent("subcontent") e.bar2["bar2value"] = "somevalue" # Check child ops - self.assertEquals(e.children[1], e.bar2) - self.assertEquals(e.children[2], e.bar) + self.assertEqual(e.children[1], e.bar2) + self.assertEqual(e.children[2], e.bar) # Check attribute ops - self.assertEquals(e["attrib1"], "value1") + self.assertEqual(e["attrib1"], "value1") del e["attrib1"] - self.assertEquals(e.hasAttribute("attrib1"), 0) - self.assertEquals(e.hasAttribute("attrib2"), 0) - self.assertEquals(e[("testns2", "attrib2")], "value2") + self.assertEqual(e.hasAttribute("attrib1"), 0) + self.assertEqual(e.hasAttribute("attrib2"), 0) + self.assertEqual(e[("testns2", "attrib2")], "value2") def test_elements(self): @@ -147,11 +147,11 @@ def testHarness(self): xml = "" self.stream.parse(xml) - self.assertEquals(self.doc_started, True) - self.assertEquals(self.root.name, 'root') - self.assertEquals(self.elements[0].name, 'child') - self.assertEquals(self.elements[1].name, 'child2') - self.assertEquals(self.doc_ended, True) + self.assertEqual(self.doc_started, True) + self.assertEqual(self.root.name, 'root') + self.assertEqual(self.elements[0].name, 'child') + self.assertEqual(self.elements[1].name, 'child2') + self.assertEqual(self.doc_ended, True) def testBasic(self): xml = "\n" + \ @@ -161,49 +161,62 @@ "" self.stream.parse(xml) - self.assertEquals(self.root.name, 'stream') - self.assertEquals(self.root.uri, 'etherx') - self.assertEquals(self.elements[0].name, 'message') - self.assertEquals(self.elements[0].uri, 'jabber') - self.assertEquals(self.elements[0]['to'], 'bar') - self.assertEquals(self.elements[0].x.uri, 'xdelay') - self.assertEquals(unicode(self.elements[0].x), 'some&data>') + self.assertEqual(self.root.name, 'stream') + self.assertEqual(self.root.uri, 'etherx') + self.assertEqual(self.elements[0].name, 'message') + self.assertEqual(self.elements[0].uri, 'jabber') + self.assertEqual(self.elements[0]['to'], 'bar') + self.assertEqual(self.elements[0].x.uri, 'xdelay') + self.assertEqual(unicode(self.elements[0].x), 'some&data>') def testNoRootNS(self): xml = "" self.stream.parse(xml) - self.assertEquals(self.root.uri, '') - self.assertEquals(self.elements[0].uri, 'etherx') + self.assertEqual(self.root.uri, '') + self.assertEqual(self.elements[0].uri, 'etherx') def testNoDefaultNS(self): xml = """" self.stream.parse(xml) - self.assertEquals(self.root.uri, 'etherx') - self.assertEquals(self.root.defaultUri, '') - self.assertEquals(self.elements[0].uri, '') - self.assertEquals(self.elements[0].defaultUri, '') + self.assertEqual(self.root.uri, 'etherx') + self.assertEqual(self.root.defaultUri, '') + self.assertEqual(self.elements[0].uri, '') + self.assertEqual(self.elements[0].defaultUri, '') def testChildDefaultNS(self): xml = "" self.stream.parse(xml) - self.assertEquals(self.root.uri, 'testns') - self.assertEquals(self.elements[0].uri, 'testns') + self.assertEqual(self.root.uri, 'testns') + self.assertEqual(self.elements[0].uri, 'testns') def testEmptyChildNS(self): xml = "" self.stream.parse(xml) - self.assertEquals(self.elements[0].child2.uri, '') + self.assertEqual(self.elements[0].child2.uri, '') + + + def test_namespaceWithWhitespace(self): + """ + Whitespace in an xmlns value is preserved in the resulting node's C{uri} + attribute. + """ + xml = "" + self.stream.parse(xml) + self.assertEqual(self.elements[0].uri, " bar baz ") + self.assertEqual( + self.elements[0].attributes, {(" bar baz ", "baz"): "quux"}) + def testChildPrefix(self): xml = "" self.stream.parse(xml) - self.assertEquals(self.root.localPrefixes['foo'], 'testns2') - self.assertEquals(self.elements[0].uri, 'testns2') + self.assertEqual(self.root.localPrefixes['foo'], 'testns2') + self.assertEqual(self.elements[0].uri, 'testns2') def testUnclosedElement(self): self.assertRaises(domish.ParserError, self.stream.parse, @@ -225,14 +238,14 @@ """ self.stream.parse(xml) - self.assertEquals('child1', self.elements[0].name) - self.assertEquals('testns', self.elements[0].uri) - self.assertEquals('', self.elements[0].defaultUri) - self.assertEquals({'foo': 'testns'}, self.elements[0].localPrefixes) - self.assertEquals('child2', self.elements[1].name) - self.assertEquals('testns', self.elements[1].uri) - self.assertEquals('testns', self.elements[1].defaultUri) - self.assertEquals({}, self.elements[1].localPrefixes) + self.assertEqual('child1', self.elements[0].name) + self.assertEqual('testns', self.elements[0].uri) + self.assertEqual('', self.elements[0].defaultUri) + self.assertEqual({'foo': 'testns'}, self.elements[0].localPrefixes) + self.assertEqual('child2', self.elements[1].name) + self.assertEqual('testns', self.elements[1].uri) + self.assertEqual('testns', self.elements[1].defaultUri) + self.assertEqual({}, self.elements[1].localPrefixes) @@ -265,62 +278,62 @@ class SerializerTests(unittest.TestCase): def testNoNamespace(self): e = domish.Element((None, "foo")) - self.assertEquals(e.toXml(), "") - self.assertEquals(e.toXml(closeElement = 0), "") + self.assertEqual(e.toXml(), "") + self.assertEqual(e.toXml(closeElement = 0), "") def testDefaultNamespace(self): e = domish.Element(("testns", "foo")) - self.assertEquals(e.toXml(), "") + self.assertEqual(e.toXml(), "") def testOtherNamespace(self): e = domish.Element(("testns", "foo"), "testns2") - self.assertEquals(e.toXml({'testns': 'bar'}), + self.assertEqual(e.toXml({'testns': 'bar'}), "") def testChildDefaultNamespace(self): e = domish.Element(("testns", "foo")) e.addElement("bar") - self.assertEquals(e.toXml(), "") + self.assertEqual(e.toXml(), "") def testChildSameNamespace(self): e = domish.Element(("testns", "foo")) e.addElement(("testns", "bar")) - self.assertEquals(e.toXml(), "") + self.assertEqual(e.toXml(), "") def testChildSameDefaultNamespace(self): e = domish.Element(("testns", "foo")) e.addElement("bar", "testns") - self.assertEquals(e.toXml(), "") + self.assertEqual(e.toXml(), "") def testChildOtherDefaultNamespace(self): e = domish.Element(("testns", "foo")) e.addElement(("testns2", "bar"), 'testns2') - self.assertEquals(e.toXml(), "") + self.assertEqual(e.toXml(), "") def testOnlyChildDefaultNamespace(self): e = domish.Element((None, "foo")) e.addElement(("ns2", "bar"), 'ns2') - self.assertEquals(e.toXml(), "") + self.assertEqual(e.toXml(), "") def testOnlyChildDefaultNamespace2(self): e = domish.Element((None, "foo")) e.addElement("bar") - self.assertEquals(e.toXml(), "") + self.assertEqual(e.toXml(), "") def testChildInDefaultNamespace(self): e = domish.Element(("testns", "foo"), "testns2") e.addElement(("testns2", "bar")) - self.assertEquals(e.toXml(), "") + self.assertEqual(e.toXml(), "") def testQualifiedAttribute(self): e = domish.Element((None, "foo"), attribs = {("testns2", "bar"): "baz"}) - self.assertEquals(e.toXml(), "") + self.assertEqual(e.toXml(), "") def testQualifiedAttributeDefaultNS(self): e = domish.Element(("testns", "foo"), attribs = {("testns", "bar"): "baz"}) - self.assertEquals(e.toXml(), "") + self.assertEqual(e.toXml(), "") def testTwoChilds(self): e = domish.Element(('', "foo")) @@ -328,18 +341,18 @@ child1.addElement(('testns2', 'quux')) child2 = e.addElement(("testns3", "baz"), "testns4") child2.addElement(('testns', 'quux')) - self.assertEquals(e.toXml(), "") + self.assertEqual(e.toXml(), "") def testXMLNamespace(self): e = domish.Element((None, "foo"), attribs = {("http://www.w3.org/XML/1998/namespace", "lang"): "en_US"}) - self.assertEquals(e.toXml(), "") + self.assertEqual(e.toXml(), "") def testQualifiedAttributeGivenListOfPrefixes(self): e = domish.Element((None, "foo"), attribs = {("testns2", "bar"): "baz"}) - self.assertEquals(e.toXml({"testns2": "qux"}), + self.assertEqual(e.toXml({"testns2": "qux"}), "") def testNSPrefix(self): @@ -348,7 +361,7 @@ c = e.addElement(("testns2", "qux")) c[("testns2", "bar")] = "quux" - self.assertEquals(e.toXml(), "") + self.assertEqual(e.toXml(), "") def testDefaultNSPrefix(self): e = domish.Element((None, "foo"), @@ -357,24 +370,24 @@ c[("testns2", "bar")] = "quux" c.addElement('foo') - self.assertEquals(e.toXml(), "") + self.assertEqual(e.toXml(), "") def testPrefixScope(self): e = domish.Element(('testns', 'foo')) - self.assertEquals(e.toXml(prefixes={'testns': 'bar'}, + self.assertEqual(e.toXml(prefixes={'testns': 'bar'}, prefixesInScope=['bar']), "") def testLocalPrefixes(self): e = domish.Element(('testns', 'foo'), localPrefixes={'bar': 'testns'}) - self.assertEquals(e.toXml(), "") + self.assertEqual(e.toXml(), "") def testLocalPrefixesWithChild(self): e = domish.Element(('testns', 'foo'), localPrefixes={'bar': 'testns'}) e.addElement('baz') self.assertIdentical(e.baz.defaultUri, None) - self.assertEquals(e.toXml(), "") + self.assertEqual(e.toXml(), "") def test_prefixesReuse(self): """ @@ -394,10 +407,10 @@ # test proper serialization on prefixes reuse e = domish.Element(('testns2', 'foo'), localPrefixes={'quux': 'testns2'}) - self.assertEquals("", + self.assertEqual("", e.toXml(prefixes=prefixes)) e = domish.Element(('testns2', 'foo')) - self.assertEquals("", + self.assertEqual("", e.toXml(prefixes=prefixes)) def testRawXMLSerialization(self): @@ -406,16 +419,16 @@ # The testcase below should NOT generate valid XML -- that's # the whole point of using the raw XML call -- it's the callers # responsiblity to ensure that the data inserted is valid - self.assertEquals(e.toXml(), "") + self.assertEqual(e.toXml(), "") def testRawXMLWithUnicodeSerialization(self): e = domish.Element((None, "foo")) e.addRawXml(u"\u00B0") - self.assertEquals(e.toXml(), u"\u00B0") + self.assertEqual(e.toXml(), u"\u00B0") def testUnicodeSerialization(self): e = domish.Element((None, "foo")) e["test"] = u"my value\u0221e" e.addContent(u"A degree symbol...\u00B0") - self.assertEquals(e.toXml(), + self.assertEqual(e.toXml(), u"A degree symbol...\u00B0") diff -Nru twisted-words-10.0.0/twisted/words/test/test_irc.py twisted-words-12.1.0/twisted/words/test/test_irc.py --- twisted-words-10.0.0/twisted/words/test/test_irc.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/test/test_irc.py 2012-03-14 05:06:21.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2010 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -11,7 +11,7 @@ from twisted.trial.unittest import TestCase from twisted.words.protocols import irc from twisted.words.protocols.irc import IRCClient -from twisted.internet import protocol +from twisted.internet import protocol, task from twisted.test.proto_helpers import StringTransport, StringIOWithoutClosing @@ -67,12 +67,12 @@ "removed" direction. """ added, removed = irc.parseModes('+s', []) - self.assertEquals(added, [('s', None)]) - self.assertEquals(removed, []) + self.assertEqual(added, [('s', None)]) + self.assertEqual(removed, []) added, removed = irc.parseModes('-s', []) - self.assertEquals(added, []) - self.assertEquals(removed, [('s', None)]) + self.assertEqual(added, []) + self.assertEqual(removed, [('s', None)]) def test_singleDirection(self): @@ -81,14 +81,14 @@ parameters, results in all modes falling into the same direction group. """ added, removed = irc.parseModes('+stn', []) - self.assertEquals(added, [('s', None), + self.assertEqual(added, [('s', None), ('t', None), ('n', None)]) - self.assertEquals(removed, []) + self.assertEqual(removed, []) added, removed = irc.parseModes('-nt', []) - self.assertEquals(added, []) - self.assertEquals(removed, [('n', None), + self.assertEqual(added, []) + self.assertEqual(removed, [('n', None), ('t', None)]) @@ -97,10 +97,10 @@ Parsing a multi-direction mode setting with no parameters. """ added, removed = irc.parseModes('+s-n+ti', []) - self.assertEquals(added, [('s', None), + self.assertEqual(added, [('s', None), ('t', None), ('i', None)]) - self.assertEquals(removed, [('n', None)]) + self.assertEqual(removed, [('n', None)]) def test_consecutiveDirection(self): @@ -110,11 +110,11 @@ there were only one mode sequence in the same direction. """ added, removed = irc.parseModes('+sn+ti', []) - self.assertEquals(added, [('s', None), + self.assertEqual(added, [('s', None), ('n', None), ('t', None), ('i', None)]) - self.assertEquals(removed, []) + self.assertEqual(removed, []) def test_mismatchedParams(self): @@ -142,18 +142,18 @@ '+klbb', ['somekey', '42', 'nick!user@host', 'other!*@*'], self.paramModes) - self.assertEquals(added, [('k', 'somekey'), + self.assertEqual(added, [('k', 'somekey'), ('l', '42'), ('b', 'nick!user@host'), ('b', 'other!*@*')]) - self.assertEquals(removed, []) + self.assertEqual(removed, []) added, removed = irc.parseModes( '-klbb', ['nick!user@host', 'other!*@*'], self.paramModes) - self.assertEquals(added, []) - self.assertEquals(removed, [('k', None), + self.assertEqual(added, []) + self.assertEqual(removed, [('k', None), ('l', None), ('b', 'nick!user@host'), ('b', 'other!*@*')]) @@ -163,11 +163,11 @@ '+knbb', ['somekey', 'nick!user@host', 'other!*@*'], self.paramModes) - self.assertEquals(added, [('k', 'somekey'), + self.assertEqual(added, [('k', 'somekey'), ('n', None), ('b', 'nick!user@host'), ('b', 'other!*@*')]) - self.assertEquals(removed, []) + self.assertEqual(removed, []) @@ -183,15 +183,19 @@ class QuotingTest(unittest.TestCase): def test_lowquoteSanity(self): - """Testing client-server level quote/dequote""" + """ + Testing client-server level quote/dequote. + """ for s in stringSubjects: - self.failUnlessEqual(s, irc.lowDequote(irc.lowQuote(s))) + self.assertEqual(s, irc.lowDequote(irc.lowQuote(s))) def test_ctcpquoteSanity(self): - """Testing CTCP message level quote/dequote""" + """ + Testing CTCP message level quote/dequote. + """ for s in stringSubjects: - self.failUnlessEqual(s, irc.ctcpDequote(irc.ctcpQuote(s))) + self.assertEqual(s, irc.ctcpDequote(irc.ctcpQuote(s))) @@ -227,7 +231,7 @@ disp = Dispatcher() args = (1, 2) res = disp.dispatch('working', *args) - self.assertEquals(res, args) + self.assertEqual(res, args) def test_dispatchUnknown(self): @@ -238,7 +242,7 @@ name = 'missing' args = (1, 2) res = disp.dispatch(name, *args) - self.assertEquals(res, (name,) + args) + self.assertEqual(res, (name,) + args) def test_dispatchMissingUnknown(self): @@ -261,12 +265,12 @@ L{_intOrDefault} converts values to C{int} if possible, otherwise returns a default value. """ - self.assertEquals(irc._intOrDefault(None), None) - self.assertEquals(irc._intOrDefault([]), None) - self.assertEquals(irc._intOrDefault(''), None) - self.assertEquals(irc._intOrDefault('hello', 5), 5) - self.assertEquals(irc._intOrDefault('123'), 123) - self.assertEquals(irc._intOrDefault(123), 123) + self.assertEqual(irc._intOrDefault(None), None) + self.assertEqual(irc._intOrDefault([]), None) + self.assertEqual(irc._intOrDefault(''), None) + self.assertEqual(irc._intOrDefault('hello', 5), 5) + self.assertEqual(irc._intOrDefault('123'), 123) + self.assertEqual(irc._intOrDefault(123), 123) def test_splitParam(self): @@ -289,7 +293,7 @@ for param, expected in params: res = _splitParam(param) - self.assertEquals(res, expected) + self.assertEqual(res, expected) self.assertRaises(ValueError, _splitParam, 'FOO=\\x') self.assertRaises(ValueError, _splitParam, 'FOO=\\xNN') @@ -304,7 +308,7 @@ split into a key and an empty string. """ res = irc.ServerSupportedFeatures._splitParamArgs(['A:1', 'B:2', 'C:', 'D']) - self.assertEquals(res, [('A', '1'), + self.assertEqual(res, [('A', '1'), ('B', '2'), ('C', ''), ('D', '')]) @@ -318,7 +322,7 @@ """ res = irc.ServerSupportedFeatures._splitParamArgs(['A:1', 'B:2', 'C'], irc._intOrDefault) - self.assertEquals(res, [('A', 1), + self.assertEqual(res, [('A', 1), ('B', 2), ('C', None)]) @@ -331,9 +335,9 @@ C{ValueError} if the prefix parameter is malformed. """ _parsePrefixParam = irc.ServerSupportedFeatures._parsePrefixParam - self.assertEquals(_parsePrefixParam(''), None) + self.assertEqual(_parsePrefixParam(''), None) self.assertRaises(ValueError, _parsePrefixParam, 'hello') - self.assertEquals(_parsePrefixParam('(ov)@+'), + self.assertEqual(_parsePrefixParam('(ov)@+'), {'o': ('@', 0), 'v': ('+', 1)}) @@ -347,21 +351,21 @@ C{ValueError}. """ _parseChanModesParam = irc.ServerSupportedFeatures._parseChanModesParam - self.assertEquals( + self.assertEqual( _parseChanModesParam([]), {'addressModes': '', 'param': '', 'setParam': '', 'noParam': ''}) - self.assertEquals( + self.assertEqual( _parseChanModesParam(['b', 'k', 'l', 'imnpst']), {'addressModes': 'b', 'param': 'k', 'setParam': 'l', 'noParam': 'imnpst'}) - self.assertEquals( + self.assertEqual( _parseChanModesParam(['b', 'k', 'l']), {'addressModes': 'b', 'param': 'k', @@ -387,13 +391,13 @@ 'EXCEPTS=Z', 'UNKNOWN=A,B,C']) - self.assertEquals(supported.getFeature('MODES'), 4) - self.assertEquals(supported.getFeature('CHANLIMIT'), + self.assertEqual(supported.getFeature('MODES'), 4) + self.assertEqual(supported.getFeature('CHANLIMIT'), [('#', 20), ('&', 10)]) - self.assertEquals(supported.getFeature('INVEX'), 'I') - self.assertEquals(supported.getFeature('EXCEPTS'), 'Z') - self.assertEquals(supported.getFeature('UNKNOWN'), ('A', 'B', 'C')) + self.assertEqual(supported.getFeature('INVEX'), 'I') + self.assertEqual(supported.getFeature('EXCEPTS'), 'Z') + self.assertEqual(supported.getFeature('UNKNOWN'), ('A', 'B', 'C')) self.assertTrue(supported.hasFeature('INVEX')) supported.parse(['-INVEX']) @@ -431,13 +435,13 @@ """ Perform some common tests on a feature known to use L{_intOrDefault}. """ - self.assertEquals( + self.assertEqual( self._parseFeature(name, None), default) - self.assertEquals( + self.assertEqual( self._parseFeature(name, 'notanint'), default) - self.assertEquals( + self.assertEqual( self._parseFeature(name, '42'), 42) @@ -455,7 +459,7 @@ supported = self._parse(features) self.assertTrue(supported.hasFeature(name)) - self.assertEquals(supported.getFeature(name), default) + self.assertEqual(supported.getFeature(name), default) def test_support_CHANMODES(self): @@ -468,21 +472,21 @@ self._testFeatureDefault('CHANMODES', [('CHANMODES', 'b,,lk,')]) self._testFeatureDefault('CHANMODES', [('CHANMODES', 'b,,lk,ha,ha')]) - self.assertEquals( + self.assertEqual( self._parseFeature('CHANMODES', ''), {'addressModes': '', 'param': '', 'setParam': '', 'noParam': ''}) - self.assertEquals( + self.assertEqual( self._parseFeature('CHANMODES', ',A'), {'addressModes': '', 'param': 'A', 'setParam': '', 'noParam': ''}) - self.assertEquals( + self.assertEqual( self._parseFeature('CHANMODES', 'A,Bc,Def,Ghij'), {'addressModes': 'A', 'param': 'Bc', @@ -495,7 +499,7 @@ The IDCHAN support parameter is parsed into a sequence of two-tuples giving channel prefix and ID length pairs. """ - self.assertEquals( + self.assertEqual( self._parseFeature('IDCHAN', '!:5'), [('!', '5')]) @@ -505,14 +509,14 @@ The MAXLIST support parameter is parsed into a sequence of two-tuples giving modes and their limits. """ - self.assertEquals( + self.assertEqual( self._parseFeature('MAXLIST', 'b:25,eI:50'), [('b', 25), ('eI', 50)]) # A non-integer parameter argument results in None. - self.assertEquals( + self.assertEqual( self._parseFeature('MAXLIST', 'b:25,eI:50,a:3.1415'), [('b', 25), ('eI', 50), ('a', None)]) - self.assertEquals( + self.assertEqual( self._parseFeature('MAXLIST', 'b:25,eI:50,a:notanint'), [('b', 25), ('eI', 50), ('a', None)]) @@ -522,7 +526,7 @@ The NETWORK support parameter is parsed as the network name, as specified by the server. """ - self.assertEquals( + self.assertEqual( self._parseFeature('NETWORK', 'IRCNet'), 'IRCNet') @@ -532,7 +536,7 @@ The SAFELIST support parameter is parsed into a boolean indicating whether the safe "list" command is supported or not. """ - self.assertEquals( + self.assertEqual( self._parseFeature('SAFELIST'), True) @@ -542,7 +546,7 @@ The STATUSMSG support parameter is parsed into a string of channel status that support the exclusive channel notice method. """ - self.assertEquals( + self.assertEqual( self._parseFeature('STATUSMSG', '@+'), '@+') @@ -553,17 +557,17 @@ strings to integers, of the maximum number of targets for a particular command. """ - self.assertEquals( + self.assertEqual( self._parseFeature('TARGMAX', 'PRIVMSG:4,NOTICE:3'), {'PRIVMSG': 4, 'NOTICE': 3}) # A non-integer parameter argument results in None. - self.assertEquals( + self.assertEqual( self._parseFeature('TARGMAX', 'PRIVMSG:4,NOTICE:3,KICK:3.1415'), {'PRIVMSG': 4, 'NOTICE': 3, 'KICK': None}) - self.assertEquals( + self.assertEqual( self._parseFeature('TARGMAX', 'PRIVMSG:4,NOTICE:3,KICK:notanint'), {'PRIVMSG': 4, 'NOTICE': 3, @@ -599,7 +603,7 @@ """ self._testFeatureDefault('CHANTYPES') - self.assertEquals( + self.assertEqual( self._parseFeature('CHANTYPES', '#&%'), ('#', '&', '%')) @@ -620,15 +624,15 @@ self._testFeatureDefault('PREFIX') self._testFeatureDefault('PREFIX', [('PREFIX', 'hello')]) - self.assertEquals( + self.assertEqual( self._parseFeature('PREFIX', None), None) - self.assertEquals( + self.assertEqual( self._parseFeature('PREFIX', '(ohv)@%+'), {'o': ('@', 0), 'h': ('%', 1), 'v': ('+', 2)}) - self.assertEquals( + self.assertEqual( self._parseFeature('PREFIX', '(hov)@%+'), {'o': ('%', 1), 'h': ('@', 0), @@ -660,10 +664,10 @@ to be used for "ban exception" modes. If no parameter is specified then the character C{e} is assumed. """ - self.assertEquals( + self.assertEqual( self._parseFeature('EXCEPTS', 'Z'), 'Z') - self.assertEquals( + self.assertEqual( self._parseFeature('EXCEPTS'), 'e') @@ -674,10 +678,10 @@ used for "invite exception" modes. If no parameter is specified then the character C{I} is assumed. """ - self.assertEquals( + self.assertEqual( self._parseFeature('INVEX', 'Z'), 'Z') - self.assertEquals( + self.assertEqual( self._parseFeature('INVEX'), 'I') @@ -687,13 +691,20 @@ performLogin = 0 + class CTCPTest(unittest.TestCase): + """ + Tests for L{twisted.words.protocols.irc.IRCClient} CTCP handling. + """ def setUp(self): self.file = StringIOWithoutClosing() self.transport = protocol.FileWrapper(self.file) self.client = IRCClientWithoutLogin() self.client.makeConnection(self.transport) + self.addCleanup(self.transport.loseConnection) + self.addCleanup(self.client.connectionLost, None) + def test_ERRMSG(self): """Testing CTCP query ERRMSG. @@ -716,7 +727,7 @@ self.client.dataReceived(errQuery) reply = self.file.getvalue() - self.failUnlessEqual(errReply, reply) + self.assertEqual(errReply, reply) def test_noNumbersVERSION(self): @@ -733,7 +744,7 @@ 'EOL': irc.CR + irc.LF, 'vname': self.client.versionName}) reply = self.file.getvalue() - self.assertEquals(versionReply, reply) + self.assertEqual(versionReply, reply) def test_fullVERSION(self): @@ -754,14 +765,60 @@ 'vnum': self.client.versionNum, 'venv': self.client.versionEnv}) reply = self.file.getvalue() - self.assertEquals(versionReply, reply) + self.assertEqual(versionReply, reply) + + + def test_noDuplicateCTCPDispatch(self): + """ + Duplicated CTCP messages are ignored and no reply is made. + """ + def testCTCP(user, channel, data): + self.called += 1 + + self.called = 0 + self.client.ctcpQuery_TESTTHIS = testCTCP + + self.client.irc_PRIVMSG( + 'foo!bar@baz.quux', [ + '#chan', + '%(X)sTESTTHIS%(X)sfoo%(X)sTESTTHIS%(X)s' % {'X': irc.X_DELIM}]) + self.assertEqual( + self.file.getvalue(), + '') + self.assertEqual(self.called, 1) + + + def test_noDefaultDispatch(self): + """ + The fallback handler is invoked for unrecognized CTCP messages. + """ + def unknownQuery(user, channel, tag, data): + self.calledWith = (user, channel, tag, data) + self.called += 1 + + self.called = 0 + self.patch(self.client, 'ctcpUnknownQuery', unknownQuery) + self.client.irc_PRIVMSG( + 'foo!bar@baz.quux', [ + '#chan', + '%(X)sNOTREAL%(X)s' % {'X': irc.X_DELIM}]) + self.assertEqual( + self.file.getvalue(), + '') + self.assertEqual( + self.calledWith, + ('foo!bar@baz.quux', '#chan', 'NOTREAL', None)) + self.assertEqual(self.called, 1) + + # The fallback handler is not invoked for duplicate unknown CTCP + # messages. + self.client.irc_PRIVMSG( + 'foo!bar@baz.quux', [ + '#chan', + '%(X)sNOTREAL%(X)sfoo%(X)sNOTREAL%(X)s' % {'X': irc.X_DELIM}]) + self.assertEqual(self.called, 2) - def tearDown(self): - self.transport.loseConnection() - self.client.connectionLost() - del self.client - del self.transport class NoticingClient(IRCClientWithoutLogin, object): methods = { @@ -841,19 +898,16 @@ del dict[key] return value + + class ClientImplementationTests(unittest.TestCase): def setUp(self): - self.file = StringIOWithoutClosing() - self.transport = protocol.FileWrapper(self.file) + self.transport = StringTransport() self.client = NoticingClient() self.client.makeConnection(self.transport) - - def tearDown(self): - self.transport.loseConnection() - self.client.connectionLost() - del self.client - del self.transport + self.addCleanup(self.transport.loseConnection) + self.addCleanup(self.client.connectionLost, None) def _serverTestImpl(self, code, msg, func, **kw): @@ -869,7 +923,7 @@ msg + "\r\n") self.client.dataReceived(message) - self.assertEquals( + self.assertEqual( self.client.calls, [(func, kw)]) @@ -965,10 +1019,10 @@ ":host.name 372 nickname :- Welcome to host.name", ":host.name 376 nickname :End of /MOTD command."] for L in lines: - self.assertEquals(self.client.calls, []) + self.assertEqual(self.client.calls, []) self.client.dataReceived(L + '\r\n') - self.assertEquals( + self.assertEqual( self.client.calls, [("receivedMOTD", {"motd": ["host.name Message of the Day -", "Welcome to host.name"]})]) @@ -990,7 +1044,7 @@ for L in lines: self.client.dataReceived(L + '\r\n') - self.assertEquals( + self.assertEqual( self.client.calls, [("receivedMOTD", {"motd": ["Welcome to host.name"]})]) @@ -1006,7 +1060,7 @@ group + " :" + msg + "\r\n") self.client.dataReceived(message) - self.assertEquals( + self.assertEqual( self.client.calls, [(func, kw)]) self.client.calls = [] @@ -1036,8 +1090,8 @@ require arguments when being added or removed. """ add, remove = map(sorted, self.client.getChannelModeParams()) - self.assertEquals(add, ['b', 'h', 'k', 'l', 'o', 'v']) - self.assertEquals(remove, ['b', 'h', 'o', 'v']) + self.assertEqual(add, ['b', 'h', 'k', 'l', 'o', 'v']) + self.assertEqual(remove, ['b', 'h', 'o', 'v']) def removeFeature(name): name = '-' + name @@ -1052,14 +1106,14 @@ # None. removeFeature('CHANMODES') add, remove = map(sorted, self.client.getChannelModeParams()) - self.assertEquals(add, ['h', 'o', 'v']) - self.assertEquals(remove, ['h', 'o', 'v']) + self.assertEqual(add, ['h', 'o', 'v']) + self.assertEqual(remove, ['h', 'o', 'v']) # Remove PREFIX feature, causing getFeature('PREFIX') to return None. removeFeature('PREFIX') add, remove = map(sorted, self.client.getChannelModeParams()) - self.assertEquals(add, []) - self.assertEquals(remove, []) + self.assertEqual(add, []) + self.assertEqual(remove, []) # Restore ISUPPORT features. self._sendISUPPORT() @@ -1074,8 +1128,8 @@ parameters when added and removed, respectively. """ add, remove = map(sorted, self.client.getUserModeParams()) - self.assertEquals(add, []) - self.assertEquals(remove, []) + self.assertEqual(add, []) + self.assertEqual(remove, []) def _sendModeChange(self, msg, args='', target=None): @@ -1098,9 +1152,9 @@ for n, result in enumerate(results): method, data = result - self.assertEquals(method, 'modeChanged') - self.assertEquals(data['user'], 'Wolf!~wolf@yok.utu.fi') - self.assertEquals(data['channel'], target) + self.assertEqual(method, 'modeChanged') + self.assertEqual(data['user'], 'Wolf!~wolf@yok.utu.fi') + self.assertEqual(data['channel'], target) results[n] = tuple([data[key] for key in ('set', 'modes', 'args')]) return results @@ -1110,7 +1164,7 @@ Compare the expected result with the one returned by the client. """ result = self._parseModeChange(self.client.calls, target) - self.assertEquals(result, expected) + self.assertEqual(result, expected) self.client.calls = [] @@ -1166,7 +1220,7 @@ self._sendModeChange('+s', 'wrong') self._checkModeChange([]) errors = self.flushLoggedErrors(irc.IRCBadModes) - self.assertEquals(len(errors), 1) + self.assertEqual(len(errors), 1) self.assertSubstring( 'Too many parameters', errors[0].getErrorMessage()) @@ -1179,7 +1233,7 @@ self._sendModeChange('+o') self._checkModeChange([]) errors = self.flushLoggedErrors(irc.IRCBadModes) - self.assertEquals(len(errors), 1) + self.assertEqual(len(errors), 1) self.assertSubstring( 'Not enough parameters', errors[0].getErrorMessage()) @@ -1206,6 +1260,51 @@ self._checkModeChange([(True, 'Z', ('an_arg',))], target=target) + def test_heartbeat(self): + """ + When the I{RPL_WELCOME} message is received a heartbeat is started that + will send a I{PING} message to the IRC server every + L{irc.IRCClient.heartbeatInterval} seconds. When the transport is + closed the heartbeat looping call is stopped too. + """ + def _createHeartbeat(): + heartbeat = self._originalCreateHeartbeat() + heartbeat.clock = self.clock + return heartbeat + + self.clock = task.Clock() + self._originalCreateHeartbeat = self.client._createHeartbeat + self.patch(self.client, '_createHeartbeat', _createHeartbeat) + + self.assertIdentical(self.client._heartbeat, None) + self.client.irc_RPL_WELCOME('foo', []) + self.assertNotIdentical(self.client._heartbeat, None) + self.assertEqual(self.client.hostname, 'foo') + + # Pump the clock enough to trigger one LoopingCall. + self.assertEqual(self.transport.value(), '') + self.clock.advance(self.client.heartbeatInterval) + self.assertEqual(self.transport.value(), 'PING foo\r\n') + + # When the connection is lost the heartbeat is stopped. + self.transport.loseConnection() + self.client.connectionLost(None) + self.assertEqual( + len(self.clock.getDelayedCalls()), 0) + self.assertIdentical(self.client._heartbeat, None) + + + def test_heartbeatDisabled(self): + """ + If L{irc.IRCClient.heartbeatInterval} is set to C{None} then no + heartbeat is created. + """ + self.assertIdentical(self.client._heartbeat, None) + self.client.heartbeatInterval = None + self.client.irc_RPL_WELCOME('foo', []) + self.assertIdentical(self.client._heartbeat, None) + + class BasicServerFunctionalityTestCase(unittest.TestCase): def setUp(self): @@ -1216,7 +1315,7 @@ def check(self, s): - self.assertEquals(self.f.getvalue(), s) + self.assertEqual(self.f.getvalue(), s) def testPrivmsg(self): @@ -1266,67 +1365,294 @@ self.check(expected) + class DummyClient(irc.IRCClient): + """ + A L{twisted.words.protocols.irc.IRCClient} that stores sent lines in a + C{list} rather than transmitting them. + """ def __init__(self): self.lines = [] + + + def connectionMade(self): + irc.IRCClient.connectionMade(self) + self.lines = [] + + + def _truncateLine(self, line): + """ + Truncate an IRC line to the maximum allowed length. + """ + return line[:irc.MAX_COMMAND_LENGTH - len(self.delimiter)] + + + def lineReceived(self, line): + # Emulate IRC servers throwing away our important data. + line = self._truncateLine(line) + return irc.IRCClient.lineReceived(self, line) + + def sendLine(self, m): - self.lines.append(m) + self.lines.append(self._truncateLine(m)) + + + +class ClientInviteTests(unittest.TestCase): + """ + Tests for L{IRCClient.invite}. + """ + def setUp(self): + """ + Create a L{DummyClient} to call C{invite} on in test methods. + """ + self.client = DummyClient() + + + def test_channelCorrection(self): + """ + If the channel name passed to L{IRCClient.invite} does not begin with a + channel prefix character, one is prepended to it. + """ + self.client.invite('foo', 'bar') + self.assertEqual(self.client.lines, ['INVITE foo #bar']) + + + def test_invite(self): + """ + L{IRCClient.invite} sends an I{INVITE} message with the specified + username and a channel. + """ + self.client.invite('foo', '#bar') + self.assertEqual(self.client.lines, ['INVITE foo #bar']) + class ClientMsgTests(unittest.TestCase): + """ + Tests for messages sent with L{twisted.words.protocols.irc.IRCClient}. + """ def setUp(self): self.client = DummyClient() + self.client.connectionMade() - def testSingleLine(self): + def test_singleLine(self): + """ + A message containing no newlines is sent in a single command. + """ self.client.msg('foo', 'bar') - self.assertEquals(self.client.lines, ['PRIVMSG foo :bar']) + self.assertEqual(self.client.lines, ['PRIVMSG foo :bar']) - def testDodgyMaxLength(self): + def test_invalidMaxLength(self): + """ + Specifying a C{length} value to L{IRCClient.msg} that is too short to + contain the protocol command to send a message raises C{ValueError}. + """ self.assertRaises(ValueError, self.client.msg, 'foo', 'bar', 0) self.assertRaises(ValueError, self.client.msg, 'foo', 'bar', 3) - def testMultipleLine(self): + def test_multipleLine(self): + """ + Messages longer than the C{length} parameter to L{IRCClient.msg} will + be split and sent in multiple commands. + """ maxLen = len('PRIVMSG foo :') + 3 + 2 # 2 for line endings self.client.msg('foo', 'barbazbo', maxLen) - self.assertEquals(self.client.lines, ['PRIVMSG foo :bar', - 'PRIVMSG foo :baz', - 'PRIVMSG foo :bo']) + self.assertEqual( + self.client.lines, + ['PRIVMSG foo :bar', + 'PRIVMSG foo :baz', + 'PRIVMSG foo :bo']) - def testSufficientWidth(self): + def test_sufficientWidth(self): + """ + Messages exactly equal in length to the C{length} paramtere to + L{IRCClient.msg} are sent in a single command. + """ msg = 'barbazbo' maxLen = len('PRIVMSG foo :%s' % (msg,)) + 2 self.client.msg('foo', msg, maxLen) - self.assertEquals(self.client.lines, ['PRIVMSG foo :%s' % (msg,)]) + self.assertEqual(self.client.lines, ['PRIVMSG foo :%s' % (msg,)]) self.client.lines = [] self.client.msg('foo', msg, maxLen-1) - self.assertEquals(2, len(self.client.lines)) + self.assertEqual(2, len(self.client.lines)) self.client.lines = [] self.client.msg('foo', msg, maxLen+1) - self.assertEquals(1, len(self.client.lines)) + self.assertEqual(1, len(self.client.lines)) + + + def test_newlinesAtStart(self): + """ + An LF at the beginning of the message is ignored. + """ + self.client.lines = [] + self.client.msg('foo', '\nbar') + self.assertEqual(self.client.lines, ['PRIVMSG foo :bar']) + + + def test_newlinesAtEnd(self): + """ + An LF at the end of the message is ignored. + """ + self.client.lines = [] + self.client.msg('foo', 'bar\n') + self.assertEqual(self.client.lines, ['PRIVMSG foo :bar']) + + + def test_newlinesWithinMessage(self): + """ + An LF within a message causes a new line. + """ + self.client.lines = [] + self.client.msg('foo', 'bar\nbaz') + self.assertEqual( + self.client.lines, + ['PRIVMSG foo :bar', + 'PRIVMSG foo :baz']) + + + def test_consecutiveNewlines(self): + """ + Consecutive LFs do not cause a blank line. + """ + self.client.lines = [] + self.client.msg('foo', 'bar\n\nbaz') + self.assertEqual( + self.client.lines, + ['PRIVMSG foo :bar', + 'PRIVMSG foo :baz']) + + + def assertLongMessageSplitting(self, message, expectedNumCommands, + length=None): + """ + Assert that messages sent by L{IRCClient.msg} are split into an + expected number of commands and the original message is transmitted in + its entirety over those commands. + """ + responsePrefix = ':%s!%s@%s ' % ( + self.client.nickname, + self.client.realname, + self.client.hostname) + self.client.msg('foo', message, length=length) + + privmsg = [] + self.patch(self.client, 'privmsg', lambda *a: privmsg.append(a)) + # Deliver these to IRCClient via the normal mechanisms. + for line in self.client.lines: + self.client.lineReceived(responsePrefix + line) + + self.assertEqual(len(privmsg), expectedNumCommands) + receivedMessage = ''.join( + message for user, target, message in privmsg) + + # Did the long message we sent arrive as intended? + self.assertEqual(message, receivedMessage) + + + def test_splitLongMessagesWithDefault(self): + """ + If a maximum message length is not provided to L{IRCClient.msg} a + best-guess effort is made to determine a safe maximum, messages longer + than this are split into multiple commands with the intent of + delivering long messages without losing data due to message truncation + when the server relays them. + """ + message = 'o' * (irc.MAX_COMMAND_LENGTH - 2) + self.assertLongMessageSplitting(message, 2) + + + def test_splitLongMessagesWithOverride(self): + """ + The maximum message length can be specified to L{IRCClient.msg}, + messages longer than this are split into multiple commands with the + intent of delivering long messages without losing data due to message + truncation when the server relays them. + """ + message = 'o' * (irc.MAX_COMMAND_LENGTH - 2) + self.assertLongMessageSplitting( + message, 3, length=irc.MAX_COMMAND_LENGTH / 2) - def testSplitSanity(self): + + def test_newlinesBeforeLineBreaking(self): + """ + IRCClient breaks on newlines before it breaks long lines. + """ + # Because MAX_COMMAND_LENGTH includes framing characters, this long + # line is slightly longer than half the permissible message size. + longline = 'o' * (irc.MAX_COMMAND_LENGTH // 2) + + self.client.msg('foo', longline + '\n' + longline) + self.assertEqual( + self.client.lines, + ['PRIVMSG foo :' + longline, + 'PRIVMSG foo :' + longline]) + + + def test_lineBreakOnWordBoundaries(self): + """ + IRCClient prefers to break long lines at word boundaries. + """ + # Because MAX_COMMAND_LENGTH includes framing characters, this long + # line is slightly longer than half the permissible message size. + longline = 'o' * (irc.MAX_COMMAND_LENGTH // 2) + + self.client.msg('foo', longline + ' ' + longline) + self.assertEqual( + self.client.lines, + ['PRIVMSG foo :' + longline, + 'PRIVMSG foo :' + longline]) + + + def test_splitSanity(self): + """ + L{twisted.words.protocols.irc.split} raises C{ValueError} if given a + length less than or equal to C{0} and returns C{[]} when splitting + C{''}. + """ # Whiteboxing self.assertRaises(ValueError, irc.split, 'foo', -1) self.assertRaises(ValueError, irc.split, 'foo', 0) - self.assertEquals([], irc.split('', 1)) - self.assertEquals([], irc.split('')) + self.assertEqual([], irc.split('', 1)) + self.assertEqual([], irc.split('')) def test_splitDelimiters(self): """ - Test that split() skips any delimiter (space or newline) that it finds - at the very beginning of the string segment it is operating on. - Nothing should be added to the output list because of it. + L{twisted.words.protocols.irc.split} skips any delimiter (space or + newline) that it finds at the very beginning of the string segment it + is operating on. Nothing should be added to the output list because of + it. """ r = irc.split("xx yyz", 2) - self.assertEquals(['xx', 'yy', 'z'], r) + self.assertEqual(['xx', 'yy', 'z'], r) r = irc.split("xx\nyyz", 2) - self.assertEquals(['xx', 'yy', 'z'], r) + self.assertEqual(['xx', 'yy', 'z'], r) + + + def test_splitValidatesLength(self): + """ + L{twisted.words.protocols.irc.split} raises C{ValueError} if given a + length less than or equal to C{0}. + """ + self.assertRaises(ValueError, irc.split, "foo", 0) + self.assertRaises(ValueError, irc.split, "foo", -1) + + + def test_say(self): + """ + L{IRCClient.say} prepends the channel prefix C{"#"} if necessary and + then sends the message to the server for delivery to that channel. + """ + self.client.say("thechannel", "the message") + self.assertEquals( + self.client.lines, ["PRIVMSG #thechannel :the message"]) + class ClientTests(TestCase): @@ -1345,7 +1671,10 @@ # Sanity check - we don't want anything to have happened at this # point, since we're not in a test yet. - self.assertEquals(self.transport.value(), "") + self.assertEqual(self.transport.value(), "") + + self.addCleanup(self.transport.loseConnection) + self.addCleanup(self.protocol.connectionLost, None) def getLastLine(self, transport): @@ -1365,7 +1694,7 @@ 'AWAY :%s' % (message,), '', ] - self.assertEquals(self.transport.value().split('\r\n'), expected) + self.assertEqual(self.transport.value().split('\r\n'), expected) def test_back(self): @@ -1377,7 +1706,7 @@ 'AWAY :', '', ] - self.assertEquals(self.transport.value().split('\r\n'), expected) + self.assertEqual(self.transport.value().split('\r\n'), expected) def test_whois(self): @@ -1385,7 +1714,7 @@ L{IRCClient.whois} sends a WHOIS message. """ self.protocol.whois('alice') - self.assertEquals( + self.assertEqual( self.transport.value().split('\r\n'), ['WHOIS alice', '']) @@ -1396,7 +1725,7 @@ value is passed for the C{server} parameter. """ self.protocol.whois('alice', 'example.org') - self.assertEquals( + self.assertEqual( self.transport.value().split('\r\n'), ['WHOIS example.org alice', '']) @@ -1417,7 +1746,7 @@ 'USER %s %s %s :%s' % ( username, hostname, servername, self.protocol.realname), ''] - self.assertEquals(self.transport.value().split('\r\n'), expected) + self.assertEqual(self.transport.value().split('\r\n'), expected) def test_registerWithPassword(self): @@ -1438,7 +1767,7 @@ 'USER %s %s %s :%s' % ( username, hostname, servername, self.protocol.realname), ''] - self.assertEquals(self.transport.value().split('\r\n'), expected) + self.assertEqual(self.transport.value().split('\r\n'), expected) def test_registerWithTakenNick(self): @@ -1460,7 +1789,7 @@ # Keep chaining underscores for each collision self.protocol.irc_ERR_NICKNAMEINUSE('prefix', ['param']) lastLine = self.getLastLine(self.transport) - self.assertEquals(lastLine, 'NICK %s' % (username + '__',)) + self.assertEqual(lastLine, 'NICK %s' % (username + '__',)) def test_overrideAlterCollidedNick(self): @@ -1473,7 +1802,7 @@ self.protocol.register(nick) self.protocol.irc_ERR_NICKNAMEINUSE('prefix', ['param']) lastLine = self.getLastLine(self.transport) - self.assertEquals( + self.assertEqual( lastLine, 'NICK %s' % (nick + '***',)) @@ -1487,9 +1816,9 @@ self.protocol.register(oldnick) self.protocol.irc_RPL_WELCOME('prefix', ['param']) self.protocol.setNick(newnick) - self.assertEquals(self.protocol.nickname, oldnick) + self.assertEqual(self.protocol.nickname, oldnick) self.protocol.irc_NICK('%s!quux@qux' % (oldnick,), [newnick]) - self.assertEquals(self.protocol.nickname, newnick) + self.assertEqual(self.protocol.nickname, newnick) def test_erroneousNick(self): @@ -1500,16 +1829,16 @@ """ # Registration case: change illegal nickname to erroneousNickFallback badnick = 'foo' - self.assertEquals(self.protocol._registered, False) + self.assertEqual(self.protocol._registered, False) self.protocol.register(badnick) self.protocol.irc_ERR_ERRONEUSNICKNAME('prefix', ['param']) lastLine = self.getLastLine(self.transport) - self.assertEquals( + self.assertEqual( lastLine, 'NICK %s' % (self.protocol.erroneousNickFallback,)) self.protocol.irc_RPL_WELCOME('prefix', ['param']) - self.assertEquals(self.protocol._registered, True) + self.assertEqual(self.protocol._registered, True) self.protocol.setNick(self.protocol.erroneousNickFallback) - self.assertEquals( + self.assertEqual( self.protocol.nickname, self.protocol.erroneousNickFallback) # Illegal nick change attempt after registration. Fall back to the old @@ -1518,9 +1847,9 @@ self.protocol.setNick(badnick) self.protocol.irc_ERR_ERRONEUSNICKNAME('prefix', ['param']) lastLine = self.getLastLine(self.transport) - self.assertEquals( + self.assertEqual( lastLine, 'NICK %s' % (badnick,)) - self.assertEquals(self.protocol.nickname, oldnick) + self.assertEqual(self.protocol.nickname, oldnick) def test_describe(self): @@ -1537,30 +1866,33 @@ 'PRIVMSG %s :\01ACTION %s\01' % (target, action), 'PRIVMSG %s :\01ACTION %s\01' % (channel, action), ''] - self.assertEquals(self.transport.value().split('\r\n'), expected) + self.assertEqual(self.transport.value().split('\r\n'), expected) - def test_me(self): + def test_noticedDoesntPrivmsg(self): """ - L{IRCClient.me} sends a CTCP ACTION message to the target channel - specified. - If the target does not begin with a standard channel prefix, - '#' is prepended. + The default implementation of L{IRCClient.noticed} doesn't invoke + C{privmsg()} """ - target = 'foo' - channel = '#bar' - action = 'waves' - self.protocol.me(target, action) - self.protocol.me(channel, action) - expected = [ - 'PRIVMSG %s :\01ACTION %s\01' % ('#' + target, action), - 'PRIVMSG %s :\01ACTION %s\01' % (channel, action), - ''] - self.assertEquals(self.transport.value().split('\r\n'), expected) - warnings = self.flushWarnings( - offendingFunctions=[self.test_me]) - self.assertEquals( - warnings[0]['message'], - "me() is deprecated since Twisted 9.0. Use IRCClient.describe().") - self.assertEquals(warnings[0]['category'], DeprecationWarning) - self.assertEquals(len(warnings), 2) + def privmsg(user, channel, message): + self.fail("privmsg() should not have been called") + self.protocol.privmsg = privmsg + self.protocol.irc_NOTICE( + 'spam', ['#greasyspooncafe', "I don't want any spam!"]) + + + +class DccChatFactoryTests(unittest.TestCase): + """ + Tests for L{DccChatFactory} + """ + def test_buildProtocol(self): + """ + An instance of the DccChat protocol is returned, which has the factory + property set to the factory which created it. + """ + queryData = ('fromUser', None, None) + f = irc.DccChatFactory(None, queryData) + p = f.buildProtocol('127.0.0.1') + self.assertTrue(isinstance(p, irc.DccChat)) + self.assertEqual(p.factory, f) diff -Nru twisted-words-10.0.0/twisted/words/test/test_irc_service.py twisted-words-12.1.0/twisted/words/test/test_irc_service.py --- twisted-words-10.0.0/twisted/words/test/test_irc_service.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/test/test_irc_service.py 2011-07-14 19:05:14.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2009 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -7,7 +7,7 @@ from twisted.trial import unittest from twisted.test import proto_helpers -from twisted.words.service import InMemoryWordsRealm, IRCFactory +from twisted.words.service import InMemoryWordsRealm, IRCFactory, IRCUser from twisted.words.protocols import irc from twisted.cred import checkers, portal @@ -38,7 +38,7 @@ self.ircUser.irc_NICK("", ["mynick"]) self.stringTransport.clear() self.ircUser.sendMessage("foo") - self.assertEquals(":example.com foo mynick\r\n", + self.assertEqual(":example.com foo mynick\r\n", self.stringTransport.value()) @@ -54,12 +54,12 @@ def scanResponse(self, response, messageType): """ Gets messages out of a response - + @param response: The parsed IRC messages of the response, as returned by L{IRCServiceTestCase.response} - + @param messageType: The string type of the desired messages. - + @return: An iterator which yields 2-tuples of C{(index, ircMessage)} """ for n, message in enumerate(response): @@ -77,9 +77,9 @@ response = self.response() start = list(self.scanResponse(response, irc.RPL_MOTDSTART)) end = list(self.scanResponse(response, irc.RPL_ENDOFMOTD)) - self.assertEquals(start, + self.assertEqual(start, [(0, ('example.com', '375', ['mynick', '- example.com Message of the Day - ']))]) - self.assertEquals(end, + self.assertEqual(end, [(1, ('example.com', '376', ['mynick', 'End of /MOTD command.']))]) @@ -98,7 +98,7 @@ creation = ('This server was created on %s' % (self.factory._serverInfo["creationDate"],)) - self.assertEquals(self.response(), + self.assertEqual(self.response(), [('example.com', '375', ['john', '- example.com Message of the Day - ']), ('example.com', '376', ['john', 'End of /MOTD command.']), @@ -108,3 +108,109 @@ ('example.com', '004', ['john', 'example.com', self.factory._serverInfo["serviceVersion"], 'w', 'n'])]) + + + +class MocksyIRCUser(IRCUser): + def __init__(self): + self.mockedCodes = [] + + def sendMessage(self, code, *_, **__): + self.mockedCodes.append(code) + +BADTEXT = '\xff' + +class IRCUserBadEncodingTestCase(unittest.TestCase): + """ + Verifies that L{IRCUser} sends the correct error messages back to clients + when given indecipherable bytes + """ + # TODO: irc_NICK -- but NICKSERV is used for that, so it isn't as easy. + + def setUp(self): + self.ircuser = MocksyIRCUser() + + def assertChokesOnBadBytes(self, irc_x, error): + """ + Asserts that IRCUser sends the relevant error code when a given irc_x + dispatch method is given undecodable bytes. + + @param irc_x: the name of the irc_FOO method to test. + For example, irc_x = 'PRIVMSG' will check irc_PRIVMSG + + @param error: the error code irc_x should send. For example, + irc.ERR_NOTONCHANNEL + """ + getattr(self.ircuser, 'irc_%s' % irc_x)(None, [BADTEXT]) + self.assertEqual(self.ircuser.mockedCodes, [error]) + + # no such channel + + def test_JOIN(self): + """ + Tests that irc_JOIN sends ERR_NOSUCHCHANNEL if the channel name can't + be decoded. + """ + self.assertChokesOnBadBytes('JOIN', irc.ERR_NOSUCHCHANNEL) + + def test_NAMES(self): + """ + Tests that irc_NAMES sends ERR_NOSUCHCHANNEL if the channel name can't + be decoded. + """ + self.assertChokesOnBadBytes('NAMES', irc.ERR_NOSUCHCHANNEL) + + def test_TOPIC(self): + """ + Tests that irc_TOPIC sends ERR_NOSUCHCHANNEL if the channel name can't + be decoded. + """ + self.assertChokesOnBadBytes('TOPIC', irc.ERR_NOSUCHCHANNEL) + + def test_LIST(self): + """ + Tests that irc_LIST sends ERR_NOSUCHCHANNEL if the channel name can't + be decoded. + """ + self.assertChokesOnBadBytes('LIST', irc.ERR_NOSUCHCHANNEL) + + # no such nick + + def test_MODE(self): + """ + Tests that irc_MODE sends ERR_NOSUCHNICK if the target name can't + be decoded. + """ + self.assertChokesOnBadBytes('MODE', irc.ERR_NOSUCHNICK) + + def test_PRIVMSG(self): + """ + Tests that irc_PRIVMSG sends ERR_NOSUCHNICK if the target name can't + be decoded. + """ + self.assertChokesOnBadBytes('PRIVMSG', irc.ERR_NOSUCHNICK) + + def test_WHOIS(self): + """ + Tests that irc_WHOIS sends ERR_NOSUCHNICK if the target name can't + be decoded. + """ + self.assertChokesOnBadBytes('WHOIS', irc.ERR_NOSUCHNICK) + + # not on channel + + def test_PART(self): + """ + Tests that irc_PART sends ERR_NOTONCHANNEL if the target name can't + be decoded. + """ + self.assertChokesOnBadBytes('PART', irc.ERR_NOTONCHANNEL) + + # probably nothing + + def test_WHO(self): + """ + Tests that irc_WHO immediately ends the WHO list if the target name + can't be decoded. + """ + self.assertChokesOnBadBytes('WHO', irc.RPL_ENDOFWHO) diff -Nru twisted-words-10.0.0/twisted/words/test/test_ircsupport.py twisted-words-12.1.0/twisted/words/test/test_ircsupport.py --- twisted-words-10.0.0/twisted/words/test/test_ircsupport.py 1970-01-01 00:00:00.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/test/test_ircsupport.py 2011-07-14 19:05:14.000000000 +0000 @@ -0,0 +1,79 @@ +# Copyright (c) Twisted Matrix Laboratories. +# See LICENSE for details. + +""" +Tests for L{twisted.words.im.ircsupport}. +""" + +from twisted.trial.unittest import TestCase +from twisted.test.proto_helpers import StringTransport + +from twisted.words.im.basechat import Conversation, ChatUI +from twisted.words.im.ircsupport import IRCAccount, IRCProto + + + +class StubConversation(Conversation): + def show(self): + pass + + + +class StubChatUI(ChatUI): + def getGroupConversation(self, group, Class=StubConversation, stayHidden=0): + return ChatUI.getGroupConversation(self, group, Class, stayHidden) + + + +class IRCProtoTests(TestCase): + """ + Tests for L{IRCProto}. + """ + def setUp(self): + self.account = IRCAccount( + "Some account", False, "alice", None, "example.com", 6667) + self.proto = IRCProto(self.account, StubChatUI(), None) + + + def test_login(self): + """ + When L{IRCProto} is connected to a transport, it sends I{NICK} and + I{USER} commands with the username from the account object. + """ + transport = StringTransport() + self.proto.makeConnection(transport) + self.assertEqual( + transport.value(), + "NICK alice\r\n" + "USER alice foo bar :Twisted-IM user\r\n") + + + def test_authenticate(self): + """ + If created with an account with a password, L{IRCProto} sends a + I{PASS} command before the I{NICK} and I{USER} commands. + """ + self.account.password = "secret" + transport = StringTransport() + self.proto.makeConnection(transport) + self.assertEqual( + transport.value(), + "PASS :secret\r\n" + "NICK alice\r\n" + "USER alice foo bar :Twisted-IM user\r\n") + + + def test_channels(self): + """ + If created with an account with a list of channels, L{IRCProto} + joins each of those channels after registering. + """ + self.account.channels = ['#foo', '#bar'] + transport = StringTransport() + self.proto.makeConnection(transport) + self.assertEqual( + transport.value(), + "NICK alice\r\n" + "USER alice foo bar :Twisted-IM user\r\n" + "JOIN #foo\r\n" + "JOIN #bar\r\n") diff -Nru twisted-words-10.0.0/twisted/words/test/test_jabberclient.py twisted-words-12.1.0/twisted/words/test/test_jabberclient.py --- twisted-words-10.0.0/twisted/words/test/test_jabberclient.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/test/test_jabberclient.py 2011-07-14 19:05:14.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2009 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -40,7 +40,7 @@ """ self.init.xmlstream.version = (0, 0) exc = self.assertRaises(error.StreamError, self.init.initialize) - self.assertEquals('unsupported-version', exc.condition) + self.assertEqual('unsupported-version', exc.condition) @@ -136,9 +136,9 @@ The server checks the credentials and responds with an empty result signalling success. """ - self.assertEquals('user', unicode(iq.query.username)) - self.assertEquals('secret', unicode(iq.query.password)) - self.assertEquals('resource', unicode(iq.query.resource)) + self.assertEqual('user', unicode(iq.query.username)) + self.assertEqual('secret', unicode(iq.query.password)) + self.assertEqual('resource', unicode(iq.query.resource)) # Send server response response = xmlstream.toResponse(iq, 'result') @@ -192,10 +192,10 @@ The server checks the credentials and responds with an empty result signalling success. """ - self.assertEquals('user', unicode(iq.query.username)) - self.assertEquals(sha1('12345secret').hexdigest(), + self.assertEqual('user', unicode(iq.query.username)) + self.assertEqual(sha1('12345secret').hexdigest(), unicode(iq.query.digest).encode('utf-8')) - self.assertEquals('resource', unicode(iq.query.resource)) + self.assertEqual('resource', unicode(iq.query.resource)) # Send server response response = xmlstream.toResponse(iq, 'result') @@ -312,7 +312,7 @@ self.pipe.source.send(response) def cb(result): - self.assertEquals(jid.JID('user@example.com/other resource'), + self.assertEqual(jid.JID('user@example.com/other resource'), self.authenticator.jid) d1 = self.waitFor(IQ_BIND_SET, onBind) diff -Nru twisted-words-10.0.0/twisted/words/test/test_jabbercomponent.py twisted-words-12.1.0/twisted/words/test/test_jabbercomponent.py --- twisted-words-10.0.0/twisted/words/test/test_jabbercomponent.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/test/test_jabbercomponent.py 2011-07-14 19:05:14.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2009 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -47,9 +47,9 @@ # the initializer should have sent the handshake request handshake = self.output[-1] - self.assertEquals('handshake', handshake.name) - self.assertEquals('test:component', handshake.uri) - self.assertEquals(sha1("%s%s" % ('12345', 'secret')).hexdigest(), + self.assertEqual('handshake', handshake.name) + self.assertEqual('test:component', handshake.uri) + self.assertEqual(sha1("%s%s" % ('12345', 'secret')).hexdigest(), unicode(handshake)) # successful authentication @@ -81,11 +81,11 @@ # Calculate what we expect the handshake value to be hv = sha1("%s%s" % ("12345", "secret")).hexdigest() - self.assertEquals(outlist[1], "%s" % (hv)) + self.assertEqual(outlist[1], "%s" % (hv)) xs.dataReceived("") - self.assertEquals(self.authComplete, True) + self.assertEqual(self.authComplete, True) class JabberServiceHarness(component.Service): @@ -123,19 +123,19 @@ xs.connectionMade() # Ensure the test service harness got notified - self.assertEquals(True, svc.transportConnectedFlag) + self.assertEqual(True, svc.transportConnectedFlag) # Jump ahead and pretend like the stream got auth'd xs.dispatch(xs, xmlstream.STREAM_AUTHD_EVENT) # Ensure the test service harness got notified - self.assertEquals(True, svc.componentConnectedFlag) + self.assertEqual(True, svc.componentConnectedFlag) # Pretend to drop the connection xs.connectionLost(None) # Ensure the test service harness got notified - self.assertEquals(True, svc.componentDisconnectedFlag) + self.assertEqual(True, svc.componentDisconnectedFlag) @@ -154,12 +154,12 @@ pipe = XmlPipe() router.addRoute('example.org', pipe.sink) - self.assertEquals(1, len(router.routes)) - self.assertEquals(pipe.sink, router.routes['example.org']) + self.assertEqual(1, len(router.routes)) + self.assertEqual(pipe.sink, router.routes['example.org']) element = domish.Element(('testns', 'test')) pipe.source.send(element) - self.assertEquals([element], routed) + self.assertEqual([element], routed) def test_route(self): @@ -179,7 +179,7 @@ stanza['from'] = 'component1.example.org' stanza['to'] = 'component2.example.org' component1.source.send(stanza) - self.assertEquals([stanza], outgoing) + self.assertEqual([stanza], outgoing) def test_routeDefault(self): @@ -202,7 +202,7 @@ stanza['from'] = 'component1.example.org' stanza['to'] = 'example.com' component1.source.send(stanza) - self.assertEquals([stanza], outgoing) + self.assertEqual([stanza], outgoing) @@ -247,7 +247,7 @@ self.assertEqual((0, 0), xs.version) self.assertNotIdentical(None, xs.sid) self.assertTrue(xs._headerSent) - self.assertEquals(('/*', xs.authenticator.onElement), observers[-1]) + self.assertEqual(('/*', xs.authenticator.onElement), observers[-1]) def test_streamStartedWrongNamespace(self): @@ -262,8 +262,8 @@ xs.dataReceived("") - self.assertEquals(1, len(streamErrors)) - self.assertEquals('invalid-namespace', streamErrors[-1].condition) + self.assertEqual(1, len(streamErrors)) + self.assertEqual('invalid-namespace', streamErrors[-1].condition) def test_streamStartedNoTo(self): @@ -277,8 +277,8 @@ xs.makeConnection(self) xs.dataReceived("") - self.assertEquals(1, len(streamErrors)) - self.assertEquals('improper-addressing', streamErrors[-1].condition) + self.assertEqual(1, len(streamErrors)) + self.assertEqual('improper-addressing', streamErrors[-1].condition) def test_onElement(self): @@ -309,7 +309,7 @@ element = domish.Element(('jabber:component:accept', 'message')) xs.authenticator.onElement(element) self.assertFalse(handshakes) - self.assertEquals('not-authorized', streamErrors[-1].condition) + self.assertEqual('not-authorized', streamErrors[-1].condition) def test_onHandshake(self): @@ -327,7 +327,7 @@ theHash = '32532c0f7dbf1253c095b18b18e36d38d94c1256' xs.authenticator.onHandshake(theHash) self.assertEqual('', self.output[-1]) - self.assertEquals(1, len(authd)) + self.assertEqual(1, len(authd)) def test_onHandshakeWrongHash(self): @@ -347,8 +347,8 @@ xs.sid = u'1234' theHash = '1234' xs.authenticator.onHandshake(theHash) - self.assertEquals('not-authorized', streamErrors[-1].condition) - self.assertEquals(0, len(authd)) + self.assertEqual('not-authorized', streamErrors[-1].condition) + self.assertEqual(0, len(authd)) diff -Nru twisted-words-10.0.0/twisted/words/test/test_jabbererror.py twisted-words-12.1.0/twisted/words/test/test_jabbererror.py --- twisted-words-10.0.0/twisted/words/test/test_jabbererror.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/test/test_jabbererror.py 2011-07-14 19:05:14.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -24,7 +24,7 @@ e = error.BaseError('feature-not-implemented') element = e.getElement() self.assertIdentical(element.uri, None) - self.assertEquals(len(element.children), 1) + self.assertEqual(len(element.children), 1) def test_getElementText(self): """ @@ -32,9 +32,9 @@ """ e = error.BaseError('feature-not-implemented', 'text') element = e.getElement() - self.assertEquals(len(element.children), 2) - self.assertEquals(unicode(element.text), 'text') - self.assertEquals(element.text.getAttribute((NS_XML, 'lang')), None) + self.assertEqual(len(element.children), 2) + self.assertEqual(unicode(element.text), 'text') + self.assertEqual(element.text.getAttribute((NS_XML, 'lang')), None) def test_getElementTextLang(self): """ @@ -42,9 +42,9 @@ """ e = error.BaseError('feature-not-implemented', 'text', 'en_US') element = e.getElement() - self.assertEquals(len(element.children), 2) - self.assertEquals(unicode(element.text), 'text') - self.assertEquals(element.text[(NS_XML, 'lang')], 'en_US') + self.assertEqual(len(element.children), 2) + self.assertEqual(unicode(element.text), 'text') + self.assertEqual(element.text[(NS_XML, 'lang')], 'en_US') def test_getElementAppCondition(self): """ @@ -53,8 +53,8 @@ ac = domish.Element(('testns', 'myerror')) e = error.BaseError('feature-not-implemented', appCondition=ac) element = e.getElement() - self.assertEquals(len(element.children), 2) - self.assertEquals(element.myerror, ac) + self.assertEqual(len(element.children), 2) + self.assertEqual(element.myerror, ac) class StreamErrorTest(unittest.TestCase): @@ -64,7 +64,7 @@ """ e = error.StreamError('feature-not-implemented') element = e.getElement() - self.assertEquals(element.uri, NS_STREAMS) + self.assertEqual(element.uri, NS_STREAMS) def test_getElementConditionNamespace(self): """ @@ -72,7 +72,7 @@ """ e = error.StreamError('feature-not-implemented') element = e.getElement() - self.assertEquals(NS_XMPP_STREAMS, getattr(element, 'feature-not-implemented').uri) + self.assertEqual(NS_XMPP_STREAMS, getattr(element, 'feature-not-implemented').uri) def test_getElementTextNamespace(self): """ @@ -80,9 +80,24 @@ """ e = error.StreamError('feature-not-implemented', 'text') element = e.getElement() - self.assertEquals(NS_XMPP_STREAMS, element.text.uri) + self.assertEqual(NS_XMPP_STREAMS, element.text.uri) + + class StanzaErrorTest(unittest.TestCase): + """ + Tests for L{error.StreamError}. + """ + + + def test_typeRemoteServerTimeout(self): + """ + Remote Server Timeout should yield type wait, code 504. + """ + e = error.StanzaError('remote-server-timeout') + self.assertEqual('wait', e.type) + self.assertEqual('504', e.code) + def test_getElementPlain(self): """ @@ -90,9 +105,10 @@ """ e = error.StanzaError('feature-not-implemented') element = e.getElement() - self.assertEquals(element.uri, None) - self.assertEquals(element['type'], 'cancel') - self.assertEquals(element['code'], '501') + self.assertEqual(element.uri, None) + self.assertEqual(element['type'], 'cancel') + self.assertEqual(element['code'], '501') + def test_getElementType(self): """ @@ -100,9 +116,10 @@ """ e = error.StanzaError('feature-not-implemented', 'auth') element = e.getElement() - self.assertEquals(element.uri, None) - self.assertEquals(element['type'], 'auth') - self.assertEquals(element['code'], '501') + self.assertEqual(element.uri, None) + self.assertEqual(element['type'], 'auth') + self.assertEqual(element['code'], '501') + def test_getElementConditionNamespace(self): """ @@ -110,7 +127,8 @@ """ e = error.StanzaError('feature-not-implemented') element = e.getElement() - self.assertEquals(NS_XMPP_STANZAS, getattr(element, 'feature-not-implemented').uri) + self.assertEqual(NS_XMPP_STANZAS, getattr(element, 'feature-not-implemented').uri) + def test_getElementTextNamespace(self): """ @@ -118,7 +136,8 @@ """ e = error.StanzaError('feature-not-implemented', text='text') element = e.getElement() - self.assertEquals(NS_XMPP_STANZAS, element.text.uri) + self.assertEqual(NS_XMPP_STANZAS, element.text.uri) + def test_toResponse(self): """ @@ -143,11 +162,18 @@ self.assertEqual(response.error['type'], 'cancel') self.assertNotEqual(stanza.children, response.children) + + class ParseErrorTest(unittest.TestCase): + """ + Tests for L{error._parseError}. + """ + def setUp(self): self.error = domish.Element((None, 'error')) + def test_empty(self): """ Test parsing of the empty error element. @@ -158,6 +184,7 @@ 'textLang': None, 'appCondition': None}, result) + def test_condition(self): """ Test parsing of an error element with a condition. @@ -166,6 +193,7 @@ result = error._parseError(self.error, 'errorns') self.assertEqual('bad-request', result['condition']) + def test_text(self): """ Test parsing of an error element with a text. @@ -176,6 +204,7 @@ self.assertEqual('test', result['text']) self.assertEqual(None, result['textLang']) + def test_textLang(self): """ Test parsing of an error element with a text with a defined language. @@ -186,6 +215,7 @@ result = error._parseError(self.error, 'errorns') self.assertEqual('en_US', result['textLang']) + def test_textLangInherited(self): """ Test parsing of an error element with a text with inherited language. @@ -197,6 +227,7 @@ self.assertEqual('en_US', result['textLang']) test_textLangInherited.todo = "xml:lang inheritance not implemented" + def test_appCondition(self): """ Test parsing of an error element with an app specific condition. @@ -205,14 +236,17 @@ result = error._parseError(self.error, 'errorns') self.assertEqual(condition, result['appCondition']) + def test_appConditionMultiple(self): """ Test parsing of an error element with multiple app specific conditions. """ - condition = self.error.addElement(('testns', 'condition')) - condition2 = self.error.addElement(('testns', 'condition2')) + self.error.addElement(('testns', 'condition')) + condition = self.error.addElement(('testns', 'condition2')) result = error._parseError(self.error, 'errorns') - self.assertEqual(condition2, result['appCondition']) + self.assertEqual(condition, result['appCondition']) + + class ExceptionFromStanzaTest(unittest.TestCase): @@ -252,10 +286,10 @@ result = error.exceptionFromStanza(stanza) self.assert_(isinstance(result, error.StanzaError)) - self.assertEquals('feature-not-implemented', result.condition) - self.assertEquals('cancel', result.type) - self.assertEquals(uc, result.appCondition) - self.assertEquals([p], result.children) + self.assertEqual('feature-not-implemented', result.condition) + self.assertEqual('cancel', result.type) + self.assertEqual(uc, result.appCondition) + self.assertEqual([p], result.children) def test_legacy(self): """ @@ -280,10 +314,10 @@ result = error.exceptionFromStanza(stanza) self.assert_(isinstance(result, error.StanzaError)) - self.assertEquals('service-unavailable', result.condition) - self.assertEquals('wait', result.type) - self.assertEquals('Unable to resolve hostname.', result.text) - self.assertEquals([p], result.children) + self.assertEqual('service-unavailable', result.condition) + self.assertEqual('wait', result.type) + self.assertEqual('Unable to resolve hostname.', result.text) + self.assertEqual([p], result.children) class ExceptionFromStreamErrorTest(unittest.TestCase): @@ -305,4 +339,4 @@ result = error.exceptionFromStreamError(e) self.assert_(isinstance(result, error.StreamError)) - self.assertEquals('xml-not-well-formed', result.condition) + self.assertEqual('xml-not-well-formed', result.condition) diff -Nru twisted-words-10.0.0/twisted/words/test/test_jabberjid.py twisted-words-12.1.0/twisted/words/test/test_jabberjid.py --- twisted-words-10.0.0/twisted/words/test/test_jabberjid.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/test/test_jabberjid.py 2011-07-14 19:05:14.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -15,27 +15,27 @@ Test different forms of JIDs. """ # Basic forms - self.assertEquals(jid.parse("user@host/resource"), + self.assertEqual(jid.parse("user@host/resource"), ("user", "host", "resource")) - self.assertEquals(jid.parse("user@host"), + self.assertEqual(jid.parse("user@host"), ("user", "host", None)) - self.assertEquals(jid.parse("host"), + self.assertEqual(jid.parse("host"), (None, "host", None)) - self.assertEquals(jid.parse("host/resource"), + self.assertEqual(jid.parse("host/resource"), (None, "host", "resource")) # More interesting forms - self.assertEquals(jid.parse("foo/bar@baz"), + self.assertEqual(jid.parse("foo/bar@baz"), (None, "foo", "bar@baz")) - self.assertEquals(jid.parse("boo@foo/bar@baz"), + self.assertEqual(jid.parse("boo@foo/bar@baz"), ("boo", "foo", "bar@baz")) - self.assertEquals(jid.parse("boo@foo/bar/baz"), + self.assertEqual(jid.parse("boo@foo/bar/baz"), ("boo", "foo", "bar/baz")) - self.assertEquals(jid.parse("boo/foo@bar@baz"), + self.assertEqual(jid.parse("boo/foo@bar@baz"), (None, "boo", "foo@bar@baz")) - self.assertEquals(jid.parse("boo/foo/bar"), + self.assertEqual(jid.parse("boo/foo/bar"), (None, "boo", "foo/bar")) - self.assertEquals(jid.parse("boo//foo"), + self.assertEqual(jid.parse("boo//foo"), (None, "boo", "/foo")) def test_noHost(self): @@ -69,21 +69,21 @@ """ Test case mapping of the user part of the JID. """ - self.assertEquals(jid.prep("UsEr", "host", "resource"), + self.assertEqual(jid.prep("UsEr", "host", "resource"), ("user", "host", "resource")) def test_prepCaseMapHost(self): """ Test case mapping of the host part of the JID. """ - self.assertEquals(jid.prep("user", "hoST", "resource"), + self.assertEqual(jid.prep("user", "hoST", "resource"), ("user", "host", "resource")) def test_prepNoCaseMapResource(self): """ Test no case mapping of the resourcce part of the JID. """ - self.assertEquals(jid.prep("user", "hoST", "resource"), + self.assertEqual(jid.prep("user", "hoST", "resource"), ("user", "host", "resource")) self.assertNotEquals(jid.prep("user", "host", "Resource"), ("user", "host", "resource")) @@ -101,23 +101,23 @@ Test that the attributes correspond with the JID parts. """ j = jid.JID("user@host/resource") - self.assertEquals(j.user, "user") - self.assertEquals(j.host, "host") - self.assertEquals(j.resource, "resource") + self.assertEqual(j.user, "user") + self.assertEqual(j.host, "host") + self.assertEqual(j.resource, "resource") def test_userhost(self): """ Test the extraction of the bare JID. """ j = jid.JID("user@host/resource") - self.assertEquals("user@host", j.userhost()) + self.assertEqual("user@host", j.userhost()) def test_userhostOnlyHost(self): """ Test the extraction of the bare JID of the full form host/resource. """ j = jid.JID("host/resource") - self.assertEquals("host", j.userhost()) + self.assertEqual("host", j.userhost()) def test_userhostJID(self): """ @@ -206,14 +206,14 @@ Test unicode representation of JIDs. """ j = jid.JID(tuple=('user', 'host', 'resource')) - self.assertEquals("user@host/resource", unicode(j)) + self.assertEqual("user@host/resource", unicode(j)) def test_repr(self): """ Test representation of JID objects. """ j = jid.JID(tuple=('user', 'host', 'resource')) - self.assertEquals("JID(u'user@host/resource')", repr(j)) + self.assertEqual("JID(u'user@host/resource')", repr(j)) class InternJIDTest(unittest.TestCase): def test_identity(self): diff -Nru twisted-words-10.0.0/twisted/words/test/test_jabberjstrports.py twisted-words-12.1.0/twisted/words/test/test_jabberjstrports.py --- twisted-words-10.0.0/twisted/words/test/test_jabberjstrports.py 1970-01-01 00:00:00.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/test/test_jabberjstrports.py 2011-07-14 19:05:14.000000000 +0000 @@ -0,0 +1,34 @@ +# Copyright (c) Twisted Matrix Laboratories. +# See LICENSE for details. + +""" +Tests for L{twisted.words.protocols.jabber.jstrports}. +""" + +from twisted.trial import unittest + +from twisted.words.protocols.jabber import jstrports +from twisted.application.internet import TCPClient + + +class JabberStrPortsPlaceHolderTest(unittest.TestCase): + """ + Tests for L{jstrports} + """ + + def test_parse(self): + """ + L{jstrports.parse} accepts an endpoint description string and returns a + tuple and dict of parsed endpoint arguments. + """ + expected = ('TCP', ('DOMAIN', 65535, 'Factory'), {}) + got = jstrports.parse("tcp:DOMAIN:65535", "Factory") + self.assertEqual(expected, got) + + + def test_client(self): + """ + L{jstrports.client} returns a L{TCPClient} service. + """ + got = jstrports.client("tcp:DOMAIN:65535", "Factory") + self.assertIsInstance(got, TCPClient) diff -Nru twisted-words-10.0.0/twisted/words/test/test_jabbersaslmechanisms.py twisted-words-12.1.0/twisted/words/test/test_jabbersaslmechanisms.py --- twisted-words-10.0.0/twisted/words/test/test_jabbersaslmechanisms.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/test/test_jabbersaslmechanisms.py 2011-07-14 19:05:14.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2009 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -15,7 +15,7 @@ Test the initial response. """ m = sasl_mechanisms.Plain(None, 'test', 'secret') - self.assertEquals(m.getInitialResponse(), '\x00test\x00secret') + self.assertEqual(m.getInitialResponse(), '\x00test\x00secret') @@ -28,7 +28,7 @@ Test the initial response to be empty. """ m = sasl_mechanisms.Anonymous() - self.assertEquals(m.getInitialResponse(), None) + self.assertEqual(m.getInitialResponse(), None) diff -Nru twisted-words-10.0.0/twisted/words/test/test_jabbersasl.py twisted-words-12.1.0/twisted/words/test/test_jabbersasl.py --- twisted-words-10.0.0/twisted/words/test/test_jabbersasl.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/test/test_jabbersasl.py 2011-07-14 19:05:14.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2009 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. from zope.interface import implements @@ -86,7 +86,7 @@ self.init.onFailure(failure) self.assertFailure(self.init._deferred, sasl.SASLAuthError) self.init._deferred.addCallback(lambda e: - self.assertEquals('not-authorized', + self.assertEqual('not-authorized', e.condition)) return self.init._deferred @@ -98,10 +98,10 @@ self.init.initialResponse = "dummy" self.init.start() auth = self.output[0] - self.assertEquals(NS_XMPP_SASL, auth.uri) - self.assertEquals('auth', auth.name) - self.assertEquals('DUMMY', auth['mechanism']) - self.assertEquals('ZHVtbXk=', str(auth)) + self.assertEqual(NS_XMPP_SASL, auth.uri) + self.assertEqual('auth', auth.name) + self.assertEqual('DUMMY', auth['mechanism']) + self.assertEqual('ZHVtbXk=', str(auth)) def test_sendAuthNoInitialResponse(self): @@ -111,7 +111,7 @@ self.init.initialResponse = None self.init.start() auth = self.output[0] - self.assertEquals('', str(auth)) + self.assertEqual('', str(auth)) def test_sendAuthEmptyInitialResponse(self): @@ -121,7 +121,7 @@ self.init.initialResponse = "" self.init.start() auth = self.output[0] - self.assertEquals('=', str(auth)) + self.assertEqual('=', str(auth)) def test_onChallenge(self): diff -Nru twisted-words-10.0.0/twisted/words/test/test_jabberxmlstream.py twisted-words-12.1.0/twisted/words/test/test_jabberxmlstream.py --- twisted-words-10.0.0/twisted/words/test/test_jabberxmlstream.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/test/test_jabberxmlstream.py 2011-07-14 19:05:14.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2009 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -12,6 +12,7 @@ from twisted.internet import defer, task from twisted.internet.error import ConnectionLost from twisted.internet.interfaces import IProtocolFactory +from twisted.python import failure from twisted.test import proto_helpers from twisted.words.test.test_xmlstream import GenericXmlStreamFactoryTestsMixin from twisted.words.xish import domish @@ -80,20 +81,20 @@ def testBasic(self): - self.assertEquals(self.iq['type'], 'get') + self.assertEqual(self.iq['type'], 'get') self.assertTrue(self.iq['id']) def testSend(self): self.xmlstream.transport.clear() self.iq.send() - self.assertEquals("" % self.iq['id'], + self.assertEqual("" % self.iq['id'], self.xmlstream.transport.value()) def testResultResponse(self): def cb(result): - self.assertEquals(result['type'], 'result') + self.assertEqual(result['type'], 'result') d = self.iq.send() d.addCallback(cb) @@ -608,6 +609,10 @@ class ListenAuthenticatorTest(unittest.TestCase): + """ + Tests for L{xmlstream.ListenAuthenticator} + """ + def setUp(self): self.authenticator = xmlstream.ListenAuthenticator() self.xmlstream = xmlstream.XmlStream(self.authenticator) @@ -633,6 +638,19 @@ self.assertEqual('example.com', xs.thisEntity.host) + def test_streamStartUnicodeSessionID(self): + """ + The generated session id must be a unicode object. + """ + xs = self.xmlstream + xs.makeConnection(proto_helpers.StringTransport()) + xs.dataReceived("") + self.assertIsInstance(xs.sid, unicode) + + class TLSInitiatingInitializerTest(unittest.TestCase): def setUp(self): @@ -665,12 +683,12 @@ self.xmlstream.sendHeader = lambda: self.done.append('header') d = self.init.start() - d.addCallback(self.assertEquals, xmlstream.Reset) + d.addCallback(self.assertEqual, xmlstream.Reset) starttls = self.output[0] - self.assertEquals('starttls', starttls.name) - self.assertEquals(NS_XMPP_TLS, starttls.uri) + self.assertEqual('starttls', starttls.name) + self.assertEqual(NS_XMPP_TLS, starttls.uri) self.xmlstream.dataReceived("" % NS_XMPP_TLS) - self.assertEquals(['TLS', 'reset', 'header'], self.done) + self.assertEqual(['TLS', 'reset', 'header'], self.done) return d @@ -685,8 +703,8 @@ xmlstream.ssl = None d = self.init.start() - d.addCallback(self.assertEquals, None) - self.assertEquals([], self.output) + d.addCallback(self.assertEqual, None) + self.assertEqual([], self.output) return d @@ -700,7 +718,7 @@ d = self.init.start() self.assertFailure(d, xmlstream.TLSNotSupported) - self.assertEquals([], self.output) + self.assertEqual([], self.output) return d @@ -715,7 +733,7 @@ self.init.wanted = False d = self.init.start() - self.assertEquals([], self.output) + self.assertEqual([], self.output) self.assertFailure(d, xmlstream.TLSRequired) return d @@ -731,7 +749,7 @@ d = self.init.start() d.addCallback(self.assertEqual, None) - self.assertEquals([], self.output) + self.assertEqual([], self.output) return d @@ -906,6 +924,20 @@ +class FailureReasonXMPPHandler(xmlstream.XMPPHandler): + """ + Dummy handler specifically for failure Reason tests. + """ + def __init__(self): + self.gotFailureReason = False + + + def connectionLost(self, reason): + if isinstance(reason, failure.Failure): + self.gotFailureReason = True + + + class XMPPHandlerTest(unittest.TestCase): """ Tests for L{xmlstream.XMPPHandler}. @@ -932,7 +964,7 @@ handler = xmlstream.XMPPHandler() handler.parent = DummyStreamManager() handler.send('') - self.assertEquals([''], handler.parent.outlist) + self.assertEqual([''], handler.parent.outlist) def test_makeConnection(self): @@ -1016,14 +1048,14 @@ """ sm = self.streamManager self.assertIdentical(None, sm.xmlstream) - self.assertEquals([], sm.handlers) - self.assertEquals(sm._connected, + self.assertEqual([], sm.handlers) + self.assertEqual(sm._connected, sm.factory.callbacks['//event/stream/connected']) - self.assertEquals(sm._authd, + self.assertEqual(sm._authd, sm.factory.callbacks['//event/stream/authd']) - self.assertEquals(sm._disconnected, + self.assertEqual(sm._disconnected, sm.factory.callbacks['//event/stream/end']) - self.assertEquals(sm.initializationFailed, + self.assertEqual(sm.initializationFailed, sm.factory.callbacks['//event/xmpp/initfailed']) @@ -1037,9 +1069,9 @@ handler.setHandlerParent(sm) xs = xmlstream.XmlStream(xmlstream.Authenticator()) sm._connected(xs) - self.assertEquals(1, handler.doneMade) - self.assertEquals(0, handler.doneInitialized) - self.assertEquals(0, handler.doneLost) + self.assertEqual(1, handler.doneMade) + self.assertEqual(0, handler.doneInitialized) + self.assertEqual(0, handler.doneLost) def test_connectedLogTrafficFalse(self): @@ -1079,9 +1111,9 @@ handler.setHandlerParent(sm) xs = xmlstream.XmlStream(xmlstream.Authenticator()) sm._authd(xs) - self.assertEquals(0, handler.doneMade) - self.assertEquals(1, handler.doneInitialized) - self.assertEquals(0, handler.doneLost) + self.assertEqual(0, handler.doneMade) + self.assertEqual(1, handler.doneInitialized) + self.assertEqual(0, handler.doneLost) def test_disconnected(self): @@ -1094,9 +1126,22 @@ handler.setHandlerParent(sm) xs = xmlstream.XmlStream(xmlstream.Authenticator()) sm._disconnected(xs) - self.assertEquals(0, handler.doneMade) - self.assertEquals(0, handler.doneInitialized) - self.assertEquals(1, handler.doneLost) + self.assertEqual(0, handler.doneMade) + self.assertEqual(0, handler.doneInitialized) + self.assertEqual(1, handler.doneLost) + + + def test_disconnectedReason(self): + """ + A L{STREAM_END_EVENT} results in L{StreamManager} firing the handlers + L{connectionLost} methods, passing a L{failure.Failure} reason. + """ + sm = self.streamManager + handler = FailureReasonXMPPHandler() + handler.setHandlerParent(sm) + xs = xmlstream.XmlStream(xmlstream.Authenticator()) + sm._disconnected(failure.Failure(Exception("no reason"))) + self.assertEqual(True, handler.gotFailureReason) def test_addHandler(self): @@ -1107,9 +1152,9 @@ handler = DummyXMPPHandler() handler.setHandlerParent(sm) - self.assertEquals(0, handler.doneMade) - self.assertEquals(0, handler.doneInitialized) - self.assertEquals(0, handler.doneLost) + self.assertEqual(0, handler.doneMade) + self.assertEqual(0, handler.doneInitialized) + self.assertEqual(0, handler.doneLost) def test_addHandlerInitialized(self): @@ -1128,9 +1173,9 @@ handler = DummyXMPPHandler() handler.setHandlerParent(sm) - self.assertEquals(1, handler.doneMade) - self.assertEquals(1, handler.doneInitialized) - self.assertEquals(0, handler.doneLost) + self.assertEqual(1, handler.doneMade) + self.assertEqual(1, handler.doneInitialized) + self.assertEqual(0, handler.doneLost) def test_sendInitialized(self): @@ -1149,7 +1194,7 @@ "from='example.com' id='12345'>") xs.dispatch(xs, "//event/stream/authd") sm.send("") - self.assertEquals("", xs.transport.value()) + self.assertEqual("", xs.transport.value()) def test_sendNotConnected(self): @@ -1167,19 +1212,19 @@ xs = factory.buildProtocol(None) xs.transport = proto_helpers.StringTransport() sm.send("") - self.assertEquals("", xs.transport.value()) - self.assertEquals("", sm._packetQueue[0]) + self.assertEqual("", xs.transport.value()) + self.assertEqual("", sm._packetQueue[0]) xs.connectionMade() - self.assertEquals("", xs.transport.value()) - self.assertEquals("", sm._packetQueue[0]) + self.assertEqual("", xs.transport.value()) + self.assertEqual("", sm._packetQueue[0]) xs.dataReceived("") xs.dispatch(xs, "//event/stream/authd") - self.assertEquals("", xs.transport.value()) + self.assertEqual("", xs.transport.value()) self.assertFalse(sm._packetQueue) @@ -1198,8 +1243,8 @@ "xmlns:stream='http://etherx.jabber.org/streams' " "from='example.com' id='12345'>") sm.send("") - self.assertEquals("", xs.transport.value()) - self.assertEquals("", sm._packetQueue[0]) + self.assertEqual("", xs.transport.value()) + self.assertEqual("", sm._packetQueue[0]) def test_sendDisconnected(self): @@ -1220,8 +1265,8 @@ xs.connectionLost(None) sm.send("") - self.assertEquals("", xs.transport.value()) - self.assertEquals("", sm._packetQueue[0]) + self.assertEqual("", xs.transport.value()) + self.assertEqual("", sm._packetQueue[0]) @@ -1265,7 +1310,7 @@ instance gets an authenticator. """ xs = self.factory.buildProtocol(None) - self.assertEquals([xs], xs.authenticator.xmlstreams) + self.assertEqual([xs], xs.authenticator.xmlstreams) def test_buildProtocolXmlStream(self): diff -Nru twisted-words-10.0.0/twisted/words/test/test_jabberxmppstringprep.py twisted-words-12.1.0/twisted/words/test/test_jabberxmppstringprep.py --- twisted-words-10.0.0/twisted/words/test/test_jabberxmppstringprep.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/test/test_jabberxmppstringprep.py 2011-07-14 19:05:14.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2005 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. from twisted.trial import unittest @@ -23,26 +23,26 @@ """ def testResourcePrep(self): - self.assertEquals(resourceprep.prepare(u'resource'), u'resource') + self.assertEqual(resourceprep.prepare(u'resource'), u'resource') self.assertNotEquals(resourceprep.prepare(u'Resource'), u'resource') - self.assertEquals(resourceprep.prepare(u' '), u' ') + self.assertEqual(resourceprep.prepare(u' '), u' ') if crippled: return - self.assertEquals(resourceprep.prepare(u'Henry \u2163'), u'Henry IV') - self.assertEquals(resourceprep.prepare(u'foo\xad\u034f\u1806\u180b' + self.assertEqual(resourceprep.prepare(u'Henry \u2163'), u'Henry IV') + self.assertEqual(resourceprep.prepare(u'foo\xad\u034f\u1806\u180b' u'bar\u200b\u2060' u'baz\ufe00\ufe08\ufe0f\ufeff'), u'foobarbaz') - self.assertEquals(resourceprep.prepare(u'\u00a0'), u' ') + self.assertEqual(resourceprep.prepare(u'\u00a0'), u' ') self.assertRaises(UnicodeError, resourceprep.prepare, u'\u1680') - self.assertEquals(resourceprep.prepare(u'\u2000'), u' ') - self.assertEquals(resourceprep.prepare(u'\u200b'), u'') + self.assertEqual(resourceprep.prepare(u'\u2000'), u' ') + self.assertEqual(resourceprep.prepare(u'\u200b'), u'') self.assertRaises(UnicodeError, resourceprep.prepare, u'\u0010\u007f') self.assertRaises(UnicodeError, resourceprep.prepare, u'\u0085') self.assertRaises(UnicodeError, resourceprep.prepare, u'\u180e') - self.assertEquals(resourceprep.prepare(u'\ufeff'), u'') + self.assertEqual(resourceprep.prepare(u'\ufeff'), u'') self.assertRaises(UnicodeError, resourceprep.prepare, u'\uf123') self.assertRaises(UnicodeError, resourceprep.prepare, u'\U000f1234') self.assertRaises(UnicodeError, resourceprep.prepare, u'\U0010f234') @@ -51,28 +51,36 @@ self.assertRaises(UnicodeError, resourceprep.prepare, u'\udf42') self.assertRaises(UnicodeError, resourceprep.prepare, u'\ufffd') self.assertRaises(UnicodeError, resourceprep.prepare, u'\u2ff5') - self.assertEquals(resourceprep.prepare(u'\u0341'), u'\u0301') + self.assertEqual(resourceprep.prepare(u'\u0341'), u'\u0301') self.assertRaises(UnicodeError, resourceprep.prepare, u'\u200e') self.assertRaises(UnicodeError, resourceprep.prepare, u'\u202a') self.assertRaises(UnicodeError, resourceprep.prepare, u'\U000e0001') self.assertRaises(UnicodeError, resourceprep.prepare, u'\U000e0042') self.assertRaises(UnicodeError, resourceprep.prepare, u'foo\u05bebar') self.assertRaises(UnicodeError, resourceprep.prepare, u'foo\ufd50bar') - #self.assertEquals(resourceprep.prepare(u'foo\ufb38bar'), + #self.assertEqual(resourceprep.prepare(u'foo\ufb38bar'), # u'foo\u064ebar') self.assertRaises(UnicodeError, resourceprep.prepare, u'\u06271') - self.assertEquals(resourceprep.prepare(u'\u06271\u0628'), + self.assertEqual(resourceprep.prepare(u'\u06271\u0628'), u'\u06271\u0628') self.assertRaises(UnicodeError, resourceprep.prepare, u'\U000e0002') def testNodePrep(self): - self.assertEquals(nodeprep.prepare(u'user'), u'user') - self.assertEquals(nodeprep.prepare(u'User'), u'user') + self.assertEqual(nodeprep.prepare(u'user'), u'user') + self.assertEqual(nodeprep.prepare(u'User'), u'user') self.assertRaises(UnicodeError, nodeprep.prepare, u'us&er') + + def test_nodeprepUnassignedInUnicode32(self): + """ + Make sure unassigned code points from Unicode 3.2 are rejected. + """ + self.assertRaises(UnicodeError, nodeprep.prepare, u'\u1d39') + + def testNamePrep(self): - self.assertEquals(nameprep.prepare(u'example.com'), u'example.com') - self.assertEquals(nameprep.prepare(u'Example.com'), u'example.com') + self.assertEqual(nameprep.prepare(u'example.com'), u'example.com') + self.assertEqual(nameprep.prepare(u'Example.com'), u'example.com') self.assertRaises(UnicodeError, nameprep.prepare, u'ex@mple.com') self.assertRaises(UnicodeError, nameprep.prepare, u'-example.com') self.assertRaises(UnicodeError, nameprep.prepare, u'example-.com') @@ -80,5 +88,5 @@ if crippled: return - self.assertEquals(nameprep.prepare(u'stra\u00dfe.example.com'), + self.assertEqual(nameprep.prepare(u'stra\u00dfe.example.com'), u'strasse.example.com') diff -Nru twisted-words-10.0.0/twisted/words/test/test_msn.py twisted-words-12.1.0/twisted/words/test/test_msn.py --- twisted-words-10.0.0/twisted/words/test/test_msn.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/test/test_msn.py 2011-07-14 19:05:14.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2009 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -60,7 +60,7 @@ for (h, v) in headers.items(): protocol.dataReceived('%s: %s\r\n' % (h,v)) protocol.dataReceived('\r\n') - self.assertEquals(self.result[0], "https://login.myserver.com/") + self.assertEqual(self.result[0], "https://login.myserver.com/") def _doLoginTest(self, response, headers): @@ -175,12 +175,12 @@ transport = StringTransport() client.makeConnection(transport) - self.assertEquals( + self.assertEqual( transport.value(), "VER 1 MSNP8 CVR0\r\n") transport.clear() client.dataReceived(serverVersionResponse) - self.assertEquals( + self.assertEqual( transport.value(), "CVR 2 0x0409 win 4.10 i386 MSNMSGR 5.0.0544 MSMSGS foo\r\n") @@ -228,12 +228,12 @@ transport = StringTransport() self.client.makeConnection(transport) - self.assertEquals( + self.assertEqual( transport.value(), "VER 1 MSNP8 CVR0\r\n") transport.clear() self.client.dataReceived(serverVersionResponse) - self.assertEquals( + self.assertEqual( transport.value(), "CVR 2 0x0409 win 4.10 i386 MSNMSGR 5.0.0544 MSMSGS foo\r\n") @@ -273,9 +273,9 @@ # md5 of the challenge and a magic string defined by the protocol response = "8f2f5a91b72102cd28355e9fc9000d6e" # Sanity check - the response is what the comment above says it is. - self.assertEquals( + self.assertEqual( response, md5(challenge + "Q1P7W2E4J9R8U3S5").hexdigest()) - self.assertEquals( + self.assertEqual( transport.value(), # 2 is the next transaction identifier. 32 is the length of the # response. @@ -287,6 +287,26 @@ self.failUnless((self.client.state == 'LOGIN'), msg='Failed to detect successful login') + def test_loginWithoutSSLFailure(self): + """ + L{NotificationClient.loginFailure} is called if the necessary SSL APIs + are unavailable. + """ + self.patch(msn, 'ClientContextFactory', None) + success = [] + self.client.loggedIn = lambda *args: success.append(args) + failure = [] + self.client.loginFailure = failure.append + + self.client.lineReceived('USR 6 TWN S opaque-string-goes-here') + self.assertEqual(success, []) + self.assertEqual( + failure, + ["Exception while authenticating: " + "Connecting to the Passport server requires SSL, but SSL is " + "unavailable."]) + + def testProfile(self): m = 'MSG Hotmail Hotmail 353\r\nMIME-Version: 1.0\r\nContent-Type: text/x-msmsgsprofile; charset=UTF-8\r\n' m += 'LoginTime: 1016941010\r\nEmailEnabled: 1\r\nMemberIdHigh: 40000\r\nMemberIdLow: -600000000\r\nlang_preference: 1033\r\n' @@ -401,8 +421,8 @@ def testClientCapabilitiesCheck(self): m = msn.MSNMessage() m.setHeader('Content-Type', 'text/x-clientcaps') - self.assertEquals(self.client.checkMessage(m), 0, 'Failed to detect client capability message') - + self.assertEqual(self.client.checkMessage(m), 0, 'Failed to detect client capability message') + def testTypingCheck(self): m = msn.MSNMessage() m.setHeader('Content-Type', 'text/x-msmsgscontrol') @@ -494,9 +514,8 @@ d.addCallback(check) return d - if msn is None: - for testClass in [PassportTests, NotificationTests, + for testClass in [DispatchTests, PassportTests, NotificationTests, MessageHandlingTests, FileTransferTestCase]: testClass.skip = ( "MSN requires an HTTP client but none is available, " diff -Nru twisted-words-10.0.0/twisted/words/test/test_oscar.py twisted-words-12.1.0/twisted/words/test/test_oscar.py --- twisted-words-10.0.0/twisted/words/test/test_oscar.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/test/test_oscar.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2008 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ diff -Nru twisted-words-10.0.0/twisted/words/test/test_service.py twisted-words-12.1.0/twisted/words/test/test_service.py --- twisted-words-10.0.0/twisted/words/test/test_service.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/test/test_service.py 2011-07-14 19:05:14.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2009 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -34,7 +34,7 @@ d = wFD(create(name)) yield d p = d.getResult() - self.assertEquals(p.name, name) + self.assertEqual(p.name, name) # Creating the same user again should not d = wFD(create(name)) @@ -46,7 +46,7 @@ d = wFD(get(u"new" + kind.lower())) yield d p = d.getResult() - self.assertEquals(p.name, "new" + kind.lower()) + self.assertEqual(p.name, "new" + kind.lower()) # Getting that user again should return the same object d = wFD(get(u"new" + kind.lower())) @@ -190,7 +190,7 @@ n = [g.name for g in groups] n.sort() - self.assertEquals(n, ["groupone", "grouptwo"]) + self.assertEqual(n, ["groupone", "grouptwo"]) testEnumeration = dG(testEnumeration) @@ -324,10 +324,10 @@ user = TestCaseUserAgg(firstuser, self.realm, self.factory) user.write('NICK firstuser extrainfo\r\n') response = self._response(user, 'PRIVMSG') - self.assertEquals(len(response), 1) - self.assertEquals(response[0][0], service.NICKSERV) - self.assertEquals(response[0][1], 'PRIVMSG') - self.assertEquals(response[0][2], ['firstuser', 'Password?']) + self.assertEqual(len(response), 1) + self.assertEqual(response[0][0], service.NICKSERV) + self.assertEqual(response[0][1], 'PRIVMSG') + self.assertEqual(response[0][2], ['firstuser', 'Password?']) user.transport.clear() user.write('PRIVMSG nickserv firstuser_password\r\n') @@ -343,8 +343,8 @@ user = TestCaseUserAgg(firstuser, self.realm, self.factory) self._login(user, "firstuser", "wrongpass") response = self._response(user, "PRIVMSG") - self.assertEquals(len(response), 1) - self.assertEquals(response[0][2], ['firstuser', 'Login failed. Goodbye.']) + self.assertEqual(len(response), 1) + self.assertEqual(response[0][2], ['firstuser', 'Login failed. Goodbye.']) testFailedLogin = dG(testFailedLogin) @@ -358,7 +358,7 @@ self._login(user, "firstuser") user.protocol.logout = lambda: logout.append(True) user.write('QUIT\r\n') - self.assertEquals(logout, [True]) + self.assertEqual(logout, [True]) testLogout = dG(testLogout) @@ -380,20 +380,20 @@ user.write('JOIN #somechannel\r\n') response = self._response(user) - self.assertEquals(len(response), 5) + self.assertEqual(len(response), 5) # Join message - self.assertEquals(response[0][0], 'firstuser!firstuser@realmname') - self.assertEquals(response[0][1], 'JOIN') - self.assertEquals(response[0][2], ['#somechannel']) + self.assertEqual(response[0][0], 'firstuser!firstuser@realmname') + self.assertEqual(response[0][1], 'JOIN') + self.assertEqual(response[0][2], ['#somechannel']) # User list - self.assertEquals(response[1][1], '353') - self.assertEquals(response[2][1], '366') + self.assertEqual(response[1][1], '353') + self.assertEqual(response[2][1], '366') # Topic (or lack thereof, as the case may be) - self.assertEquals(response[3][1], '332') - self.assertEquals(response[4][1], '333') + self.assertEqual(response[3][1], '332') + self.assertEqual(response[4][1], '333') # Hook up another client! It is a CHAT SYSTEM!!!!!!! @@ -409,14 +409,14 @@ response = self._response(other) event = self._response(user) - self.assertEquals(len(event), 1) - self.assertEquals(event[0][0], 'otheruser!otheruser@realmname') - self.assertEquals(event[0][1], 'JOIN') - self.assertEquals(event[0][2], ['#somechannel']) - - self.assertEquals(response[1][0], 'realmname') - self.assertEquals(response[1][1], '353') - self.assertEquals(response[1][2], ['otheruser', '=', '#somechannel', 'firstuser otheruser']) + self.assertEqual(len(event), 1) + self.assertEqual(event[0][0], 'otheruser!otheruser@realmname') + self.assertEqual(event[0][1], 'JOIN') + self.assertEqual(event[0][2], ['#somechannel']) + + self.assertEqual(response[1][0], 'realmname') + self.assertEqual(response[1][1], '353') + self.assertEqual(response[1][2], ['otheruser', '=', '#somechannel', 'firstuser otheruser']) testJoin = dG(testJoin) @@ -472,11 +472,11 @@ response = self._response(user) event = self._response(other) - self.assertEquals(len(response), 1) - self.assertEquals(response[0][0], 'useruser!useruser@realmname') - self.assertEquals(response[0][1], 'PART') - self.assertEquals(response[0][2], ['#somechannel', 'leaving']) - self.assertEquals(response, event) + self.assertEqual(len(response), 1) + self.assertEqual(response[0][0], 'useruser!useruser@realmname') + self.assertEqual(response[0][1], 'PART') + self.assertEqual(response[0][2], ['#somechannel', 'leaving']) + self.assertEqual(response, event) # Now again, with a part message user.write('JOIN #somechannel\r\n') @@ -489,11 +489,11 @@ response = self._response(user) event = self._response(other) - self.assertEquals(len(response), 1) - self.assertEquals(response[0][0], 'useruser!useruser@realmname') - self.assertEquals(response[0][1], 'PART') - self.assertEquals(response[0][2], ['#somechannel', 'goodbye stupidheads']) - self.assertEquals(response, event) + self.assertEqual(len(response), 1) + self.assertEqual(response[0][0], 'useruser!useruser@realmname') + self.assertEqual(response[0][1], 'PART') + self.assertEqual(response[0][2], ['#somechannel', 'goodbye stupidheads']) + self.assertEqual(response, event) testLeave = dG(testLeave) @@ -516,13 +516,13 @@ response = self._response(user) - self.assertEquals(response[3][0], 'realmname') - self.assertEquals(response[3][1], '332') + self.assertEqual(response[3][0], 'realmname') + self.assertEqual(response[3][1], '332') # XXX Sigh. irc.parsemsg() is not as correct as one might hope. - self.assertEquals(response[3][2], ['useruser', '#somechannel', 'This is a test topic.']) - self.assertEquals(response[4][1], '333') - self.assertEquals(response[4][2], ['useruser', '#somechannel', 'some_fellow', '77777777']) + self.assertEqual(response[3][2], ['useruser', '#somechannel', 'This is a test topic.']) + self.assertEqual(response[4][1], '333') + self.assertEqual(response[4][2], ['useruser', '#somechannel', 'some_fellow', '77777777']) user.transport.clear() @@ -530,10 +530,10 @@ response = self._response(user) - self.assertEquals(response[0][1], '332') - self.assertEquals(response[0][2], ['useruser', '#somechannel', 'This is a test topic.']) - self.assertEquals(response[1][1], '333') - self.assertEquals(response[1][2], ['useruser', '#somechannel', 'some_fellow', '77777777']) + self.assertEqual(response[0][1], '332') + self.assertEqual(response[0][2], ['useruser', '#somechannel', 'This is a test topic.']) + self.assertEqual(response[1][1], '333') + self.assertEqual(response[1][2], ['useruser', '#somechannel', 'some_fellow', '77777777']) testGetTopic = dG(testGetTopic) @@ -562,11 +562,11 @@ response = self._response(other) event = self._response(user) - self.assertEquals(response, event) + self.assertEqual(response, event) - self.assertEquals(response[0][0], 'otheruser!otheruser@realmname') - self.assertEquals(response[0][1], 'TOPIC') - self.assertEquals(response[0][2], ['#somechannel', 'This is the new topic.']) + self.assertEqual(response[0][0], 'otheruser!otheruser@realmname') + self.assertEqual(response[0][1], 'TOPIC') + self.assertEqual(response[0][2], ['#somechannel', 'This is the new topic.']) other.transport.clear() @@ -574,16 +574,16 @@ other.write('TOPIC #somechannel\r\n') response = self._response(other) - self.assertEquals(response[0][1], '332') - self.assertEquals(response[0][2], ['otheruser', '#somechannel', 'This is the new topic.']) - self.assertEquals(response[1][1], '333') - self.assertEquals(response[1][2], ['otheruser', '#somechannel', 'otheruser', '12345']) + self.assertEqual(response[0][1], '332') + self.assertEqual(response[0][2], ['otheruser', '#somechannel', 'This is the new topic.']) + self.assertEqual(response[1][1], '333') + self.assertEqual(response[1][2], ['otheruser', '#somechannel', 'otheruser', '12345']) other.transport.clear() other.write('TOPIC #asdlkjasd\r\n') response = self._response(other) - self.assertEquals(response[0][1], '403') + self.assertEqual(response[0][1], '403') testSetTopic = dG(testSetTopic) @@ -613,10 +613,10 @@ event = self._response(other) self.failIf(response) - self.assertEquals(len(event), 1) - self.assertEquals(event[0][0], 'useruser!useruser@realmname') - self.assertEquals(event[0][1], 'PRIVMSG', -1) - self.assertEquals(event[0][2], ['#somechannel', 'Hello, world.']) + self.assertEqual(len(event), 1) + self.assertEqual(event[0][0], 'useruser!useruser@realmname') + self.assertEqual(event[0][1], 'PRIVMSG', -1) + self.assertEqual(event[0][2], ['#somechannel', 'Hello, world.']) testGroupMessage = dG(testGroupMessage) @@ -638,19 +638,19 @@ event = self._response(other) self.failIf(response) - self.assertEquals(len(event), 1) - self.assertEquals(event[0][0], 'useruser!useruser@realmname') - self.assertEquals(event[0][1], 'PRIVMSG') - self.assertEquals(event[0][2], ['otheruser', 'Hello, monkey.']) + self.assertEqual(len(event), 1) + self.assertEqual(event[0][0], 'useruser!useruser@realmname') + self.assertEqual(event[0][1], 'PRIVMSG') + self.assertEqual(event[0][2], ['otheruser', 'Hello, monkey.']) user.write('PRIVMSG nousernamedthis :Hello, monkey.\r\n') response = self._response(user) - self.assertEquals(len(response), 1) - self.assertEquals(response[0][0], 'realmname') - self.assertEquals(response[0][1], '401') - self.assertEquals(response[0][2], ['useruser', 'nousernamedthis', 'No such nick/channel.']) + self.assertEqual(len(response), 1) + self.assertEqual(response[0][0], 'realmname') + self.assertEqual(response[0][1], '401') + self.assertEqual(response[0][2], ['useruser', 'nousernamedthis', 'No such nick/channel.']) testPrivateMessage = dG(testPrivateMessage) @@ -663,8 +663,8 @@ user.write('OPER user pass\r\n') response = self._response(user) - self.assertEquals(len(response), 1) - self.assertEquals(response[0][1], '491') + self.assertEqual(len(response), 1) + self.assertEqual(response[0][1], '491') testOper = dG(testOper) @@ -677,10 +677,10 @@ user.write('MODE useruser\r\n') response = self._response(user) - self.assertEquals(len(response), 1) - self.assertEquals(response[0][0], 'realmname') - self.assertEquals(response[0][1], '221') - self.assertEquals(response[0][2], ['useruser', '+']) + self.assertEqual(len(response), 1) + self.assertEqual(response[0][0], 'realmname') + self.assertEqual(response[0][1], '221') + self.assertEqual(response[0][2], ['useruser', '+']) testGetUserMode = dG(testGetUserMode) @@ -693,8 +693,8 @@ user.write('MODE useruser +abcd\r\n') response = self._response(user) - self.assertEquals(len(response), 1) - self.assertEquals(response[0][1], '472') + self.assertEqual(len(response), 1) + self.assertEqual(response[0][1], '472') testSetUserMode = dG(testSetUserMode) @@ -713,8 +713,8 @@ user.write('MODE #somechannel\r\n') response = self._response(user) - self.assertEquals(len(response), 1) - self.assertEquals(response[0][1], '324') + self.assertEqual(len(response), 1) + self.assertEqual(response[0][1], '324') testGetGroupMode = dG(testGetGroupMode) @@ -733,8 +733,8 @@ user.write('MODE #groupname +abcd\r\n') response = self._response(user) - self.assertEquals(len(response), 1) - self.assertEquals(response[0][1], '472') + self.assertEqual(len(response), 1) + self.assertEqual(response[0][1], '472') testSetGroupMode = dG(testSetGroupMode) @@ -762,27 +762,27 @@ wantusers = ['userone', 'usertwo', 'userthree'] for (prefix, code, stuff) in r[:-1]: - self.assertEquals(prefix, 'realmname') - self.assertEquals(code, '352') + self.assertEqual(prefix, 'realmname') + self.assertEqual(code, '352') (myname, group, theirname, theirhost, theirserver, theirnick, flag, extra) = stuff - self.assertEquals(myname, 'userone') - self.assertEquals(group, '#groupname') + self.assertEqual(myname, 'userone') + self.assertEqual(group, '#groupname') self.failUnless(theirname in wantusers) - self.assertEquals(theirhost, 'realmname') - self.assertEquals(theirserver, 'realmname') + self.assertEqual(theirhost, 'realmname') + self.assertEqual(theirserver, 'realmname') wantusers.remove(theirnick) - self.assertEquals(flag, 'H') - self.assertEquals(extra, '0 ' + theirnick) + self.assertEqual(flag, 'H') + self.assertEqual(extra, '0 ' + theirnick) self.failIf(wantusers) prefix, code, stuff = r[-1] - self.assertEquals(prefix, 'realmname') - self.assertEquals(code, '315') + self.assertEqual(prefix, 'realmname') + self.assertEqual(code, '315') myname, channel, extra = stuff - self.assertEquals(myname, 'userone') - self.assertEquals(channel, '#groupname') - self.assertEquals(extra, 'End of /WHO list.') + self.assertEqual(myname, 'userone') + self.assertEqual(channel, '#groupname') + self.assertEqual(extra, 'End of /WHO list.') testWho = dG(testWho) @@ -802,36 +802,36 @@ user.write('LIST #somegroup\r\n') r = self._response(user) - self.assertEquals(len(r), 2) + self.assertEqual(len(r), 2) resp, end = r - self.assertEquals(resp[0], 'realmname') - self.assertEquals(resp[1], '322') - self.assertEquals(resp[2][0], 'someuser') - self.assertEquals(resp[2][1], 'somegroup') - self.assertEquals(resp[2][2], '17') - self.assertEquals(resp[2][3], 'this is the topic woo') - - self.assertEquals(end[0], 'realmname') - self.assertEquals(end[1], '323') - self.assertEquals(end[2][0], 'someuser') - self.assertEquals(end[2][1], 'End of /LIST') + self.assertEqual(resp[0], 'realmname') + self.assertEqual(resp[1], '322') + self.assertEqual(resp[2][0], 'someuser') + self.assertEqual(resp[2][1], 'somegroup') + self.assertEqual(resp[2][2], '17') + self.assertEqual(resp[2][3], 'this is the topic woo') + + self.assertEqual(end[0], 'realmname') + self.assertEqual(end[1], '323') + self.assertEqual(end[2][0], 'someuser') + self.assertEqual(end[2][1], 'End of /LIST') user.transport.clear() # Test all groups user.write('LIST\r\n') r = self._response(user) - self.assertEquals(len(r), 2) + self.assertEqual(len(r), 2) fg1, end = r - self.assertEquals(fg1[1], '322') - self.assertEquals(fg1[2][1], 'somegroup') - self.assertEquals(fg1[2][2], '17') - self.assertEquals(fg1[2][3], 'this is the topic woo') + self.assertEqual(fg1[1], '322') + self.assertEqual(fg1[2][1], 'somegroup') + self.assertEqual(fg1[2][2], '17') + self.assertEqual(fg1[2][3], 'this is the topic woo') - self.assertEquals(end[1], '323') + self.assertEqual(end[1], '323') testList = dG(testList) @@ -855,44 +855,44 @@ user.write('WHOIS otherguy\r\n') r = self._response(user) - self.assertEquals(len(r), 5) + self.assertEqual(len(r), 5) wuser, wserver, idle, channels, end = r - self.assertEquals(wuser[0], 'realmname') - self.assertEquals(wuser[1], '311') - self.assertEquals(wuser[2][0], 'someguy') - self.assertEquals(wuser[2][1], 'otherguy') - self.assertEquals(wuser[2][2], 'otherguy') - self.assertEquals(wuser[2][3], 'realmname') - self.assertEquals(wuser[2][4], '*') - self.assertEquals(wuser[2][5], 'otherguy') - - self.assertEquals(wserver[0], 'realmname') - self.assertEquals(wserver[1], '312') - self.assertEquals(wserver[2][0], 'someguy') - self.assertEquals(wserver[2][1], 'otherguy') - self.assertEquals(wserver[2][2], 'realmname') - self.assertEquals(wserver[2][3], 'Hi mom!') - - self.assertEquals(idle[0], 'realmname') - self.assertEquals(idle[1], '317') - self.assertEquals(idle[2][0], 'someguy') - self.assertEquals(idle[2][1], 'otherguy') - self.assertEquals(idle[2][2], '15') - self.assertEquals(idle[2][3], '10') - self.assertEquals(idle[2][4], "seconds idle, signon time") - - self.assertEquals(channels[0], 'realmname') - self.assertEquals(channels[1], '319') - self.assertEquals(channels[2][0], 'someguy') - self.assertEquals(channels[2][1], 'otherguy') - self.assertEquals(channels[2][2], '#groupA #groupB') - - self.assertEquals(end[0], 'realmname') - self.assertEquals(end[1], '318') - self.assertEquals(end[2][0], 'someguy') - self.assertEquals(end[2][1], 'otherguy') - self.assertEquals(end[2][2], 'End of WHOIS list.') + self.assertEqual(wuser[0], 'realmname') + self.assertEqual(wuser[1], '311') + self.assertEqual(wuser[2][0], 'someguy') + self.assertEqual(wuser[2][1], 'otherguy') + self.assertEqual(wuser[2][2], 'otherguy') + self.assertEqual(wuser[2][3], 'realmname') + self.assertEqual(wuser[2][4], '*') + self.assertEqual(wuser[2][5], 'otherguy') + + self.assertEqual(wserver[0], 'realmname') + self.assertEqual(wserver[1], '312') + self.assertEqual(wserver[2][0], 'someguy') + self.assertEqual(wserver[2][1], 'otherguy') + self.assertEqual(wserver[2][2], 'realmname') + self.assertEqual(wserver[2][3], 'Hi mom!') + + self.assertEqual(idle[0], 'realmname') + self.assertEqual(idle[1], '317') + self.assertEqual(idle[2][0], 'someguy') + self.assertEqual(idle[2][1], 'otherguy') + self.assertEqual(idle[2][2], '15') + self.assertEqual(idle[2][3], '10') + self.assertEqual(idle[2][4], "seconds idle, signon time") + + self.assertEqual(channels[0], 'realmname') + self.assertEqual(channels[1], '319') + self.assertEqual(channels[2][0], 'someguy') + self.assertEqual(channels[2][1], 'otherguy') + self.assertEqual(channels[2][2], '#groupA #groupB') + + self.assertEqual(end[0], 'realmname') + self.assertEqual(end[1], '318') + self.assertEqual(end[2][0], 'someguy') + self.assertEqual(end[2][1], 'otherguy') + self.assertEqual(end[2][2], 'End of WHOIS list.') testWhois = dG(testWhois) diff -Nru twisted-words-10.0.0/twisted/words/test/test_tap.py twisted-words-12.1.0/twisted/words/test/test_tap.py --- twisted-words-10.0.0/twisted/words/test/test_tap.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/test/test_tap.py 2011-07-14 19:05:14.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2005 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. from twisted.cred import credentials, error @@ -40,7 +40,7 @@ """ opt = tap.Options() opt.parseOptions(['--hostname', 'myhost']) - self.assertEquals(opt['hostname'], 'myhost') + self.assertEqual(opt['hostname'], 'myhost') def test_passwd(self): @@ -69,10 +69,10 @@ @param opt: An instance of L{tap.Options}. """ - self.assertEquals(len(opt['credCheckers']), 1) + self.assertEqual(len(opt['credCheckers']), 1) checker = opt['credCheckers'][0] self.assertFailure(checker.requestAvatarId(self.joeWrong), error.UnauthorizedLogin) def _gotAvatar(username): - self.assertEquals(username, self.admin.username) + self.assertEqual(username, self.admin.username) return checker.requestAvatarId(self.admin).addCallback(_gotAvatar) diff -Nru twisted-words-10.0.0/twisted/words/test/test_toc.py twisted-words-12.1.0/twisted/words/test/test_toc.py --- twisted-words-10.0.0/twisted/words/test/test_toc.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/test/test_toc.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,340 +0,0 @@ -# Copyright (c) 2001-2009 Twisted Matrix Laboratories. -# See LICENSE for details. - - -from twisted.trial import unittest - -from twisted.words.protocols import toc -from twisted.internet import protocol, main -from twisted.python import failure -from twisted.test.proto_helpers import StringIOWithoutClosing - -from struct import pack,unpack - - -class DummyTOC(toc.TOC): - """ - used to override authentication, now overrides printing. - """ - def _debug(self,data): - pass -SEQID=1001 -def flap(type,data): - global SEQID - send="*" - send=send+pack("!BHH",type,SEQID,len(data)) - send=send+data - SEQID=SEQID+1 - return send -def readFlap(data): - if data=="": return [None,""] - null,type,seqid,length=unpack("!BBHH",data[:6]) - val=data[6:6+length] - return [[type,val],data[6+length:]] - -class TOCGeneralTestCase(unittest.TestCase): - """ - general testing of TOC functions. - """ - def testTOC(self): - self.runTest() - def runTest(self): - USERS=2 - data=range(USERS) - data[0]=("FLAPON\r\n\r\n",\ - flap(1,"\000\000\000\001\000\001\000\004test"),\ - flap(2,"toc_signon localhost 9999 test 0x100000 english \"penguin 0.1\"\000"),\ - flap(2,"toc_add_buddy test\000"),\ - flap(2,"toc_init_done\000"),\ - flap(2,"toc_send_im test \"hi\"\000"),\ - flap(2,"toc_send_im test2 \"hello\"\000"),\ - flap(2,"toc_set_away \"not here\"\000"),\ - flap(2,"toc_set_idle 602\000"),\ - flap(2,"toc_set_idle 0\000"),\ - flap(2,"toc_set_away\000"),\ - flap(2,"toc_evil test norm\000"),\ - flap(2,"toc_chat_join 4 \"Test Chat\"\000"),\ - flap(2,"toc_chat_send 0 \"hello\"\000"),\ - #flap(2,"toc_chat_leave 0\000")) #,\ - flap(2,"toc_chat_invite 0 \"come\" ooga\000"),\ - #flap(2,"toc_chat_accept 0\000"),\ - flap(5,"\000"),\ - flap(2,"toc_chat_whisper 0 ooga \"boo ga\"\000"),\ - flap(2,"toc_chat_leave 0"),\ - flap(5,"\000")) - data[1]=("FLAPON\r\n\r\n",\ - flap(1,"\000\000\000\001\000\001\000\004ooga"),\ - flap(2,"toc_signon localhost 9999 ooga 0x100000 english \"penguin 0.1\"\000"),\ - flap(2,"toc_add_buddy test\000"),\ - flap(2,"toc_init_done\000"),\ - flap(5,"\000"),\ - flap(5,"\000"),\ - #flap(5,"\000"),\ - #flap(5,"\000"),\ - #flap(5,"\000"),\ - flap(5,"\000"),\ - flap(5,"\000"),\ - flap(5,"\000"),\ - flap(5,"\000"),\ - flap(5,"\000"),\ - flap(5,"\000"),\ - flap(5,"\000"),\ - #flap(5,"\000"),\ - flap(2,"toc_chat_accept 0\000"),\ - flap(2,"toc_chat_send 0 \"hi test\"\000"),\ - flap(5,"\000"),\ - flap(2,"toc_chat_leave 0\000")) - strings=range(USERS) - for i in strings: - strings[i]=StringIOWithoutClosing() - fac=toc.TOCFactory() - dummy=range(USERS) - for i in dummy: - dummy[i]=DummyTOC() - dummy[i].factory=fac - dummy[i].makeConnection(protocol.FileWrapper(strings[i])) - while sum(map(lambda x: x == (), data)) != USERS: - for i in range(USERS): - d=data[i] - if len(d)>0: - k,data[i]=d[0],d[1:] - for j in k: - dummy[i].dataReceived(j) # test by doing a character at a time - else: - dummy[i].connectionLost(failure.Failure(main.CONNECTION_DONE)) - values=range(USERS) - for i in values: - values[i]=strings[i].getvalue() - flaps=map(lambda x:[],range(USERS)) - for value in values: - i=values.index(value) - f,value=readFlap(value) - while f: - flaps[i].append(f) - f,value=readFlap(value) - ts=range(USERS) - for t in ts: - ts[t]=dummy[t].signontime - shouldequal=range(USERS) - shouldequal[0]=[ \ - [1,"\000\000\000\001"],\ - [2,"SIGN_ON:TOC1.0\000"],\ - [2,"NICK:test\000"],\ - [2,"CONFIG:\00"],\ - [2,"UPDATE_BUDDY:test:T:0:%s:0: O\000"%ts[0]],\ - [2,"IM_IN:test:F:hi\000"],\ - [2,"ERROR:901:test2\000"],\ - #[2,"UPDATE_BUDDY:test:T:0:%s:0: O\000"%ts[0]],\ - [2,"UPDATE_BUDDY:test:T:0:%s:0: OU\000"%ts[0]],\ - [2,"UPDATE_BUDDY:test:T:0:%s:10: OU\000"%ts[0]],\ - [2,"UPDATE_BUDDY:test:T:0:%s:0: OU\000"%ts[0]],\ - [2,"UPDATE_BUDDY:test:T:0:%s:0: O\000"%ts[0]],\ - [2,"EVILED:10:test\000"],\ - [2,"UPDATE_BUDDY:test:T:10:%s:0: O\000"%ts[0]],\ - [2,"CHAT_JOIN:0:Test Chat\000"],\ - [2,"CHAT_UPDATE_BUDDY:0:T:test\000"],\ - [2,"CHAT_IN:0:test:F:hello\000"],\ - [2,"CHAT_UPDATE_BUDDY:0:T:ooga\000"],\ - [2,"CHAT_IN:0:ooga:F:hi test\000"],\ - [2,"CHAT_LEFT:0\000"]] - shouldequal[1]=[ \ - [1,"\000\000\000\001"],\ - [2,"SIGN_ON:TOC1.0\000"],\ - [2,"NICK:ooga\000"],\ - [2,"CONFIG:\000"],\ - #[2,"UPDATE_BUDDY:test:T:0:%s:0: O\000"%ts[0]],\ - [2,"UPDATE_BUDDY:test:T:0:%s:0: OU\000"%ts[0]],\ - [2,"UPDATE_BUDDY:test:T:0:%s:10: OU\000"%ts[0]],\ - [2,"UPDATE_BUDDY:test:T:0:%s:0: OU\000"%ts[0]],\ - [2,"UPDATE_BUDDY:test:T:0:%s:0: O\000"%ts[0]],\ - [2,"UPDATE_BUDDY:test:T:10:%s:0: O\000"%ts[0]],\ - [2,"CHAT_INVITE:Test Chat:0:test:come\000"],\ - [2,"CHAT_JOIN:0:Test Chat\000"],\ - [2,"CHAT_UPDATE_BUDDY:0:T:test:ooga\000"],\ - [2,"CHAT_IN:0:ooga:F:hi test\000"],\ - [2,"CHAT_IN:0:test:T:boo ga\000"],\ - [2,"CHAT_UPDATE_BUDDY:0:F:test\000"],\ - [2,"CHAT_LEFT:0\000"]] - if flaps!=shouldequal: - for i in range(len(shouldequal)): - for j in range(len(shouldequal[i])): - if shouldequal[i][j]!=flaps[i][j]: - raise AssertionError("GeneralTest Failed!\nUser %s Line %s\nactual:%s\nshould be:%s"%(i,j,flaps[i][j],shouldequal[i][j])) - raise AssertionError("GeneralTest Failed with incorrect lengths!") -class TOCMultiPacketTestCase(unittest.TestCase): - """ - i saw this problem when using GAIM. It only read the flaps onces per dataReceived, and would basically block if it ever received two packets together in one dataReceived. this tests for that occurance. - """ - def testTOC(self): - self.runTest() - def runTest(self): - packets=["FLAPON\r\n\r\n",\ - flap(1,"\000\000\000\001\000\001\000\004test"),\ - flap(2,"toc_signon null 9999 test 0x100000 english \"penguin 0.1\"\000"),\ - flap(2,"toc_init_done\000"),\ - flap(2,"toc_send_im test hi\000")] - shouldbe=[[1,"\000\000\000\001"],\ - [2,"SIGN_ON:TOC1.0\000"],\ - [2,"NICK:test\000"],\ - [2,"CONFIG:\000"],\ - [2,"IM_IN:test:F:hi\000"]] - data="" - for i in packets: - data=data+i - s=StringIOWithoutClosing() - d=DummyTOC() - fac=toc.TOCFactory() - d.factory=fac - d.makeConnection(protocol.FileWrapper(s)) - d.dataReceived(data) - d.connectionLost(failure.Failure(main.CONNECTION_DONE)) - value=s.getvalue() - flaps=[] - f,value=readFlap(value) - while f: - flaps.append(f) - f,value=readFlap(value) - if flaps!=shouldbe: - for i in range(len(flaps)): - if flaps[i]!=shouldbe[i]:raise AssertionError("MultiPacketTest Failed!\nactual:%s\nshould be:%s"%(flaps[i],shouldbe[i])) - raise AssertionError("MultiPacketTest Failed with incorrect length!, printing both lists\nactual:%s\nshould be:%s"%(flaps,shouldbe)) -class TOCSavedValuesTestCase(unittest.TestCase): - def testTOC(self): - self.runTest() - def runTest(self): - password1=toc.roast("test pass") - password2=toc.roast("pass test") - beforesend=[\ - "FLAPON\r\n\r\n",\ - flap(1,"\000\000\000\001\000\001\000\004test"),\ - flap(2,"toc_signon localhost 9999 test %s english \"penguin 0.1\"\000"%password1),\ - flap(2,"toc_init_done\000"),\ - flap(2,"toc_set_config \"{m 4}\"\000"),\ - flap(2,"toc_format_nickname BOOGA\000"),\ - flap(2,"toc_format_nickname \"T E S T\"\000"),\ - flap(2,"toc_change_passwd \"testpass\" \"pass test\"\000"),\ - flap(2,"toc_change_passwd \"test pass\" \"pass test\"\000")] - beforeexpect=[\ - [1,"\000\000\000\001"],\ - [2,"SIGN_ON:TOC1.0\000"],\ - [2,"NICK:test\000"],\ - [2,"CONFIG:\000"],\ - [2,"ERROR:911\000"],\ - [2,"ADMIN_NICK_STATUS:0\000"],\ - [2,"ERROR:911\000"],\ - [2,"ADMIN_PASSWD_STATUS:0\000"]] - badpasssend=[\ - "FLAPON\r\n\r\n",\ - flap(1,"\000\000\000\001\000\001\000\004test"),\ - flap(2,"toc_signon localhost 9999 test 0x1000 english \"penguin 0.1\"\000"),\ - flap(2,"toc_init_done")] - badpassexpect=[\ - [1,"\000\00\000\001"],\ - [2,"ERROR:980\000"]] - goodpasssend=[\ - "FLAPON\r\n\r\n",\ - flap(1,"\000\000\000\001\000\001\000\004test"),\ - flap(2,"toc_signon localhost 9999 test %s english \"penguin 0.1\"\000"%password2),\ - flap(2,"toc_init_done")] - goodpassexpect=[\ - [1,"\000\000\000\001"],\ - [2,"SIGN_ON:TOC1.0\000"],\ - [2,"NICK:T E S T\000"],\ - [2,"CONFIG:{m 4}\000"]] - fac=toc.TOCFactory() - d=DummyTOC() - d.factory=fac - s=StringIOWithoutClosing() - d.makeConnection(protocol.FileWrapper(s)) - for i in beforesend: - d.dataReceived(i) - d.connectionLost(failure.Failure(main.CONNECTION_DONE)) - v=s.getvalue() - flaps=[] - f,v=readFlap(v) - while f: - flaps.append(f) - f,v=readFlap(v) - if flaps!=beforeexpect: - for i in range(len(flaps)): - if flaps[i]!=beforeexpect[i]: - raise AssertionError("SavedValuesTest Before Failed!\nactual:%s\nshould be:%s"%(flaps[i],beforeexpect[i])) - raise AssertionError("SavedValuesTest Before Failed with incorrect length!\nactual:%s\nshould be:%s"%(flaps,beforeexpect)) - d=DummyTOC() - d.factory=fac - s=StringIOWithoutClosing() - d.makeConnection(protocol.FileWrapper(s)) - for i in badpasssend: - d.dataReceived(i) - d.connectionLost(failure.Failure(main.CONNECTION_DONE)) - v=s.getvalue() - flaps=[] - f,v=readFlap(v) - while f: - flaps.append(f) - f,v=readFlap(v) - if flaps!=badpassexpect: - for i in range(len(flaps)): - if flaps[i]!=badpassexpect[i]: - raise AssertionError("SavedValuesTest BadPass Failed!\nactual:%s\nshould be:%s"%(flaps[i],badpassexpect[i])) - raise AssertionError("SavedValuesTest BadPass Failed with incorrect length!\nactual:%s\nshould be:%s"%(flaps,badpassexpect)) - d=DummyTOC() - d.factory=fac - s=StringIOWithoutClosing() - d.makeConnection(protocol.FileWrapper(s)) - for i in goodpasssend: - d.dataReceived(i) - d.connectionLost(failure.Failure(main.CONNECTION_DONE)) - v=s.getvalue() - flaps=[] - f,v=readFlap(v) - while f: - flaps.append(f) - f,v=readFlap(v) - if flaps!=goodpassexpect: - for i in range(len(flaps)): - if flaps[i]!=goodpassexpect[i]: - raise AssertionError("SavedValuesTest GoodPass Failed!\nactual:%s\nshould be:%s"%(flaps[i],goodpassexpect[i])) - raise AssertionError("SavedValuesTest GoodPass Failed with incorrect length!\nactual:%s\nshould be:%s"%(flaps,beforeexpect)) -class TOCPrivacyTestCase(unittest.TestCase): - def runTest(self): - sends=["FLAPON\r\n\r\n",\ - flap(1,"\000\000\000\001\000\001\000\004test"),\ - flap(2,"toc_signon localhost 9999 test 0x00 english penguin\000"),\ - flap(2,"toc_init_done\000"),\ - flap(2,"toc_add_deny\000"),\ - flap(2,"toc_send_im test 1\000"),\ - flap(2,"toc_add_deny test\000"),\ - flap(2,"toc_send_im test 2\000"),\ - flap(2,"toc_add_permit\000"),\ - flap(2,"toc_send_im test 3\000"),\ - flap(2,"toc_add_permit test\000"),\ - flap(2,"toc_send_im test 4\000")] - expect=[[1,"\000\000\000\001"],\ - [2,"SIGN_ON:TOC1.0\000"],\ - [2,"NICK:test\000"],\ - [2,"CONFIG:\000"],\ - [2,"IM_IN:test:F:1\000"],\ - [2,"ERROR:901:test\000"],\ - [2,"ERROR:901:test\000"],\ - [2,"IM_IN:test:F:4\000"]] - d=DummyTOC() - d.factory=toc.TOCFactory() - s=StringIOWithoutClosing() - d.makeConnection(protocol.FileWrapper(s)) - for i in sends: - d.dataReceived(i) - d.connectionLost(failure.Failure(main.CONNECTION_DONE)) - v=s.getvalue() - flaps=[] - f,v=readFlap(v) - while f: - flaps.append(f) - f,v=readFlap(v) - if flaps!=expect: - for i in range(len(flaps)): - if flaps[i]!=expect[i]: - raise AssertionError("PrivacyTest Before Failed!\nactual:%s\nshould be:%s"%(flaps[i],expect[i])) - raise AssertionError("PrivacyTest Before Failed with incorrect length!\nactual:%s\nshould be:%s"%(flaps,expect)) -testCases=[TOCGeneralTestCase,TOCMultiPacketTestCase,TOCSavedValuesTestCase,TOCPrivacyTestCase] - diff -Nru twisted-words-10.0.0/twisted/words/test/test_xishutil.py twisted-words-12.1.0/twisted/words/test/test_xishutil.py --- twisted-words-10.0.0/twisted/words/test/test_xishutil.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/test/test_xishutil.py 2011-07-14 19:05:14.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -76,23 +76,23 @@ pres.addElement("presence") d.dispatch(msg) - self.assertEquals(cb1.called, 2) - self.assertEquals(cb1.obj, msg) - self.assertEquals(cb2.called, 0) + self.assertEqual(cb1.called, 2) + self.assertEqual(cb1.obj, msg) + self.assertEqual(cb2.called, 0) d.dispatch(pres) - self.assertEquals(cb1.called, 2) - self.assertEquals(cb2.called, 1) - self.assertEquals(cb2.obj, pres) - self.assertEquals(cb3.called, 0) + self.assertEqual(cb1.called, 2) + self.assertEqual(cb2.called, 1) + self.assertEqual(cb2.obj, pres) + self.assertEqual(cb3.called, 0) d.dispatch(d, "//event/testevent") - self.assertEquals(cb3.called, 1) - self.assertEquals(cb3.obj, d) + self.assertEqual(cb3.called, 1) + self.assertEqual(cb3.obj, d) d.removeObserver("/presence", cb2.call) d.dispatch(pres) - self.assertEquals(cb2.called, 1) + self.assertEqual(cb2.called, 1) def test_addObserverTwice(self): @@ -109,10 +109,10 @@ d.addObserver("//event/testevent", cb2.call) d.dispatch(d, "//event/testevent") - self.assertEquals(cb1.called, 1) - self.assertEquals(cb1.obj, d) - self.assertEquals(cb2.called, 1) - self.assertEquals(cb2.obj, d) + self.assertEqual(cb1.called, 1) + self.assertEqual(cb1.obj, d) + self.assertEqual(cb2.called, 1) + self.assertEqual(cb2.obj, d) def test_addObserverInDispatch(self): @@ -129,13 +129,13 @@ d.addOnetimeObserver("/message", onMessage) d.dispatch(msg) - self.assertEquals(cb.called, 0) + self.assertEqual(cb.called, 0) d.dispatch(msg) - self.assertEquals(cb.called, 1) + self.assertEqual(cb.called, 1) d.dispatch(msg) - self.assertEquals(cb.called, 2) + self.assertEqual(cb.called, 2) def test_addOnetimeObserverInDispatch(self): @@ -152,13 +152,13 @@ d.addOnetimeObserver("/message", onMessage) d.dispatch(msg) - self.assertEquals(cb.called, 0) + self.assertEqual(cb.called, 0) d.dispatch(msg) - self.assertEquals(cb.called, 1) + self.assertEqual(cb.called, 1) d.dispatch(msg) - self.assertEquals(cb.called, 1) + self.assertEqual(cb.called, 1) def testOnetimeDispatch(self): @@ -168,9 +168,9 @@ d.addOnetimeObserver("/message", cb.call) d.dispatch(msg) - self.assertEquals(cb.called, 1) + self.assertEqual(cb.called, 1) d.dispatch(msg) - self.assertEquals(cb.called, 1) + self.assertEqual(cb.called, 1) def testDispatcherResult(self): @@ -181,10 +181,10 @@ d.addObserver("/presence", cb.call) result = d.dispatch(msg) - self.assertEquals(False, result) + self.assertEqual(False, result) result = d.dispatch(pres) - self.assertEquals(True, result) + self.assertEqual(True, result) def testOrderedXPathDispatch(self): @@ -197,7 +197,7 @@ msg = Element(("ns", "message")) msg.addElement("body") d.dispatch(msg) - self.assertEquals(cb.callList, [cb.call1, cb.call2, cb.call3], + self.assertEqual(cb.callList, [cb.call1, cb.call2, cb.call3], "Calls out of order: %s" % repr([c.__name__ for c in cb.callList])) @@ -328,7 +328,7 @@ self.pipe.sink.addObserver('/test[@xmlns="testns"]', cb) element = Element(('testns', 'test')) self.pipe.source.send(element) - self.assertEquals([element], called) + self.assertEqual([element], called) def test_sendFromSink(self): @@ -342,4 +342,4 @@ self.pipe.source.addObserver('/test[@xmlns="testns"]', cb) element = Element(('testns', 'test')) self.pipe.sink.send(element) - self.assertEquals([element], called) + self.assertEqual([element], called) diff -Nru twisted-words-10.0.0/twisted/words/test/test_xmlstream.py twisted-words-12.1.0/twisted/words/test/test_xmlstream.py --- twisted-words-10.0.0/twisted/words/test/test_xmlstream.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/test/test_xmlstream.py 2011-07-14 19:05:14.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -6,11 +6,13 @@ """ from twisted.internet import protocol +from twisted.python import failure from twisted.trial import unittest from twisted.words.xish import domish, utility, xmlstream class XmlStreamTest(unittest.TestCase): def setUp(self): + self.connectionLostMsg = "no reason" self.outlist = [] self.xmlstream = xmlstream.XmlStream() self.xmlstream.transport = self @@ -21,16 +23,18 @@ """ Stub loseConnection because we are a transport. """ - self.xmlstream.connectionLost("no reason") + self.xmlstream.connectionLost(failure.Failure( + Exception(self.connectionLostMsg))) def test_send(self): """ - Sending data should result into it being written to the transport. + Calling L{xmlstream.XmlStream.send} results in the data being written + to the transport. """ self.xmlstream.connectionMade() self.xmlstream.send("") - self.assertEquals(self.outlist[0], "") + self.assertEqual(self.outlist[0], "") def test_receiveRoot(self): @@ -46,12 +50,12 @@ streamStartEvent) self.xmlstream.connectionMade() self.xmlstream.dataReceived("") - self.assertEquals(1, len(streamStarted)) + self.assertEqual(1, len(streamStarted)) def test_receiveBadXML(self): """ - Receiving malformed XML should result in in error. + Receiving malformed XML results in an L{STREAM_ERROR_EVENT}. """ streamError = [] streamEnd = [] @@ -69,13 +73,32 @@ self.xmlstream.connectionMade() self.xmlstream.dataReceived("") - self.assertEquals(0, len(streamError)) - self.assertEquals(0, len(streamEnd)) + self.assertEqual(0, len(streamError)) + self.assertEqual(0, len(streamEnd)) self.xmlstream.dataReceived("") - self.assertEquals(1, len(streamError)) + self.assertEqual(1, len(streamError)) self.assertTrue(streamError[0].check(domish.ParserError)) - self.assertEquals(1, len(streamEnd)) + self.assertEqual(1, len(streamEnd)) + + + def test_streamEnd(self): + """ + Ending the stream fires a L{STREAM_END_EVENT}. + """ + streamEnd = [] + + def streamEndEvent(reason): + streamEnd.append(reason) + + self.xmlstream.addObserver(xmlstream.STREAM_END_EVENT, + streamEndEvent) + self.xmlstream.connectionMade() + self.loseConnection() + self.assertEqual(1, len(streamEnd)) + self.assertIsInstance(streamEnd[0], failure.Failure) + self.assertEqual(streamEnd[0].getErrorMessage(), + self.connectionLostMsg) @@ -109,7 +132,7 @@ def test_installBootstraps(self): """ - Dispatching an event should fire registered bootstrap observers. + Dispatching an event fires registered bootstrap observers. """ called = [] @@ -121,7 +144,7 @@ self.factory.installBootstraps(dispatcher) dispatcher.dispatch(None, '//event/myevent') - self.assertEquals(1, len(called)) + self.assertEqual(1, len(called)) def test_addAndRemoveBootstrap(self): @@ -168,7 +191,7 @@ xs = self.factory.buildProtocol(None) xs.dispatch(None, '//event/myevent') - self.assertEquals(1, len(called)) + self.assertEqual(1, len(called)) def test_buildProtocolStoresFactory(self): @@ -192,10 +215,10 @@ def test_buildProtocolFactoryArguments(self): """ - Arguments passed to the factory should be passed to protocol on + Arguments passed to the factory are passed to protocol on instantiation. """ xs = self.factory.buildProtocol(None) - self.assertEquals((None,), xs.args) - self.assertEquals({'test': None}, xs.kwargs) + self.assertEqual((None,), xs.args) + self.assertEqual({'test': None}, xs.kwargs) diff -Nru twisted-words-10.0.0/twisted/words/test/test_xmpproutertap.py twisted-words-12.1.0/twisted/words/test/test_xmpproutertap.py --- twisted-words-10.0.0/twisted/words/test/test_xmpproutertap.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/test/test_xmpproutertap.py 2011-07-14 19:05:14.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -18,7 +18,7 @@ """ opt = tap.Options() opt.parseOptions(['--port', '7001']) - self.assertEquals(opt['port'], '7001') + self.assertEqual(opt['port'], '7001') def test_portDefault(self): @@ -27,7 +27,7 @@ """ opt = tap.Options() opt.parseOptions([]) - self.assertEquals(opt['port'], 'tcp:5347:interface=127.0.0.1') + self.assertEqual(opt['port'], 'tcp:5347:interface=127.0.0.1') def test_secret(self): @@ -36,7 +36,7 @@ """ opt = tap.Options() opt.parseOptions(['--secret', 'hushhush']) - self.assertEquals(opt['secret'], 'hushhush') + self.assertEqual(opt['secret'], 'hushhush') def test_secretDefault(self): @@ -45,7 +45,7 @@ """ opt = tap.Options() opt.parseOptions([]) - self.assertEquals(opt['secret'], 'secret') + self.assertEqual(opt['secret'], 'secret') def test_verbose(self): @@ -64,14 +64,13 @@ opt = tap.Options() opt.parseOptions([]) s = tap.makeService(opt) - self.assertIsInstance(s, internet.TCPServer) - self.assertEquals('127.0.0.1', s.kwargs['interface']) - self.assertEquals(2, len(s.args)) - self.assertEquals(5347, s.args[0]) - factory = s.args[1] + self.assertIsInstance(s, internet.StreamServerEndpointService) + self.assertEqual('127.0.0.1', s.endpoint._interface) + self.assertEqual(5347, s.endpoint._port) + factory = s.factory self.assertIsInstance(factory, component.XMPPComponentServerFactory) self.assertIsInstance(factory.router, component.Router) - self.assertEquals('secret', factory.secret) + self.assertEqual('secret', factory.secret) self.assertFalse(factory.logTraffic) @@ -82,5 +81,4 @@ opt = tap.Options() opt.parseOptions(['--verbose']) s = tap.makeService(opt) - factory = s.args[1] - self.assertTrue(factory.logTraffic) + self.assertTrue(s.factory.logTraffic) diff -Nru twisted-words-10.0.0/twisted/words/test/test_xpath.py twisted-words-12.1.0/twisted/words/test/test_xpath.py --- twisted-words-10.0.0/twisted/words/test/test_xpath.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/test/test_xpath.py 2011-07-14 19:05:14.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2005 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. @@ -72,14 +72,14 @@ """ Test basic operation of the static methods. """ - self.assertEquals(xpath.matches("/foo/bar", self.e), + self.assertEqual(xpath.matches("/foo/bar", self.e), True) - self.assertEquals(xpath.queryForNodes("/foo/bar", self.e), + self.assertEqual(xpath.queryForNodes("/foo/bar", self.e), [self.bar1, self.bar2, self.bar4, self.bar5, self.bar6, self.bar7]) - self.assertEquals(xpath.queryForString("/foo", self.e), + self.assertEqual(xpath.queryForString("/foo", self.e), "somecontent") - self.assertEquals(xpath.queryForStringList("/foo", self.e), + self.assertEqual(xpath.queryForStringList("/foo", self.e), ["somecontent", "somemorecontent"]) def test_locationFooBar(self): @@ -87,15 +87,15 @@ Test matching foo with child bar. """ xp = XPathQuery("/foo/bar") - self.assertEquals(xp.matches(self.e), 1) + self.assertEqual(xp.matches(self.e), 1) def test_locationFooBarFoo(self): """ Test finding foos at the second level. """ xp = XPathQuery("/foo/bar/foo") - self.assertEquals(xp.matches(self.e), 1) - self.assertEquals(xp.queryForNodes(self.e), [self.subfoo, + self.assertEqual(xp.matches(self.e), 1) + self.assertEqual(xp.queryForNodes(self.e), [self.subfoo, self.subfoo3, self.subfoo4]) @@ -104,15 +104,15 @@ Test not finding bar3. """ xp = XPathQuery("/foo/bar3") - self.assertEquals(xp.matches(self.e), 0) + self.assertEqual(xp.matches(self.e), 0) def test_locationAllChilds(self): """ Test finding childs of foo. """ xp = XPathQuery("/foo/*") - self.assertEquals(xp.matches(self.e), True) - self.assertEquals(xp.queryForNodes(self.e), [self.bar1, self.bar2, + self.assertEqual(xp.matches(self.e), True) + self.assertEqual(xp.queryForNodes(self.e), [self.bar1, self.bar2, self.bar4, self.bar5, self.bar6, self.bar7]) @@ -121,23 +121,23 @@ Test matching foo with attribute. """ xp = XPathQuery("/foo[@attrib1]") - self.assertEquals(xp.matches(self.e), True) + self.assertEqual(xp.matches(self.e), True) def test_attributeWithValueAny(self): """ Test find nodes with attribute having value. """ xp = XPathQuery("/foo/*[@attrib2='value2']") - self.assertEquals(xp.matches(self.e), True) - self.assertEquals(xp.queryForNodes(self.e), [self.bar2]) + self.assertEqual(xp.matches(self.e), True) + self.assertEqual(xp.queryForNodes(self.e), [self.bar2]) def test_position(self): """ Test finding element at position. """ xp = XPathQuery("/foo/bar[2]") - self.assertEquals(xp.matches(self.e), 1) - self.assertEquals(xp.queryForNodes(self.e), [self.bar1]) + self.assertEqual(xp.matches(self.e), 1) + self.assertEqual(xp.queryForNodes(self.e), [self.bar1]) test_position.todo = "XPath queries with position are not working." @@ -146,29 +146,29 @@ Test matching node with namespace. """ xp = XPathQuery("/foo[@xmlns='testns']/bar") - self.assertEquals(xp.matches(self.e), 1) + self.assertEqual(xp.matches(self.e), 1) def test_namespaceNotFound(self): """ Test not matching node with wrong namespace. """ xp = XPathQuery("/foo[@xmlns='badns']/bar2") - self.assertEquals(xp.matches(self.e), 0) + self.assertEqual(xp.matches(self.e), 0) def test_attributeWithValue(self): """ Test matching node with attribute having value. """ xp = XPathQuery("/foo[@attrib1='value1']") - self.assertEquals(xp.matches(self.e), 1) + self.assertEqual(xp.matches(self.e), 1) def test_queryForString(self): """ Test for queryForString and queryForStringList. """ xp = XPathQuery("/foo") - self.assertEquals(xp.queryForString(self.e), "somecontent") - self.assertEquals(xp.queryForStringList(self.e), + self.assertEqual(xp.queryForString(self.e), "somecontent") + self.assertEqual(xp.queryForStringList(self.e), ["somecontent", "somemorecontent"]) def test_queryForNodes(self): @@ -176,7 +176,7 @@ Test finding nodes. """ xp = XPathQuery("/foo/bar") - self.assertEquals(xp.queryForNodes(self.e), [self.bar1, self.bar2, + self.assertEqual(xp.queryForNodes(self.e), [self.bar1, self.bar2, self.bar4, self.bar5, self.bar6, self.bar7]) @@ -185,24 +185,24 @@ Test matching a node with given text. """ xp = XPathQuery("/foo[text() = 'somecontent']") - self.assertEquals(xp.matches(self.e), True) + self.assertEqual(xp.matches(self.e), True) def test_textNotOperator(self): """ Test for not operator. """ xp = XPathQuery("/foo[not(@nosuchattrib)]") - self.assertEquals(xp.matches(self.e), True) + self.assertEqual(xp.matches(self.e), True) def test_anyLocationAndText(self): """ Test finding any nodes named gar and getting their text contents. """ xp = XPathQuery("//gar") - self.assertEquals(xp.matches(self.e), True) - self.assertEquals(xp.queryForNodes(self.e), [self.gar1, self.gar2, + self.assertEqual(xp.matches(self.e), True) + self.assertEqual(xp.queryForNodes(self.e), [self.gar1, self.gar2, self.gar3, self.gar4]) - self.assertEquals(xp.queryForStringList(self.e), ["DEF", "ABC", + self.assertEqual(xp.queryForStringList(self.e), ["DEF", "ABC", "JKL", "MNO"]) def test_anyLocation(self): @@ -210,8 +210,8 @@ Test finding any nodes named bar. """ xp = XPathQuery("//bar") - self.assertEquals(xp.matches(self.e), True) - self.assertEquals(xp.queryForNodes(self.e), [self.bar1, self.bar2, + self.assertEqual(xp.matches(self.e), True) + self.assertEqual(xp.queryForNodes(self.e), [self.bar1, self.bar2, self.bar3, self.bar4, self.bar5, self.bar6, self.bar7]) @@ -229,16 +229,16 @@ Test boolean and operator in condition. """ xp = XPathQuery("//bar[@attrib4='value4' and @attrib5='value5']") - self.assertEquals(xp.matches(self.e), True) - self.assertEquals(xp.queryForNodes(self.e), [self.bar5]) + self.assertEqual(xp.matches(self.e), True) + self.assertEqual(xp.queryForNodes(self.e), [self.bar5]) def test_orOperator(self): """ Test boolean or operator in condition. """ xp = XPathQuery("//bar[@attrib5='value4' or @attrib5='value5']") - self.assertEquals(xp.matches(self.e), True) - self.assertEquals(xp.queryForNodes(self.e), [self.bar5, self.bar6]) + self.assertEqual(xp.matches(self.e), True) + self.assertEqual(xp.queryForNodes(self.e), [self.bar5, self.bar6]) def test_booleanOperatorsParens(self): """ @@ -246,8 +246,8 @@ """ xp = XPathQuery("""//bar[@attrib4='value4' and (@attrib5='value4' or @attrib5='value6')]""") - self.assertEquals(xp.matches(self.e), True) - self.assertEquals(xp.queryForNodes(self.e), [self.bar6, self.bar7]) + self.assertEqual(xp.matches(self.e), True) + self.assertEqual(xp.queryForNodes(self.e), [self.bar6, self.bar7]) def test_booleanOperatorsNoParens(self): """ @@ -256,5 +256,5 @@ xp = XPathQuery("""//bar[@attrib5='value4' or @attrib5='value5' or @attrib5='value6']""") - self.assertEquals(xp.matches(self.e), True) - self.assertEquals(xp.queryForNodes(self.e), [self.bar5, self.bar6, self.bar7]) + self.assertEqual(xp.matches(self.e), True) + self.assertEqual(xp.queryForNodes(self.e), [self.bar5, self.bar6, self.bar7]) diff -Nru twisted-words-10.0.0/twisted/words/toctap.py twisted-words-12.1.0/twisted/words/toctap.py --- twisted-words-10.0.0/twisted/words/toctap.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/toctap.py 1970-01-01 00:00:00.000000000 +0000 @@ -1,20 +0,0 @@ - -# Copyright (c) 2001-2004 Twisted Matrix Laboratories. -# See LICENSE for details. - - -""" -Support module for making TOC servers with twistd. -""" - -from twisted.words.protocols import toc -from twisted.python import usage -from twisted.application import strports - -class Options(usage.Options): - synopsis = "[-p ]" - optParameters = [["port", "p", "5190"]] - longdesc = "Makes a TOC server." - -def makeService(config): - return strports.service(config['port'], toc.TOCFactory()) diff -Nru twisted-words-10.0.0/twisted/words/_version.py twisted-words-12.1.0/twisted/words/_version.py --- twisted-words-10.0.0/twisted/words/_version.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/_version.py 2012-06-02 07:04:01.000000000 +0000 @@ -1,3 +1,3 @@ # This is an auto-generated file. Do not edit it. from twisted.python import versions -version = versions.Version('twisted.words', 10, 0, 0) +version = versions.Version('twisted.words', 12, 1, 0) diff -Nru twisted-words-10.0.0/twisted/words/xish/domish.py twisted-words-12.1.0/twisted/words/xish/domish.py --- twisted-words-10.0.0/twisted/words/xish/domish.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/xish/domish.py 2012-03-16 19:16:33.000000000 +0000 @@ -1,6 +1,5 @@ # -*- test-case-name: twisted.words.test.test_domish -*- -# -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -71,7 +70,6 @@ return # Further optimizations - parent = elem.parent name = elem.name uri = elem.uri defaultUri, currentDefaultUri = elem.defaultUri, defaultUri @@ -154,10 +152,10 @@ def escapeToXml(text, isattrib = 0): """ Escape text to proper XML form, per section 2.3 in the XML specification. - @type text: L{str} + @type text: C{str} @param text: Text to escape - @type isattrib: L{bool} + @type isattrib: C{bool} @param isattrib: Triggers escaping of characters necessary for use as attribute values """ @@ -241,18 +239,18 @@ string. A value of C{0} only generates the element's start tag. A value of C{1} yields a complete serialization. - @type closeElement: L{int} + @type closeElement: C{int} @param defaultUri: Initial default namespace URI. This is most useful for partial rendering, where the logical parent element (of which the starttag was already serialized) declares a default namespace that should be inherited. - @type defaultUri: L{str} + @type defaultUri: C{str} @param prefixesInScope: list of prefixes that are assumed to be declared by ancestors. - @type prefixesInScope: L{list} + @type prefixesInScope: C{list} @return: (partial) serialized XML - @rtype: L{unicode} + @rtype: C{unicode} """ def addElement(name, defaultUri = None, content = None): @@ -261,16 +259,16 @@ The new element is added to this element as a child, and will have this element as its parent. - @param name: element name. This can be either a L{unicode} object that + @param name: element name. This can be either a C{unicode} object that contains the local name, or a tuple of (uri, local_name) for a fully qualified name. In the former case, the namespace URI is inherited from this element. - @type name: L{unicode} or L{tuple} of (L{unicode}, L{unicode}) + @type name: C{unicode} or C{tuple} of (C{unicode}, C{unicode}) @param defaultUri: default namespace URI for child elements. If C{None}, this is inherited from this element. - @type defaultUri: L{unicode} + @type defaultUri: C{unicode} @param content: text contained by the new element. - @type content: L{unicode} + @type content: C{unicode} @return: the created element @rtype: object providing L{IElement} """ @@ -283,7 +281,7 @@ L{IElement}. @param node: the child node. - @type node: L{unicode} or object implementing L{IElement} + @type node: C{unicode} or object implementing L{IElement} """ class Element(object): @@ -361,16 +359,16 @@ As, you can see, the element is now in the empty namespace, not in the default namespace of the parent or the streams'. - @type uri: L{unicode} or None + @type uri: C{unicode} or None @ivar uri: URI of this Element's name - @type name: L{unicode} + @type name: C{unicode} @ivar name: Name of this Element - @type defaultUri: L{unicode} or None + @type defaultUri: C{unicode} or None @ivar defaultUri: URI this Element exists within - @type children: L{list} + @type children: C{list} @ivar children: List of child Elements and content @type parent: L{Element} @@ -394,7 +392,7 @@ """ @param qname: Tuple of (uri, name) @param defaultUri: The default URI of the element; defaults to the URI - specified in L{qname} + specified in C{qname} @param attribs: Dictionary of attributes @param localPrefixes: Dictionary of namespace declarations on this element. The key is the prefix to bind the @@ -758,15 +756,17 @@ raise ParserError, str(e) def _onStartElement(self, name, attrs): - # Generate a qname tuple from the provided name - qname = name.split(" ") + # Generate a qname tuple from the provided name. See + # http://docs.python.org/library/pyexpat.html#xml.parsers.expat.ParserCreate + # for an explanation of the formatting of name. + qname = name.rsplit(" ", 1) if len(qname) == 1: qname = ('', name) # Process attributes for k, v in attrs.items(): - if k.find(" ") != -1: - aqname = k.split(" ") + if " " in k: + aqname = k.rsplit(" ", 1) attrs[(aqname[0], aqname[1])] = v del attrs[k] diff -Nru twisted-words-10.0.0/twisted/words/xish/__init__.py twisted-words-12.1.0/twisted/words/xish/__init__.py --- twisted-words-10.0.0/twisted/words/xish/__init__.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/xish/__init__.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,5 +1,5 @@ # -*- test-case-name: twisted.words.test -*- -# Copyright (c) 2001-2005 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. diff -Nru twisted-words-10.0.0/twisted/words/xish/utility.py twisted-words-12.1.0/twisted/words/xish/utility.py --- twisted-words-10.0.0/twisted/words/xish/utility.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/xish/utility.py 2011-11-24 20:33:58.000000000 +0000 @@ -1,6 +1,6 @@ # -*- test-case-name: twisted.words.test.test_xishutil -*- # -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -94,7 +94,7 @@ @note: Exceptions raised by callbacks are trapped and logged. They will not propagate up to make sure other callbacks will still be - called, and the event dispatching allways succeeds. + called, and the event dispatching always succeeds. @param args: Positional arguments to the callable. @type args: C{list} @@ -157,7 +157,7 @@ observe an event, the observer is removed from the list of observers after the first observed event. - Obsevers can also prioritized, by providing an optional C{priority} + Observers can also be prioritized, by providing an optional C{priority} parameter to the L{addObserver} and L{addOnetimeObserver} methods. Higher priority observers are then called before lower priority observers. diff -Nru twisted-words-10.0.0/twisted/words/xish/xmlstream.py twisted-words-12.1.0/twisted/words/xish/xmlstream.py --- twisted-words-10.0.0/twisted/words/xish/xmlstream.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/xish/xmlstream.py 2012-03-16 19:16:33.000000000 +0000 @@ -1,6 +1,6 @@ # -*- test-case-name: twisted.words.test.test_xmlstream -*- # -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ @@ -82,7 +82,7 @@ Dispatches the L{STREAM_END_EVENT}. """ - self.dispatch(self, STREAM_END_EVENT) + self.dispatch(reason, STREAM_END_EVENT) self.stream = None ### -------------------------------------------------------------- @@ -125,16 +125,16 @@ """ Send data over the stream. Sends the given C{obj} over the connection. C{obj} may be instances of - L{domish.Element}, L{unicode} and L{str}. The first two will be - properly serialized and/or encoded. L{str} objects must be in UTF-8 + L{domish.Element}, C{unicode} and C{str}. The first two will be + properly serialized and/or encoded. C{str} objects must be in UTF-8 encoding. Note: because it is easy to make mistakes in maintaining a properly - encoded L{str} object, it is advised to use L{unicode} objects + encoded C{str} object, it is advised to use C{unicode} objects everywhere when dealing with XML Streams. @param obj: Object to be sent over the stream. - @type obj: L{domish.Element}, L{domish} or L{str} + @type obj: L{domish.Element}, L{domish} or C{str} """ if domish.IElement.providedBy(obj): diff -Nru twisted-words-10.0.0/twisted/words/xish/xpathparser.g twisted-words-12.1.0/twisted/words/xish/xpathparser.g --- twisted-words-10.0.0/twisted/words/xish/xpathparser.g 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/xish/xpathparser.g 2012-03-16 19:16:33.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. # DO NOT EDIT xpathparser.py! @@ -233,9 +233,9 @@ @param parent: Context object or C{None} @param scanner: Scanner object @param tokenpos: scanner token position - @type tokenpos: L{int} + @type tokenpos: C{int} @param rule: name of the rule - @type rule: L{str} + @type rule: C{str} @param args: tuple listing parameters to the rule """ diff -Nru twisted-words-10.0.0/twisted/words/xish/xpathparser.py twisted-words-12.1.0/twisted/words/xish/xpathparser.py --- twisted-words-10.0.0/twisted/words/xish/xpathparser.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/xish/xpathparser.py 2012-03-16 19:16:33.000000000 +0000 @@ -1,4 +1,4 @@ -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. # DO NOT EDIT xpathparser.py! @@ -233,9 +233,9 @@ @param parent: Context object or C{None} @param scanner: Scanner object @param tokenpos: scanner token position - @type tokenpos: L{int} + @type tokenpos: C{int} @param rule: name of the rule - @type rule: L{str} + @type rule: C{str} @param args: tuple listing parameters to the rule """ diff -Nru twisted-words-10.0.0/twisted/words/xish/xpath.py twisted-words-12.1.0/twisted/words/xish/xpath.py --- twisted-words-10.0.0/twisted/words/xish/xpath.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/xish/xpath.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,6 +1,6 @@ # -*- test-case-name: twisted.words.test.test_xpath -*- # -# Copyright (c) 2001-2007 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. """ diff -Nru twisted-words-10.0.0/twisted/words/xmpproutertap.py twisted-words-12.1.0/twisted/words/xmpproutertap.py --- twisted-words-10.0.0/twisted/words/xmpproutertap.py 2010-03-09 09:15:33.000000000 +0000 +++ twisted-words-12.1.0/twisted/words/xmpproutertap.py 2011-02-14 04:45:15.000000000 +0000 @@ -1,6 +1,6 @@ # -*- test-case-name: twisted.words.test.test_xmpproutertap -*- # -# Copyright (c) 2001-2008 Twisted Matrix Laboratories. +# Copyright (c) Twisted Matrix Laboratories. # See LICENSE for details. from twisted.application import strports