1 import socket
, random
, select
2 from collections
import deque
7 def __init__(self
, nick
):
14 def __str__(self
): return self
.nick
15 def __repr__(self
): return "<User: %s (%d)>" % (self
.nick
, self
.access
)
16 def authed(self
, username
):
18 if username
in cache
.admins
:
19 self
.access
= cache
.admins
[username
]
20 def joined(self
, chan
):
21 self
.commonchans
.append(chan
)
22 def parted(self
, chan
):
23 if chan
in self
.commonchans
: self
.commonchans
.remove(chan
)
24 if self
.commonchans
== []:
29 def __init__(self
, name
, bot
, id):
37 curs
= cache
.dbc
.cursor()
38 curs
.execute("SELECT authname, level FROM chusers WHERE chid = %s", (self
.id,))
40 while row
is not None:
41 self
.alist
[row
['authname']] = row
['level']
47 def joined(self
, user
):
48 self
.users
.append(user
)
49 user
.joined(self
.name
)
50 def parted(self
, user
):
51 if user
in self
.users
: self
.users
.remove(user
)
52 if user
in self
.ops
: self
.ops
.remove(user
)
53 if user
in self
.voices
: self
.voices
.remove(user
)
54 user
.parted(self
.name
)
55 def opped(self
, user
):
57 def voiced(self
, user
):
58 self
.voices
.append(user
)
59 def __str__(self
): return self
.name
60 def __repr__(self
): return "<Chan: %s>" % (self
.name
)
63 def __init__(self
, id):
68 self
.rawqueue
= deque()
77 print "<%d<%s" % (self
.id, buf
)
80 def sendRaws(self
, count
=2):
82 for i
in range(count
):
83 try: line
= self
.rawqueue
.popleft()
84 except IndexError: return
87 self
.rawqueue
.append(line
)
88 def rawnow(self
, line
):
89 self
.s
.sendall(line
+"\r\n")
90 print ">%d>%s" % (self
.id, line
)
92 def msg(self
, target
, msg
):
93 msgs
= msg
.split("\n")
96 self
.raw("PRIVMSG %s :%s" % (target
, msg
))
98 self
.raw("NOTICE %s :%s" % (target
, msg
))
99 def cmsg(self
, cmtype
, msg
, id=None):
100 if id is None: id = self
.id
101 self
.msg(cache
.ctrl
, cache
.cmsgs
[cmtype
] % {'id': id, 'msg': msg}
)
103 def joined(self
, chname
, nick
, chlevel
=None):
104 chname
= chname
.lower()
105 if chname
not in self
.chans
and chname
not in cache
.chans
:
108 self
.raw("WHO %s n%%nah" % (nick
))
109 if nick
not in cache
.users
: cache
.users
[nick
] = User(nick
)
110 self
.chans
[chname
].joined(cache
.users
[nick
])
112 self
.chans
[chname
].opped(cache
.users
[nick
])
114 self
.chans
[chname
].voiced(cache
.users
[nick
])
115 def parted(self
, chname
, nick
):
116 chname
= chname
.lower()
117 if nick
== self
.nick
:
118 del self
.chans
[chname
]
119 del cache
.chans
[chname
]
120 elif chname
in self
.chans
:
121 self
.chans
[chname
].parted(cache
.users
[nick
])
122 def quit(self
, nick
):
123 if nick
in cache
.users
:
124 user
= cache
.users
[nick
]
125 for ch
in user
.commonchans
:
126 cache
.chans
[ch
].parted(user
)
127 del cache
.users
[nick
]
129 def disconnect(self
):
130 try: cache
.mainBot
.cmsg('warn', 'Disconnected!', self
.id)
132 try: self
.rawnow("QUIT :Disconnected")
134 try: self
.s
.shutdown(socket
.SHUT_RDWR
)
138 for ch
in self
.chans
.values():
139 for user
in ch
.users
:
141 cache
.poll
.unregister(self
.s
.fileno())
145 curs
= cache
.dbc
.cursor()
146 curs
.execute("SELECT id, chname FROM chans WHERE botid = %s", (self
.id,))
147 row
= curs
.fetchone()
148 while row
is not None:
149 self
.raw("JOIN %s" % (row
['chname']))
150 chan
= Channel(row
['chname'].lower(), self
, row
['id'])
151 self
.chans
[row
['chname'].lower()] = chan
152 cache
.chans
[row
['chname']] = chan
153 row
= curs
.fetchone()
155 def connect(self
, ident
):
156 curs
= cache
.dbc
.cursor()
157 curs
.execute("SELECT irchost, ircport, ircpass, nick, vhost, realname, authname, authpass FROM bots WHERE id = %s", (self
.id,))
158 row
= curs
.fetchone()
159 self
.nick
= row
['nick']
160 self
.s
= socket
.socket(socket
.AF_INET
, socket
.SOCK_STREAM
)
161 self
.s
.setsockopt(socket
.SOL_SOCKET
, socket
.SO_REUSEADDR
, 1)
162 self
.s
.bind((row
['vhost'], 0))
163 self
.s
.connect((row
['irchost'], row
['ircport']))
164 self
.rawnow("NICK %s" % (self
.nick
))
165 self
.rawnow("USER %s * * :%s" % (ident
, row
['realname']))
169 pieces
= line
.split()
170 if pieces
[0] == "PING":
171 self
.rawnow("PONG %s" % (pieces
[1]))
172 elif pieces
[1] == "433":
173 self
.nick
= self
.nick
+str(random
.randrange(0,9))
174 self
.rawnow("NICK %s" % (self
.nick
))
175 elif pieces
[0] == "ERROR":
178 elif pieces
[1] == "376" or pieces
[1] == "422":
180 if row
['authname'] is not None and row
['authpass'] is not None:
181 self
.rawnow("AUTH %s %s" % (row
['authname'], row
['authpass']))
182 self
.rawnow("MODE %s +ix" % (self
.nick
))
183 cache
.poll
.register(self
.s
.fileno(), select
.POLLIN
)
184 cache
.botsByFD
[self
.s
.fileno()] = self
185 cache
.botsByNick
[self
.nick
] = self
189 def __str__(self
): return self
.nick
190 def __repr__(self
): return "<Bot%d: %s>" % (self
.id, self
.nick
)
200 home
= None # homechan
201 ctrl
= None # ctrlchan
203 unmodules
= {} # unloaded
217 triviapath
= '/home/ophion/modules/trivia/'
220 'debug': "\00303[\037DEBUG\037][%(id)d]: %(msg)s",
221 'info': "\00312[\037INFO\037][%(id)d]: %(msg)s",
222 'warn': "\00306[\037WARN\037][%(id)d]: %(msg)s",
223 'fatal': "\00304[\037FATAL\037][%(id)d]: %(msg)s",
230 def hooknum(self
, num
, func
):
231 try: self
.nums
[num
].append(func
)
232 except: self
.nums
[num
] = [func
]
233 def unhooknum(self
, num
, func
):
234 try: self
.nums
[num
].remove(func
)
238 def hookcmd(self
, cmd
, level
, func
, params
, helpfunc
, isadmin
=False, reqchan
=True):
239 self
.cmds
[cmd
.upper()] = {'module': cache.currmod, 'func': func, 'level': level, 'params': params, 'helpfunc': helpfunc, 'isadmin': isadmin, 'reqchan': reqchan}
240 def unhookcmd(self
, cmd
):
241 try: del self
.cmds
[cmd
]
245 def gethelp(self
, cmd
, nick
=None, user
=None, access
=None):
247 if self
.cmds
[cmd
]['level'] == 0:
248 return self
.cmds
[cmd
]['helpfunc']()
249 if nick
is None and user
is None:
250 return self
.cmds
[cmd
]['helpfunc']()
251 elif nick
is not None and nick
in self
.users
and self
.users
[nick
].access
> self
.cmds
[cmd
]['level']:
252 return self
.cmds
[cmd
]['helpfunc']()
253 elif user
is not None and user
.access
> self
.cmds
[cmd
]['level']:
254 return self
.cmds
[cmd
]['helpfunc']()
255 elif access
is not None and access
> self
.cmds
[cmd
]['level']:
256 return self
.cmds
[cmd
]['helpfunc']()
259 def isbot(self
, bid
):
260 return (toint(bid
) in self
.bots
)
261 def isonline(self
, bid
):
263 return (bid
in self
.bots
and self
.bots
[bid
].online
)