PageRenderTime 68ms CodeModel.GetById 33ms RepoModel.GetById 0ms app.codeStats 1ms

/irc.rb

https://github.com/yifili09/kk-irc-bot
Ruby | 1136 lines | 914 code | 88 blank | 134 comment | 159 complexity | a8dae9b5232e8ca6cd3f531a142175e3 MD5 | raw file
  1. #!/usr/bin/env ruby
  2. # -*- coding: utf-8 -*-
  3. #需要ruby较新的版本, 比如ruby1.8.7以上 ruby1.9.2 以上, 建议使用linux系统.
  4. =begin
  5. * Description:
  6. * Author: Sevkme@gmail.com
  7. * 源代码: http://github.com/sevk/kk-irc-bot/ 或 http://code.google.com/p/kk-irc-bot/
  8. =end
  9. #BEGIN {$VERBOSE = true}
  10. require 'rubygems'
  11. load './lib/dic.rb'
  12. require 'fileutils'
  13. include FileUtils
  14. require 'platform.rb'
  15. require 'openssl'
  16. OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE
  17. I_KNOW_THAT_OPENSSL_VERIFY_PEER_EQUALS_VERIFY_NONE_IS_WRONG = true
  18. include Math
  19. #require 'timeout'
  20. require "readline"
  21. require 'yaml'
  22. require "ipwry.rb"
  23. require 'thread'
  24. require 'open-uri'
  25. Socket.do_not_reverse_lookup = true
  26. class IRC
  27. def initialize(server,port,nick,channel,charset,name=$name)
  28. $_hour = $_min = $_sec = 0
  29. @count=0
  30. @daily_done =true
  31. @nicks = []
  32. @exit = false
  33. $otherbot_said = nil
  34. @Motded = false
  35. $name_whois = nil
  36. $re_chfreeplay ||= "sevk-free"
  37. @server = server
  38. @port = port
  39. @nick = nick
  40. @str_user= name
  41. @channel = channel
  42. mkdir_p "irclogs/#{@channel[1..-1]}"
  43. charset='UTF-8' if charset =~ /utf\-?8/i
  44. @charset = charset
  45. @send_nick=Proc.new{
  46. send "NICK #{@nick}"
  47. }
  48. loadDic
  49. mystart
  50. end
  51. #踢出
  52. def kick(ch,n,msg=$kick_info)
  53. send "kick #{ch} #{n} #{msg}"
  54. end
  55. #/mode #ubuntu-cn +q *!*@1.1.1.0
  56. def autoban(chan,nick,time=55,mode='q',ch=@channel)
  57. p ' in autoban '
  58. if $lag and $lag > 2
  59. msg(nick,"#{nick}:. .., 有刷屏嫌疑 , 或我的网络有延迟.",5)
  60. sleep 0.1
  61. restart if $lag > 6
  62. return
  63. end
  64. s="#{nick}!*@*"
  65. send "mode #{chan} +#{mode} #{s}"
  66. f = Time.now.strftime('%H%M%S_baned.ban')
  67. File.open(f,'wb'){|x|
  68. x.puts "mode #{chan} -#{mode} #{s}"
  69. }
  70. Thread.new(f,time) do |f,time|
  71. Thread.current[:name]= 'autoban del file'
  72. sleep time + 200
  73. File.delete f
  74. end
  75. $u.set_ban_time(nick)
  76. Thread.new(time) do |time|
  77. Thread.current[:name]= 'autoban'
  78. sleep time
  79. send "mode #{chan} -#{mode} #{s}"
  80. end
  81. end
  82. def ping
  83. Thread.new do
  84. Thread.current[:name]= ' ping '
  85. $needrestart = true
  86. $Lping = Time.now
  87. #p 'ping ing '
  88. @irc.write ("PING 1 \r\n" ) rescue log
  89. sleep 1
  90. @irc.puts "PING 1" rescue log
  91. #p 'ping ed '
  92. sleep 14
  93. #print "-\|/"[rand(4)]
  94. if $needrestart
  95. print '$needrestart: true && $need_reconn' , "\n"
  96. $need_reconn = true
  97. end
  98. end
  99. end
  100. #发送notice消息
  101. def notice(who,sSay,delay=5)
  102. $otherbot_said=false
  103. do_after_sec(who,sSay,15,delay)
  104. end
  105. #发送msg消息,随机 delay 秒数.
  106. #sSay 不能为空
  107. def msg(who,sSay,delay=nil)
  108. return if sSay.class != String
  109. return if sSay.empty?
  110. $otherbot_said=false
  111. do_after_sec(who,sSay,0,delay||$msg_delay)
  112. end
  113. Max=430
  114. #发送到频道$channel
  115. #$fun 为true时分行发送
  116. def say(s,chan=@channel)
  117. if $fun and s.bytesize > Max
  118. if s.bytesize > $fun
  119. s.slice_u!($fun..-1)
  120. s << ' …'
  121. end
  122. i=0.1
  123. a,b=0,140
  124. b+=1 while b<s.bytesize and s[a..b].bytesize < Max - "PRIVMSG #{chan} :".size - rand(10) -5
  125. while a < s.bytesize
  126. sleep i+=0.08
  127. send "PRIVMSG #{chan} :#{s[a..b]}"
  128. a=b+1
  129. b=a+140
  130. b+=1 while b<s.bytesize and s[a..b].bytesize < Max - "PRIVMSG #{chan} :".size - rand(10) -5
  131. end
  132. else
  133. send "PRIVMSG #{chan} :#{s}"
  134. end
  135. isaid
  136. end
  137. #发送tcp数据,如果长度大于450 就自动截断.
  138. def send(s)
  139. #print "s:"
  140. #p s
  141. s.gsub!(/\s+/,' ')
  142. if s.bytesize > Max
  143. s.slice_u!(Max..-1)
  144. if @charset == 'UTF-8'
  145. while not s[-3].between?("\xe0","\xef") and s[-1].ord > 127 #ruby1.9 可以不使用这个判断了.
  146. s.chop!
  147. end
  148. else
  149. #非utf-8的聊天室就直接截断了
  150. s=s.code_a2b("UTF-8",@charset)
  151. end
  152. s << ' …'
  153. end
  154. return if s.bytesize < 2
  155. @irc.puts s.strip
  156. $Lsay = Time.now
  157. if @charset != $local_charset
  158. s=s.code_a2b(@charset,$local_charset)
  159. end
  160. puts "----> #{s}".pink
  161. savelog s
  162. end
  163. #连接irc
  164. def connect()
  165. p 'irc.conn'
  166. trap(:INT){myexit 'ctrl_c'}
  167. return if @exit
  168. $need_reconn = false
  169. begin
  170. Timeout.timeout(8){
  171. tcpsocket = TCPSocket.open(@server, @port)
  172. if $use_ssl
  173. ssl_context = OpenSSL::SSL::SSLContext.new()
  174. ssl_context.verify_mode = OpenSSL::SSL::VERIFY_NONE
  175. @@socket = OpenSSL::SSL::SSLSocket.new(tcpsocket, ssl_context)
  176. @@socket.sync = true
  177. @@socket.connect
  178. @irc = @@socket
  179. else
  180. @irc = tcpsocket
  181. end
  182. }
  183. rescue TimeoutError
  184. log ''
  185. p 'sleep ... retry conn'
  186. sleep 30
  187. retry
  188. end
  189. @send_nick.call
  190. send "USER #@str_user"
  191. Thread.new{
  192. sleep 19
  193. identify
  194. }
  195. $bot_on = $bot_on1
  196. $min_next_say = Time.now
  197. Thread.new do
  198. Thread.current[:name]= 'connect say'
  199. sleep 400+rand(500)
  200. #send("privmsg #{@channel} :\001ACTION #{osod} #{1.chr} ")
  201. @nick = $nick[0]
  202. @send_nick.call
  203. sleep rand(30)
  204. send("privmsg #{@channel} :\001ACTION #{`uname -rv`} #{`lsb_release -d `rescue '' } #{RUBY_DESCRIPTION} \x01") if rand > 0.7
  205. end
  206. end
  207. #/ns id pass
  208. def identify(n=false)
  209. File.open(ARGV[0],'rb').each { |line|
  210. if line =~ /pass/
  211. eval line
  212. end
  213. }
  214. @irc.puts "PRIVMSG nickserv :id #{$pass}"
  215. $pass = nil
  216. end
  217. #发送字典结果 ,取字典,可以用>之类的重定向,向某人提供字典数据
  218. def sayDic(dic,from,to,s='')
  219. direction = ''
  220. tellSender = false
  221. pub =false
  222. pub =true if [1,5].include? dic
  223. b7=from
  224. if s=~/(.*?)\s?([#|>])\s?(.*?)$/i #消息重定向
  225. words=$1;direction=$2
  226. tmp=$3
  227. unless tmp.empty?
  228. b7 =$u.completename(tmp)
  229. end
  230. else
  231. words=s
  232. end
  233. case direction
  234. when '|'#公共
  235. sto='PRIVMSG'
  236. when '>' #小窗
  237. sto='PRIVMSG' ;to=b7;tellSender=true
  238. when '#' #notic
  239. sto='notice' ;to=b7;tellSender=true
  240. else
  241. sto='PRIVMSG'
  242. to=from if !pub #小窗
  243. end
  244. Thread.new(words) do |c|
  245. Thread.current[:name]= 'tSayDic'
  246. re=''
  247. case dic
  248. when /new/i
  249. re = get_feed
  250. c=''
  251. when 0
  252. re = c
  253. when 1 then re = getGoogle c
  254. when 2 then re = getBaidu(c )
  255. when 3 then re = googleFinance(c )
  256. when 4 then re = getGoogle_tran(c );c=''
  257. when 5#拼音
  258. re = "#{getPY(c)}";c='';
  259. when 6 then re= $str1.match(/(\n.*?)#{Regexp::escape c}(.*\n?)/i)[0]
  260. when 10 then re = hostA(c)
  261. when 21 then re = $u.ims(c).to_s
  262. when 22
  263. c =$u.completename(c)
  264. ip = $u.getip(c)
  265. print 'ip=',ip
  266. if ip =~ /^gateway\/|mibbit\.com/i#自动whois
  267. $name_whois = c
  268. $from_whois = from
  269. $to_whois = to
  270. $s_whois = s
  271. send('whois ' + c)
  272. return
  273. end
  274. re = "#{$u.getname(c)} #{hostA(ip)}"
  275. when 23
  276. re = "#{$u.addrgrep(c)}"
  277. when 'deb'
  278. return if c !~/^[\w\-\.]+$/#只能是字母,数字,-. "#{$`}<<#{$&}>>#{$'}"
  279. re = get_deb_info c
  280. when 99 then re = Help ;c=''
  281. when 101 then re = dictcn(c);c=''
  282. end
  283. Thread.exit if re.bytesize < 2
  284. #p b7
  285. #print 'b7:' , b7 , 10.chr
  286. if sto =~ /notice/i
  287. notice(to, "#{b7}:\0039 #{c}\017\0037 #{re}",$msg_delay)
  288. else
  289. msg(to, "#{b7}:\0039 #{c}\017\0037 #{re}",$msg_delay)
  290. end
  291. msg(from,"#{b7}:\0039 #{c}\017\0037 #{re}",$msg_delay) if tellSender
  292. end #Thread
  293. end
  294. #utf8等,乱码检测
  295. def check_code(s)
  296. tmp = guess_charset(s)
  297. return unless tmp
  298. #p tmp if $DEBUG
  299. return if tmp == 'ASCII'
  300. if tmp != @charset && tmp !~ /IBM855|windows-125|ISO-8859/i
  301. p tmp
  302. if tmp =~ /^gb./i
  303. s=s.gbtoX(@charset).strip
  304. else
  305. s=s.code_a2b(tmp,@charset).strip rescue s
  306. end
  307. return if $need_Check_code <= 0
  308. #p s
  309. #需要提示
  310. if s =~ /^:(.+?)!(.+?)@(.+?)\sPRIVMSG\s(.+?)\s:(.*)$/i
  311. from=b1=$1;name=b2=$2;ip=b3=$3;to=b4=$4;sSay=$5.to_s.untaint
  312. send "PRIVMSG #{((b4==@nick)? from: to)} :#{from} say: #{sSay} in #{tmp} ? We use #{@charset} !"
  313. send "Notice #{from} :请使用 #{@charset} 字符编码".utf8_to_gb
  314. return 'matched err charset'
  315. end
  316. end
  317. return nil
  318. end
  319. #处理频道消息,私人消息,JOINS QUITS PARTS KICK NICK NOTICE
  320. def check_msg(s)
  321. if @charset != $local_charset
  322. s=s.code_a2b(@charset,$local_charset)
  323. end
  324. case s
  325. when /^:(.+?)!(.+?)@(.+?)\sPRIVMSG\s(#{Regexp::escape @nick})\s:(.+)$/i #PRIVMSG me
  326. from=a1=$1;to=a2=$2;ip=a3=$3;to=a4=$4;sSay=a5=$5
  327. return if from =~ /freenode-connect|#{Regexp::escape @nick}/i
  328. if $u.saidAndCheckFloodMe(from,to,a3)
  329. #$u.floodmereset(a1)
  330. msg from,"..不要玩机器人..谢谢.. .. ",0
  331. return
  332. end
  333. if s =~ /help|man|\??\??/i
  334. sSay = '`help |'
  335. end
  336. if $u.isBlocked?(from)
  337. return
  338. end
  339. tmp = check_dic(a5,a1,a1)
  340. if tmp == 1 #not matched check_dic
  341. #没到下次说话时间就不处理botsay
  342. return if Time.now < $min_next_say
  343. $otherbot_said=false
  344. do_after_sec(to,"#{from}, #{botsay(sSay)}",10,$msg_delay*3+9)
  345. end
  346. when /^:(.+?)!(.+?)@(.+?)\sPRIVMSG\s(.+?)\s:(.+)$/i #PRIVMSG channel
  347. nick=from=a1=$1;name=a2=$2;ip=a3=$3;ch=to=a4=$4;sSay=a5=$5
  348. return if a1==@nick
  349. #禁掉一段时间
  350. if $u.isBlocked?(from)
  351. return nil
  352. end
  353. #bot功能是否打开
  354. if not $bot_on
  355. $u.add(nick,name,ip)
  356. return
  357. end
  358. #p 'check flood'
  359. if sSay.bytesize > 320
  360. p sSay.size
  361. $u.said(nick,name,ip,1.3)
  362. end
  363. if $u.saidAndCheckFlood(nick,name,ip,sSay)
  364. $u.floodreset(nick)
  365. if $white_list =~ /#{nick}/i or ch =~ /#$re_chfreeplay/
  366. p ' white list or freeplay channel '
  367. return
  368. end
  369. tmp = Time.now - $u.get_ban_time(nick)
  370. print "get ban time: ", tmp, "\n"
  371. case tmp
  372. when 0..80
  373. return
  374. when 79..910 #之前ban过
  375. autoban to,nick,400,'q'
  376. msg(nick,"#{nick}:. .., 别刷屏, #$kick_info +q#{$b_tim}s ",10)
  377. kick to,a1
  378. else
  379. $b_tim = 51
  380. msg(to,"#{nick}:. .., 别刷屏, #$kick_info +q#{$b_tim}s ",1)
  381. autoban to,nick,$b_tim rescue log
  382. end
  383. notice(nick,"#{a1}: . .. #$kick_info",18)
  384. return
  385. elsif $u.rep nick
  386. msg(to,"#{nick}: .. .. ..",20)
  387. end
  388. #check ctcp but not /me
  389. if sSay[0].ord == 1 then
  390. if sSay[1,6] != /ACTION/i
  391. #$u.said(nick,name,ip,1.25)
  392. end
  393. return
  394. end
  395. #有BOT说话
  396. if name =~ $botlist || nick =~ $botlist
  397. $otherbot_said=true
  398. return
  399. end
  400. #$u.setip(from,name,ip)
  401. #以我的名字开头
  402. if sSay =~ /^#{Regexp::escape @nick}[\s,:`](.*)$/i
  403. s=$1.to_s.strip #消息内容
  404. s.prepend '`' if s[0,1] != '`'
  405. tmp = check_dic(s,from,to)
  406. case tmp
  407. when 1 #非字典消息
  408. #puts '消息以我名字开头'
  409. #没到下次说话时间,就不处理botsay
  410. return if Time.now < $min_next_say
  411. $otherbot_said=false
  412. #bot say
  413. do_after_sec(to,"#{from}, #{botsay(s[1..-1])}",10,$msg_delay)
  414. when String
  415. msg to,tmp
  416. else #是字典消息
  417. if $u.saidAndCheckFloodMe(a1,a2,a3)
  418. #$u.floodmereset(a1)
  419. $otherbot_said=true
  420. msg to ,"#{from}, 不要玩机器人 . ..",0 if rand>0.5
  421. return
  422. end
  423. end
  424. return 'msg with my name:.+'
  425. else
  426. ##不处理gateway用户
  427. return if a3=~ /^gateway\//i && $black_gateway
  428. end
  429. tmp = check_dic(sSay,from,to)
  430. case tmp
  431. when 1 #非字典消息
  432. when 2,5 #是title , pinyin
  433. when String
  434. msg to,tmp
  435. else #是字典消息
  436. if $u.saidAndCheckFloodMe(a1,a2,a3)
  437. $u.floodmereset(a1)
  438. $otherbot_said=true
  439. msg to ,"#{from}, 不要玩机器人",0 if rand>0.4
  440. return
  441. end
  442. end
  443. when /^:(.+?)!(.+?)@(.+?)\s(JOIN|part|quit|kick)\s:(.*)$/i #joins
  444. #@gateway/tor/x-2f4b59a0d5adf051
  445. nick=from=$1;name=$2;ip=$3;mt=$4;chan=$5
  446. return if from =~ /#{Regexp::escape @nick}/i
  447. return if chan == $channel_o
  448. case mt
  449. when /join/i
  450. n=1
  451. $u.add(nick,name,ip)
  452. when /part|quit|kick/i
  453. n=-1
  454. $u.del(nick,ip)
  455. puts "all channel nick count : #@count" if rand(10) > 7
  456. end
  457. $need_Check_code += n if from =~ $botlist_Code
  458. $need_say_feed += n if from =~ $botlist_ub_feed
  459. @count +=n
  460. #if $u.chg_ip(nick,ip) ==1
  461. #$u.add(nick,name,ip)
  462. #end
  463. renew_Readline_complete($u.all_nick)
  464. when /^(.+?)Notice(.+)$/i #Notice
  465. #:ChanServ!ChanServ@services. NOTICE ikk-bot :[#sevk] "此频道目前主要用于BOT测试."
  466. when /^:(.+?)!(.+?)@(.+?)\sNICK\s:(.+)$/i #Nick_chg
  467. #:ikk-test!n=Sevk@125.124.130.81 NICK :ikk-new
  468. nick=$1;name=$2;ip=$3;new=$4
  469. if $u.chg_nick(nick,new) ==1
  470. $u.add(new,name,ip)
  471. end
  472. $need_Check_code -= 1 if new =~ $botlist_Code
  473. $need_say_feed -= 1 if new =~ $botlist_ub_feed
  474. renew_Readline_complete($u.all_nick)
  475. else
  476. return 1 # not match
  477. end
  478. rescue
  479. log ''
  480. end
  481. def tran_url(from,to,url,force=false)
  482. url=$last_url if url.empty?
  483. return if url.empty?
  484. url.gsub!(/([^\x0-\x7f].*$|[\s<>\\\[\]\^\`\{\}\|\~#"]|,|:).*$/,'')
  485. unless force
  486. return if $saytitle < 1
  487. return if from =~ $botlist
  488. return if url =~ /(paste|imagebin\.org\/)/i
  489. return if url == $last_url
  490. end
  491. $last_url = url.clone
  492. @ti=Thread.new(to,from,url) do |to,from,url|
  493. ti = gettitleA(url,from)
  494. if ti
  495. @ti_p.kill
  496. #Thread.exit if $u.has_said? ti[7..-1]
  497. msg(to,from + ti ,0)
  498. end
  499. end
  500. @ti_p=Thread.new(to,from,url) { |to,from,url|
  501. ti = gettitleA(url,from,false)
  502. if ti
  503. @ti.kill
  504. #Thread.exit if $u.has_said? ti[7..-1]
  505. msg(to,from + ti ,0)
  506. end
  507. }
  508. end
  509. #return 1 : 非字典
  510. # 2,5 : http, pinyin
  511. # String : 发送
  512. #检测消息是不是敏感或字典消息
  513. def check_dic(s,from,to)
  514. s.force_encoding('utf-8').strip!
  515. #tr_name = s.match($re_tran_head)[0]
  516. s.sub!($re_tran_head,''); from << $& if $&
  517. case s
  518. when /^`?>\s(.+)$/i
  519. @e=Thread.new($1){|s|
  520. return 'no ad ' if s =~ /出售/ and rand(10)>2
  521. Thread.current[:name]= 'eval > xxx'
  522. tmp = evaluate(s)
  523. #tmp = safe_eval(s.to_s)
  524. # " end " * 999999 bug
  525. msg to,"#{from}:#{tmp}", $msg_delay*4 if not tmp.empty?
  526. }
  527. @e.priority = -5
  528. when /^`host\s(.*?)$/i # host
  529. sayDic(10,from,to,$1.gsub(/http:\/\//i,''))
  530. when $re_http
  531. url = $1+$2
  532. case $1
  533. when /https?/i
  534. return if s =~ $re_ignore_url
  535. tran_url(from,to,url)
  536. when /ed2k/i
  537. msg(to,Dic.new.geted2kinfo(url),0)
  538. end
  539. return 2
  540. when /^`?(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})/i #IP查询
  541. msg to,"#{from}, #{$1} #{IpLocationSeeker.new.seek($1)} ", $msg_delay * 2
  542. when /^`tr?\s(.+?)\s?(\d?)\|?$/i #dict_cn
  543. sayDic(101,from,to,$1)
  544. when /^`?deb\s(.*)$/i #aptitude show
  545. sayDic('deb',from,to,$1)
  546. when /^`?s\s(.*)$/i #TXT search
  547. sayDic(6,from,to,$1)
  548. when /^`title\s?(.*?)$/i
  549. p $1
  550. p $last_url
  551. url=$1 || $last_url
  552. tran_url from,to,url,true
  553. when /^`help$/i #`help
  554. sayDic(99,from,to,$2)
  555. when /^`?(new)$/i
  556. sayDic('new',from,to,$1)
  557. when /^`?(什么是|what\sis)(.+[^。!.!])$/i #什么是
  558. #http://rmmseg-cpp.rubyforge.org/
  559. w=$2.to_s.strip
  560. return if w =~/这|那|的|哪/
  561. sayDic(1,from,to,"define:#{w}")
  562. when /^(.*?)?[:,]?(.+)是(什么|啥|神马).{0,3}$/i #是什么
  563. w = $1.delete '`'
  564. p w
  565. return if w =~ /^(.+)[:,]/
  566. return if w =~ /|||/
  567. return if w.empty?
  568. p w
  569. sayDic(1,from,to,"define:#{w}")
  570. when /^`ims\s(.*?)$/i #IMS查询
  571. puts 'IMS ' + s
  572. sayDic(21,from,to,$1)
  573. when /^`tt\s(.*?)$/i # getGoogle_tran
  574. sayDic(4,from,to,$1)
  575. when /^`?g\s(.*?)$/ # Google
  576. sayDic(1,from,to,$1)
  577. when /^`d(ef(ine)?)?\s(.*?)$/#define:
  578. sayDic(1,from,to,'define:' + $3.to_s.strip)
  579. when /^`b\s(.*?)$/ # 百度
  580. sayDic(2,from,to,$1)
  581. when /^`address\s(.*?)$/i #查某人ip
  582. sayDic(22,from,to,$1)
  583. when /^`f\s(.*?)$/ #查老乡
  584. sayDic(23,from,to,$1)
  585. when /^`?(大家好.?.?.?|hi(.all)?.?|hello)$/i
  586. $otherbot_said=false
  587. do_after_sec(to,from + ':点点点.',10,$msg_delay*3 )
  588. when /^((有人.?(|||))|test|测试).?$/i #有人吗?
  589. #ruby1.9 一个汉字是一个: /./ ;而1.8 3: coding: utf-8/ascii-8bit -*-
  590. #ruby2.0 终于完美了,安逸了.
  591. $otherbot_said=false
  592. do_after_sec(to,from + ':点点点.',10,$msg_delay/3 )
  593. when /^`i\s?(.*?)$/i #svn
  594. sayDic(0,from,to,$my_s )
  595. #when $dic
  596. #msg to,from + ", #$1", $msg_delay * 3
  597. when /^`rst\s?(\d*)$/i #restart soft
  598. tmp=$1
  599. #return if from !~ /^(ikk-|WiiW|lkk-|Sevk)$/
  600. tmp = "%03s" % tmp
  601. $need_Check_code -= 1 if tmp =~ /^0../
  602. $need_Check_code += 1 if tmp =~ /^1../ and $need_Check_code < 1
  603. $need_say_feed -= 1 if tmp =~ /^.0./
  604. $need_say_feed += 1 if tmp =~ /^.1./ and $need_say_feed < 1
  605. $saytitle -= 1 if tmp =~ /^..0/
  606. $saytitle += 1 if tmp =~ /^..1/ and $saytitle < 1
  607. reload_all
  608. rt = " ✔ restarted, check_charset=#$need_Check_code, get_ub_feed=#$need_say_feed, get_title=#{$saytitle}"
  609. if to != @nick
  610. msg(to,from+rt,0)
  611. else
  612. msg(from,rt,0)
  613. end
  614. #拼音
  615. when /^(.*?)[\s:,](((b|p|m|f|d|t|n|l|g|k|h|j|q|x|zh|ch|sh|r|z|c|s|y|w)(a|o|e|i|u|v|ai|ei|ui|ao|ou|iu|ie|ve|er|an|en|in|un|vn|ang|eng|ing|ong){1,2}[\s,.!?]?)+)/
  616. #!! nick 像拼音也会被匹配?
  617. #s.gsub!(/[\u4e00-\u9fa5]/ ,' ')
  618. s1= $2
  619. return nil unless s.ascii_only?
  620. return nil if s1.bytesize < 12
  621. p s1
  622. p $3
  623. #sayDic(5,from,to,s1)
  624. msg(to, "#{from} 这里有输入法:http://www.inputking.com/ 或安装fcitx: apt-get install fcitx" ,$msg_delay*4)
  625. return 5
  626. else
  627. return 1#not match dic_event
  628. end
  629. rescue
  630. return 1
  631. end
  632. Notices_head = "^:NickServ!\\w+?@\\w+?.+?\sNOTICE.+?"
  633. #服务器消息
  634. def check_irc_event(s)
  635. #:NickServ!NickServ@services. NOTICE ^k^ :You are now identified for [ub].
  636. #:NickServ!NickServ@services. NOTICE kk :You have 30 seconds to identify to your nickname before it is changed.
  637. #This nickname is registered
  638. #p s.strip
  639. notices_head = Notices_head + "#{@nick}\s?:"
  640. case s.strip
  641. when Regexp.new((notices_head + $need_identify).force_encoding('ASCII-8BIT'))
  642. p s.green
  643. identify
  644. when Regexp.new((notices_head + $need_join).force_encoding('ASCII-8BIT'))
  645. p s.green
  646. joinit
  647. when /^:NickServ!NickServ@services\.\sNOTICE.+?:(This nickname is registered)|(You have 30 seconds to identify)/i
  648. puts s
  649. identify
  650. when /^:NickServ!NickServ@services\.\sNOTICE.+?:(You are already logged in as)|(You are now identified for)/i
  651. puts s
  652. joinit
  653. #:barjavel.freenode.net PONG barjavel.freenode.net :LAG1982067890
  654. when /\sPONG\s(.+)$/i
  655. $needrestart = false
  656. #p '<< pong '
  657. $lag=Time.now - $Lping
  658. if $lag > 2
  659. puts "LAG = #{$lag} sec"
  660. end
  661. when /^(:.+?)!(.+?)@(.+?)\s(.+?)\s.+\s:(.+)$/i #all mesg from nick
  662. from=$1;name=$2;ip=$3;to=$4;sSay=$5
  663. if from =~ $re_ignore_nick
  664. return '$re_ignore_nick'
  665. end
  666. if sSay =~ /[\001]VERSION[\001]/i
  667. from.delete! ':'
  668. print from, ' get VERSION', "\n"
  669. send "NOTICE #{from} :\001VERSION kk-Ruby-irc #{Ver} birthday=2008.7.20\001"
  670. return 'match version'
  671. end
  672. return nil
  673. when /^PING :(.+)$/i # ping
  674. @irc.write "PONG :#{$1}\n"
  675. #when /^:(.+?)!(.+?)@(.+?)\sPRIVMSG\s.+\s:[\001]PING(.+)[\001]$/i #ctcp ping
  676. #send "NOTICE #{$1} :\001PONG#{$4}\001"
  677. #motd ed
  678. when /^:(.+?)\s(\d+)\s(.+?)\s:(.+)/i#motd , names list
  679. #:calvino.freenode.net 404 kk #ubuntu-cn :Cannot send to channel
  680. #:pratchett.freenode.net 482 kkk #xx :You're not a channel operator
  681. #:zelazny.freenode.net 353 ikk-bot = #sevk :ikk-bot @Sevkme @[ub]
  682. # verne.freenode.net 353 ^k^ = #ubuntu-cn :^k^ cocoleo seventh
  683. # :card.freenode.net 319 ^k^ ^k^ :@#ubuntu-cn @#sevk
  684. #:niven.freenode.net 437 * ^k^ :Nick/channel is temporarily unavailable
  685. #
  686. pos=$2.to_i;name,ch=$3.split ;data=tmp=$4.to_s
  687. if @charset != $local_charset
  688. puts s.code_a2b( @charset,$local_charset)
  689. else
  690. puts s
  691. end
  692. if pos == 391#对时
  693. $_time=Time.now - Time.parse(tmp)
  694. puts Time.now.to_s.green
  695. end
  696. case pos
  697. #whois return
  698. when 319
  699. puts data
  700. #$needrestart = false if data =~ /#@channel/
  701. when 396 #nick verifd
  702. puts '396 verifed '.red
  703. #joinit
  704. when 353
  705. p 'all nick:' + tmp
  706. @nicks |= tmp.split(/ /)
  707. @nicks.flatten!
  708. when 366#End of /NAMES list.
  709. @count = @nicks.count
  710. puts "nick list: #{ @nicks.join(' ') } , #@count ".red
  711. renew_Readline_complete(@nicks.to_a)
  712. Readline.completion_append_character = ', '
  713. puts "$need_Check_code= #{$need_Check_code}"
  714. print "$need_say_feed= " , $need_say_feed, "\n"
  715. print '$saytitle= ' , $saytitle, 10.chr
  716. when 437,433
  717. #:niven.freenode.net 437 * ^k^ :Nick/channel is temporarily unavailable
  718. #:wolfe.freenode.net 433 * [ub] :Nickname is already in use.
  719. #
  720. @nick = $nick[rand $nick.size]
  721. Thread.new{
  722. sleep 10
  723. send "PRIVMSG nickserv :ghost #{@nick}"
  724. #send "NICK #{@nick}"
  725. @send_nick.call
  726. }
  727. when 404
  728. puts s
  729. identify
  730. when 376 #end of /motd
  731. #send time , send join #sevk
  732. send 'time'
  733. sleep 1
  734. send "JOIN #sevk"
  735. when 482
  736. #:pratchett.freenode.net 482 kk-bot #sevk :You're not a channel operator
  737. #p " * need operator for #{data} ? "
  738. msg ch, "#{data} * need Op.",$msg_delay*4 if rand < 0.2
  739. end
  740. #自动 whois 返回
  741. if $name_whois && pos == 311
  742. ip= tmp
  743. $u.chg_ip($name_whois,ip)
  744. $name_whois = nil
  745. sayDic(22,$from_whois,$to_whois,$s_whois)
  746. end
  747. when /^:(.+?)\sTOPIC\s(.+)\s:(.+)$/i#topic
  748. from=$1;chan=$2;topic=$3
  749. puts s.yellow
  750. #:Wii-2!n=Sevk@60.163.53.134 TOPIC #sevk :"此频道目前主要用于闲聊和调戏BOT."
  751. #QUIT name :niven.freenode.net irc.freenode.net
  752. #Netsplit hubbard.freenode.net <-> irc.freenode.net
  753. when /^:(.+?)\sMODE\s(.+?)([\+\-])(.+?)\s(.+)$/i#mode
  754. from=$1;chan=$2;type=$3;mode=$4;nick=$5
  755. #:services. MODE ikk-bot :+e
  756. #:ChanServ!ChanServ@services. MODE #sevk +o ikk-bot
  757. puts s.yellow
  758. when /^ERROR\s:(.*?):\s(.*?)$/i # Closeing
  759. log s
  760. return if @exit
  761. $need_reconn=true
  762. when /.+?404\s#{@nick}\s#{@channel}\s:Cannot send to channel/
  763. puts s
  764. identify
  765. else
  766. return #not matched, go on
  767. end #end case
  768. return 'matched'
  769. end #end irc_event
  770. #检测消息是不是服务器消息,乱码检测或字典消息
  771. def handle_server_input(s)
  772. #puts s
  773. return if check_irc_event(s) #服务器消息
  774. return if check_code(s) #乱码
  775. pr_highlighted(s) rescue log #if not $client #简单显示消息
  776. return if not $bot_on #bot 功能
  777. return if check_msg(s).class != Fixnum rescue log('')#1 not matched 字典消息
  778. end
  779. #加入频道
  780. def joinit
  781. sleep 0.5
  782. send "JOIN #{@channel}" if @channel != '#sevk'
  783. Thread.new {sleep 40; get_baned.each{|x| sleep 10 ;send x} }
  784. end
  785. #延时发送
  786. def do_after_sec(to,sSay,flag,second=3)
  787. Thread.new do
  788. Thread.current[:name]= 'delay say'
  789. if second !=0
  790. if second < $minsaytime
  791. sleep second
  792. else
  793. sleep rand(second - $minsaytime) + $minsaytime
  794. end
  795. end
  796. if $otherbot_said
  797. say("other bot said",to) if rand < 0.2
  798. #Thread.exit
  799. end
  800. if Time.now < $min_next_say
  801. print '还没到下次说话的时间:',sSay,"\n"
  802. return if second == 0 #如果是非BOT功能,直接return,不做rand_do
  803. tmp = rand_do
  804. return if tmp.empty?
  805. say(tmp,to)
  806. Thread.exit
  807. end
  808. case flag
  809. when 0
  810. say(sSay,to)
  811. when 10
  812. #打招呼回复, 春节问好
  813. say(hello_replay(sSay),to)
  814. when 20#notice
  815. send "NOTICE #{to} :#{sSay}"
  816. isaid
  817. end
  818. end #Thread
  819. end
  820. #自动补全
  821. def renew_Readline_complete(w)
  822. Readline.completion_proc = proc {|word| w.grep(/^#{Regexp.quote word}/) }
  823. Readline.completion_case_fold=true
  824. end
  825. def mystart
  826. conf = "_#{ARGV[0]}.yaml"
  827. $u = YAML.load_file conf if File.exist? conf
  828. $u = ALL_USER.new if $u.class != ALL_USER
  829. $u.init_pp
  830. puts "#{$u.all_nick.size} nicks loaded from yaml file.".red
  831. end
  832. def exited?
  833. @exit
  834. end
  835. #自定义退出
  836. def myexit(exit_msg = 'optimize')
  837. log 'my exit '
  838. Thread.list.each {|x| puts "#{x.inspect}: #{x[:name]}" }
  839. saveu
  840. send( 'quit ' + exit_msg) rescue nil
  841. sleep 0.1
  842. @exit = true
  843. end
  844. #自动说新帖
  845. def say_new(to)
  846. return unless Time.now.hour.between? 8,22
  847. @say_new=Thread.new(to){|to|
  848. Thread.current[:name]= 'say_new'
  849. tmp = get_feed
  850. msg(to,tmp,60) unless tmp.empty?
  851. }
  852. end
  853. #大约每天一次
  854. def timer_daily
  855. #大约每天6点执行
  856. if Time.now.hour < 5
  857. @daily_done = false
  858. else
  859. return if @daily_done
  860. @daily_done =true
  861. reload_all rescue nil
  862. @nick = $nick[0]
  863. @send_nick.call
  864. saveu
  865. send('time')
  866. joinit
  867. msg(@channel, osod.addTimCh ,30)
  868. end
  869. end
  870. #检测用户输入,实现IRC客户端功能.
  871. #i Send = Proc.new do |a, *b| b.collect {|i| i*a } end
  872. #退出软件请输入 :quit
  873. def iSend(s='')
  874. #$stdout.flush
  875. return if s.empty?
  876. #p s.encoding
  877. s.force_encoding($local_charset)
  878. if @charset != $local_charset
  879. s=s.code_a2b($local_charset,@charset)
  880. end
  881. #lock.synchronize do
  882. case s
  883. when /^[:\/]quit\s?(.*)?$/i #:q退出
  884. myexit $2
  885. when /^\/msg\s(.+?)\s(.+)$/i
  886. who = $1;s=$2
  887. send "privmsg #{who} :#{s.strip}"
  888. when /^\/ns\s+(.*)$/i #发送到nick serv
  889. send "privmsg nickserv :#{$1.strip}"
  890. when /^\/ms\s+(.*)$/i #发送到memo serv
  891. send "privmsg memoserv :#{$1.strip}"
  892. when /^\/nick\s+(.*)$/i
  893. @nick = $1
  894. send s.gsub(/^[\/]/,'')
  895. when /^\/(.+)/ # /发送 RAW命令
  896. s1=$1
  897. if s1 =~ /^me/i
  898. say(s.gsub(/\/me/i,"\001ACTION") + "\001")
  899. elsif s1 =~ /^ping$/i
  900. $Lping = Time.now
  901. send s1+' 1'
  902. elsif s1 =~ /^ctcp/i
  903. say(s1.gsub(/^ctcp/i,"\001") + "\001")
  904. else
  905. send s1
  906. end
  907. when /^`/ #直接执行
  908. if s[1..-1] =~ />\s(.*)/
  909. p s
  910. begin
  911. tmp=eval($1.to_s)
  912. say tmp if tmp.class == String
  913. rescue Exception
  914. p $!.message
  915. end
  916. else
  917. check_dic(s,@nick,@nick)
  918. end
  919. else
  920. say s.prepend "人机合一说:"
  921. end
  922. end
  923. #客户端输入并发送.
  924. def input_start
  925. #$stty_save = `stty -g`.chomp rescue nil
  926. Thread.new do
  927. Thread.current[:name]= 'iSend'
  928. loop do
  929. begin
  930. s = Readline.readline("[#@channel]",true)
  931. iSend s
  932. sleep 0.01
  933. rescue
  934. log ''
  935. end
  936. end
  937. end
  938. end
  939. #timer
  940. def timer_minly #每分钟一次
  941. @timer_min = Thread.new do
  942. Thread.current[:name]= 'timer min'
  943. n = 0
  944. loop do
  945. sleep 55+rand(10)
  946. n+=1
  947. n=0 if n > 9000
  948. if n % 4 == 0
  949. ping rescue log
  950. end
  951. if n % 20 == 0
  952. check_proxy_status rescue log
  953. end
  954. end
  955. end
  956. end
  957. def timer_start
  958. timer_minly
  959. @timer1 = Thread.new do#timer 1 , interval = 2600
  960. Thread.current[:name]= 'timer 30 min'
  961. loop do
  962. sleep 500 + rand(1800)
  963. timer_daily
  964. say_new($channel) if $need_say_feed > 0
  965. end
  966. end
  967. end
  968. #主循环
  969. def main_loop()
  970. loop do
  971. begin
  972. return if @exit
  973. #p '$need_reconn' if $need_reconn
  974. return if $need_reconn
  975. ready = select([@irc], nil, nil, 30)
  976. #ready = select([@irc])
  977. next unless ready
  978. ready[0].each do |s|
  979. next unless s == @irc
  980. if $use_ssl
  981. x = @irc.readpartial(OpenSSL::Buffering::BLOCK_SIZE)
  982. else
  983. x = @irc.recvfrom(1222)[0]
  984. end
  985. if x.empty?
  986. log ' x.empty, may be lose conn '
  987. return
  988. end
  989. x.split(/\r?\n/).each {|s|
  990. handle_server_input(s) rescue log('')
  991. }
  992. end
  993. rescue Exception
  994. log
  995. sleep 8
  996. return
  997. rescue
  998. log
  999. sleep 2
  1000. return
  1001. end
  1002. end
  1003. end
  1004. end
  1005. def restart #Hard Reset
  1006. send 'quit lag' rescue nil
  1007. sleep $msg_delay*6 + rand($msg_delay*20)
  1008. p "exec #{$0} #$argv0"
  1009. sleep 5
  1010. exec "#{$0} #$argv0"
  1011. end
  1012. if not defined? $u
  1013. p 'ARGV :' ,ARGV
  1014. ARGV[0] = 'default.conf' if not ARGV[0] || ARGV[0] == $0
  1015. if __FILE__ == $0
  1016. $argv0 = ARGV[0]
  1017. else
  1018. $argv0 = 'default.conf'
  1019. end
  1020. load ARGV[0]
  1021. $bot_on1 = $bot_on
  1022. $bot_on = false
  1023. $re_ignore_nick ||= /^$/
  1024. p $server
  1025. irc = IRC.new($server,$port,$nick[0],$channel,$charset)
  1026. irc.timer_start
  1027. irc.input_start if $client
  1028. Thread.current[:name]= 'main'
  1029. loop do
  1030. check_proxy_status
  1031. begin
  1032. exit if @exit
  1033. irc.connect
  1034. irc.main_loop
  1035. p ' main_loop end'
  1036. rescue
  1037. break if irc.exited?
  1038. log
  1039. end
  1040. break if irc.exited?
  1041. #restart rescue log
  1042. p $need_reconn
  1043. p Time.now
  1044. sleep $msg_delay*2 +rand($msg_delay*20)
  1045. end
  1046. end
  1047. # vim:set shiftwidth=2 tabstop=2 expandtab: