-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathvyirc.py
313 lines (252 loc) · 9.51 KB
/
vyirc.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
"""
Overview
========
It implements a neat IRC Client interface that permits connection with multiple networks. IRC networks turn into
tabs, IRC network channels turn into tabs as well.
Key-Commands
============
Namespace: vyirc
Mode: GAMMA
Event: <Key-i>
Description: Get in IRC mode, only possible for areavi instances that are tied to IRC connections.
Mode: IRC
Event: <Control-e>
Description: Used to send raw IRC commands to the IRC network.
Mode: IRC
Event: <Control-c>
Description: Used to open a private chat channel with an user.
Commands
========
Command: IrcMode(self, addr, port, user, nick, irccmd, channels=[])
Description: Initiate a new IRC connection.
addr = The IRC network address.
port = The IRC network port.
user = The user parameters like 'vy vy vy :vy'
irccmd = A sequence of IRC commands to be executed on motd.
It is used to identify nick.
channels = A list of channels to join in.
"""
from quickirc import Irc, Misc, send_cmd, send_msg
from untwisted.network import SuperSocket
from untwisted.client import Client, lose
from untwisted.sock_writer import SockWriter
from untwisted.sock_reader import SockReader
from untwisted.event import LOAD, CLOSE, CONNECT_ERR, CONNECT
from untwisted.splits import Terminator
from vyapp.plugins import ENV
from vyapp.ask import Ask, Get
from vyapp.app import root
from vyapp.areavi import AreaVi
H1 = '<%s> %s\n'
H2 = 'Topic :%s\n'
H3 = '>>> %s has left %s :%s<<<\n'
H4 = '>>> %s has joined %s <<<\n'
H5 = '>>> %s is now known as %s <<<\n'
H6 = 'Peers:%s\n'
H7 = '>>> Connection is down ! <<<\n'
H8 = '>>> %s has kicked %s from %s (%s) <<<\n'
H9 = '>>> %s sets mode %s %s on %s <<<\n'
H10 = '>>> Connection is down ! <<<\n'
H11 = '>>> %s [%s@%s] has quit :%s <<<\n'
class ChannelController:
"""
Controls channel events and installs basic commands.
"""
def __init__(self, irc, area, chan):
self.irc = irc
self.area = area
self.chan = chan
self.peers = set()
events = (('PRIVMSG->%s' % chan , self.e_privmsg),
('332->%s' % chan, self.e_332),
('PART->%s' % chan, self.e_part),
('JOIN->%s' % chan, self.e_join),
# ('*NICK', self.e_nick),
('NICK', self.e_nick),
('QUIT', self.e_quit),
('353->%s' % chan, self.e_353),
('KICK->%s' % chan, self.e_kick),
('MODE->%s' % chan, self.e_mode),
(CLOSE, self.e_close))
def unset(con, *args):
for event, handle in events:
irc.con.del_map(event, handle)
for key, value in events:
irc.con.add_map(key, value)
irc.con.once('*PART->%s' % chan, unset)
irc.con.add_map('*KICK->%s' % chan, unset)
area.bind('<Destroy>', lambda event:
unset(irc.con), add=True)
# When area is destroyed, it sends a PART.
area.bind('<Destroy>', lambda event:
send_cmd(irc.con, 'PART %s' % chan), add=True)
# Hook to send msgs.
area.hook('vyirc', 'IRC', '<Key-i>', lambda event: Get(
events={'<Escape>': lambda wid: True,
'<Tab>' : self.c_nick,
'<Return>': lambda wid:
self.irc.drop_msg(area, wid, chan)}))
# It unbinds the above callback.
# In case the part command was sent by text
# by the user. After part it should destroy the
# area.
irc.con.once('*PART->%s' % chan, lambda con, *args:
area.unbind('<Destroy>'))
def e_privmsg(self, con, nick, user, host, msg):
self.area.append(H1 % (nick, msg), '(VYIRC-PRIVMSG)')
def e_join(self, con, nick, user, host):
self.peers.add(nick.lower())
self.area.append(H4 % (nick, self.chan), '(VYIRC-JOIN)')
def e_mode(self, con, nick, user, host, mode, target=''):
self.area.append(H9 % (nick, self.chan,
mode, target), '(VYIRC-MODE)')
def e_part(self, con, nick, user, host, msg):
self.peers.remove(nick.lower())
self.area.append(H3 % (nick, self.chan, msg), '(VYIRC-PART)')
def e_kick(self, con, nick, user, host, target, msg):
self.area.append(H8 % (nick, target,
self.chan, msg), '(VYIRC-KICK)')
def e_nick(self, con, nicka, user, host, nickb):
try:
self.peers.remove(nicka.lower())
except ValueError:
return
self.area.append(H5 % (nicka, nickb), '(VYIRC-NICK)')
self.peers.add(nickb.lower())
def e_close(self, con, *args):
self.area.append(H7, '(VYIRC-CLOSE)')
def e_332(self, con, addr, nick, msg):
self.area.append(H2 % msg, '(VYIRC-332)')
def e_353(self, con, prefix, nick, mode, peers):
self.peers.update(peers.lower().split(' '))
self.area.append(H6 % peers, '(VYIRC-353)')
def e_quit(self, con, nick, user, host, msg=''):
if not nick.lower() in self.peers: return
self.area.append(H11 % (nick, user,
host, msg), '(VYIRC-QUIT)')
def c_nick(self, wid):
data = wid.get()
size = len(data)
data = data.rsplit(' ', 1)[-1]
for ind in self.peers:
if ind.startswith(data):
index = size - len(data)
wid.delete(index, size)
wid.insert(index, ind)
break
pass
class IrcMode:
"""
Controls basic irc events and installs basic commands.
"""
TAGCONF = {
'(VYIRC-PRIVMSG)': {'foreground': '#688B96'},
'(VYIRC-JOIN)': {'foreground': '#F06EF0'},
'(VYIRC-PART)': {'foreground': '#F0BDAD'},
'(VYIRC-QUIT)': {'foreground': '#4EDB1F'},
'(VYIRC-NICK)': {'foreground': '#E9F0AD'},
'(VYIRC-KICK)': {'foreground': '#FC8D9A'},
'(VYIRC-353)': {'foreground': '#BF9163'},
'(VYIRC-332)': {'foreground': '#81BFFC'},
'(VYIRC-CLOSE)': {'foreground': '#A7F2E9'}}
def __init__(self, addr, port, user, nick, irccmd, channels=[], encoding='utf8'):
con = SuperSocket()
self.con = con
con.connect_ex((addr, int(port)))
Client(con)
con.add_map(CONNECT, self.on_connect)
con.add_map(CONNECT_ERR, self.e_connect_err)
self.misc = None
self.addr = addr
self.port = port
self.user = user
self.nick = nick
self.irccmd = irccmd
self.channels = channels
self.encoding = encoding
def send_cmd(self, event):
"""
Used to drop irc commands.
"""
ask = Ask()
send_cmd(self.con, ask.data)
def on_connect(self, con):
area = self.create_area(self.addr)
area.bind('<Destroy>', lambda event:
send_cmd(con, 'QUIT :vy rules!'), add=True)
SockWriter(con)
SockReader(con)
Terminator(con)
Irc(con)
self.misc = Misc(con)
con.add_map(CLOSE, lambda con, err: lose(con))
con.add_map('*JOIN', self.create_channel)
con.add_map(Terminator.FOUND,
lambda con, data: area.append('%s\n' % data.decode(self.encoding)))
con.add_map('PMSG', self.e_pmsg)
con.add_map('376', lambda con, *args:
send_cmd(con, self.irccmd))
con.add_map('376', self.auto_join)
con.add_map('PING', lambda con, prefix, servaddr:
send_cmd(con, 'PONG :%s' % servaddr))
send_cmd(con, 'NICK %s' % self.nick)
send_cmd(con, 'USER %s' % self.user)
def create_channel(self, con, chan):
area = self.create_area(chan)
ChannelController(self, area, chan)
def create_area(self, name):
"""
Create areavi instance for a target and installs
basic irc commands.
"""
area = root.note.create(name)
area.add_mode('IRC')
area.chmode('IRC')
area.install('vyirc', ('EXTRA', '<Key-i>', lambda event: area.chmode('IRC')),
(-1, '<<Chmode-IRC>>', lambda event: area.mark_set('insert', 'end')),
('IRC', '<Control-e>', self.send_cmd),
('IRC', '<Control-c>', self.open_private_channel))
area.tags_config(self.TAGCONF)
return area
def open_private_channel(self, event):
data = Ask()
self.create_private_channel(data)
def create_private_channel(self, nick):
"""
Create private messages channels.
"""
# In case there is no areavi for the user then creates
# a private channel.
area = self.create_area(nick)
area.hook('vyirc', 'IRC', '<Key-i>', lambda event: Get(
events={'<Escape>': lambda wid: True,
'<Return>': lambda wid:
self.drop_msg(area, wid, nick)}))
return area
def e_pmsg(self, con, nick, user, host, target, msg):
"""
Private messages sent to the user are handled here.
"""
# Attempt to retrieve the areavi which corresponds
# to the target/user.
base = lambda key_value: (key_value[0].lower(), key_value[1])
files = iter(AreaVi.get_opened_files(root).items())
targets = dict(list(map(base, files)))
try:
area = targets[nick.lower()]
except KeyError:
area = self.create_private_channel(nick)
area.append(H1 % (nick, msg))
def auto_join(self, con, *args):
for ind in self.channels:
send_cmd(con, 'JOIN %s' % ind)
def e_connect_err(self, con, err):
print('not connected')
def drop_msg(self, area, wid, target):
"""
Drop msgs and update the areavi.
"""
data = wid.get()
area.append(H1 % (self.misc.nick, data))
send_msg(self.con, target, data)
wid.delete(0, 'end')