]> jfr.im git - irc/quakenet/qwebirc.git/blame - qwebirc/ircclient.py
Merge.
[irc/quakenet/qwebirc.git] / qwebirc / ircclient.py
CommitLineData
0faa6c16 1import twisted, sys, codecs, traceback
9e769c12
CP
2from twisted.words.protocols import irc
3from twisted.internet import reactor, protocol
4from twisted.web import resource, server
5from twisted.protocols import basic
6
930be88a 7import hmac, time, config, qwebirc.config_options as config_options
9e769c12 8from config import HMACTEMPORAL
b5c84380 9
930be88a 10if hasattr(config, "WEBIRC_MODE") and config.WEBIRC_MODE == "hmac":
b5c84380 11 HMACKEY = hmac.HMAC(key=config.HMACKEY)
9e769c12
CP
12
13def hmacfn(*args):
14 h = HMACKEY.copy()
15 h.update("%d %s" % (int(time.time() / HMACTEMPORAL), " ".join(args)))
16 return h.hexdigest()
17
c70a7ff6
CP
18def utf8_iso8859_1(data, table=dict((x, x.decode("iso-8859-1")) for x in map(chr, range(0, 256)))):
19 return (table.get(data.object[data.start]), data.start+1)
20
21codecs.register_error("mixed-iso-8859-1", utf8_iso8859_1)
22
23def irc_decode(x):
24 try:
25 return x.decode("utf-8", "mixed-iso-8859-1")
26 except UnicodeDecodeError:
27 return x.decode("iso-8859-1", "ignore")
28
9e769c12
CP
29class QWebIRCClient(basic.LineReceiver):
30 delimiter = "\n"
85f01e3f
CP
31 def __init__(self, *args, **kwargs):
32 self.__nickname = "(unregistered)"
33
9e769c12
CP
34 def dataReceived(self, data):
35 basic.LineReceiver.dataReceived(self, data.replace("\r", ""))
36
37 def lineReceived(self, line):
c70a7ff6 38 line = irc_decode(irc.lowDequote(line))
9e769c12
CP
39
40 try:
41 prefix, command, params = irc.parsemsg(line)
42 self.handleCommand(command, prefix, params)
43 except irc.IRCBadMessage:
0faa6c16
CP
44 # emit and ignore
45 traceback.print_exc()
46 return
47
85f01e3f
CP
48 if command == "001":
49 self.__nickname = params[0]
ace37679 50
85f01e3f
CP
51 if self.__perform is not None:
52 for x in self.__perform:
53 self.write(x)
54 self.__perform = None
55 elif command == "NICK":
56 nick = prefix.split("!", 1)[0]
57 if nick == self.__nickname:
58 self.__nickname = params[0]
59
9e769c12
CP
60 def handleCommand(self, command, prefix, params):
61 self("c", command, prefix, params)
62
63 def __call__(self, *args):
64 self.factory.publisher.event(args)
65
66 def write(self, data):
67 self.transport.write("%s\r\n" % irc.lowQuote(data.encode("utf-8")))
68
69 def connectionMade(self):
70 basic.LineReceiver.connectionMade(self)
71
8dc46dfa 72 self.lastError = None
9e769c12 73 f = self.factory.ircinit
6ce70043 74 nick, ident, ip, realname, hostname, pass_ = f["nick"], f["ident"], f["ip"], f["realname"], f["hostname"], f.get("password")
85f01e3f 75 self.__nickname = nick
ace37679 76 self.__perform = f.get("perform")
b5c84380 77
930be88a
CP
78 if not hasattr(config, "WEBIRC_MODE"):
79 self.write("USER %s bleh bleh %s :%s" % (ident, ip, realname))
80 elif config.WEBIRC_MODE == "hmac":
b5c84380
CP
81 hmac = hmacfn(ident, ip)
82 self.write("USER %s bleh bleh %s %s :%s" % (ident, ip, hmac, realname))
28c4ad01 83 elif config.WEBIRC_MODE == "webirc":
195fe862 84 self.write("WEBIRC %s qwebirc %s %s" % (config.WEBIRC_PASSWORD, hostname, ip))
b5c84380 85 self.write("USER %s bleh %s :%s" % (ident, ip, realname))
711593cd
CP
86 elif config.WEBIRC_MODE == "cgiirc":
87 self.write("PASS %s_%s_%s" % (config.CGIIRC_STRING, ip, hostname))
88 self.write("USER %s bleh %s :%s" % (ident, ip, realname))
930be88a 89 elif config.WEBIRC_MODE == config_options.WEBIRC_REALNAME or config.WEBIRC_MODE is None: # last bit is legacy
b5c84380
CP
90 if ip == hostname:
91 dispip = ip
92 else:
93 dispip = "%s/%s" % (hostname, ip)
94
28c4ad01 95 self.write("USER %s bleh bleh :%s - %s" % (ident, dispip, realname))
b5c84380 96
2f74dea9
CP
97 if pass_ is not None:
98 self.write("PASS :%s" % pass_)
9e769c12
CP
99 self.write("NICK %s" % nick)
100
101 self.factory.client = self
102 self("connect")
103
85f01e3f
CP
104 def __str__(self):
105 return "<QWebIRCClient: %s!%s@%s>" % (self.__nickname, self.factory.ircinit["ident"], self.factory.ircinit["ip"])
106
9e769c12 107 def connectionLost(self, reason):
8dc46dfa
CP
108 if self.lastError:
109 self.disconnect("Connection to IRC server lost: %s" % self.lastError)
110 else:
111 self.disconnect("Connection to IRC server lost.")
9e769c12
CP
112 self.factory.client = None
113 basic.LineReceiver.connectionLost(self, reason)
8dc46dfa
CP
114
115 def error(self, message):
116 self.lastError = message
117 self.write("QUIT :qwebirc exception: %s" % message)
118 self.transport.loseConnection()
119
120 def disconnect(self, reason):
121 self("disconnect", reason)
122 self.factory.publisher.disconnect()
9e769c12
CP
123
124class QWebIRCFactory(protocol.ClientFactory):
125 protocol = QWebIRCClient
126 def __init__(self, publisher, **kwargs):
127 self.client = None
128 self.publisher = publisher
129 self.ircinit = kwargs
130
131 def write(self, data):
132 self.client.write(data)
8dc46dfa
CP
133
134 def error(self, reason):
135 self.client.error(reason)
136
623b5428
CP
137 def clientConnectionFailed(self, connector, reason):
138 protocol.ClientFactory.clientConnectionFailed(self, connector, reason)
139 self.publisher.event(["disconnect", "Connection to IRC server failed."])
140 self.publisher.disconnect()
8dc46dfa 141
9e769c12
CP
142def createIRC(*args, **kwargs):
143 f = QWebIRCFactory(*args, **kwargs)
144 reactor.connectTCP(config.IRCSERVER, config.IRCPORT, f)
145 return f
146
147if __name__ == "__main__":
b5c84380 148 e = createIRC(lambda x: 2, nick="slug__moo", ident="mooslug", ip="1.2.3.6", realname="mooooo", hostname="1.2.3.4")
8dc46dfa 149 reactor.run()