]> git.netwichtig.de Git - user/henk/code/ruby/rbot.git/blob - data/rbot/plugins/salut.rb
b0bf67e7769fd47d0cc5ecf80d75bc93161e6383
[user/henk/code/ruby/rbot.git] / data / rbot / plugins / salut.rb
1 # vim: set sw=2 et:\r
2 # Salutations plugin: respond to salutations\r
3 # TODO allow online editing of salutations\r
4 # TODO *REMEMBER* to set @changed to true after edit\r
5 # TODO or changes won't be saved\r
6 \r
7 class SalutPlugin < Plugin\r
8   BotConfig.register BotConfigBooleanValue.new('salut.all_languages',\r
9     :default => true, \r
10     :desc => "Check for a salutation in all languages and not just in the one defined by core.language",\r
11     :on_change => Proc.new {|bot, v| bot.plugins['salut'].reload}\r
12   )\r
13   BotConfig.register BotConfigBooleanValue.new('salut.address_only',\r
14     :default => true, \r
15     :desc => "When set to true, the bot will only reply to salutations directed at him",\r
16     :on_change => Proc.new {|bot, v| bot.plugins['salut'].reload}\r
17   )\r
18 \r
19 \r
20   def initialize\r
21     @salutations = Hash.new\r
22     @match = Hash.new\r
23     @match_langs = Array.new\r
24     @main_lang_str = nil\r
25     @main_lang = nil\r
26     @all_langs = true\r
27     @changed = false\r
28     super\r
29     reload\r
30   end\r
31 \r
32   def set_language(what)\r
33     reload\r
34   end\r
35 \r
36   def create_match\r
37     @match.clear\r
38     ar_dest = Array.new\r
39     ar_in = Array.new\r
40     ar_out = Array.new\r
41     ar_both = Array.new\r
42     @salutations.each { |lang, hash|\r
43       ar_dest.clear\r
44       ar_in.clear\r
45       ar_out.clear\r
46       ar_both.clear\r
47       hash.each { |situation, array|\r
48         case situation.to_s\r
49         when /^generic-dest$/\r
50           ar_dest += array\r
51         when /in$/\r
52           ar_in += array\r
53         when /out$/\r
54           ar_out += array\r
55         else\r
56           ar_both += array\r
57         end\r
58       }\r
59       @match[lang] = Hash.new\r
60       @match[lang][:in] = Regexp.new("\\b(?:" + ar_in.uniq.map { |txt|\r
61         Regexp.escape(txt)\r
62       }.join('|') + ")\\b", Regexp::IGNORECASE) unless ar_in.empty?\r
63       @match[lang][:out] = Regexp.new("\\b(?:" + ar_out.uniq.map { |txt|\r
64         Regexp.escape(txt)\r
65       }.join('|') + ")\\b", Regexp::IGNORECASE) unless ar_out.empty?\r
66       @match[lang][:both] = Regexp.new("\\b(?:" + ar_both.uniq.map { |txt|\r
67         Regexp.escape(txt)\r
68       }.join('|') + ")\\b", Regexp::IGNORECASE) unless ar_both.empty?\r
69       @match[lang][:dest] = Regexp.new("\\b(?:" + ar_dest.uniq.map { |txt|\r
70         Regexp.escape(txt)\r
71       }.join('|') + ")\\b", Regexp::IGNORECASE) unless ar_dest.empty?\r
72     }\r
73     @punct = /\s*[.,:!;?]?\s*/ # Punctuation\r
74 \r
75     # Languages to match for, in order\r
76     @match_langs.clear\r
77     @match_langs << @main_lang if @match.key?(@main_lang)\r
78     @match_langs << :english if @match.key?(:english)\r
79     @match.each_key { |key|\r
80       @match_langs << key\r
81     }\r
82     @match_langs.uniq!\r
83   end\r
84 \r
85   def listen(m)\r
86     return if @match.empty?\r
87     return unless m.kind_of?(PrivMessage)\r
88     return if m.address? and m.plugin == 'config'\r
89     to_me = m.address? || m.message =~ /#{Regexp.escape(@bot.nick)}/i\r
90     if @bot.config['salut.address_only']\r
91       return unless to_me\r
92     end\r
93     salut = nil\r
94     @match_langs.each { |lang|\r
95       [:both, :in, :out].each { |k|\r
96         next unless @match[lang][k]\r
97         if m.message =~ @match[lang][k]\r
98           salut = [@match[lang][k], lang, k]\r
99           break\r
100         end\r
101       }\r
102       break if salut\r
103     }\r
104     return unless salut\r
105     # If the bot wasn't addressed, we continue only if the match was exact\r
106     # (apart from space and punctuation) or if @match[:dest] matches too\r
107     return unless to_me or m.message =~ /^#{@punct}#{salut.first}#{@punct}$/ or m.message =~ @match[salut[1]][:dest] \r
108     h = Time.new.hour\r
109     case h\r
110     when 4...12\r
111       salut_reply(m, salut, :morning)\r
112     when 12...18\r
113       salut_reply(m, salut, :afternoon)\r
114     else\r
115       salut_reply(m, salut, :evening)\r
116     end\r
117   end\r
118 \r
119   def salut_reply(m, salut, time)\r
120     lang = salut[1]\r
121     k = salut[2]\r
122     debug "Replying to #{salut.first} (#{lang} #{k}) in the #{time}"\r
123     # salut_ar = @salutations[@main_lang].update @salutations[:english].update @salutations[lang]\r
124     salut_ar = @salutations[lang]\r
125     case k\r
126     when :both\r
127       sfx = ""\r
128     else\r
129       sfx = "-#{k}"\r
130     end\r
131     debug "Building array ..."\r
132     rep_ar = Array.new\r
133     rep_ar += salut_ar.fetch("#{time}#{sfx}".to_sym, [])\r
134     rep_ar += salut_ar.fetch("#{time}".to_sym, []) unless sfx.empty?\r
135     rep_ar += salut_ar.fetch("generic#{sfx}".to_sym, [])\r
136     rep_ar += salut_ar.fetch("generic".to_sym, []) unless sfx.empty?\r
137     debug "Choosing reply in #{rep_ar.inspect} ..."\r
138     if rep_ar.empty?\r
139       if m.public? # and (m.address? or m =~ /#{Regexp.escape(@bot.nick)}/)\r
140         choice = @bot.lang.get("hello_X") % m.sourcenick\r
141       else\r
142         choice = @bot.lang.get("hello") % m.sourcenick\r
143       end\r
144     else\r
145       choice = rep_ar.pick_one\r
146       if m.public? and (m.address? or m.message =~ /#{Regexp.escape(@bot.nick)}/)\r
147         choice += "#{[',',''].pick_one} #{m.sourcenick}"\r
148         choice += [" :)", " :D", "!", "", "", ""].pick_one\r
149       end\r
150     end\r
151     debug "Replying #{choice}"\r
152     m.plainreply choice\r
153   end\r
154 \r
155   def reload\r
156     save\r
157     @main_lang_str = @bot.config['core.language']\r
158     @main_lang = @main_lang_str.to_sym\r
159     @all_langs = @bot.config['salut.all_languages']\r
160     if @all_langs\r
161       # Get all available languages\r
162       langs = Dir.new("#{@bot.botclass}/salut").collect {|f|\r
163         f =~ /salut-([^.]+)/ ? $1 : nil\r
164       }.compact\r
165       langs.each { |lang|\r
166         @salutations[lang.to_sym] = load_lang(lang)\r
167       }\r
168     else\r
169       @salutations.clear\r
170       @salutations[@main_lang] = load_lang(@main_lang_str)\r
171     end\r
172     create_match\r
173     @changed = false\r
174   end\r
175 \r
176   def load_lang(lang)\r
177     dir = "#{@bot.botclass}/salut"\r
178     if not File.exist?(dir)\r
179       Dir.mkdir(dir)\r
180     end\r
181     file = "#{@bot.botclass}/salut/salut-#{lang}"\r
182     if File.exist?(file)\r
183       begin\r
184         salutations = Hash.new\r
185         content = YAML::load_file(file)\r
186         content.each { |key, val|\r
187           salutations[key.to_sym] = val\r
188         }\r
189         return salutations\r
190       rescue\r
191         error "failed to read salutations in #{lang}: #{$!}"\r
192       end\r
193     end\r
194     return nil\r
195   end\r
196 \r
197   def save\r
198     return if @salutations.empty?\r
199     return unless @changed\r
200     @salutations.each { |lang, val|\r
201       l = lang.to_s\r
202       save_lang(lang, val)\r
203     }\r
204     @changed = false\r
205   end\r
206 \r
207   def save_lang(lang, val)\r
208     fn = "#{@bot.botclass}/salut/salut-#{lang}"\r
209     Utils.safe_save(fn) { |file|\r
210       file.puts val.to_yaml\r
211     }\r
212   end\r
213 \r
214 end\r
215 \r
216 plugin = SalutPlugin.new\r
217 \r