class RestClientFactory(protocol.ClientFactory): protocol = client.HTTPPageGetter noisy = False def __init__(self, host, port, path, data, timeout = 60): self.log = log.getChild('ClientFactory') self.timeout = timeout self.agent = "RestClient" self.headers = InsensitiveDict() self.headers.setdefault('Content-Length', len(data)) self.headers.setdefault("connection", "close") self.method = 'POST' self.url = 'http://' + host + ':' + str(port) + path self.scheme = 'http' self.postdata = data self.host = host self.port = port self.path = path self.waiting = 1 self.deferred = defer.Deferred() self.response_headers = None self.cookies = {} def __repr__(self): return "<%s: %s>" % (self.__class__.__name__, self.url) def buildProtocol(self, addr): p = protocol.ClientFactory.buildProtocol(self, addr) if self.timeout: timeoutCall = reactor.callLater(self.timeout, p.timeout) self.deferred.addBoth(self._cancelTimeout, timeoutCall) return p def _cancelTimeout(self, result, timeoutCall): if timeoutCall.active(): timeoutCall.cancel() return result def gotHeaders(self, headers): self.response_headers = headers def gotStatus(self, version, status): self.version, self.status = version, status def page(self, page): if self.waiting: self.waiting = 0 self.deferred.callback(page) def noPage(self, reason): if self.waiting: self.waiting = 0 self.deferred.errback(reason) def clientConnectionFailed(self, _, reason): if self.waiting: self.waiting = 0 self.deferred.errback(reason)
class RestClientFactory(protocol.ClientFactory): protocol = client.HTTPPageGetter noisy = False def __init__(self, host, port, path, data, timeout=60): self.timeout = timeout self.agent = "RestClient" self.headers = InsensitiveDict() self.headers.setdefault('Content-Length', len(data)) self.headers.setdefault("connection", "close") self.method = 'POST' self.url = 'http://' + host + ':' + str(port) + path self.scheme = 'http' self.postdata = data self.host = host self.port = port self.path = path self.waiting = 1 self.deferred = defer.Deferred() self.response_headers = None self.cookies = {} def __repr__(self): return "<%s: %s>" % (self.__class__.__name__, self.url) def buildProtocol(self, addr): p = protocol.ClientFactory.buildProtocol(self, addr) if self.timeout: timeoutCall = reactor.callLater(self.timeout, p.timeout) self.deferred.addBoth(self._cancelTimeout, timeoutCall) return p def _cancelTimeout(self, result, timeoutCall): if timeoutCall.active(): timeoutCall.cancel() return result def gotHeaders(self, headers): self.response_headers = headers def gotStatus(self, version, status, message): self.version, self.status, self.message = version, status, message def page(self, page): if self.waiting: self.waiting = 0 self.deferred.callback(page) def noPage(self, reason): if self.waiting: self.waiting = 0 self.deferred.errback(reason) def clientConnectionFailed(self, _, reason): if self.waiting: self.waiting = 0 self.deferred.errback(reason)
class HeaderAwareHTTPClientFactory(client.HTTPClientFactory): protocol = myHTTPPageGetter noisy = False def __init__(self, url, method='GET', postdata=None, headers=None, agent="Twisted PageGetter", timeout=0, cookies=None, followRedirect=True, redirectLimit=20): self.followRedirect = followRedirect self.redirectLimit = redirectLimit self._redirectCount = 0 self.timeout = timeout self.agent = agent if cookies is None: cookies = {} self.cookies = cookies if headers is not None: self.headers = InsensitiveDict(headers) else: self.headers = InsensitiveDict() if postdata is not None: self.headers.setdefault('Content-Length', len(postdata)) # just in case a broken http/1.1 decides to keep connection alive self.headers.setdefault("connection", "close") self.postdata = postdata self.method = method self.setURL(url) self.waiting = 1 self.deferred = defer.Deferred() self.response_headers = None def buildProtocol(self, addr): p = protocol.ClientFactory.buildProtocol(self, addr) p.method = self.method p.followRedirect = self.followRedirect if self.timeout: timeoutCall = reactor.callLater(self.timeout, p.timeout) self.deferred.addBoth(self._cancelTimeout, timeoutCall) return p def page(self, page): if self.waiting: self.waiting = 0 self.deferred.callback((page, self.response_headers))
class HeaderAwareHTTPClientFactory(client.HTTPClientFactory): protocol = yourHTTPPageGetter noisy = False def __init__(self, url, method='GET', postdata=None, headers=None, agent="Coherence PageGetter", timeout=0, cookies=None, followRedirect=True, redirectLimit=20): self.followRedirect = followRedirect self.redirectLimit = redirectLimit self._redirectCount = 0 self.timeout = timeout self.agent = agent if cookies is None: cookies = {} self.cookies = cookies if headers is not None: self.headers = InsensitiveDict(headers) else: self.headers = InsensitiveDict() if postdata is not None: self.headers.setdefault('Content-Length', len(postdata)) # just in case a broken http/1.1 decides to keep connection alive self.headers.setdefault("connection", "close") self.postdata = postdata self.method = method self.setURL(url) self.waiting = 1 self.deferred = defer.Deferred() self._disconnectedDeferred = defer.Deferred() self.response_headers = None def buildProtocol(self, addr): p = protocol.ClientFactory.buildProtocol(self, addr) p.method = self.method p.followRedirect = self.followRedirect if self.timeout: timeoutCall = reactor.callLater(self.timeout, p.timeout) self.deferred.addBoth(self._cancelTimeout, timeoutCall) self._disconnectedDeferred = defer.Deferred() return p def page(self, page): if self.waiting: self.waiting = 0 self.deferred.callback((page, self.response_headers))
def test01_proxy(self): data = '{"type": "PacketPing"}' headers = InsensitiveDict() headers.setdefault('Content-Length', len(data)) headers.setdefault("connection", "close") headers.setdefault("proxy-connection", "foo") host = '127.0.0.1' port = 19481 path = '/POKER_REST' factory = pokerrestclient.PokerProxyClientFactory('POST', path, '1.1', headers, data, MockRequest(), 6, host + ':' + str(port) + path) reactor.connectTCP(host, port, factory) factory.deferred.addCallback(self.assertNotEquals, None) return factory.deferred
class HTTPClientFactory(protocol.ClientFactory): """Download a given URL. @type deferred: Deferred @ivar deferred: A Deferred that will fire when the content has been retrieved. Once this is fired, the ivars `status', `version', and `message' will be set. @type status: str @ivar status: The status of the response. @type version: str @ivar version: The version of the response. @type message: str @ivar message: The text message returned with the status. @type response_headers: dict @ivar response_headers: The headers that were specified in the response from the server. """ protocol = HTTPPageGetter url = None scheme = None host = '' port = None path = None def __init__(self, url, method='GET', postdata=None, headers=None, agent="Twisted PageGetter", timeout=0, cookies=None, followRedirect=1, proxy=None): self.protocol.followRedirect = followRedirect self.timeout = timeout self.agent = agent self.proxy = proxy if cookies is None: cookies = {} self.cookies = cookies if headers is not None: self.headers = InsensitiveDict(headers) else: self.headers = InsensitiveDict() if postdata is not None: self.headers.setdefault('Content-Length', len(postdata)) # just in case a broken http/1.1 decides to keep connection alive self.headers.setdefault("connection", "close") self.postdata = postdata self.method = method self.setURL(url) self.waiting = 1 self.deferred = defer.Deferred() self.response_headers = None def __repr__(self): return "<%s: %s>" % (self.__class__.__name__, self.url) def setURL(self, url): self.url = url scheme, host, port, path = _parse(url) if scheme and host: self.scheme = scheme self.host = host self.port = port if self.proxy: self.path = "%s://%s:%s%s" % (self.scheme, self.host, self.port, path) else: self.path = path def buildProtocol(self, addr): p = protocol.ClientFactory.buildProtocol(self, addr) if self.timeout: timeoutCall = reactor.callLater(self.timeout, p.timeout) self.deferred.addBoth(self._cancelTimeout, timeoutCall) return p def _cancelTimeout(self, result, timeoutCall): if timeoutCall.active(): timeoutCall.cancel() return result def gotHeaders(self, headers): self.response_headers = headers if headers.has_key('set-cookie'): for cookie in headers['set-cookie']: cookparts = cookie.split(';') cook = cookparts[0] cook.lstrip() k, v = cook.split('=', 1) self.cookies[k.lstrip()] = v.lstrip() def gotStatus(self, version, status, message): self.version, self.status, self.message = version, status, message def page(self, page): if self.waiting: self.waiting = 0 self.deferred.callback(page) def noPage(self, reason): if self.waiting: self.waiting = 0 self.deferred.errback(reason) def clientConnectionFailed(self, _, reason): if self.waiting: self.waiting = 0 self.deferred.errback(reason)
class HTTPClientFactory(protocol.ClientFactory): """Download a given URL. @type deferred: Deferred @ivar deferred: A Deferred that will fire when the content has been retrieved. Once this is fired, the ivars `status', `version', and `message' will be set. @type status: str @ivar status: The status of the response. @type version: str @ivar version: The version of the response. @type message: str @ivar message: The text message returned with the status. @type response_headers: dict @ivar response_headers: The headers that were specified in the response from the server. @type method: str @ivar method: The HTTP method to use in the request. This should be one of OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, or CONNECT (case matters). Other values may be specified if the server being contacted supports them. @type redirectLimit: int @ivar redirectLimit: The maximum number of HTTP redirects that can occur before it is assumed that the redirection is endless. @type afterFoundGet: C{bool} @ivar afterFoundGet: Deviate from the HTTP 1.1 RFC by handling redirects the same way as most web browsers; if the request method is POST and a 302 status is encountered, the redirect is followed with a GET method @type _redirectCount: int @ivar _redirectCount: The current number of HTTP redirects encountered. """ protocol = HTTPPageGetter url = None scheme = None host = "" port = None path = None def __init__( self, url, method="GET", postdata=None, headers=None, agent="Twisted PageGetter", timeout=0, cookies=None, followRedirect=True, redirectLimit=20, afterFoundGet=False, ): self.followRedirect = followRedirect self.redirectLimit = redirectLimit self._redirectCount = 0 self.timeout = timeout self.agent = agent self.afterFoundGet = afterFoundGet if cookies is None: cookies = {} self.cookies = cookies if headers is not None: self.headers = InsensitiveDict(headers) else: self.headers = InsensitiveDict() if postdata is not None: self.headers.setdefault("Content-Length", len(postdata)) # just in case a broken http/1.1 decides to keep connection alive self.headers.setdefault("connection", "close") self.postdata = postdata self.method = method self.setURL(url) self.waiting = 1 self.deferred = defer.Deferred() self.response_headers = None def __repr__(self): return "<%s: %s>" % (self.__class__.__name__, self.url) def setURL(self, url): self.url = url scheme, host, port, path = _parse(url) if scheme and host: self.scheme = scheme self.host = host self.port = port self.path = path def buildProtocol(self, addr): p = protocol.ClientFactory.buildProtocol(self, addr) p.followRedirect = self.followRedirect p.afterFoundGet = self.afterFoundGet if self.timeout: timeoutCall = reactor.callLater(self.timeout, p.timeout) self.deferred.addBoth(self._cancelTimeout, timeoutCall) return p def _cancelTimeout(self, result, timeoutCall): if timeoutCall.active(): timeoutCall.cancel() return result def gotHeaders(self, headers): self.response_headers = headers if headers.has_key("set-cookie"): for cookie in headers["set-cookie"]: cookparts = cookie.split(";") cook = cookparts[0] cook.lstrip() k, v = cook.split("=", 1) self.cookies[k.lstrip()] = v.lstrip() def gotStatus(self, version, status, message): self.version, self.status, self.message = version, status, message def page(self, page): if self.waiting: self.waiting = 0 self.deferred.callback(page) def noPage(self, reason): if self.waiting: self.waiting = 0 self.deferred.errback(reason) def clientConnectionFailed(self, _, reason): if self.waiting: self.waiting = 0 self.deferred.errback(reason)
class HTTPClientFactory(protocol.ClientFactory): """Download a given URL. @type deferred: Deferred @ivar deferred: A Deferred that will fire when the content has been retrieved. Once this is fired, the ivars `status', `version', and `message' will be set. @type status: str @ivar status: The status of the response. @type version: str @ivar version: The version of the response. @type message: str @ivar message: The text message returned with the status. @type response_headers: dict @ivar response_headers: The headers that were specified in the response from the server. @type method: str @ivar method: The HTTP method to use in the request. This should be one of OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, or CONNECT (case matters). Other values may be specified if the server being contacted supports them. @type redirectLimit: int @ivar redirectLimit: The maximum number of HTTP redirects that can occur before it is assumed that the redirection is endless. @type afterFoundGet: C{bool} @ivar afterFoundGet: Deviate from the HTTP 1.1 RFC by handling redirects the same way as most web browsers; if the request method is POST and a 302 status is encountered, the redirect is followed with a GET method @type _redirectCount: int @ivar _redirectCount: The current number of HTTP redirects encountered. """ protocol = HTTPPageGetter url = None scheme = None host = '' port = None path = None def __init__(self, url, method='GET', postdata=None, headers=None, agent="Twisted PageGetter", timeout=0, cookies=None, followRedirect=True, redirectLimit=20, afterFoundGet=False): self.followRedirect = followRedirect self.redirectLimit = redirectLimit self._redirectCount = 0 self.timeout = timeout self.agent = agent self.afterFoundGet = afterFoundGet if cookies is None: cookies = {} self.cookies = cookies if headers is not None: self.headers = InsensitiveDict(headers) else: self.headers = InsensitiveDict() if postdata is not None: self.headers.setdefault('Content-Length', len(postdata)) # just in case a broken http/1.1 decides to keep connection alive self.headers.setdefault("connection", "close") self.postdata = postdata self.method = method self.setURL(url) self.waiting = 1 self.deferred = defer.Deferred() self.response_headers = None def __repr__(self): return "<%s: %s>" % (self.__class__.__name__, self.url) def setURL(self, url): self.url = url scheme, host, port, path = _parse(url) if scheme and host: self.scheme = scheme self.host = host self.port = port self.path = path def buildProtocol(self, addr): p = protocol.ClientFactory.buildProtocol(self, addr) p.followRedirect = self.followRedirect p.afterFoundGet = self.afterFoundGet if self.timeout: timeoutCall = reactor.callLater(self.timeout, p.timeout) self.deferred.addBoth(self._cancelTimeout, timeoutCall) return p def _cancelTimeout(self, result, timeoutCall): if timeoutCall.active(): timeoutCall.cancel() return result def gotHeaders(self, headers): self.response_headers = headers if headers.has_key('set-cookie'): for cookie in headers['set-cookie']: cookparts = cookie.split(';') cook = cookparts[0] cook.lstrip() k, v = cook.split('=', 1) self.cookies[k.lstrip()] = v.lstrip() def gotStatus(self, version, status, message): self.version, self.status, self.message = version, status, message def page(self, page): if self.waiting: self.waiting = 0 self.deferred.callback(page) def noPage(self, reason): if self.waiting: self.waiting = 0 self.deferred.errback(reason) def clientConnectionFailed(self, _, reason): if self.waiting: self.waiting = 0 self.deferred.errback(reason)
class HTTPClientFactory(protocol.ClientFactory): """Download a given URL. @type deferred: Deferred @ivar deferred: A Deferred that will fire when the content has been retrieved. Once this is fired, the ivars `status', `version', and `message' will be set. @type status: str @ivar status: The status of the response. @type version: str @ivar version: The version of the response. @type message: str @ivar message: The text message returned with the status. @type response_headers: dict @ivar response_headers: The headers that were specified in the response from the server. @type method: str @ivar method: The HTTP method to use in the request. This should be one of OPTIONS, GET, HEAD, POST, PUT, DELETE, TRACE, or CONNECT (case matters). Other values may be specified if the server being contacted supports them. @type redirectLimit: int @ivar redirectLimit: The maximum number of HTTP redirects that can occur before it is assumed that the redirection is endless. @type afterFoundGet: C{bool} @ivar afterFoundGet: Deviate from the HTTP 1.1 RFC by handling redirects the same way as most web browsers; if the request method is POST and a 302 status is encountered, the redirect is followed with a GET method @type _redirectCount: int @ivar _redirectCount: The current number of HTTP redirects encountered. @ivar _disconnectedDeferred: A L{Deferred} which only fires after the last connection associated with the request (redirects may cause multiple connections to be required) has closed. The result Deferred will only fire after this Deferred, so that callers can be assured that there are no more event sources in the reactor once they get the result. """ protocol = HTTPPageGetter url = None scheme = None host = '' port = None path = None def __init__(self, url, method='GET', postdata=None, headers=None, agent="Twisted PageGetter", timeout=0, cookies=None, followRedirect=True, redirectLimit=20, afterFoundGet=False): self.followRedirect = followRedirect self.redirectLimit = redirectLimit self._redirectCount = 0 self.timeout = timeout self.agent = agent self.afterFoundGet = afterFoundGet if cookies is None: cookies = {} self.cookies = cookies if headers is not None: self.headers = InsensitiveDict(headers) else: self.headers = InsensitiveDict() if postdata is not None: self.headers.setdefault('Content-Length', len(postdata)) # just in case a broken http/1.1 decides to keep connection alive self.headers.setdefault("connection", "close") self.postdata = postdata self.method = method self.setURL(url) self.waiting = 1 self._disconnectedDeferred = defer.Deferred() self.deferred = defer.Deferred() # Make sure the first callback on the result Deferred pauses the # callback chain until the request connection is closed. self.deferred.addBoth(self._waitForDisconnect) self.response_headers = None def _waitForDisconnect(self, passthrough): """ Chain onto the _disconnectedDeferred, preserving C{passthrough}, so that the result is only available after the associated connection has been closed. """ self._disconnectedDeferred.addCallback(lambda ignored: passthrough) return self._disconnectedDeferred def __repr__(self): return "<%s: %s>" % (self.__class__.__name__, self.url) def setURL(self, url): self.url = url scheme, host, port, path = _parse(url) if scheme and host: self.scheme = scheme self.host = host self.port = port self.path = path def buildProtocol(self, addr): p = protocol.ClientFactory.buildProtocol(self, addr) p.followRedirect = self.followRedirect p.afterFoundGet = self.afterFoundGet if self.timeout: timeoutCall = reactor.callLater(self.timeout, p.timeout) self.deferred.addBoth(self._cancelTimeout, timeoutCall) return p def _cancelTimeout(self, result, timeoutCall): if timeoutCall.active(): timeoutCall.cancel() return result def gotHeaders(self, headers): self.response_headers = headers if headers.has_key('set-cookie'): for cookie in headers['set-cookie']: cookparts = cookie.split(';') cook = cookparts[0] cook.lstrip() k, v = cook.split('=', 1) self.cookies[k.lstrip()] = v.lstrip() def gotStatus(self, version, status, message): self.version, self.status, self.message = version, status, message def page(self, page): if self.waiting: self.waiting = 0 self.deferred.callback(page) def noPage(self, reason): if self.waiting: self.waiting = 0 self.deferred.errback(reason) def clientConnectionFailed(self, _, reason): """ When a connection attempt fails, the request cannot be issued. If no result has yet been provided to the result Deferred, provide the connection failure reason as an error result. """ if self.waiting: self.waiting = 0 # If the connection attempt failed, there is nothing more to # disconnect, so just fire that Deferred now. self._disconnectedDeferred.callback(None) self.deferred.errback(reason)
class HTTPClientFactory(protocol.ClientFactory): """Download a given URL. @type deferred: Deferred @ivar deferred: A Deferred that will fire when the content has been retrieved. Once this is fired, the ivars `status', `version', and `message' will be set. @type status: str @ivar status: The status of the response. @type version: str @ivar version: The version of the response. @type message: str @ivar message: The text message returned with the status. @type response_headers: dict @ivar response_headers: The headers that were specified in the response from the server. """ protocol = HTTPPageGetter url = None scheme = None host = '' port = None path = None def __init__(self, url, method='GET', postdata=None, headers=None, agent="Twisted PageGetter", timeout=0, cookies=None, followRedirect=1): self.protocol.followRedirect = followRedirect self.timeout = timeout self.agent = agent if cookies is None: cookies = {} self.cookies = cookies if headers is not None: self.headers = InsensitiveDict(headers) else: self.headers = InsensitiveDict() if postdata is not None: self.headers.setdefault('Content-Length', len(postdata)) # just in case a broken http/1.1 decides to keep connection alive self.headers.setdefault("connection", "close") self.postdata = postdata self.method = method self.setURL(url) self.waiting = 1 self.deferred = defer.Deferred() self.response_headers = None def __repr__(self): return "<%s: %s>" % (self.__class__.__name__, self.url) def setURL(self, url): self.url = url scheme, host, port, path = _parse(url) if scheme and host: self.scheme = scheme self.host = host self.port = port self.path = path def buildProtocol(self, addr): p = protocol.ClientFactory.buildProtocol(self, addr) if self.timeout: timeoutCall = reactor.callLater(self.timeout, p.timeout) self.deferred.addBoth(self._cancelTimeout, timeoutCall) return p def _cancelTimeout(self, result, timeoutCall): if timeoutCall.active(): timeoutCall.cancel() return result def gotHeaders(self, headers): self.response_headers = headers if headers.has_key('set-cookie'): for cookie in headers['set-cookie']: cookparts = cookie.split(';') cook = cookparts[0] cook.lstrip() k, v = cook.split('=', 1) self.cookies[k.lstrip()] = v.lstrip() def gotStatus(self, version, status, message): self.version, self.status, self.message = version, status, message def page(self, page): if self.waiting: self.waiting = 0 self.deferred.callback(page) def noPage(self, reason): if self.waiting: self.waiting = 0 self.deferred.errback(reason) def clientConnectionFailed(self, _, reason): if self.waiting: self.waiting = 0 self.deferred.errback(reason)
class IRCBot(irc.IRCClient): sasl_buffer = "" sasl_result = None sasl_login = None cancel_hilight_re = re.compile(ur"(?:(?<=\u00a7[0-9a-flmnor])|(?<!\u00a7)\b).+?\b") def __init__(self, factory, parent): self.factory = factory self.nickname = parent.nickname.encode('ascii') self.realname = parent.realname.encode('ascii') self.username = parent.ident.encode('ascii') self.ns_username = parent.username self.ns_password = parent.password self.password = parent.server_password.encode('ascii') self.join_channels = parent.channel_map.keys() self.users = InsensitiveDict() self.channels = InsensitiveDict() self.cap_requests = set() self.parent = parent def register(self, nickname, hostname="foo", servername="bar"): self.sendLine("CAP LS") return irc.IRCClient.register(self, nickname, hostname, servername) def sendLine(self, line): if isinstance(line, unicode): line = line.encode('utf8', 'replace') irc.IRCClient.sendLine(self, line) def _parse_cap(self, cap): mod = '' while cap[0] in "-~=": mod, cap = mod + cap[0], cap[1:] if '/' in cap: vendor, cap = cap.split('/', 1) else: vendor = None return (cap, mod, vendor) def request_cap(self, *caps): self.cap_requests |= set(caps) self.sendLine("CAP REQ :{0}".format(' '.join(caps))) @defer.inlineCallbacks def end_cap(self): if self.sasl_result: yield self.sasl_result self.sendLine("CAP END") def irc_CAP(self, prefix, params): self.supports_cap = True identifier, subcommand, args = params args = args.split(' ') if subcommand == "LS": self.sasl_start(args) if not self.cap_requests: self.sendLine("CAP END") elif subcommand == "ACK": ack = [] for cap in args: if not cap: continue cap, mod, vendor = self._parse_cap(cap) if '-' in mod: if cap in self.capabilities: del self.capabilities[cap] continue self.cap_requests.remove(cap) if cap == 'sasl': self.sasl_next() if ack: self.sendLine("CAP ACK :{0}".format(' '.join(ack))) if not self.cap_requests: self.end_cap() elif subcommand == "NAK": # this implementation is probably not compliant but it will have to do for now for cap in args: self.cap_requests.remove(cap) if not self.cap_requests: self.end_cap() def signedOn(self): if ISSLTransport.providedBy(self.transport): cert = self.transport.getPeerCertificate() fp = cert.digest("sha1") verified = "verified" if self.factory.parent.server_fingerprint else "unverified" print("irc: connected securely. server fingerprint: {0} ({1})".format(fp, verified)) else: print("irc: connected") if self.ns_username and self.ns_password and not self.sasl_login: self.msg('NickServ', 'IDENTIFY {0} {1}'.format(self.ns_username, self.ns_password)) for channel in self.join_channels: self.join(channel) def irc_JOIN(self, prefix, params): nick = prefix.split('!')[0] channel = params[-1] if nick == self.nickname: self.joined(channel) else: self.userJoined(prefix, channel) def joined(self, channel): print('irc: joined channel') self.factory.client = self def who(): self.sendLine("WHO " + channel) task.LoopingCall(who).start(30) def isupport(self, args): self.compute_prefix_names() def compute_prefix_names(self): KNOWN_NAMES = {"o": "op", "h": "halfop", "v": "voice"} prefixdata = self.supported.getFeature("PREFIX", {"o": ("@", 0), "v": ("+", 1)}).items() op_priority = ([priority for mode, (prefix, priority) in prefixdata if mode == "o"] + [None])[0] self.prefixes, self.statuses, self.priority = {}, {}, {} for mode, (prefix, priority) in prefixdata: name = "?" if mode in KNOWN_NAMES: name = KNOWN_NAMES[mode] elif priority == 0: if op_priority == 2: name = "owner" else: name = "admin" else: name = "+" + mode self.prefixes[mode] = prefix self.statuses[prefix] = name self.priority[name] = priority self.priority[mode] = priority self.priority[prefix] = priority def parse_prefixes(self, user, nick, prefixes=''): status = [] prefixdata = self.supported.getFeature("PREFIX", {"o": ("@", 0), "v": ("+", 1)}).items() for mode, (prefix, priority) in prefixdata: if prefix in prefixes + nick: nick = nick.replace(prefix, '') status.append((prefix, priority)) if nick == self.nickname: return user.status = ''.join(t[0] for t in sorted(status, key=lambda t: t[1])) def irc_RPL_WHOREPLY(self, prefix, params): _, channel, username, host, server, nick, status, hg = params if nick == self.nickname: return hops, gecos = hg.split(' ', 1) user = self.get_user(nick) or IRCUser(self, nick) user.username = username user.hostname = host user.oper = '*' in status user.away = status[0] == 'G' self.users[nick] = user self.get_channel(channel)[nick] = IRCUserInChannel(user, channel) self.parse_prefixes(user, nick, status[1:].replace('*', '')) def modeChanged(self, user, channel, _set, modes, args): args = list(args) if channel not in self.parent.channel_map: return for m, arg in zip(modes, args): if m in self.prefixes and arg != self.nickname: u = self.get_user(arg).on(channel) if u: u.status = u.status.replace(self.prefixes[m], '') if _set: u.status = ''.join(sorted(list(u.status + self.prefixes[m]), key=lambda k: self.priority[k])) def has_status(self, nick, status): if status != 0 and not status: return True if status not in self.priority: return False priority = self.priority[status] u = self.users.get(nick, None) return u and (u.priority is not None) and u.priority <= priority def get_channel(self, channel): return self.channels.setdefault(channel, InsensitiveDict()) def get_user(self, nick): return self.users.get(nick, False) def userJoined(self, user, channel): nick = user.split('!')[0] user = IRCUser(self, nick) self.users[nick] = user self.get_channel(channel)[nick] = IRCUserInChannel(user, channel) def userRenamed(self, oldname, newname): if oldname not in self.users: return u = self.users[oldname] u.nick = newname self.users[newname] = u del self.users[oldname] for k, v in self.channels.items(): if oldname in v: v[newname] = v[oldname] del v[oldname] def userLeft(self, user, channel): if user not in self.users: return del self.users[user] for k, v in self.channels.items(): if user in v: del v[user] def userKicked(self, kickee, channel, kicker, message): if kickee not in self.users: return del self.users[kickee] for k, v in self.channels.items(): if user in v: del v[user] def userQuit(self, user, quitMessage): if user not in self.users: return del self.users[user] for k, v in self.channels.items(): if user in v: del v[user] def privmsg(self, user, channel, msg): pass def action(self, user, channel, msg): pass def irc_AUTHENTICATE(self, prefix, params): self.sasl_continue(params[0]) def sasl_send(self, data): while data and len(data) >= 400: en, data = data[:400].encode('base64').replace('\n', ''), data[400:] self.sendLine("AUTHENTICATE " + en) if data: self.sendLine("AUTHENTICATE " + data.encode('base64').replace('\n', '')) else: self.sendLine("AUTHENTICATE +") def sasl_start(self, cap_list): if 'sasl' not in cap_list: return self.request_cap('sasl') self.sasl_result = defer.Deferred() self.sasl_mechanisms = list(SASL_MECHANISMS) def sasl_next(self): mech = None while not mech or not mech.is_valid(): if not self.sasl_mechanisms: return False self.sasl_auth = mech = self.sasl_mechanisms.pop(0)(self.ns_username, self.ns_password) self.sendLine("AUTHENTICATE " + self.sasl_auth.name) return True def sasl_continue(self, data): if data == '+': data = '' else: data = data.decode('base64') if len(data) == 400: self.sasl_buffer += data else: response = self.sasl_auth.respond(self.sasl_buffer + data) if response is False: # abort self.sendLine("AUTHENTICATE *") else: self.sasl_send(response) self.sasl_buffer = "" def sasl_finish(self): if self.sasl_result: self.sasl_result.callback(True) self.sasl_result = None def sasl_failed(self, whine=True): if self.sasl_login is False: return if self.sasl_next(): return self.sasl_login = False self.sendLine("AUTHENTICATE *") self.sasl_finish() if whine: print("irc: failed to log in.") def irc_904(self, prefix, params): self.sasl_failed() def irc_905(self, prefix, params): self.sasl_failed() def irc_906(self, prefix, params): self.sasl_failed(False) def irc_907(self, prefix, params): self.sasl_failed(False) def irc_900(self, prefix, params): self.sasl_login = params[2] print("irc: logged in as '{0}' (using {1})".format(self.sasl_login, self.sasl_auth.name)) def irc_903(self, prefix, params): self.sasl_finish() def alterCollidedNick(self, nickname): return nickname + '_' def cancel_hilights(self, channel, text): def hl(match): s = match.group(0) if len(s) >= 2 and s in self.get_channel(channel): return s[:-1] + '*' + s[-1] else: return s return self.cancel_hilight_re.sub(hl, text) def translate_colors(self, text): tr = { "0": "\x0301", "1": "\x0302", "2": "\x0303", "3": "\x0310", "4": "\x0304", "5": "\x0306", "6": "\x0308", "7": "\x0315", "8": "\x0314", "9": "\x0312", "a": "\x0309", "b": "\x0311", "c": "\x0304", "d": "\x0313", "e": "\x0308", "f": "\x0F", } return re.sub(ur"\u00a7([0-9a-f])", lambda m: tr.get(m.group(1), ""), text) def irc_relay(self, channel, message): message = message.decode('utf8') self.say(channel, self.translate_colors(self.cancel_hilights(channel, message)))
class HeaderAwareHTTPClientFactory(client.HTTPClientFactory): protocol = myHTTPPageGetter noisy = False def __init__(self, url, method='GET', postdata=None, headers=None, agent="Twisted PageGetter", timeout=0, cookies=None, followRedirect=True, redirectLimit=20): self.followRedirect = followRedirect self.redirectLimit = redirectLimit self._redirectCount = 0 self.timeout = timeout self.agent = agent if cookies is None: cookies = {} self.cookies = cookies if headers is not None: self.headers = InsensitiveDict(headers) else: self.headers = InsensitiveDict() if postdata is not None: self.headers.setdefault('Content-Length', len(postdata)) # just in case a broken http/1.1 decides to keep connection alive self.headers.setdefault("connection", "close") self.postdata = postdata self.method = method self.setURL(url) #print( 'method: {}\nurl:{}\nheaders:{}\npostdata:{}'.format( method, url, self.headers, postdata ) ) self.waiting = 1 # Fixes Twisted 11.1.0+ support as HTTPClientFactory is expected # to have _disconnectedDeferred. See Twisted r32329. # As Scrapy implements it's own logic to handle redirects is not # needed to add the callback _waitForDisconnect. # Specifically this avoids the AttributeError exception when # clientConnectionFailed method is called. self._disconnectedDeferred = defer.Deferred() self.deferred = defer.Deferred() self.response_headers = None def buildProtocol(self, addr): p = protocol.ClientFactory.buildProtocol(self, addr) p.method = self.method p.followRedirect = self.followRedirect if self.timeout: timeoutCall = reactor.callLater(self.timeout, p.timeout) self.deferred.addBoth(self._cancelTimeout, timeoutCall) return p def page(self, page): if self.waiting: self.waiting = 0 self.deferred.callback((page, self.response_headers))