summaryrefslogtreecommitdiff
path: root/data/rbot/plugins/bash.rb
blob: 8dac9671792b7b1c2e0375a751674464aac799ab (plain)
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
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
#-- vim:sw=2:et
#++
#
# :title: bash.org quote retrieval
#
# Author:: Robin Kearney <robin@riviera.org.uk>
# Author:: cs
# Author:: Giuseppe "Oblomov" Bilotta <giuseppe.bilotta@gmail.com>
#
# Copyright:: (C) 2005 Robin Kearney
# Copyright:: (C) 2007 cs, Giuseppe Bilotta
#
# License:: public domain
#
# TODO improve output of quote
# TODO show more than one quote
# TODO allow selection of only quotes with vote > 0

require 'rexml/document'

class ::BashQuote
  attr_accessor :num, :text, :irc_text, :vote

  def initialize(num, text, vote)
    @num = num.to_i
    @text = text
    @vote = vote
    @irc_text = mk_irc_text
  end

  def url
    "http://www.bash.org/?#{@num}"
  end

  def to_s
    "#%d (%d): %s" % [self.num, self.vote, self.irc_text]
  end

  private
  def mk_irc_text
    cur_nick = nil
    last_nick = nil
    text = String.new
    @text.each_line { |l|
      debug "line: #{l.inspect}"
      cur_nick = l.match(/^\s*(&lt;.*?&gt;|\(.*?\)|.*?:)\s/)[1] rescue nil
      debug "nick: #{cur_nick.inspect}; last: #{last_nick.inspect}"
      if cur_nick and cur_nick == last_nick
        text << l.sub(cur_nick,"")
      else
        last_nick = cur_nick.dup if cur_nick
        text << l
      end
    }
    debug text
    # TODO: the gsub of br tags to | should be an ircify_html option
    text.gsub(/(?:<br \/>\s*)+/, ' | ').ircify_html
  end

end

class BashPlugin < Plugin

  Config.register Config::EnumValue.new('bash.access',
    :values => ['xml', 'html'], :default => 'html',
    :desc => "Which method the bot should use to access bash.org quotes: xml files or standard webpages")

  include REXML
  def help(plugin, topic="")
    [
      _("bash => print a random quote from bash.org"),
      _("bash quote_id => print that quote id from bash.org"),
      _("bash search <terms> => print the first bash.org quote matching <terms>"),
      _("bash latest => print the latest quote from bash.org")
    ].join(", ")
  end

  def bash_filter(s)
    # check if we like the location of the page
    loc = Utils.check_location(s, %r{http://(?:www\.)?bash\.org/\?})
    return unless loc
    # check if there are any quotes
    quotes = get_html_quotes(s[:text])
    return if quotes.empty?
    title = s[:text].ircify_html_title
    # return the first quote
    return {
          :title => title,
          :content => quotes.first.to_s,
          :bash_quotes => quotes
    }
  end

  def initialize
    super

    @bot.register_filter(:bash, :htmlinfo) { |s| bash_filter(s) }
  end

  def bash(m, params)
    id = params[:id]
    case @bot.config['bash.access'].intern
    when :xml
      xml_bash(m, id)
    else
      html_bash(m, :id => id)
    end
  end

  def search(m, params)
    esc = CGI.escape(params[:words].to_s)
    html = @bot.httputil.get("http://bash.org/?search=#{esc}")
    html_bash(m, :html => html)
  end

  def get_html_quotes(html)
    quotes = []

    html_quotes = html.split(/<p class="quote">/)
    html_quotes.each { |htqt|
      # debug htqt.inspect
      if htqt.match(/<a href="\?(\d+)"[^>]*>.*?\((-?\d+)\).*?<p class="qt">(.*)<\/p>\s+(?:<\/td>.*)?\z/m)
        num = $1
        vote = $2
        text = $3
        quotes << BashQuote.new(num, text, vote)
      end
    }
    return quotes
  end

  def html_bash(m, opts={})
    html = opts[:html]
    if not html
      id = opts[:id]
      case id
      when 'latest'
        html = @bot.httputil.get("http://bash.org/?latest")
      when nil
        html = @bot.httputil.get("http://bash.org/?random", :cache => false)
      else
        html = @bot.httputil.get("http://bash.org/?" + id)
      end
    end

    if not html
      m.reply "unable to retrieve quotes"
      return
    end

    quotes = get_html_quotes(html)

    case quotes.length
    when 0
      m.reply "no quotes found"
      return
    when 1
      quote = quotes.first
    else
      # For the time being, we only echo the first quote, but in the future we
      # may want to echo more than one for latest/random
      quote = quotes.first
    end
    m.reply quote.to_s, :split_at => /\s+\|\s+/
  end

  def xml_bash(m, id=nil)
    case id
    when 'latest'
      xml = @bot.httputil.get("http://bash.org/xml/?latest&num=1")
    when nil
      xml = @bot.httputil.get("http://bash.org/xml/?random&num=1", :cache => false)
    else
      xml = @bot.httputil.get("http://bash.org/xml/?" + id + "&num=1")
    end

    unless xml
      m.reply "bash.org rss parse failed"
      return
    end
    doc = Document.new xml
    unless doc
      m.reply "bash.org rss parse failed"
      return
    end
    doc.elements.each("*/item") {|e|
      if(id != 0)
        reply = e.elements["title"].text.gsub(/QDB: /,"") + " " + e.elements["link"].text.gsub(/QDB: /,"") + "\n"
        reply = reply + e.elements["description"].text.gsub(/\<br \/\>/, "\n")
      else
        reply = e.elements["title"].text.gsub(/QDB: /,"") + " " + e.elements["link"].text.gsub(/QDB: /,"") + "\n"
        reply = reply + e.elements["description"].text.gsub(/\<br \/\>/, "\n")
      end
      m.reply reply
    }
  end
end

plugin = BashPlugin.new

plugin.map "bash search *words", :action => :search
plugin.map "bash [:id]"