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 import config
35
36
37 import socket
38 import jabber
39 import xmlstream
40 import sys
41 import time
42 import random
43 import traceback
44 import urllib
45 import os.path
46
47 version='1.2'
48 commandchrs = '/)'
49
50
51
52 if config.recordflag:
53 logf = open(os.path.join(config.logpath, time.strftime("%Y%m%d%H%M%S.log")),"w")
54 xmllogf = open("xmllog","w")
55 last_activity=time.time()
56
57
58
59 try:
60 adminfile = open("adminlist.txt","r")
61 admins=[i.strip() for i in adminfile.readlines()]
62 adminfile.close()
63 except:
64 print "Could not open admin file, creating a new one"
65
66 con=None
67
68 def getdisplayname(x):
69 "显示一个用户名,去掉/后面的东西和@gmail.com"
70 x=unicode(x)
71 if '/' in x:
72 x=x[:x.find("/")]
73 if '@' in x and x[x.find('@'):]=="@gmail.com":
74 x=x[:x.find("@")]
75 return x
76
77 def getjid(x):
78 "根据显示名得到一个完整的gmail帐号"
79 if '@' not in x:
80 x=x+"@gmail.com"
81 return x
82
83 def saveadminlist():
84 "保存管理员列表到文件中"
85 a=open("adminlist.txt","w")
86 for i in admins:
87 print >>a,i
88 a.close()
89
90 def sendtoone(who,msg):
91 "向一个用户发送消息"
92 m = jabber.Message(who,msg)
93 m.setType('chat')
94 con.send(m)
95
96 def sendtoall(msg,butnot=[],including=[]):
97 "向所有用户发送消息, 列在butnot中的用户不发送消息,including为必发消息名单列表"
98 "如果用户的状态为'available', 'chat', None则可以发送消息,如果为busy则不会收到消息"
99 r = con.getRoster()
100 if config.recordflag:
101 print >>logf,time.strftime("%Y-%m-%d %H:%M:%S"),msg.encode("utf-8")
102 logf.flush()
103
104 for i in r.getJIDs():
105 if getdisplayname(i) in butnot:
106 continue
107 state=r.getShow(unicode(i))
108 if state in ['available','chat',None] or getdisplayname(i) in including:
109 sendtoone(i,msg)
110 time.sleep(.1)
111
112 statuses={}
113 suppressing=1
114 def sendstatus(who,txt,msg):
115 "群发某人的状态"
116 who = getdisplayname(who)
117 if statuses.has_key(who) and statuses[who]==txt:
118 return
119 if txt == 'busy':
120 txt = u'忙碌'
121 statuses[who]=txt
122 if not statuses.has_key(who):
123
124 return
125 if suppressing:
126 return
127 if msg:
128 sendtoall(config.system_prompt + u'%s %s (%s)' % (who,txt,msg),including=[who])
129 else:
130 sendtoall(config.system_prompt + u'%s %s' % (who,txt),including=[who])
131
132 def boot(jid):
133 "将某人从聊天室中去掉"
134 con.send(jabber.Presence(to=jid, type='unsubscribe'))
135 con.send(jabber.Presence(to=jid, type='unsubscribed'))
136 if statuses.has_key(getdisplayname(jid)):
137 del statuses[getdisplayname(jid)]
138
139 def cmd(who,msg):
140 "聊天指令处理"
141 if " " in msg:
142 cmd,msg=msg.split(" ",1)
143 else:
144 cmd,msg=msg.strip(),""
145 if cmd[:1] in commandchrs:
146 cmd=cmd[1:]
147 if cmd in ["me"]:
148 if msg.strip()=="":
149 action=random.choice(config.emotes.keys())
150 sendtoone(who, config.system_prompt + u'用法: /me <表情串>\n表现你的一种表情。\n'
151 u'例如 "/me %(action)s" 将表示为 "* %(nick)s %(emote)s" <消息>' % {
152 "nick" : getdisplayname(who),
153 "action" : action,
154 "emote" : config.emotes[action]
155 })
156 else:
157 if " " in msg:
158 action, msg = msg.split(" ", 1)
159 else:
160 action, msg = "", msg
161 sendtoall('%s%s%s _%s_ %s' % (config.name_quote_begin, getdisplayname(who), config.name_quote_end, config.emotes.get(action, ""), msg),butnot=[getdisplayname(who)])
162 elif cmd in ["help"]:
163 sendtoone(who, config.system_prompt + u"""命令列表:
164 /help 显示本帮助信息
165 /me <emote> <msg> 设置表情串
166 /names 显示聊天室人名
167 /quit <msg> 退出聊天室,一旦退出需要重新加入
168 /msg <nick> <msg> 私聊""")
169 if who.getStripped() in admins:
170 sendtoone(who, config.system_prompt + u'''管理员命令列表:
171 /die 关闭聊天室
172 /addadmin <nick> 增加管理员
173 /deladmin <nick> 删除管理员
174 /kick <nick> 踢除某个人
175 /reload 重新装入配置信息''')
176 sendtoone(who, config.system_prompt + u'请访问 http://coders.meta.net.nz/~perry/jabber/confbot.php 了解更多内容\n'
177 u'还可以访问 http://www.donews.net/limodou 的Blog了解本汉化修正版')
178 elif cmd in ["names"]:
179 r = con.getRoster()
180 names=[]
181 for i in r.getJIDs():
182 state=r.getShow(unicode(i))
183 name=getdisplayname(i)
184 if i.getStripped() in admins:
185 name="@%s" % name
186 if state in ['available','chat',None]:
187 names.insert(0,name)
188 else:
189 names.append('(%s)' % name)
190 sendtoone(who, config.system_prompt + u'名单:\n%s\n有@符的为管理员' % " ".join(names))
191 elif cmd in ["quit","leave","exit"]:
192 if msg:
193 msg = u' (%s)' % msg
194 sendtoall(config.system_prompt + u'%s 已经退出%s' % (getdisplayname(who), msg))
195 boot(who.getStripped())
196 elif cmd in ['msg']:
197 if not ' ' in msg:
198 sendtoone(who, config.system_prompt + u'用法: /msg <对方名称> <消息>')
199 else:
200 target,msg = msg.split(' ',1)
201 sendtoone(getjid(target),'%s%s%s 对你悄悄说: %s' % (config.name_quote_begin, getdisplayname(who),config.name_quote_end, msg))
202 sendtoone(who,'你对 %s%s%s 悄悄说: %s' % (config.name_quote_begin, getdisplayname(target), config.name_quote_end, msg))
203 elif cmd in ['kick','boot'] and who.getStripped() in admins:
204 boot(getjid(msg))
205 sendtoall(config.system_prompt + u'%s 被管理员踢掉了' % msg.strip())
206 elif cmd in ['addadmin'] and who.getStripped() in admins:
207 admins.append(getjid(msg.strip()))
208 sendtoone(who, config.system_prompt + u'把 %s 加为管理员' % getjid(msg.strip()))
209 sendtoone(getjid(msg.strip()), config.system_prompt + u'%s 已经把你加为管理员' % getdisplayname(who))
210 saveadminlist()
211 elif cmd in ['deladmin'] and who.getStripped() in admins:
212 if getjid(msg.strip()) in admins:
213 admins.remove(getjid(msg.strip()))
214 sendtoone(who, config.system_prompt + u'把 %s 从管理员中删除' % getjid(msg.strip()))
215 sendtoone(getjid(msg.strip()), config.system_prompt + u'%s 把你从管理员中删除了' % getdisplayname(who))
216 saveadminlist()
217 else:
218 sendtoone(who, config.system_prompt + u'%s 不是一个管理员' % getjid(msg.strip()))
219 elif cmd in ['die'] and who.getStripped() in admins:
220 sendtoall(config.system_prompt + u'聊天室被 %s 关闭' % who.getStripped())
221 sys.exit(1)
222 elif cmd in ['reload'] and who.getStripped() in admins:
223 reload(config)
224 sendtoone(who, config.system_prompt + u'重载配置成功')
225 print 'reload config'
226 else:
227 sendtoone(who, config.system_prompt + u'不可识别的命令 %s' % cmd)
228
229 def messageCB(con,msg):
230 if msg.getError()!=None:
231 if statuses.has_key(getdisplayname(msg.getFrom())):
232 sendstatus(unicode(msg.getFrom()), u'离开',"Blocked")
233 boot(msg.getFrom().getStripped())
234 elif msg.getBody():
235 if len(msg.getBody())>1024:
236 sendtoall(config.system_prompt + u"%s 正在刷屏" % (getdisplayname(msg.getFrom())))
237 elif msg.getBody()[:1] in commandchrs:
238 cmd(msg.getFrom(),msg.getBody())
239 else:
240 global suppressing,last_activity
241 suppressing=0
242 last_activity=time.time()
243 sendtoall('%s%s%s %s' % (config.name_quote_begin, getdisplayname(msg.getFrom()), config.name_quote_end, msg.getBody()),
244 butnot=[getdisplayname(msg.getFrom())],
245 )
246 print 'status:',con.getRoster().getShow(msg.getFrom().getStripped()),msg.getFrom().getStripped()
247 if con.getRoster().getShow(msg.getFrom()) not in ['available','chat',None]:
248 sendtoone(msg.getFrom(),
249 u'config.system_prompt 警告: 你已经在客户端标记为"忙(busy)",\n'
250 u'你将不会收到其他人的谈话,在客户端将你自已\n'
251 u'设为"在线(available)"才可以看到别人的回复')
252 xmllogf.flush()
253
254
255 def presenceCB(con,prs):
256 who = unicode(prs.getFrom())
257 type = prs.getType()
258
259 if type == 'subscribe':
260 con.send(jabber.Presence(to=who, type='subscribed'))
261 con.send(jabber.Presence(to=who, type='subscribe'))
262 print "Subscribe from",who
263 elif type == 'unsubscribe':
264 boot(prs.getFrom().getStripped())
265 print "Unsubscribe from",who
266 elif type == 'subscribed':
267 sendtoone(who, config.welcome)
268 sendstatus(who,u'在线', u'加入')
269 elif type == 'unsubscribed':
270 sendtoall(config.system_prompt + u'%s 已经退出' % getdisplayname(who))
271 elif type == 'available' or type == None:
272 show = prs.getShow()
273 if show in [None,'chat','available']:
274 sendstatus(who, u'在线', prs.getStatus())
275 elif show in ['xa']:
276 sendstatus(who, u'离开',prs.getStatus())
277 elif show in ['away']:
278 sendstatus(who,u'离开',prs.getStatus())
279 elif show in ['dnd']:
280 sendstatus(who,u'离开',prs.getStatus())
281 else:
282 sendstatus(who,u'离开',show+" [[%s]]" % prs.getStatus())
283
284 elif type == 'unavailable':
285 status = prs.getShow()
286 sendstatus(who, u'离开', status)
287 else:
288 print "Unknown presence:",who,type
289
290 def iqCB(con,iq):
291
292 reply=None
293 try:
294
295
296 reply=jabber.Iq(to=iq.getFrom(),type='error')
297 stuff=iq._node.getChildren()
298 for i in stuff:
299 reply._node.insertNode(i)
300 reply.setError('501','Feature not implemented')
301 con.send(reply)
302 except:
303 traceback.print_exc()
304
305 def disconnectedCB(con):
306 sys.exit(1)
307
308 reload(sys)
309 sys.setdefaultencoding('utf-8')
310
311 def connect():
312 con = jabber.Client(host=config.server,debug=False ,log=xmllogf,
313 port=5223, connection=xmlstream.TCP_SSL)
314 con.connect()
315 con.setMessageHandler(messageCB)
316 con.setPresenceHandler(presenceCB)
317 con.setIqHandler(iqCB)
318 con.setDisconnectHandler(disconnectedCB)
319 con.auth(config.account,config.password,config.resource)
320 con.requestRoster()
321 con.sendInitPresence()
322 _roster = con.getRoster()
323 for jid in _roster.getJIDs():
324 print jid,_roster.getOnline(jid),_roster.getStatus(jid),_roster.getShow(jid)
325 return con
326
327 con = connect()
328
329 JID="%s@%s/%s" % (config.account,config.server,config.resource)
330 last_update=0
331 saveadminlist()
332 while 1:
333
334
335
336 if time.time()-last_update>4*60*60:
337 args={
338 'action':'register',
339 'account':"%s@%s" % (config.account,config.server),
340 'users':len(con.getRoster().getJIDs()),
341 'last_activity':time.time()-last_activity,
342 'version':version,
343 'topic':config.topic,
344 }
345 try:
346 urllib.urlretrieve('http://coders.meta.net.nz/~perry/jabber/confbot.php?'+urllib.urlencode(args))
347 print "Updated directory site"
348 except:
349 print "Can't reach the directory site"
350 traceback.print_exc()
351 last_update = time.time()
352 try:
353 con.process(1)
354 except KeyboardInterrupt:
355 break
356 except SystemExit:
357 break
358 except:
359 traceback.print_exc()
360 try:
361 time.sleep(1)
362 con = connect()
363 except:
364 traceback.print_exc()