]> jfr.im git - z_archive/pyp10.git/blob - pyp10.py
Disallow access to Do by non-opers
[z_archive/pyp10.git] / pyp10.py
1 #!/usr/bin/python
2
3 import socket, time
4
5
6 uplink = None
7 modules = {}
8 modcount = 0
9
10 class config(object):
11 name = 'services.p10'
12 numeric = ']S'
13 uplink = {
14 'address': '127.0.0.1',
15 'port': 4400,
16 'name': 'test.p10',
17 'password': 'password',
18 'vhost': '', #bind to this ip - empty string '' for auto-select
19 }
20 autoload = ['q', 'do']
21
22 b64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789[]"
23
24 class User(object):
25 def __init__(self, num, nick, hostmask, modes, account):
26 self.num = num
27 self.nick = nick
28 self.hostmask = hostmask
29 self.modes = modes
30 self.account = account
31
32 if 'o' in self.modes:
33 self.oper = True
34 else:
35 self.oper = False
36
37 if self.account is not None:
38 self.authed = True
39 else:
40 self.authed = False
41
42 class Uplink(object):
43 def __init__(self):
44 global uplink
45 uplink = self
46
47 self.lastnum = None # last numeric used, as [int,int,int]
48 self.nicks = {} # 'nick': Pseudo-object
49 self.nums = {} # 'num': Pseudo-objecta
50 self.users = {} # 'num': User-objects
51 self.data = "" # receive buffer
52
53 self.bursting = True
54 self.bursted = 0
55 self.burstchans = {}
56
57 self.sock = socket.socket()
58 self.sock.bind((config.uplink['vhost'], 0))
59 self.sock.connect((config.uplink['address'], config.uplink['port']))
60
61 self._transmit("PASS %s" % (config.uplink['password']))
62 self._transmit("SERVER %(name)s 1 %(time)s %(time)s J10 %(numeric)s]]] +s :PyP10 Services" % {'name': config.name, 'time': time.time(), 'numeric': config.numeric})
63 def send(self, line, source=None, **kwargs):
64 if source is None:
65 source = config.numeric
66 self._transmit(source+" "+(line % kwargs))
67 def _transmit(self, line):
68 print ">", line
69 self.sock.sendall(line+"\r\n")
70 def _receive(self):
71 self.data += self.sock.recv(4096)
72 while "\n" in self.data:
73 pieces = self.data.split("\n", 1)
74 line = pieces[0].strip()
75 print "<", line
76 self._process(line)
77 self.data = pieces[1]
78 return True
79 def loop(self):
80 keepgoing = True
81 while keepgoing:
82 if self.bursting and self.bursted >= modcount:
83 self._burstisdone()
84 keepgoing = self._receive()
85
86 def _process(self, line):
87 if ' :' in line:
88 extrapos = line.find(' :')
89 extra = line[extrapos+2:]
90 line = line[0:extrapos]
91 words = line.split()
92 words.append(extra)
93 else:
94 extrapos = -1
95 extra = None
96 words = line.split()
97
98 # words = ['ABACB', 'P', '#p10']; extra = 'Hi there!'
99 if words[1] == "G" or words[1] == "PING":
100 self.send("Z %(numeric)s :%(id)s" % {'numeric': config.numeric, 'id': config.uplink['name']})
101 elif words[1] == "EB":
102 self.send("EA")
103 elif words[1] == "P" or words[1] == "PRIVMSG":
104 source = words[0]
105 target = words[2]
106 if extra is None:
107 extra = ' '.join(words[3:])
108 if '@' in target:
109 tonick = target.split('@', 1)
110 self.nicks[tonick].gotmsg(extra, source, target)
111 elif '#' in target:
112 pass # no processing
113 elif '$' in target:
114 pass # no processing
115 else:
116 self.nums[target].gotmsg(extra, source, target)
117 elif words[1] == "N" or words[1] == "NICK":
118 nick = words[2]
119 hostmask = words[5]+"@"+words[6]
120 if words[7][0] == '+':
121 modes = words[7][1:]
122 if 'r' in modes and 'h' in modes:
123 rpos = modes.find('r')
124 hpos = modes.find('h')
125 if rpos > hpos:
126 account = words[9]
127 else:
128 account = words[8]
129 elif 'r' in modes:
130 account = modes[8]
131 else:
132 account = None
133 num = words[-2]
134 print repr((num, nick, hostmask, modes, account, extra))
135 self.users[num] = User(num, nick, hostmask, modes, account)
136 def _newnum(self): #FIXME increment only one value, not all!
137 if self.lastnum is None:
138 self.lastnum = [0,0,0]
139 else:
140 self.lastnum = [i+1 for i in self.lastnum]
141 num = config.numeric
142 num += b64[self.lastnum[2]]
143 num += b64[self.lastnum[1]]
144 num += b64[self.lastnum[0]]
145 return num
146
147 def makenick(self, obj, nick, ident, realname):
148 newnum = self._newnum()
149 self.send("N %(nick)s 1 %(time)s %(ident)s %(host)s +doknXr pyp10 DAqAAB %(num)s :%(name)s", nick=nick, ident=ident, name=realname, time=time.time(), host=config.name, num=newnum)
150 self.nums[newnum] = obj
151 self.nicks[nick] = obj
152 return newnum
153 def getuser(self, num):
154 return self.users[num]
155 def join(self, chan, source, op=False):
156 # if self.bursting:
157 # if chan not in self.burstchans:
158 # self.burstchans[chan] = {'ops':[], 'regs':[]}
159 #
160 # if op:
161 # self.burstchans[chan]['ops'].append(source)
162 # else:
163 # self.burtschans[chan]['regs'].append(source)
164 # else: # not bursting
165 self.send("J %(chan)s %(time)s", source, chan=chan, time=time.time()+3600)
166 if op:
167 self.send("OM %(chan)s +nto %(num)s", source, chan=chan, num=source)
168 def endburst(self, module):
169 self.bursted += 1
170 print module.num, self.bursted, modcount
171 def _burstisdone(self):
172 self.bursting = False
173 for chname, chan in self.burstchans.iteritems():
174 users = chan['regs']
175
176 if len(chan['ops']) != 0:
177 chan['ops'][0] += ':o'
178 users.extend(chan['ops'])
179
180 mems = ','.join(users)
181 self.send("B %(chan)s 780000001 +nt %(members)s", chan=chname, members=mems)
182 self.send("EB")
183 self.burtchans = {}
184
185 class Account(object):
186 pass
187
188 class Client(object):
189 pass
190
191 uplink = Uplink()
192
193 for modu in config.autoload:
194 modules[modu] = (__import__('modules.'+str(modu), globals(), locals(), ['Pseudo'], 0)).Pseudo(uplink)
195 modcount += 1
196
197 uplink.loop()