summaryrefslogtreecommitdiff
path: root/lib/rbot/core/userdata.rb
blob: a08285f4bfd34385755e074dba89bcb744d9132e (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
#-- vim:sw=2:et
#++
#
# :title: rbot user data management from IRC
#
# Author:: Giuseppe "Oblomov" Bilotta <giuseppe.bilotta@gmail.com>

module ::Irc
  class User
    # Retrive Bot data associated with the receiver. This method is
    # intended for data retrieval only. See #set_bot_data() if you
    # need to alter User data.
    #
    def botdata(key=nil)
      Irc::Utils.bot.plugins['userdata'].get_data(self,key)
    end
    alias :get_botdata :botdata

    # This method is used to store Bot data associated with the
    # receiver. If no block is passed, _value_ is stored for the key
    # _key_; if a block is passed, it will be called with the previous
    # _key_ value as parameter, and its return value will be stored as
    # the new value. If _value_ is present in the block form, it will
    # be used to initialize _key_ if it's missing.
    #
    # If you have to do large-scale editing of the Bot data Hash,
    # please use with_botdata.
    # 
    def set_botdata(key, value=nil, &block)
      Irc::Utils.bot.plugins['userdata'].set_data(self, key, value, &block)
    end

    # This method yields the entire Bot data Hash to the block,
    # and stores any changes done to it, returning a copy
    # of the (changed) Hash.
    #
    def with_botdata(&block)
      Irc::Utils.bot.plugins['userdata'].with_data(self, &block)
    end

  end
end

# User data is stored in registries indexed by BotUser
# name and Irc::User nick. This core module takes care
# of handling its usage.
#
class UserDataModule < CoreBotModule

  def initialize
    super
    @ircuser = @registry.sub_registry('ircuser')
    @transient = @registry.sub_registry('transient')
    @botuser = @registry.sub_registry('botuser')
  end

  def get_data_hash(user, opts={})
    plain = opts[:plain]
    iu = user.to_irc_user
    bu = iu.botuser

    ih = @ircuser[iu.nick] || {}

    if bu.default?
      return ih
    elsif bu.transient?
      bh = @transient[bu.netmasks.first.fullform] || {}
    else
      bh = @botuser[bu.username] || {}
    end
    ih.merge!(bh)

    unless plain
      class << ih
        alias :single_retrieve :[]
        alias :single_assign :[]=
          include DottedIndex
      end
    end

    return ih
  end

  def get_data(user, key=nil)
    h = get_data_hash(user)
    debug h
    return h if key.nil?
    return h[key]
  end

  def set_data_hash(user, hh)
    iu = user.to_irc_user
    bu = iu.botuser

    # we .dup the hash to remove singleton methods
    # and make it dump-able
    h = hh.dup

    @ircuser[iu.nick] = h
    return h if bu.default?

    if bu.transient?
      @transient[bu.netmasks.first.fullform] = h
    else
      @botuser[bu.username] = h
    end
    return h
  end

  def set_data(user, key, value=nil, &block)
    h = get_data_hash(user)
    debug h

    ret = value

    if not block_given?
      h[key] = value
    else
      if value and not h.has_key?(key)
        h[key] = value
      end
      ret = yield h[key]
    end
    debug ret

    set_data_hash(user, h)

    return ret
  end

  def with_data(user, &block)
    h = get_data_hash(user)
    debug h
    yield h

    set_data_hash(user, h)

    return h
  end

  def handle_get(m, params)
    user = m.server.get_user(params[:nick]) || m.source
    key = params[:key].intern
    data = get_data(user, key)
    if data
      m.reply(_("%{key} data for %{user}: %{data}") % {
        :key => key,
        :user => user.nick,
        :data => data
      })
    else
      m.reply(_("sorry, no %{key} data for %{user}") % {
        :key => key,
        :user => user.nick,
      })
    end
  end

  ### TODO FIXME not yet: are we going to allow non-string
  ### values for data? if so, this can't work ...
  #
  # def handle_set(m, params)
  #   user = m.server.get_user(params[:nick]) || m.source
  #   key = params[:key].intern
  #   data = params[:data].to_s
  # end

  def event_botuser(action, opts={})
    case action
    when :copy, :rename
      source = opts[:source]
      return unless @botuser.key?(source)
      dest = opts[:dest]
      @botuser[dest] = @botuser[source].dup
      @botuser.delete(source) if action == :rename
    when :pre_perm
      @permification ||= {}
      k = [opts[:irc_user], opts[:bot_user]]
      @permification[k] = get_data_hash(opts[:irc_user], :plain => true)
    when :post_perm
      @permification ||= {}
      k = [opts[:irc_user], opts[:bot_user]]
      if @permification.has_key?(k)
        @botuser[opts[:bot_user]] = @permification[k]
        @permification.delete(k)
      end
    end
  end

end

plugin = UserDataModule.new

plugin.map "get [:nick's] :key [data]",   :action => 'handle_get'
plugin.map "get :key [data] [for :nick]", :action => 'handle_get'
plugin.map "get :key [data] [of :nick]",  :action => 'handle_get'

# plugin.map "set [:nick's] :key [data] to :data", :action => handle_get
# plugin.map "set :key [data] [for :nick] to :data", :action => handle_get
# plugin.map "set :key [data] [of :nick] to :data", :action => handle_get