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 if row
['vhost'] is not None:
163 self
.s
.bind((row
['vhost'], 0))
164 self
.s
.connect((row
['irchost'], row
['ircport']))
165 self
.rawnow("NICK %s" % (self
.nick
))
166 self
.rawnow("USER %s * * :%s" % (ident
, row
['realname']))
170 pieces
= line
.split()
171 if pieces
[0] == "PING":
172 self
.rawnow("PONG %s" % (pieces
[1]))
173 elif pieces
[1] == "433":
174 self
.nick
= self
.nick
+str(random
.randrange(0,9))
175 self
.rawnow("NICK %s" % (self
.nick
))
176 elif pieces
[0] == "ERROR":
179 elif pieces
[1] == "376" or pieces
[1] == "422":
181 if row
['authname'] is not None and row
['authpass'] is not None:
182 self
.rawnow("AUTH %s %s" % (row
['authname'], row
['authpass']))
183 self
.rawnow("MODE %s +ix" % (self
.nick
))
184 cache
.poll
.register(self
.s
.fileno(), select
.POLLIN
)
185 cache
.botsByFD
[self
.s
.fileno()] = self
186 cache
.botsByNick
[self
.nick
] = self
190 def __str__(self
): return self
.nick
191 def __repr__(self
): return "<Bot%d: %s>" % (self
.id, self
.nick
)
197 moduledata
= '/home/bots/modules/'
199 cmsgs
= { # %(id)d = bot id, %(msg)s = log message.
200 'debug': "\00303[\037DEBUG\037][%(id)d]: %(msg)s",
201 'info': "\00312[\037INFO\037][%(id)d]: %(msg)s",
202 'warn': "\00306[\037WARN\037][%(id)d]: %(msg)s",
203 'fatal': "\00304[\037FATAL\037][%(id)d]: %(msg)s",
215 home
= None # homechan
216 ctrl
= None # ctrlchan
218 unmodules
= {} # unloaded
233 def hooknum(self
, num
, func
):
234 try: self
.nums
[num
].append(func
)
235 except: self
.nums
[num
] = [func
]
236 def unhooknum(self
, num
, func
):
237 try: self
.nums
[num
].remove(func
)
241 def hookcmd(self
, cmd
, level
, func
, params
, helpfunc
, isadmin
=False, reqchan
=True):
242 self
.cmds
[cmd
.upper()] = {'module': cache.currmod, 'func': func, 'level': level, 'params': params, 'helpfunc': helpfunc, 'isadmin': isadmin, 'reqchan': reqchan}
243 def unhookcmd(self
, cmd
):
244 try: del self
.cmds
[cmd
]
248 def gethelp(self
, cmd
, nick
=None, user
=None, access
=None):
250 if self
.cmds
[cmd
]['level'] == 0:
251 return self
.cmds
[cmd
]['helpfunc']()
252 if nick
is None and user
is None:
253 return self
.cmds
[cmd
]['helpfunc']()
254 elif nick
is not None and nick
in self
.users
and self
.users
[nick
].access
> self
.cmds
[cmd
]['level']:
255 return self
.cmds
[cmd
]['helpfunc']()
256 elif user
is not None and user
.access
> self
.cmds
[cmd
]['level']:
257 return self
.cmds
[cmd
]['helpfunc']()
258 elif access
is not None and access
> self
.cmds
[cmd
]['level']:
259 return self
.cmds
[cmd
]['helpfunc']()
262 def isbot(self
, bid
):
263 return (toint(bid
) in self
.bots
)
264 def isonline(self
, bid
):
266 return (bid
in self
.bots
and self
.bots
[bid
].online
)