diff options
| author | Telyn <telyn@telynz.uk> | 2018-01-31 11:30:50 +0000 | 
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-01-31 11:30:50 +0000 | 
| commit | 9ef70ed3d53e11dacc5d4df4478d5ff452a2dd6d (patch) | |
| tree | ace44f0ea0a81d7d369df74c3d95c219905e7fa6 /lib/mauve/notifiers | |
| parent | 0be1fa0ebadf9435a760582d17f47ff96dc0851c (diff) | |
| parent | 9af0d1761552601db30de7a991d90d64ec6c88f5 (diff) | |
Release to master
Diffstat (limited to 'lib/mauve/notifiers')
| -rw-r--r-- | lib/mauve/notifiers/hipchat.rb | 12 | ||||
| l--------- | lib/mauve/notifiers/templates/email_subject.txt.erb | 2 | ||||
| l--------- | lib/mauve/notifiers/templates/hipchat.txt.erb | 2 | ||||
| -rw-r--r--[l---------] | lib/mauve/notifiers/templates/sms.txt.erb | 23 | ||||
| -rw-r--r-- | lib/mauve/notifiers/templates/xmpp.html.erb | 23 | ||||
| -rw-r--r-- | lib/mauve/notifiers/templates/xmpp.txt.erb | 22 | ||||
| -rw-r--r-- | lib/mauve/notifiers/xmpp.rb | 837 | 
7 files changed, 30 insertions, 891 deletions
diff --git a/lib/mauve/notifiers/hipchat.rb b/lib/mauve/notifiers/hipchat.rb index 7537bc5..b29f450 100644 --- a/lib/mauve/notifiers/hipchat.rb +++ b/lib/mauve/notifiers/hipchat.rb @@ -27,13 +27,13 @@ module Mauve        def send_alert(destination, alert, all_alerts, conditions = {})          msg = prepare_message(destination, alert, all_alerts, conditions) -        colour = case alert.level -          when :urgent -            "red" -          when :normal -            "yellow" +        colour = case alert.update_type +          when 'cleared' +            'green' +          when 'acknowledged' +            'yellow'            else -            "green" +            'red'          end          opts = { diff --git a/lib/mauve/notifiers/templates/email_subject.txt.erb b/lib/mauve/notifiers/templates/email_subject.txt.erb index 802c711..45fda99 120000 --- a/lib/mauve/notifiers/templates/email_subject.txt.erb +++ b/lib/mauve/notifiers/templates/email_subject.txt.erb @@ -1 +1 @@ -xmpp.txt.erb
\ No newline at end of file +sms.txt.erb
\ No newline at end of file diff --git a/lib/mauve/notifiers/templates/hipchat.txt.erb b/lib/mauve/notifiers/templates/hipchat.txt.erb index 802c711..45fda99 120000 --- a/lib/mauve/notifiers/templates/hipchat.txt.erb +++ b/lib/mauve/notifiers/templates/hipchat.txt.erb @@ -1 +1 @@ -xmpp.txt.erb
\ No newline at end of file +sms.txt.erb
\ No newline at end of file diff --git a/lib/mauve/notifiers/templates/sms.txt.erb b/lib/mauve/notifiers/templates/sms.txt.erb index 802c711..c148f41 120000..100644 --- a/lib/mauve/notifiers/templates/sms.txt.erb +++ b/lib/mauve/notifiers/templates/sms.txt.erb @@ -1 +1,22 @@ -xmpp.txt.erb
\ No newline at end of file +<%=alert.id %>: <%= alert.update_type.upcase %> (<%= alert.level %>): <%  +case alert.update_type +when "cleared" +%><%= alert.cleared_at.to_s_relative %><%  +when "acknowledged" +%><%= alert.acknowledged_at.to_s_relative %> by <%= alert.acknowledged_by %> until <%= alert.will_unacknowledge_at.to_s_human %><%  +else +%><%= alert.raised_at.to_s_relative %><%  +end  +%>: <%= alert.subject %> <%= alert.summary %><% +if alert.source != alert.subject  +%> -- from <%= alert.source %><% +end  +%>. <%=WebInterface.url_for(alert)%><% +if defined? was_suppressed and defined? will_suppress +  if was_suppressed and not will_suppress  +%> (Normal service for <%= alert.level %> alerts has resumed.)<% +  elsif will_suppress and not was_suppressed +%> (Further <%= alert.level %> alerts suppressed until things calm down.)<% +  end  +end +%> diff --git a/lib/mauve/notifiers/templates/xmpp.html.erb b/lib/mauve/notifiers/templates/xmpp.html.erb deleted file mode 100644 index 7792bd9..0000000 --- a/lib/mauve/notifiers/templates/xmpp.html.erb +++ /dev/null @@ -1,23 +0,0 @@ -  <html xmlns="http://jabber.org/protocol/xhtml-im"><body xmlns="http://www.w3.org/1999/xhtml"> -<a href="<%=WebInterface.url_for(alert)%>"><%= alert.id%>: <%= alert.update_type.upcase %></a> (<%= alert.level %>): <%  -case alert.update_type -when "cleared" -%><%= alert.cleared_at.to_s_relative %><%  -when "acknowledged" -%><%= alert.acknowledged_at.to_s_relative %> by <%= alert.acknowledged_by %> until <%= alert.will_unacknowledge_at.to_s_human %><%  -else -%><%= alert.raised_at.to_s_relative %><%  -end  -%>: <strong><%= alert.subject %></strong> <%= alert.summary %><% -if alert.source != alert.subject  -%> -- from <%= alert.source %><% -end  -%>.<% -if defined? was_suppressed and defined? will_suppress -  if was_suppressed and not will_suppress  -%><br /><em>Normal service for <%= alert.level %> alerts has resumed.</em><% -  elsif will_suppress and not was_suppressed -%><br /><em>Further <%= alert.level %> alerts suppressed until things calm down.</em><% -  end -end -%></body></html> diff --git a/lib/mauve/notifiers/templates/xmpp.txt.erb b/lib/mauve/notifiers/templates/xmpp.txt.erb deleted file mode 100644 index c148f41..0000000 --- a/lib/mauve/notifiers/templates/xmpp.txt.erb +++ /dev/null @@ -1,22 +0,0 @@ -<%=alert.id %>: <%= alert.update_type.upcase %> (<%= alert.level %>): <%  -case alert.update_type -when "cleared" -%><%= alert.cleared_at.to_s_relative %><%  -when "acknowledged" -%><%= alert.acknowledged_at.to_s_relative %> by <%= alert.acknowledged_by %> until <%= alert.will_unacknowledge_at.to_s_human %><%  -else -%><%= alert.raised_at.to_s_relative %><%  -end  -%>: <%= alert.subject %> <%= alert.summary %><% -if alert.source != alert.subject  -%> -- from <%= alert.source %><% -end  -%>. <%=WebInterface.url_for(alert)%><% -if defined? was_suppressed and defined? will_suppress -  if was_suppressed and not will_suppress  -%> (Normal service for <%= alert.level %> alerts has resumed.)<% -  elsif will_suppress and not was_suppressed -%> (Further <%= alert.level %> alerts suppressed until things calm down.)<% -  end  -end -%> diff --git a/lib/mauve/notifiers/xmpp.rb b/lib/mauve/notifiers/xmpp.rb deleted file mode 100644 index 8ab6d48..0000000 --- a/lib/mauve/notifiers/xmpp.rb +++ /dev/null @@ -1,837 +0,0 @@ -require 'log4r' -require 'xmpp4r' -require 'xmpp4r/roster' -require 'xmpp4r/muc' -# require 'xmpp4r/xhtml' -# require 'xmpp4r/discovery/helper/helper' -require 'mauve/notifiers/debug' - - - -# -# A couple of monkey patches to fix up all this nonsense. -# -module Jabber -  # -  # Monkey patch of the close commands.  For good reasons, though I can't -  # remember why. -  # -  class Stream -    def close -      # -      # Just close -      # -      close! -    end - -    def close! -      10.times do -        pr = 0 -        @tbcbmutex.synchronize { pr = @processing } -        break if pr == 0 -        Thread::pass if pr > 0 -        sleep 1 -      end - -      # Order Matters here! If this method is called from within -      # @parser_thread then killing @parser_thread first would -      # mean the other parts of the method fail to execute. -      # That would be bad. So kill parser_thread last -      @tbcbmutex.synchronize { @processing = 0 } -      if @fd and !@fd.closed? -        @fd.close -        stop -      end -      @status = DISCONNECTED -    end -  end -end - - - - -module Mauve -  module Notifiers - -    # -    # This is the Jabber/XMMP notifiers module. -    # -    module Xmpp - -      # -      # The default provider is XMMP, although this should really be broken out -      # into its own provider to allow multple ways of doing XMPP. -      # -      class Default - -        include Jabber - -        # Atrtribute. -        attr_reader :name - -        # Atrtribute. -        attr_accessor :password - -        def initialize(name) -          Jabber::logger = self.logger -#         Jabber::debug = true -#          Jabber::warnings = true - -          @name = name -          @mucs = {} -          @roster = nil -          @closing = false -          @client = nil -        end - -        # The logger instance -        # -        # @return [Log4r::Logger] -        def logger -          # Give the logger a sane name -          @logger ||= Log4r::Logger.new self.class.to_s.sub(/::Default$/,"") -        end - -        # Sets the client's JID -        # -        # @param [String] jid The JID required. -        # @return [Jabber::JID] The client JID. -        def jid=(jid) -          @jid = JID.new(jid) -        end - -        # Connects to the XMPP server, and sets up the roster -        # -        # @return [Jabber::Client, NilClass] The connected client, or nil in the case of failure -        def connect -          logger.debug "Starting connection to #{@jid}" - -          # Make sure we're disconnected. -          self.close if @client.is_a?(Client) - -          @client = Client.new(@jid) - -          @closing = false -          @client.connect -          @client.auth_nonsasl(@password, false) -          @roster = Roster::Helper.new(@client) - -          # Unconditionally accept all roster add requests, and respond with a -          # roster add + subscription request of our own if we're not subscribed -          # already -          @roster.add_subscription_request_callback do |ri, presence| -            Thread.new do -              if is_known_contact?(presence.from) -                logger.info("Accepting subscription request from #{presence.from}") -                @roster.accept_subscription(presence.from) -                ensure_roster_and_subscription!(presence.from) -              else -                logger.info("Declining subscription request from #{presence.from}") -                @roster.decline_subscription(presence.from) -              end -            end.join -          end - -          @client.add_message_callback do |m| -            receive_message(m) -          end - -          @roster.wait_for_roster - -          @client.send(Presence.new(nil, "Woo!").set_type(nil)) - -          logger.info "Connected as #{@jid}" - -          # @client.on_exception do |ex, stream, where| -            # -            # The XMPP4R exception clauses in Stream all close the stream, so -            # we just need to reconnect. -            # -          #   unless ex.nil? or @closing -          #     logger.warn(["Caught",ex.class,ex.to_s,"during XMPP",where].join(" ")) -          #     logger.debug ex.backtrace.join("\n") -          #     self.close -          #   end -          # end -        rescue StandardError => ex -          logger.error "Connect failed #{ex.to_s}" -          logger.debug ex.backtrace.join("\n") -          self.close -          @client = nil -        end - -        def stop -          @client.stop -        end - -        # -        # Closes the XMPP connection, if possible.  Sets @client to nil. -        # -        # @return [NilClass] -        def close -          @closing = true -          if @client -            if  @client.is_connected? -              @mucs.each do |jid, muc| -                muc[:client].exit("Goodbye!") if muc[:client].active? -              end -              @client.send(Presence.new(nil, "Goodbye!").set_type(:unavailable)) -            end -            @client.close! -          end -          @client = nil -        end - -        # Determines if the client is ready. -        # -        # @return [Boolean] -        def ready? -          @client.is_a?(Jabber::Client) and @client.is_connected? -        end - -        # Attempt to send an alert using XMPP. -        # -        # @param [String] destination The JID you're sending the alert to. This should be -        #   a bare JID in the case of an individual, or +muc:room@server+ for -        #   chatrooms (XEP0045). -        # -        # @param [Mauve::Alert] alert This is turned into a pretty -        #   message and sent to the destination as a message, if +conditions+ -        #   are met. -        # -        # @param [Array] all_alerts Currently ignored. -        # -        # @param [Hash] conditions Conditions that determine if an alert should be sent -        # -        # @option conditions [Array] :if_presence Checks whether the jid in question -        #   has a presence matching one or more of the choices - see -        #   Mauve::Notifiers::Xmpp::Default#check_jid_has_presence for options. -        # -        # @return [Boolean] -        def send_alert(destination, alert, all_alerts, conditions = {}) -          destination_jid = JID.new(destination) - -          was_suppressed = conditions[:was_suppressed] || false -          will_suppress  = conditions[:will_suppress]  || false - -          if conditions && !check_alert_conditions(destination_jid, conditions) -            logger.info("Alert conditions not met, not sending XMPP alert to #{destination_jid}") -            return false -          end - -          template_file = File.join(File.dirname(__FILE__),"templates","xmpp.txt.erb") - -          txt = if File.exists?(template_file) -            ERB.new(File.read(template_file)).result(binding).chomp -          else -            logger.error("Could not find xmpp.txt.erb template") -            alert.to_s -          end - -          template_file = File.join(File.dirname(__FILE__),"templates","xmpp.html.erb") - -          xhtml = if File.exists?(template_file) -            ERB.new(File.read(template_file)).result(binding).chomp -          else -            logger.error("Could not find xmpp.txt.erb template") -            alert.to_s -          end - -          msg_type = (is_muc?(destination_jid) ? :groupchat : :chat) - -          send_message(destination_jid, txt, xhtml, msg_type) -        end - -        # Sends a message to the destionation. -        def send_message(jid, msg, html_msg=nil, msg_type=:chat) -          return false unless self.ready? - -          jid = JID.new(jid) unless jid.is_a?(JID) - -          message = Message.new(jid) -          message.body = msg -          if html_msg -            begin -              html_msg = REXML::Document.new(html_msg) unless html_msg.is_a?(REXML::Document) -              message.add_element(html_msg) -            rescue REXML::ParseException -              logger.error "Bad XHTML: #{html_msg.inspect}" -            end -          end - -          message.to   = jid -          message.type = msg_type - -          if message.type == :groupchat and is_muc?(jid) -            jid = join_muc(jid.strip) -            muc = @mucs[jid][:client] - -            if muc -              muc.send(message) -              true -            else -              logger.warn "Failed to join MUC #{jid} when trying to send a message" -              false -            end -          else -            # -            # We aren't interested in sending things to people who aren't online. -            # -            ensure_roster_and_subscription!(jid) - -            if check_jid_has_presence(jid) -              @client.send(message) -              true -            else -              false -            end -          end -        end - -        # -        # Joins a chat, and returns the stripped JID of the chat joined. -        # -        def join_muc(jid, password=nil) -          self.connect unless self.ready? - -          return unless self.ready? - -          if jid.is_a?(String) and jid =~ /^muc:(.*)/ -            jid = JID.new($1) -          end - -          unless jid.is_a?(JID) -            logger.warn "#{jid} is not a MUC" -            return -          end - -          jid.resource = @client.jid.resource if jid.resource.to_s.empty? - -          if !@mucs[jid.strip] - -            logger.debug("Adding new MUC client for #{jid}") - -            @mucs[jid.strip] = {:jid => jid, :password => password, :client => Jabber::MUC::MUCClient.new(@client)} - -            # Add some callbacks -            @mucs[jid.strip][:client].add_message_callback do |m| -              receive_message(m) -            end - -            @mucs[jid.strip][:client].add_private_message_callback do |m| -              receive_message(m) -            end - -          end - -          if !@mucs[jid.strip][:client].active? -            # -            # Make sure we have a resource. -            # -            @mucs[jid.strip][:client].join(jid, password) - -            logger.info("Joined #{jid.strip}") -          else -            logger.debug("Already joined #{jid.strip}.") -          end - -          # -          # Return the JID object -          # -          jid.strip -        end - -        # -        # Checks whether the destination JID is a MUC. -        # -        def is_muc?(jid) -          (jid.is_a?(JID)    and @mucs.keys.include?(jid.strip)) or -          (jid.to_s =~ /^muc:(.*)/) - -          # -          # It would be nice to use service discovery to determin this, but it -          # turns out that it is shite in xmpp4r.  It doesn't return straight -          # away with an answer, making it a bit useless.  Some sort of weird -          # threading issue, I think. -          # -          # begin -          #   logger.warn caller.join("\n") -          #   cl  = Discovery::Helper.new(@client) -          #   res = cl.get_info_for(jid.strip) -          #   @client.wait -          #   logger.warn "hello #{res.inspect}" -          #   res.is_a?(Discovery::IqQueryDiscoInfo) and res.identity.category == :conference -          # rescue Jabber::ServerError => ex -          #  false -          # end -        end - -        # -        # Checks to see if the JID is in our roster, and whether we are -        # subscribed to it or not. Will add to the roster and subscribe as -        # is necessary to ensure both are true. -        # -        def ensure_roster_and_subscription!(jid) -          self.connect unless self.ready? - -          return unless self.ready? - -          return jid if is_muc?(jid) - -          jid = JID.new(jid) unless jid.is_a?(JID) - -          ri = @roster.find(jid).values.first -          @roster.add(jid, nil, true) if ri.nil? - -          ri = @roster.find(jid).values.first -          ri.subscribe unless [:to, :both, :remove].include?(ri.subscription) -          ri.jid -        rescue StandardError => ex -          logger.error("Problem ensuring that #{jid} is subscribed and in mauve's roster: #{ex.inspect}") -          nil -        end - -        protected - -        def receive_message(msg) -          # -          # Don't talk to self -          # -          if @jid == msg.from or @mucs.any?{|jid, muc| muc.is_a?(Hash) and muc.has_key?(:client) and muc[:client].jid == msg.from} -            return nil -          end - -          # We only want to hear messages from known contacts. -          unless is_known_contact?(msg.from) -            # ignore message -            logger.info "Ignoring message from unknown contact #{msg.from}" -            return nil -          end - -          case msg.type -            when :error -              receive_error_message(msg) -            when :groupchat -              receive_groupchat_message(msg) -            else -              receive_normal_message(msg) -          end -        end - -        def receive_error_message(msg) -          logger.warn("Caught XMPP error #{msg}") -          nil -        end - -        def receive_normal_message(msg) -          # -          # Treat invites specially -          # -          if msg.x("jabber:x:conference") -            # -            # recieved an invite.  Need to mangle the jid. -            # -            jid =JID.new(msg.x("jabber:x:conference").attribute("jid")) -            # jid.resource = @client.jid.resource -            logger.info "Received an invite to #{jid}" -            unless join_muc(jid) -              logger.warn "Failed to join MUC #{jid} following invitation" -              return nil -            end -          elsif msg.body -            # -            # Received a message with a body. -            # -            jid = msg.from -          end - -          if jid -            reply = parse_command(msg) -            send_message(jid, reply, nil, msg.type) -          end -        end - -        def receive_groupchat_message(msg) -          # -          # We only want group chat messages from MUCs we're already joined to, -          # that we've not sent ourselves, that are not historical, and that -          # match our resource or node in the body. -          # -          if @mucs[msg.from.strip][:client].is_a?(MUC::MUCClient) and -                msg.x("jabber:x:delay") == nil and -                (msg.body =~ /\b#{Regexp.escape(@mucs[msg.from.strip][:client].jid.resource)}\b/i or -                msg.body =~ /\b#{Regexp.escape(@client.jid.node)}\b/i) - -            receive_normal_message(msg) -          end -        end - -        def parse_command(msg) -          case msg.body -            when /help(\s+\w+)?/i -              do_parse_help(msg) -            when /show\s?/i -              do_parse_show(msg) -            when /ack/i -              do_parse_ack(msg) -            when /clear/i -              do_parse_clear(msg) -            when /destroy\s?/i -              "Sorry -- destroy has been disabled.  Try \"clear\" instead." -            else -              File.executable?('/usr/games/fortune') ? `/usr/games/fortune -s -n 60`.chomp : "I'd love to stay and chat, but I'm really quite busy" -          end -        end - -        def do_parse_help(msg) -          msg.body =~ /help\s+(\w+)/i -          cmd = $1 - -          return case cmd -            when /^show/ -               <<EOF -Show command: Lists all raised or acknowledged alerts, or the first or last few. - -e.g. -  show  -- shows all raised alerts -  show ack -- shows all acknowledged alerts -  show first 10 acknowledged -- shows first 10 acknowledged -  show last 5 raised -- shows last 5 raised alerts -EOF -            when /^ack/ -              <<EOF -Acknowledge command: Acknowledges one or more alerts for a set period of time. - -The syntax is - -  acknowledge <alert list> for <time period> because <note> - - * The alert list is a comma separated list. - * The time period can be spefied in terms of days, hours, minutes, seconds, -    which can be wall-clock (default), working, or daytime (see the examples). - * The note is appended to the acknowledgement. - -e.g. -  acknowledge 1 for 2 hours -- acknowledges alert no. 1 for 2 wall-clock hours -  ack 1,2,3 for 2 working hours -- acknowledges alerts 1, 2, and 3 for 2 working hours -  ack 4 for 3 days because something bad happened -- acknowledge alert 4 for 3 wall-clock days with the note "something bad happened" -EOF -            when /^destroy/ -              <<EOF -Destroy command: Destroys one or more alerts. - -The syntax is - -  destroy <alert list> - -where <alert list> is a comma separated list of alert IDs. - -e.g. -  destroy 1,2,3  -- destroys alerts 1, 2, and 3. -EOF - -            else -              "I am Mauve #{Mauve::VERSION}.  I understand \"help\", \"show\", \"acknowledge\", and \"destroy\" commands.  Try \"help show\"." -          end -        end - -        def do_parse_show(msg) -          return "Sorry -- I don't understand your show command." unless -             msg.body =~ /show(?:\s+(first|last)\s+(\d+))?(?:\s+(events|raised|ack(?:d|nowledged)?))?/i - -          first_or_last = $1 -          n_items = ($2 || -1).to_i - -          type = $3 || "raised" -          type = "acknowledged" if type =~ /^ack/ - -          msg = [] - -          items = case type -            when "acknowledged" -              Alert.all_acknowledged.all(:order => [:acknowledged_at.asc]) -            when "events" -              History.all(:created_at.gte => Time.now - 24.hours) -            else -              Alert.all_unacknowledged.all(:order => [:raised_at.asc]) -          end - -          if first_or_last == "first" -            items = items.first(n_items) if n_items >= 0 -          elsif first_or_last == "last" -            items = items.last(n_items) if n_items >= 0 -          end - -          return "Nothing to show" if items.length == 0 - -          template_file = File.join(File.dirname(__FILE__),"templates","xmpp.txt.erb") -          if File.exists?(template_file) -            template = File.read(template_file) -          else -            logger.error("Could not find xmpp.txt.erb template") -            template = nil -          end - -          (["Alerts #{type}:"] + items.collect do |alert| -            ERB.new(template).result(binding).chomp -          end).join("\n") -        end - -        def do_parse_ack(msg) -          return "Sorry -- I don't understand your acknowledge command." unless -             msg.body =~ /ack(?:nowledge)?\s+([\d\D]+)\s+for\s+(\d+(?:\.\d+)?)\s+(work(?:ing)?|day(?:time)?|wall(?:-?clock)?)?\s*(day|hour|min(?:ute)?|sec(?:ond))s?(?:\s+(?:cos|cause|as|because)?\s*(.*))?/i - -          alerts, n_hours, type_hours, dhms, note = [$1,$2, $3, $4, $5] - -          alerts = alerts.split(/\D+/) - -          n_hours = case dhms -            when /^day/ -              n_hours.to_f * 24.0 -            when /^min/ -              n_hours.to_f / 60.0 -            when /^sec/ -              n_hours.to_f / 3600.0 -            else -              n_hours.to_f -          end - -          type_hours = case type_hours -            when /^day/ -              "daytime" -            when /^work/ -              "working" -            else -              "wallclock" -          end - -          begin -            now = Time.now -            ack_until = now.in_x_hours(n_hours, type_hours) -          rescue RangeError -            return "I'm sorry, you tried to acknowedge for far too long, and my buffers overflowed!" -          end - -          username = get_username_for(msg.from) - -          if is_muc?(Configuration.current.people[username].xmpp) -            return "I'm sorry -- if you want to acknowledge alerts, please do it from a private chat" -          end - -          msg = [] -          msg << "Acknowledgement results:" if alerts.length > 1 - -          succeeded = [] - -          alerts.each do |alert_id| -            alert = Alert.get(alert_id) - -            if alert.nil? -              msg << "#{alert_id}: alert not found" -              next -            end - -            if alert.cleared? -              msg << "#{alert_id}: alert already cleared" if alert.cleared? -              next -            end - -            if alert.acknowledge!(Configuration.current.people[username], ack_until) -              msg << "#{alert_id}: Acknowledged until #{alert.will_unacknowledge_at.to_s_human}" -              succeeded << alert -            else -              msg << "#{alert_id}: Acknowledgement failed." -            end -          end - -          # -          # Add the note. -          # -          unless note.to_s.empty? -            note = Alert.remove_html(note) -            h = History.new(:alerts => succeeded, :type => "note", :event => note.to_s, :user => username) -            logger.debug h.errors unless h.save -          end - -          return msg.join("\n") -        end - -        def do_parse_clear(msg) -          return "Sorry -- I don't understand your clear command." unless -             msg.body =~ /clear\s+([\d\D]+)(?:\s+(?:coz|cause|cos|because|as)?\s*(.*))?/i - -          alerts = $1.split(/\D+/) -          note   = $2 - -          username = get_username_for(msg.from) - -          if is_muc?(Configuration.current.people[username].xmpp) -            return "I'm sorry -- if you want to clear alerts, please do it from a private chat" -          end - -          msg = [] -          msg << "Clearing results:" if alerts.length > 1 - -          alerts.each do |alert_id| -            alert = Alert.get(alert_id) - -            if alert.nil? -              msg << "#{alert_id}: alert not found." -              next -            end - -            if alert.cleared? -              msg << "#{alert_id}: alert already cleared." -              next -            end - -            if alert.clear! -              msg << "#{alert.to_s} cleared." -            else -              msg << "#{alert.to_s}: clearing failed." -            end -          end - -          # -          # Add the note. -          # -          unless note.to_s.empty? -            note = Alert.remove_html(note) -            h = History.new(:alerts => succeeded, :type => "note", :event => note.to_s, :user => username) -            logger.debug h.errors unless h.save -          end - -          return msg.join("\n") -        end - -        def check_alert_conditions(destination, conditions) -          any_failed = conditions.keys.collect do |key| -            case key -            when :if_presence -              check_jid_has_presence(destination, conditions[:if_presence]) -            else -                #raise ArgumentError.new("Unknown alert condition, #{key} => #{conditions[key]}") -                # FIXME - clean up this use of :conditions to pass arbitrary -                # parameters to notifiers; for now we need to ignore this. -                true -            end -          end.include?(false) -          !any_failed -        end - -        # Checks our roster to see whether the jid has a resource with at least -        # one of the included presences. Acceptable +presence+ types and their -        # meanings for individuals: -        # -        #   :online, :offline               - user is logged in or out -        #   :available                      - jabber status is nil (available) or chat -        #   :unavailable -                  - jabber status is away, dnd or xa -        #   :unknown                        - don't know (not in roster) -        # -        # Returns true if at least one of the presence specifiers for the jid -        # is met, false otherwise. Note that if the alerter can't see the alertee's -        # presence, only 'unknown' will match - generally, you'll want [:online, :unknown] -        def check_jid_has_presence(jid, presence_or_presences = [:online, :unknown]) -          return true if is_muc?(jid) - -          jid = JID.new(jid) unless jid.is_a?(JID) - -          self.connect unless self.ready? - -          return false unless self.ready? - -          presences = [presence_or_presences].flatten -          roster_item = @roster.find(jid) -          roster_item = roster_item[roster_item.keys[0]] -          resource_presences = [] -          roster_item.each_presence {|p| resource_presences << p.show } if roster_item - -          results = presences.collect do |need_presence| -            case need_presence -            when :online -              (roster_item && -               [:to, :both].include?(roster_item.subscription) && -               roster_item.online?) -            when :offline -              (roster_item && -               [:to, :both].include?(roster_item.subscription) && -               !roster_item.online?) -            when :available -              (roster_item && -               [:to, :both].include?(roster_item.subscription) && -               (resource_presences.include?(nil) || -                resource_presences.include?(:chat))) -              # No resources are nil or chat -            when :unavailable -              (roster_item && -               [:to, :both].include?(roster_item.subscription) && -               (resource_presences - [:away, :dnd, :xa]).empty?) -              # Not in roster or don't know subscription -            when :unknown -              (roster_item.nil? || -               [:none, :from].include?(roster_item.subscription)) -            else -              raise ArgumentError.new("Unknown presence possibility: #{need_presence}") -            end -          end -          results.include?(true) -        end - -        # -        # Returns the username of the jid, if any -        # -        def get_username_for(jid) -          jid = JID.new(jid) unless jid.is_a?(JID) - -          # -          # Resolve MUC JIDs. -          # -          if is_muc?(jid) -            muc_jid = get_jid_from_muc_jid(jid) -            jid = muc_jid unless muc_jid.nil? -          end - -          ans = Configuration.current.people.find do |username, person| -            next unless person.xmpp.is_a?(JID) -            person.xmpp.strip == jid.strip -          end - -          ans.nil? ? ans : ans.first -        end - -        # -        # Tries to establish a real JID from a MUC JID. -        # -        def get_jid_from_muc_jid(jid) -          # -          # Resolve the JID for MUCs. -          # -          jid = JID.new(jid) unless jid.is_a?(JID) -          return nil unless @mucs.has_key?(jid.strip) -          return nil unless @mucs[jid.strip].has_key?(:client) -          return nil unless @mucs[jid.strip][:client].active? - -          roster = @mucs[jid.strip][:client].roster[jid.resource] -          return nil unless roster - -          x = roster.x('http://jabber.org/protocol/muc#user') -          return nil unless x - -          items = x.items -          return nil if items.nil? or items.empty? - -          jids = items.collect{|item| item.jid} -          return nil if jids.empty? - -          jids.first -        end - -        def is_known_contact?(jid) -          !get_username_for(jid).nil? -        end - -      end -    end -  end -end -  | 
