wcc 1.3.0 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -1,17 +1,22 @@
1
1
  web change checker
2
2
  ==================
3
3
 
4
- This is a simple ruby script to track changes of websites and get notified via mail on
4
+ This is a powerful ruby program to track changes of websites and get notified via mail on
5
5
  change with configurable scope of adresses per website. All mails contain a unified diff
6
6
  from old content to new content so minor changes produce only few lines of text even on large sites.
7
7
 
8
- Note: wcc relies on native `diff` command to produce the unified diff shown in mails -
9
- plans are to remove this dependency by using [something like this](https://github.com/samg/diffy) later...
8
+ Since version 2.0 wcc has a completely rewritten notification system so emails are now only *one*
9
+ way to recieve notifications - the currently supported other are XMPP/Jabber and the Syslog.
10
+ These changes are reflected in 'conf.yml' as well so take care of migrating it (that basically
11
+ means to create a *recipients* section and update your site entries from *emails* to *notify*).
12
+
13
+ Note: wcc relies on native `diff` command to produce the unified diff shown in mails and native
14
+ `syslog` command as well as user information from /etc/login.
10
15
 
11
16
  Setup
12
17
  -----
13
18
 
14
- You need Ruby (preferably version 1.8.7) and Rubygems installed
19
+ You need Ruby (preferably version 1.8.7, Ruby 1.9 untested) and Rubygems installed
15
20
  (consider using [rvm](http://beginrescueend.com/)). Install wcc:
16
21
 
17
22
  gem install wcc
@@ -46,13 +51,18 @@ can itself be given on command line as last argument. Each option has a hard-cod
46
51
  (e.g. the configuration file name is assumed to be './conf.yml'). Command line options
47
52
  overwrite configuration file entries.
48
53
 
49
- The core option is the From: mail address and the SMTP configuration for sending emails.
50
- It is highly encouraged to use the configuration file for all rare changing things
51
- (even because you have to specify the list of tracked sites there anyways).
54
+ To see how such a configuration might look open 'conf.yml' in your '/my/conf' directory after
55
+ doing `wcc-init` - it contains a bunch of comments that describe your options. The basic structure
56
+ is made up from three sections: generic entries in *conf*, user profiles in *recipients* and a
57
+ list of sites to check for changes in *sites*. Each site entry should contain an URL and a
58
+ list of user profile names to notify on change.
59
+
60
+ An example crontab entry that runs wcc every 5 minutes might look like this:
52
61
 
53
- An example crontab entry that runs wcc every 10 minutes might look like this:
62
+ */5 * * * * root cd /my/conf;./wcc
54
63
 
55
- */10 * * * * root cd /path/to/dir/with/conf;./wcc
64
+ Since you can configure an individual check_interval per site these 5 minutes in crontab are only
65
+ the least common multiple for wcc check if each sites check_interval has passed.
56
66
 
57
67
  By default wcc only outputs ERROR and FATAL messages to avoid your cron daemon spammin' around.
58
68
  It is recommended to place 'conf.yml' (and optionally the 'filter.d' and 'template.d') within
data/assets/conf.yml CHANGED
@@ -1,43 +1,73 @@
1
1
  # web-change-checker
2
2
 
3
3
  conf:
4
- from_addr: root@localhost
5
4
  # # /var/tmp won't get ereased on restart!
6
5
  # cache_dir: /var/tmp/wcc
7
6
  # tag: wcc
8
- # use_syslog: yes
9
7
  # filterd: ./filter.d
10
8
  # templated: ./template.d
11
9
  # email:
12
10
  # smtp:
11
+ # from: root@localhost
13
12
  # host: localhost
14
13
  # port: 25
15
- # ...or for TESTING purposes:
14
+ # # ... or for TESTING purposes only:
16
15
  # email:
17
- # fake_file
16
+ # fake_file:
17
+ # from: root@localhost
18
+ # # this allows wcc to send IM messages via
19
+ # # it's own jabber account
20
+ # jabber:
21
+ # jid: wcc@example.org/wcc
22
+ # password: s3cr3t
23
+
24
+ # a recipient is like a user profile, it says in which ways wcc
25
+ # might contact you and provides a central place where to change
26
+ # email addresses etc.
27
+ recipients:
28
+ - me:
29
+ - email: me@my.place
30
+ - jabber: me@jabber.org
31
+ - my_friend:
32
+ - email: mail@example.com
33
+ # 'syslog' profile that notifies syslog on change
34
+ - syslog:
35
+ - syslog
18
36
 
19
37
  sites:
20
38
  - url: http://google.com/
21
- emails:
22
- - mail@example.com
23
- - mail2@example.com
39
+ notify:
40
+ - me
41
+ - my_friend
42
+ - syslog
43
+
44
+ # Filters
45
+ - url: http:/filter-test.com/
46
+ #notify: ...
47
+ # These filters will be executed and every single one has to
48
+ # return 'true' for the user to be notified
24
49
  filters:
25
50
  - test
26
51
  - arg-test: {number: 5, hello: world}
27
52
  - only_changes_of: {at_least: 4, t: lines}
28
53
  # Regex filter that performs matching against <scope> (one of full or diff)
29
54
  - matches: {regex: '(normal|regex)[!]+', flags: i, scope: diff}
30
- # readable, isn't it?
55
+
56
+ # HTTP Basic Auth
31
57
  - url: https://my.secret.place/
32
- emails:
33
- - me@my.place
34
- # only supports basic auth currently
58
+ #notify: ...
59
+ # Only supports basic auth currently
35
60
  auth: {type: basic, username: me, password: secret}
61
+
62
+ # (Session) Cookie
36
63
  - url: http://your.cms.com/
37
- #emails: ...
64
+ #notify: ...
38
65
  # Don't add trailing newline just the pure bytes of your cookie
39
66
  cookie: file.cookie
67
+
68
+ # Check interval
40
69
  - url: http://heavily.loaded.site/
41
- # this will check at most every 30 minutes
70
+ #notify: ...
71
+ # This will check at most every 30 minutes
42
72
  # (or next time ´wcc´ gets called after 30mins passed)
43
73
  check_interval: 30
@@ -1,5 +1,5 @@
1
- From: <%= from.name %> <<%= from.address %>>
2
- To: <%= to %>
1
+ From: <%= data.from.name %> <<%= data.from.address %>>
2
+ To: <%= data.to %>
3
3
  Subject: [<%= data.tag %>] <%= data.site.uri.host %> changed
4
4
  Content-Type: multipart/alternative; boundary="<%= data.boundary %>"
5
5
  MIME-Version: 1.0
@@ -1,5 +1,5 @@
1
- From: <%= from.name %> <<%= from.address %>>
2
- To: <%= to %>
1
+ From: <%= data.from.name %> <<%= data.from.address %>>
2
+ To: <%= data.to %>
3
3
  Subject: [<%= data.tag %>] <%= data.site.uri.host %> changed
4
4
  Content-Type: text/plain; charset="utf-8"
5
5
  Content-Transfer-Encoding: base64
@@ -0,0 +1,9 @@
1
+ <% if data.diff.nil? %>
2
+ Checked <%= data.site.uri.to_s %> the first time so no diff was possible.
3
+ <% else %>
4
+ Change at <%= data.site.uri.to_s %> - diff follows:
5
+
6
+ <%= data.diff.to_s %>
7
+
8
+ nHunks: <%= data.diff.nhunks %>, nIns: <%= data.diff.ninsertions %>, nDel: <%= data.diff.ndeletions %>, nLinesC: <%= data.diff.nlinesc %>, nCharsC: <%= data.diff.ncharsc %>
9
+ <% end %>
data/lib/wcc.rb CHANGED
@@ -2,6 +2,7 @@
2
2
  require 'base64'
3
3
  require 'digest/md5'
4
4
  require 'erb'
5
+ require 'etc'
5
6
  require 'iconv'
6
7
  require 'logger'
7
8
  require 'net/http'
@@ -18,12 +19,16 @@ require 'yaml'
18
19
  # ruby gem dependencies
19
20
  require 'diff-lcs'
20
21
  require 'htmlentities'
22
+ require 'xmpp4r/client'
21
23
 
22
24
  # wcc
23
25
  require 'wcc/diff'
24
26
  require 'wcc/filter'
25
27
  require 'wcc/mail'
26
28
  require 'wcc/site'
29
+ require 'wcc/syslog'
30
+ require 'wcc/version'
31
+ require 'wcc/xmpp'
27
32
 
28
33
  class String
29
34
  # Remove all HTML tags with at least one character name and
@@ -45,8 +50,6 @@ end
45
50
 
46
51
  module WCC
47
52
 
48
- VERSION = "1.3.0"
49
-
50
53
  DIFF_TIME_FMT = '%Y-%m-%d %H:%M:%S %Z'
51
54
 
52
55
  # logging via WCC.logger.blub
@@ -62,6 +65,8 @@ module WCC
62
65
  class Conf
63
66
  include Singleton
64
67
 
68
+ attr_reader :recipients
69
+
65
70
  # use Conf like a hash containing all options
66
71
  def [](key)
67
72
  @options[key.to_sym] || Conf.default[key.to_sym]
@@ -80,12 +85,8 @@ module WCC
80
85
  # when you want to use ./tmp it must be writeable
81
86
  :cache_dir => '/var/tmp/wcc',
82
87
  :tag => 'wcc',
83
- :syslog => false,
84
88
  :filter_dir => './filter.d',
85
89
  :template_dir => './template.d',
86
- :mailer => 'smtp',
87
- :smtp_host => 'localhost',
88
- :smtp_port => 25
89
90
  }
90
91
  end
91
92
 
@@ -101,10 +102,7 @@ module WCC
101
102
  opts.on('-s', '--simulate', 'Check for update but do not save hash or diff files') do self[:simulate] = true end
102
103
  opts.on('--clean', 'Remove all saved hash and diff files') do self[:clean] = true end
103
104
  opts.on('-t', '--tag TAG', 'Set TAG used in output') do |t| self[:tag] = t end
104
- opts.on('-n', '--no-mails', 'Do not send any emails') do self[:nomails] = true end
105
- opts.on('-f', '--from MAIL', 'Set From: mail address') do |m| self[:from_mail] = m end
106
- opts.on('--host HOST', 'Set SMTP host') do |h| self[:host] = h end
107
- opts.on('--port PORT', 'Set SMTP port') do |p| self[:port] = p end
105
+ opts.on('-n', '--no-mails', 'Do not notify users in any way') do self[:nomails] = true end
108
106
  opts.on('--show-config', 'Show config after loading config file (debug purposes)') do self[:show_config] = true end
109
107
  opts.on('-h', '-?', '--help', 'Display this screen') do
110
108
  puts opts
@@ -139,28 +137,14 @@ module WCC
139
137
  # may be false if file is empty
140
138
  yaml = YAML.load_file(self[:conf])
141
139
  if yaml.is_a?(Hash) and (yaml = yaml['conf']).is_a?(Hash)
142
- @options[:from_mail] ||= yaml['from_addr']
143
140
  @options[:cache_dir] ||= yaml['cache_dir']
144
141
  @options[:tag] ||= yaml['tag']
145
- @options[:syslog] ||= yaml['use_syslog']
146
142
  @options[:filter_dir] ||= yaml['filterd']
147
143
  @options[:template_dir] ||= yaml['templated']
148
144
 
149
- if yaml['email'].is_a?(Hash)
150
- if yaml['email']['smtp'].is_a?(Hash)
151
- @options[:mailer] = 'smtp'
152
- @options[:smtp_host] ||= yaml['email']['smtp']['host']
153
- # yaml parser should provide an integer here
154
- @options[:smtp_port] ||= yaml['email']['smtp']['port']
155
- end
156
- elsif yaml['email'] == 'fake_file'
157
- @options[:mailer] = 'fake_file'
158
- end
159
- end
160
-
161
- if self[:from_mail].to_s.empty?
162
- WCC.logger.fatal "No sender mail address given! See help."
163
- exit 1
145
+ MailNotificator.parse_conf(yaml['email']).each { |k,v| @options[k] ||= v }
146
+ XMPPNotificator.parse_conf(yaml['jabber']).each { |k,v| @options[k] ||= v }
147
+ SyslogNotificator.parse_conf(yaml['syslog']).each { |k,v| @options[k] ||= v }
164
148
  end
165
149
 
166
150
  if self[:show_config]
@@ -170,6 +154,29 @@ module WCC
170
154
  exit 0
171
155
  end
172
156
 
157
+ @recipients = {}
158
+ WCC.logger.debug "Load recipients from '#{self[:conf]}'"
159
+ # may be *false* if file is empty
160
+ yaml = YAML.load_file(self[:conf])
161
+ if not yaml
162
+ WCC.logger.info "No recipients loaded"
163
+ else
164
+ yaml['recipients'].to_a.each do |yaml_rec|
165
+ name = yaml_rec.keys.first
166
+ rec = []
167
+ yaml_rec[name].to_a.each do |yaml_way|
168
+ # TODO: find options and pass them to every notificator
169
+ if yaml_way.is_a?(Hash)
170
+ rec << XMPPNotificator.new(yaml_way['jabber']) if yaml_way.key?('jabber')
171
+ rec << MailNotificator.new(yaml_way['email']) if yaml_way.key?('email')
172
+ elsif yaml_way == 'syslog'
173
+ rec << SyslogNotificator.new
174
+ end
175
+ end
176
+ @recipients[name] = rec
177
+ end
178
+ end
179
+
173
180
  # attach --no-mails filter
174
181
  WCC::Filters.add '--no-mails' do |data|
175
182
  !self[:nomails]
@@ -182,10 +189,8 @@ module WCC
182
189
  @sites = []
183
190
 
184
191
  WCC.logger.debug "Load sites from '#{Conf[:conf]}'"
185
-
186
192
  # may be *false* if file is empty
187
193
  yaml = YAML.load_file(Conf[:conf])
188
-
189
194
  if not yaml
190
195
  WCC.logger.info "No sites loaded"
191
196
  return @sites
@@ -209,10 +214,11 @@ module WCC
209
214
  cookie = File.open(yaml_site['cookie'], 'r') { |f| f.read }
210
215
  end
211
216
 
217
+
212
218
  @sites << Site.new(
213
219
  yaml_site['url'],
214
220
  yaml_site['strip_html'] || true,
215
- yaml_site['emails'].map { |m| MailAddress.new(m) } || [],
221
+ yaml_site['notify'] || [],
216
222
  frefs,
217
223
  yaml_site['auth'] || {},
218
224
  cookie,
@@ -225,17 +231,8 @@ module WCC
225
231
  @sites
226
232
  end
227
233
 
228
- def self.mailer
229
- return @mailer unless @mailer.nil?
230
-
231
- # smtp mailer
232
- if Conf[:mailer] == 'smtp'
233
- @mailer = SmtpMailer.new(Conf[:smtp_host], Conf[:smtp_port])
234
- elsif Conf[:mailer] == 'fake_file'
235
- @mailer = FakeFileMailer.new
236
- end
237
-
238
- @mailer
234
+ def self.recipients
235
+ return Conf.instance.recipients
239
236
  end
240
237
 
241
238
  def self.file(path = nil) File.join(self[:cache_dir], path) end
@@ -332,8 +329,6 @@ module WCC
332
329
  diff = %x[diff -U 1 --label "#{old_label}" --label "#{new_label}" #{old_site_file.path} #{Conf.file(site.id + '.site')}]
333
330
  end
334
331
 
335
- system("logger -t '#{Conf[:tag]}' 'Change at #{site.uri.to_s} (tag #{site.id}) detected'") if Conf[:syslog]
336
-
337
332
  # construct the data made available to filters and templates
338
333
  data = OpenStruct.new
339
334
  data.site = site
@@ -343,7 +338,14 @@ module WCC
343
338
  # HACK: there *was* an update but no notification is required
344
339
  return false if not Filters.accept(data, site.filters)
345
340
 
346
- Conf.mailer.send(data, @@mail_plain, @@mail_bodies, MailAddress.new(Conf[:from_mail]), site.emails)
341
+ site.notify.each do |name|
342
+ rec = Conf.recipients[name]
343
+ if rec.nil?
344
+ WCC.logger.error "Could not notify recipient #{name} - not found!"
345
+ else
346
+ rec.each { |way| way.notify!(data) }
347
+ end
348
+ end
347
349
 
348
350
  true
349
351
  end
@@ -364,6 +366,7 @@ module WCC
364
366
  Dir.foreach(Conf[:cache_dir]) do |f|
365
367
  File.delete(Conf.file(f)) if f =~ /^.*\.(md5|site)$/
366
368
  end
369
+ # TODO: delete timestamps on clean?
367
370
  end
368
371
 
369
372
  # read filter.d
@@ -386,13 +389,6 @@ module WCC
386
389
  @@timestamps = {}
387
390
  end
388
391
 
389
- # templates
390
- @@mail_plain = load_template('mail.alt.erb')
391
- @@mail_bodies = {
392
- :plain => load_template('mail-body.plain.erb'),
393
- :html => load_template('mail-body.html.erb')
394
- }
395
-
396
392
  Conf.sites.each do |site|
397
393
  ts_old = get_timestamp(site)
398
394
  ts_new = Time.now.to_i
@@ -411,10 +407,13 @@ module WCC
411
407
 
412
408
  # save timestamps
413
409
  File.open(cache_file, 'w+') do |f| YAML.dump({"timestamps" => @@timestamps}, f) end
410
+
411
+ # shut down notificators
412
+ MailNotificator.shut_down
413
+ XMPPNotificator.shut_down
414
+ SyslogNotificator.shut_down
414
415
  end
415
416
 
416
- private
417
-
418
417
  def self.load_template(name)
419
418
  t_path = File.join(Conf[:template_dir], name)
420
419
  t = File.open(t_path, 'r') { |f| f.read }
@@ -422,6 +421,8 @@ module WCC
422
421
  ERB.new(t, 0, "<>")
423
422
  end
424
423
 
424
+ private
425
+
425
426
  def self.get_timestamp(site)
426
427
  @@timestamps[site.uri.to_s] || 0
427
428
  end
data/lib/wcc/mail.rb CHANGED
@@ -1,5 +1,6 @@
1
1
 
2
2
  module WCC
3
+
3
4
  # An email address container with internal conversion
4
5
  # routines.
5
6
  class MailAddress
@@ -36,78 +37,116 @@ module WCC
36
37
 
37
38
  def to_s; @email end
38
39
  end
39
-
40
- # SmtpMailer is a specific implementation of an mail deliverer that
41
- # does plain SMTP to host:port using [Net::SMTP].
42
- class SmtpMailer
43
- def initialize(host, port)
44
- @host = host
45
- @port = port
46
- WCC.logger.info "Send mail via SMTP to #{@host}:#{@port}"
40
+
41
+ class MailNotificator
42
+ @@main = nil
43
+ @@bodies = nil
44
+
45
+ def initialize(opts)
46
+ @to = MailAddress.new(opts)
47
47
  end
48
48
 
49
49
  # Sends a mail built up from some [ERB] templates to the
50
50
  # specified adresses.
51
51
  #
52
- # @param [OpenStruct] data used to construct ERB binding
53
- # @param [ERB] main the main template
54
- # @param [Hash] bodies :name, ERB template pairs
55
- # @param [String] from the From: address
56
- # @param [Array] tos array of To: addresses
57
- def send(data, main, bodies, from, tos = [])
52
+ # @param [Object] data used to construct ERB binding
53
+ def notify!(data)
54
+ # from/to addresses
55
+ data.from = Conf[:from_mail]
56
+ data.to = @to
58
57
  # generate a boundary that may be used for multipart
59
58
  data.boundary = "frontier-#{data.site.id}"
60
- # generate messages
61
- msgs = {}
62
- tos.each do |to|
63
- data.bodies = {}
64
- # eval all body templates
65
- bodies.each do |name,template|
66
- data.bodies[name] = template.result(binding)
67
- end
68
- # eval main template
69
- msgs[to] = main.result(binding)
59
+ # generate message
60
+ data.bodies = {}
61
+ # eval all body templates
62
+ self.class.get_bodies.each do |name,template|
63
+ data.bodies[name] = template.result(binding)
70
64
  end
71
- # send messages
72
- Net::SMTP.start(@host, @port) do |smtp|
73
- msgs.each do |to,msg|
74
- smtp.send_message(msg, from.address, to.address)
65
+ # eval main template
66
+ msg = self.class.get_main.result(binding)
67
+
68
+ case Conf[:mailer]
69
+ when 'smtp'
70
+ self.class.send_smtp(msg, Conf[:from_mail], @to, Conf[:smtp_host], Conf[:smtp_port])
71
+ when 'fake_file'
72
+ self.class.send_fake_file(msg, Conf[:from_mail], @to)
73
+ end
74
+ end
75
+
76
+ def self.parse_conf(conf)
77
+ if conf.is_a?(Hash)
78
+ if conf['smtp'].is_a?(Hash)
79
+ from_mail = MailAddress.new(conf['smtp']['from'] || "#{Etc.getlogin}@localhost")
80
+ return {
81
+ :mailer => 'smtp',
82
+ :from_mail => from_mails,
83
+ :smtp_host => conf['smtp']['host'] || 'localhost',
84
+ :smtp_port => conf['smtp']['port'] || 25
85
+ }
86
+ elsif conf['fake_file'].is_a?(Hash)
87
+ return {
88
+ :mailer => 'fake_file',
89
+ :from_mail => conf['fake_file']['from'] || "#{Etc.getlogin}@localhost"
90
+ }
75
91
  end
76
92
  end
77
- rescue
78
- WCC.logger.fatal "Cannot send mails via SMTP to #{@host}:#{@port} : #{$!.to_s}"
93
+ # default is smtp
94
+ return {
95
+ :mailer => 'smtp',
96
+ :from_mail => MailAddress.new("#{Etc.getlogin}@localhost"),
97
+ :smtp_host => 'localhost',
98
+ :smtp_port => 25
99
+ }
79
100
  end
80
- end
101
+
102
+ def self.shut_down; end
81
103
 
82
- # This "mailer" just dumps a mail's contents into eml files in the current
83
- # working directory. This should be for TESTING ONLY as it doesn't
84
- # take care of standards and stuff like that...
85
- class FakeFileMailer
86
- def initialize
87
- WCC.logger.info "Write mail to eml-files in #{Dir.getwd}"
104
+ # This is a specific implementation of an mail deliverer that
105
+ # does plain SMTP to host:port using [Net::SMTP].
106
+ #
107
+ # @param [String] msg the mail
108
+ # @param [MailAddress] from the From: address
109
+ # @param [MailAddress] to array of To: address
110
+ # @param [String] host the SMTP host
111
+ # @param [Integer] port the SMTP port
112
+ def self.send_smtp(msg, from, to, host, port)
113
+ # send message
114
+ Net::SMTP.start(host, port) do |smtp|
115
+ smtp.send_message(msg, from.address, to.address)
116
+ end
117
+ rescue => ex
118
+ WCC.logger.fatal "Cannot send mail via SMTP to #{host}:#{port} : #{ex}"
119
+ end
120
+
121
+ # This just dumps a mail's contents into an eml file in the current
122
+ # working directory. This should be for TESTING ONLY as it doesn't
123
+ # take care of standards and stuff like that...
124
+ #
125
+ # @param [String] msg the mail
126
+ # @param [MailAddress] from the From: address
127
+ # @param [MailAddress] to array of To: address
128
+ def self.send_fake_file(msg, from, to)
129
+ # dump mail to eml-file
130
+ filename = "#{Time.new.strftime('%Y%m%d-%H%M%S')} #{to.name}.eml"
131
+ File.open(filename, 'w') { |f| f.write(msg) }
88
132
  end
89
133
 
90
- def send(data, main, bodies, from, tos = [])
91
- # generate a boundary that may be used for multipart
92
- data.boundary = "frontier-#{data.site.id}"
93
- # generate messages
94
- msgs = {}
95
- tos.each do |to|
96
- data.bodies = {}
97
- # eval all body templates
98
- bodies.each do |name,template|
99
- data.bodies[name] = template.result(binding)
100
- end
101
- # eval main template
102
- msgs[to] = main.result(binding)
134
+ # template loading
135
+ def self.get_main
136
+ if @@main.nil?
137
+ @@main = WCC::Prog.load_template('mail.alt.erb')
103
138
  end
104
- # dump mails to eml-files
105
- i = 0
106
- msgs.each do |to,msg|
107
- filename = "#{Time.new.strftime('%Y%m%d-%H%M%S')} to_#{i}.eml"
108
- File.open(filename, 'w') { |f| f.write(msg) }
109
- i += 1
139
+ @@main
140
+ end
141
+
142
+ def self.get_bodies
143
+ if @@bodies.nil?
144
+ @@bodies = {
145
+ :plain => WCC::Prog.load_template('mail-body.plain.erb'),
146
+ :html => WCC::Prog.load_template('mail-body.html.erb')
147
+ }
110
148
  end
149
+ @@bodies
111
150
  end
112
151
  end
113
152
  end
data/lib/wcc/site.rb CHANGED
@@ -1,12 +1,12 @@
1
1
 
2
2
  module WCC
3
3
  class Site
4
- attr_reader :uri, :emails, :filters, :auth, :cookie, :check_interval, :id
4
+ attr_reader :uri, :notify, :filters, :auth, :cookie, :check_interval, :id
5
5
 
6
- def initialize(url, strip_html, emails, filters, auth, cookie, check_interval)
6
+ def initialize(url, strip_html, notify, filters, auth, cookie, check_interval)
7
7
  @uri = URI.parse(url)
8
8
  @strip_html = strip_html
9
- @emails = emails.is_a?(Array) ? emails : [emails]
9
+ @notify = notify.is_a?(Array) ? notify : [notify]
10
10
  @filters = filters.is_a?(Array) ? filters : [filters]
11
11
  @auth = auth
12
12
  @cookie = cookie
data/lib/wcc/syslog.rb ADDED
@@ -0,0 +1,15 @@
1
+
2
+ module WCC
3
+ class SyslogNotificator
4
+ def initialize
5
+ end
6
+
7
+ def notify!(data)
8
+ system("logger -t '#{data.tag}' 'Change at #{data.site.uri.to_s} (tag #{data.site.id}) detected'")
9
+ end
10
+
11
+ def self.parse_conf(conf); {} end
12
+
13
+ def self.shut_down; end
14
+ end
15
+ end
@@ -0,0 +1,4 @@
1
+
2
+ module WCC
3
+ VERSION = "2.0.0"
4
+ end
data/lib/wcc/xmpp.rb ADDED
@@ -0,0 +1,69 @@
1
+
2
+ module WCC
3
+ class XMPPNotificator
4
+ @@client = nil
5
+ @@template = nil
6
+
7
+ def initialize(opts)
8
+ @jid = Jabber::JID.new(opts)
9
+ end
10
+
11
+ def notify!(data)
12
+ # prepare message
13
+ subject = "[#{data.tag}] #{data.site.uri.host} changed"
14
+ body = self.class.get_template.result(binding)
15
+ m = Jabber::Message.new(@jid, body)
16
+ m.type = :normal
17
+ m.subject = subject
18
+ # send it
19
+ c = self.class.get_client
20
+ c.send(m) unless c.nil?
21
+ end
22
+
23
+ def self.parse_conf(conf)
24
+ if conf.is_a?(Hash)
25
+ if conf['jid'].nil?
26
+ WCC.logger.fatal "Missing jabber ID!"
27
+ return {:xmpp_jid => nil}
28
+ elsif conf['password'].nil?
29
+ WCC.logger.fatal "Missing jabber password!"
30
+ else
31
+ return {
32
+ :xmpp_jid => Jabber::JID.new(conf['jid']),
33
+ :xmpp_password => conf['password']
34
+ }
35
+ end
36
+ end
37
+ end
38
+
39
+ def self.shut_down
40
+ if not @@client.nil?
41
+ #@@client.send(Jabber::Presence.new.set_type(:unavailable))
42
+ @@client.close
43
+ end
44
+ end
45
+
46
+ def self.get_client
47
+ if @@client.nil? and not Conf[:xmpp_jid].nil?
48
+ @@client = Jabber::Client.new(Conf[:xmpp_jid])
49
+ @@client.connect
50
+ begin
51
+ @@client.auth(Conf[:xmpp_password])
52
+ @@client.send(Jabber::Presence.new.set_status('At your service every night.'))
53
+ rescue Jabber::ClientAuthenticationFailure => ex
54
+ WCC.logger.fatal "Wrong jabber password for #{Conf[:xmpp_jid]}!"
55
+ @@client.close
56
+ @@client = nil
57
+ end
58
+ end
59
+ @@client
60
+ end
61
+
62
+ def self.get_template
63
+ if @@template.nil?
64
+ @@template = WCC::Prog.load_template('xmpp-body.plain.erb')
65
+ end
66
+ @@template
67
+ end
68
+ end
69
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: wcc
3
3
  version: !ruby/object:Gem::Version
4
- hash: 27
4
+ hash: 15
5
5
  prerelease:
6
6
  segments:
7
- - 1
8
- - 3
7
+ - 2
9
8
  - 0
10
- version: 1.3.0
9
+ - 0
10
+ version: 2.0.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Christian Nicolai
@@ -15,7 +15,7 @@ autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
17
 
18
- date: 2011-10-15 00:00:00 Z
18
+ date: 2011-10-16 00:00:00 Z
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
21
  name: htmlentities
@@ -23,18 +23,34 @@ dependencies:
23
23
  requirement: &id001 !ruby/object:Gem::Requirement
24
24
  none: false
25
25
  requirements:
26
- - - ">="
26
+ - - ~>
27
27
  - !ruby/object:Gem::Version
28
- hash: 3
28
+ hash: 29
29
29
  segments:
30
- - 0
31
- version: "0"
30
+ - 4
31
+ - 3
32
+ version: "4.3"
32
33
  type: :runtime
33
34
  version_requirements: *id001
34
35
  - !ruby/object:Gem::Dependency
35
36
  name: diff-lcs
36
37
  prerelease: false
37
38
  requirement: &id002 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ~>
42
+ - !ruby/object:Gem::Version
43
+ hash: 13
44
+ segments:
45
+ - 1
46
+ - 1
47
+ version: "1.1"
48
+ type: :runtime
49
+ version_requirements: *id002
50
+ - !ruby/object:Gem::Dependency
51
+ name: xmpp4r
52
+ prerelease: false
53
+ requirement: &id003 !ruby/object:Gem::Requirement
38
54
  none: false
39
55
  requirements:
40
56
  - - ">="
@@ -44,8 +60,8 @@ dependencies:
44
60
  - 0
45
61
  version: "0"
46
62
  type: :runtime
47
- version_requirements: *id002
48
- description: wcc tracks changes of websites and notifies you by email.
63
+ version_requirements: *id003
64
+ description: wcc tracks changes of websites and notifies you by email and as of version 2.0 via XMPP/Jabber too.
49
65
  email: chrnicolai@gmail.com
50
66
  executables:
51
67
  - wcc
@@ -70,6 +86,7 @@ files:
70
86
  - assets/template.d/mail-body.html.erb
71
87
  - assets/template.d/mail-body.plain.erb
72
88
  - assets/template.d/mail.plain.erb
89
+ - assets/template.d/xmpp-body.plain.erb
73
90
  - bin/wcc
74
91
  - bin/wcc-init
75
92
  - bin/wcc-upgrade
@@ -78,6 +95,9 @@ files:
78
95
  - lib/wcc/filter.rb
79
96
  - lib/wcc/mail.rb
80
97
  - lib/wcc/site.rb
98
+ - lib/wcc/syslog.rb
99
+ - lib/wcc/version.rb
100
+ - lib/wcc/xmpp.rb
81
101
  - lib/wcc.rb
82
102
  - LICENSE
83
103
  - README.md