Project

General

Profile

« Previous | Next » 

Revision d4b5798a

Added by Marc Dequènes about 15 years ago

  • ID d4b5798aee4e9b3ddb65a7087ddb0c7726363333

[evol] added setup.rb installer, with hooks to generate locales and a 'lib/cyborghood/config.rb' file having a new CyborgHood::Config providing with installation paths, and created CyborgHood::Info to contain software general information (rakefile build-depends are then reduced to the minimum)

View differences:

.gitignore
# backup files (mostly made by editors)
*~
\#*#
config
log
var
locale
# generated by installer
.config
lib/cyborghood/config.rb
data/locale
#
conf
INSTALL
# for a real install in /usr/local
ruby setup.rb config
ruby setup.rb setup
ruby setup.rb install
ruby setup.rb clean
# for packagers
ruby setup.rb config --installdirs=std
ruby setup.rb setup
ruby setup.rb install --prefix=debian/cyborghood
ruby setup.rb clean
# for in-place tests
ruby setup.rb config --bindir=bin --rbdir=lib --datadir=data --sysconfdir=conf --localstatedir=var
ruby setup.rb setup
ruby setup.rb install
ruby setup.rb clean
README
rake
libgettext-ruby1.8
libgettext-ruby-util
libtmail-ruby1.8
Depends:
--------
liblog4r-ruby
libgettext-ruby1.8
libtmail-ruby1.8
libxmpp4r-ruby
liblog4r-ruby
rails
libgpgme-ruby
libactiveldap-ruby
libxmpp4r-ruby
libdaemons-ruby
libgpgme-ruby
rails
Rakefile
APP_ROOT = File.dirname(File.expand_path(__FILE__))
Dir.chdir(APP_ROOT)
$: << "./lib"
# to allow in-place run
$: << File.join(File.dirname(__FILE__), ".", "lib")
ENV['LC_ALL'] = "C"
require 'rake'
require 'gettext/utils'
require 'lib/cyborghood/base.rb'
require 'lib/cyborghood/config'
require 'lib/cyborghood/info'
namespace :i18n do
desc "Create mo-files for l10n"
task :makemo do
GetText.create_mofiles(true, "po", "locale")
GetText.create_mofiles(true, "po", CyborgHood::Config::L10N_DIR)
end
desc "Update pot/po files to match new version."
......
Dir.glob("lib/**/*.{rb,rhtml}"),
CyborgHood::PRODUCT + " " + CyborgHood::VERSION)
# temporary component listing
["Postman"].each do |component|
GetText.update_pofiles("cyborghood_" + component.downcase,
component.downcase,
["postman"].each do |component|
GetText.update_pofiles("cyborghood_" + component,
File.join(CyborgHood::Config::BIN_DIR, component),
CyborgHood::PRODUCT + " " + CyborgHood::VERSION)
end
end
TODO
- split product info in a separate file, to reduce build-depends (at mo files creation time for example)
- split libs into common and per component and adapt translations accordingly
- ban keys from unknow users flooding -> counter, reseted when key added in DB
- protect against intercepted mail with falsified headers (From/Reply-To/... could be tampered to get replies, reply tampered too, and then resent to avoid being detected)
bin/guard
#!/usr/bin/ruby -Ku
#--
# CyborgHood, a distributed system management software.
# Copyright (c) 2009 Marc Dequènes (Duck) <Duck@DuckCorp.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#++
# to allow in-place run for test
$: << File.join(File.dirname(__FILE__), "..", "lib")
require 'cyborghood/cyborg'
module CyborgHood
class Guard < Cyborg
ROOM_PARAMS = {
'muc#roomconfig_allowinvites' => 0,
'muc#roomconfig_changesubject' => 0,
'muc#roomconfig_membersonly' => 1,
'muc#roomconfig_publicroom' => 1,
'muc#roomconfig_persistentroom' => 1,
'muc#roomconfig_roomsecret' => 'moderators',
}
def initialize
super {
@in_room = true
}
end
def run
super do
logger.debug "COIN !"
p @muc.roster.collect{|k, v| [k, v.show] }
#sleep 3
Thread.stop
p "pompompom"
p @muc.roster.collect{|k, v| [k, v.show] }
end
end
private
def on_missing_room
logger.info "CyborgHood HeadQuarters meeting room does not exist yet; creating..."
logger.debug "Fetching and checking room config form"
room_config_form = @muc.get_room_configuration
missing_params = ROOM_PARAMS.keys - room_config_form
unless missing_params.empty?
logger.fatal "CyborgHood HeadQuarters do not provide the following meeting room facilities: " + missing_params.join(", ")
quit(true)
end
logger.debug "Setting room configuration"
@muc.submit_room_configuration(ROOM_PARAMS)
end
def on_existing_room
logger.debug "Checking ownership"
unless @muc.owner?
logger.fatal "CyborgHood HeadQuarters meeting room has been taken over !!!"
quit(true)
end
end
end
end
#Jabber::debug = true
bot = CyborgHood::Guard.new
trap('INT') do
bot.ask_to_stop
end
trap('TERM') do
bot.ask_to_stop
end
bot.run
bin/postman
#!/usr/bin/ruby -Ku
#--
# CyborgHood, a distributed system management software.
# Copyright (c) 2009 Marc Dequènes (Duck) <Duck@DuckCorp.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#++
# to allow in-place run for test
$: << File.join(File.dirname(__FILE__), "..", "lib")
#require 'socket'
require 'tempfile'
require 'shellwords'
require 'cyborghood/imap'
require 'cyborghood/mail'
require 'cyborghood/objects'
require 'cyborghood/services/dns'
require 'fileutils'
#Socket.gethostname
module CyborgHood
module PostmanHome
include GetText
bindtextdomain("cyborghood_postman", {:path => Config::L10N_DIR, :charset => "UTF-8"})
# not yet ready to be a real Cyborg
class Postman #< Cyborg
include GetText
def initialize
# load config
Config.load(self.human_name.downcase)
@config = Config.instance
ldap_config = @config.ldap
ldap_config.logger = logger
ActiveLdap::Base.establish_connection(ldap_config.marshal_dump)
# setup logs
unless @config.log.nil?
logger.output_level(@config.log.console_level) unless @config.log.console_level.nil?
logger.log_to_file(@config.log.file) unless @config.log.file.nil?
end
@current_thread = Thread.current
@stop_asap = false
@waiting = false
logger.info "Bot '#{self.human_name}' loaded"
end
def run
imap = IMAP.new(@config.imap)
until @stop_asap
t = Time.now.to_i
logger.debug "Starting mail check"
check_mails(imap)
logger.debug "Mail check finished"
t2 = Time.now.to_i
sleep_time = @config.imap.min_check_interval - (t2 - t)
if sleep_time > 0
logger.debug "Having a break before new check..."
@waiting = true
begin
sleep(sleep_time)
rescue
end
@waiting = false
end
end
logger.info "Bot was asked to stop..." if @stop_asap
logger.info "Bot terminating"
end
def ask_to_stop
@stop_asap = true
Thread.critical = true
@current_thread.raise if @waiting
Thread.critical = false
end
private
def check_mails(imap)
imap.check_mail do |msg|
if @stop_asap
logger.info "Bot was asked to stop..."
break
end
mail = Mail.new(msg.content)
logger.info "Received mail with ID '#{mail.message_id}': #{mail.from_addrs} -> #{mail.to_addrs} (#{mail.subject})"
# ignore mails not signed or encrypted
unless mail.is_pgp_signed? or mail.is_pgp_encrypted?
logger.info "Mail not signed/encrypted or not RFC3156 compliant, ignoring..."
msg.delete
next
end
logger.debug "RFC3156 content detected"
begin
order = mail.parse
rescue CyberError => e
case e.severity
when :dangerous
logger.fatal " (#{e.message})"
exit 2
when :unrecoverable
logger.error "Internal processing error, skipping mail (#{e.message})"
next
when :ignorable
end
end
result_tag = order.ok ? "SUCCESS" : "FAILURE"
logger.info "Processing result: #{result_tag} (#{order.message})"
logger.info "Extra processing information: " + order.system_message if order.system_message
if order.user
if order.user.preferredLanguage
logger.debug "User preference for langage: " + order.user.preferredLanguage
set_locale(order.user.preferredLanguage)
else
logger.debug "No user preference for langage, using english"
set_locale("en")
end
else
set_locale("en")
end
unless order.ok
if order.warn_sender
logger.info "Sending reply for rejected message"
mail_reply = mail.create_simple_reject_reply(_("Hello,") + "\n\n" + sprintf(
_("A message (ID: %s), apparently from you, was rejected for the following reason:"),
mail.message_id) + "\n " + _(order.message) + "\n" + mail_signature())
mail_reply.deliver
end
msg.delete
next
end
logger.debug "Message accepted, processing orders..."
result_list = CommandParser.run(order)
# create transcript
logger.debug "Preparing reply"
reply_txt = sprintf(_("Hello %s,"), order.user.cn) + "\n\n"
reply_txt += _(order.message) + "\n\n" if order.message
reply_txt += _("Follows the transcript of your commands:") + "\n"
reply_attachments = []
result_list.each do |result|
reply_txt << "> #{result.cmd}\n"
reply_txt << "#{result.message}\n"
reply_attachments += result.refs unless result.refs.nil?
end
reply_txt << mail_signature()
# create mail
logger.debug "Preparing mail"
mail_reply = mail.create_reply
if reply_attachments.empty?
transcript_part = mail_reply
else
mail_reply.set_content_type("multipart", "mixed", {'boundary' => TMail.new_boundary})
parts = []
p = CyborgHood::Mail.new
transcript_part = p
mail_reply.parts << p
reply_attachments.each do |attachment|
p = CyborgHood::Mail.new
p.set_content_type("text", "plain", {'charset' => "utf-8"})
p.set_disposition("attachment", {'filename' => attachment.filename})
p.quoted_printable_body = attachment.content
mail_reply.parts << p
end
end
# insert transcript
transcript_part.set_content_type("text", "plain", {'charset' => 'utf-8', 'format' => 'flowed'})
transcript_part.set_disposition("inline")
transcript_part.quoted_printable_body = reply_txt
# send reply
logger.debug "Sending mail"
mail_reply.sign_and_crypt(order.user.keyFingerPrint)
mail_reply.deliver
logger.info "Message processed completely, deleting"
msg.delete
end
end
def mail_signature
s = "\n" +
"-- \n" +
"#{CyborgHood::PRODUCT} v#{CyborgHood::VERSION}\n"
s += _("Contact eMail:") + " \"#{@config.contact.name}\" <#{@config.contact.email}>\n" if @config.contact.email
s += _("Contact URL:") + " #{@config.contact.url}\n" if @config.contact.url
s
end
end
class CommandParser
include GetText
def self.run(order)
result_list = []
order.commands.each do |cmdstr|
logger.info "Executing command: #{cmdstr}"
begin
result = execute_cmd(order.user, cmdstr, order.references)
if result.nil?
result = OpenStruct.new
result.cmd = cmdstr
result.ok = false
result.message = _("Command not recognized.")
result.refs = nil
end
rescue CyberError => e
result = OpenStruct.new
result.cmd = cmdstr
result.ok = false
result.message = e.message.capitalize + "."
result.refs = nil
rescue
logger.warn "Command crashed: " + $!
result = OpenStruct.new
result.cmd = cmdstr
result.ok = false
result.message = _("Internal error. Administrator is warned.")
result.refs = nil
end
tag = result.ok ? "SUCCESS" :"FAILURE"
logger.debug "Command result: [#{tag}] #{result.message}"
result_list << result
end
result_list
end
private
def self.execute_cmd(user, cmdstr, refs)
cmdline = Shellwords.shellwords(cmdstr)
subsys = cmdline.shift
result = OpenStruct.new
result.cmd = cmdstr
result.ok = false
ok = true
case subsys.upcase
when "DNS"
return if cmdline.empty?
case cmdline.shift.upcase
when "INFO"
return unless cmdline.empty?
list = CyborgHood::DnsDomain.find_by_manager(user)
txt_list = list.collect{|z| z.cn }.sort.join(", ")
result.ok = true
result.message = sprintf(_("You are manager of the following zones: %s."), txt_list)
when "GET"
return if cmdline.empty?
case cmdline.shift.upcase
when "ZONE"
return if cmdline.empty?
zone = cmdline.shift.downcase
dom = CyborgHood::DnsDomain.new(zone)
unless dom.hosted?
result.message = ("This zone is not hosted here.")
return result
end
unless dom.managed_by? user
result.message = _("You are not allowed to manage this zone.")
return result
end
srv_dns = CyborgHood::Services::DNS.new(zone)
result.ok = true
result.message = _("Requested zone content attached.")
zone_ref = {:content => srv_dns.read_zone, :filename => "dnszone_#{zone}.txt"}.to_ostruct
result.refs = [zone_ref]
end
when "SET"
return if cmdline.empty?
case cmdline.shift.upcase
when "ZONE"
return if cmdline.empty?
zone = cmdline.shift.downcase
dom = CyborgHood::DnsDomain.new(zone)
unless dom.hosted?
result.message = _("This zone is not hosted here.")
return result
end
unless dom.managed_by? user
result.message = _("You are not allowed to manage this zone.")
return result
end
srv_dns = CyborgHood::Services::DNS.new(zone)
return if cmdline.empty?
content_ref = cmdline.shift.downcase
return unless content_ref =~ /^@(\d+)$/
part_ref = $1.to_i
unless (1..refs.size).include? part_ref
result.message = _("Attachment number not found.")
return result
end
part = refs[part_ref]
unless part.content_type == "text/plain"
result.message = _("Attachment has wrong content-type.")
return result
end
f = Tempfile.new(zone)
f.write(part.body)
f.close
logger.debug "Created temporary zone file '#{f.path}'"
srv_dns = CyborgHood::Services::DNS.new(zone)
current_serial = srv_dns.serial
logger.debug "Current serial: #{current_serial}"
dns_result = srv_dns.check_zone_file(f.path)
unless dns_result.ok
result.message = _("Invalid zone data.")
f.close!
return result
end
logger.debug "New serial: #{dns_result.serial}"
# allow new serial or missing serial (to allow creating a new zone or replacing a broken zone)
unless current_serial.nil? or dns_result.serial > current_serial
result.message = _("Zone serial is not superior to current serial.")
f.close!
return result
end
begin
srv_dns.write_zone_from_file(f.path)
logger.debug "zone changed"
if srv_dns.reload_zone
logger.debug "zone reloaded"
result.ok = true
result.message = _("Zone updated.")
else
logger.warn "zone reload failed, replacing old content"
srv_dns.replace_zone_with_backup
result.message = _("Internal error. Administrator is warned.")
end
rescue
logger.warn "Writing zone file failed"
raise
ensure
f.close!
end
end
end
end
if result.message.nil?
# here fall lost souls
nil
else
result
end
end
end
end
end
bot = CyborgHood::PostmanHome::Postman.new
trap('INT') do
bot.ask_to_stop
end
trap('TERM') do
bot.ask_to_stop
end
bot.run
bin/postman_daemon
#!/usr/bin/ruby
#--
# CyborgHood, a distributed system management software.
# Copyright (c) 2009 Marc Dequènes (Duck) <Duck@DuckCorp.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#++
# to allow in-place run for test
$: << File.join(File.dirname(__FILE__), "..", "lib")
require 'daemons'
require 'cyborghood/config'
options = {
:app_name => "CyborgHood_Postman",
:dir_mode => :normal,
:dir => CyborgHood::Config::RUN_DIR,
:multiple => false,
:mode => :exec,
:monitor => true
}
# deactivated: monitor process not stopped when program is asked to stop
# :backtrace => true,
Daemons.run(File.join(CyborgHood::Config::BIN_DIR, 'postman'), options)
guard
#!/usr/bin/ruby -Ku
#--
# CyborgHood, a distributed system management software.
# Copyright (c) 2009 Marc Dequènes (Duck) <Duck@DuckCorp.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#++
$: << "./lib"
require 'cyborghood/cyborg'
module CyborgHood
class Guard < Cyborg
ROOM_PARAMS = {
'muc#roomconfig_allowinvites' => 0,
'muc#roomconfig_changesubject' => 0,
'muc#roomconfig_membersonly' => 1,
'muc#roomconfig_publicroom' => 1,
'muc#roomconfig_persistentroom' => 1,
'muc#roomconfig_roomsecret' => 'moderators',
}
def initialize
super {
@in_room = true
}
end
def run
super do
logger.debug "COIN !"
p @muc.roster.collect{|k, v| [k, v.show] }
#sleep 3
Thread.stop
p "pompompom"
p @muc.roster.collect{|k, v| [k, v.show] }
end
end
private
def on_missing_room
logger.info "CyborgHood HeadQuarters meeting room does not exist yet; creating..."
logger.debug "Fetching and checking room config form"
room_config_form = @muc.get_room_configuration
missing_params = ROOM_PARAMS.keys - room_config_form
unless missing_params.empty?
logger.fatal "CyborgHood HeadQuarters do not provide the following meeting room facilities: " + missing_params.join(", ")
quit(true)
end
logger.debug "Setting room configuration"
@muc.submit_room_configuration(ROOM_PARAMS)
end
def on_existing_room
logger.debug "Checking ownership"
unless @muc.owner?
logger.fatal "CyborgHood HeadQuarters meeting room has been taken over !!!"
quit(true)
end
end
end
end
#Jabber::debug = true
bot = CyborgHood::Guard.new
trap('INT') do
bot.ask_to_stop
end
trap('TERM') do
bot.ask_to_stop
end
bot.run
lib/cyborghood/base.rb
require 'singleton'
require 'yaml'
require 'log4r'
require "cyborghood/lang_additions"
require 'gettext'
require "cyborghood/config"
require "cyborghood/info"
require "cyborghood/lang_additions"
module CyborgHood
include GetText
bindtextdomain("cyborghood", {:path => File.join(APP_ROOT, "locale"), :charset => "UTF-8"})
PRODUCT = "CyborgHood"
VERSION = "0.2.0~dev"
bindtextdomain("cyborghood", {:path => Config::L10N_DIR, :charset => "UTF-8"})
# severities: # :dangerous :unrecoverable :ignorable
# categories:
......
class Config
include Singleton
CFG_DIR = './config/'
WORK_DIR = './var/lib/cyborghood/'
CONFFILE_GLOBAL = "cyborghood.conf"
CONFFILE_BOT = "cyborghood_%s.conf"
......
end
end
# temporary
def work_dir
WORK_DIR
end
private
def self.fetch_config(name = nil)
lib/cyborghood/info.rb
module CyborgHood
PRODUCT = "CyborgHood"
VERSION = "0.2.0~dev"
end
lib/cyborghood/mail.rb
end
def mark_dir
File.join(@config.work_dir, "marks")
File.join(Config::VAR_DIR, "marks")
end
def mark_filename
po/cyborghood.pot
msgid ""
msgstr ""
"Project-Id-Version: CyborgHood 0.2.0~dev\n"
"POT-Creation-Date: 2009-03-08 12:52+0100\n"
"POT-Creation-Date: 2009-03-08 19:14+0100\n"
"PO-Revision-Date: 2009-03-07 21:38+0100\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
po/cyborghood_postman.pot
msgid ""
msgstr ""
"Project-Id-Version: CyborgHood 0.2.0~dev\n"
"POT-Creation-Date: 2009-03-08 12:52+0100\n"
"POT-Creation-Date: 2009-03-08 19:14+0100\n"
"PO-Revision-Date: 2009-03-07 21:38+0100\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
......
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=INTEGER; plural=EXPRESSION;\n"
#: postman:152
#: /opt/cyborghood-dev/bin/postman:149
msgid "Hello,"
msgstr ""
#: postman:153
#: /opt/cyborghood-dev/bin/postman:150
msgid ""
"A message (ID: %s), apparently from you, was rejected for the following "
"reason:"
msgstr ""
#: postman:166
#: /opt/cyborghood-dev/bin/postman:163
msgid "Hello %s,"
msgstr ""
#: postman:168
#: /opt/cyborghood-dev/bin/postman:165
msgid "Follows the transcript of your commands:"
msgstr ""
#: postman:217
#: /opt/cyborghood-dev/bin/postman:214
msgid "Contact eMail:"
msgstr ""
#: postman:218
#: /opt/cyborghood-dev/bin/postman:215
msgid "Contact URL:"
msgstr ""
#: postman:236
#: /opt/cyborghood-dev/bin/postman:233
msgid "Command not recognized."
msgstr ""
#: postman:250 postman:368
#: /opt/cyborghood-dev/bin/postman:247 /opt/cyborghood-dev/bin/postman:365
msgid "Internal error. Administrator is warned."
msgstr ""
#: postman:280
#: /opt/cyborghood-dev/bin/postman:277
msgid "You are manager of the following zones: %s."
msgstr ""
#: postman:294 postman:316
#: /opt/cyborghood-dev/bin/postman:291 /opt/cyborghood-dev/bin/postman:313
msgid "You are not allowed to manage this zone."
msgstr ""
#: postman:300
#: /opt/cyborghood-dev/bin/postman:297
msgid "Requested zone content attached."
msgstr ""
#: postman:312
#: /opt/cyborghood-dev/bin/postman:309
msgid "This zone is not hosted here."
msgstr ""
#: postman:326
#: /opt/cyborghood-dev/bin/postman:323
msgid "Attachment number not found."
msgstr ""
#: postman:331
#: /opt/cyborghood-dev/bin/postman:328
msgid "Attachment has wrong content-type."
msgstr ""
#: postman:346
#: /opt/cyborghood-dev/bin/postman:343
msgid "Invalid zone data."
msgstr ""
#: postman:353
#: /opt/cyborghood-dev/bin/postman:350
msgid "Zone serial is not superior to current serial."
msgstr ""
#: postman:364
#: /opt/cyborghood-dev/bin/postman:361
msgid "Zone updated."
msgstr ""
po/fr/cyborghood.po
msgid ""
msgstr ""
"Project-Id-Version: CyborgHood 0.2.0~dev\n"
"POT-Creation-Date: 2009-03-08 12:52+0100\n"
"POT-Creation-Date: 2009-03-08 19:14+0100\n"
"PO-Revision-Date: 2009-03-07 20:59+0100\n"
"Last-Translator: Marc Dequènes (Duck) <Duck@DuckCorp.org>\n"
"MIME-Version: 1.0\n"
po/fr/cyborghood_postman.po
msgid ""
msgstr ""
"Project-Id-Version: CyborgHood 0.2.0~dev\n"
"POT-Creation-Date: 2009-03-08 12:52+0100\n"
"POT-Creation-Date: 2009-03-08 19:14+0100\n"
"PO-Revision-Date: 2009-03-07 21:27+0100\n"
"Last-Translator: Marc Dequènes (Duck) <Duck@DuckCorp.org>\n"
"MIME-Version: 1.0\n"
......
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=(n != 1);\n"
#: postman:152
#: /opt/cyborghood-dev/bin/postman:149
msgid "Hello,"
msgstr "Bonjour,"
#: postman:153
#: /opt/cyborghood-dev/bin/postman:150
msgid ""
"A message (ID: %s), apparently from you, was rejected for the following "
"reason:"
......
"Un message (ID: %s), provenant apparemment de vous, a été rejeté pour la "
"raison suivante :"
#: postman:166
#: /opt/cyborghood-dev/bin/postman:163
msgid "Hello %s,"
msgstr "Bonjour %s,"
#: postman:168
#: /opt/cyborghood-dev/bin/postman:165
msgid "Follows the transcript of your commands:"
msgstr "La retranscription des commandes suit :"
#: postman:217
#: /opt/cyborghood-dev/bin/postman:214
msgid "Contact eMail:"
msgstr "eMail de Contact :"
#: postman:218
#: /opt/cyborghood-dev/bin/postman:215
msgid "Contact URL:"
msgstr "URL de Contact :"
#: postman:236
#: /opt/cyborghood-dev/bin/postman:233
msgid "Command not recognized."
msgstr "Commande non reconnue"
#: postman:250 postman:368
#: /opt/cyborghood-dev/bin/postman:247 /opt/cyborghood-dev/bin/postman:365
msgid "Internal error. Administrator is warned."
msgstr "Erreur interne. L'administrateur a été prévenu."
#: postman:280
#: /opt/cyborghood-dev/bin/postman:277
msgid "You are manager of the following zones: %s."
msgstr "Vous gérez les zones suivantes : %s."
#: postman:294 postman:316
#: /opt/cyborghood-dev/bin/postman:291 /opt/cyborghood-dev/bin/postman:313
msgid "You are not allowed to manage this zone."
msgstr "Vous n'êtes pas autorisé à gérer cette zone."
#: postman:300
#: /opt/cyborghood-dev/bin/postman:297
msgid "Requested zone content attached."
msgstr "Le contenu de la zone demandée est en pièce jointe."
#: postman:312
#: /opt/cyborghood-dev/bin/postman:309
msgid "This zone is not hosted here."
msgstr "Cette zone n'est pas hébergée ici."
#: postman:326
#: /opt/cyborghood-dev/bin/postman:323
msgid "Attachment number not found."
msgstr "Numéro de pièce jointe non trouvé."
#: postman:331
#: /opt/cyborghood-dev/bin/postman:328
msgid "Attachment has wrong content-type."
msgstr "La pièce jointe a un mauvais type de contenu (content-type)."
#: postman:346
#: /opt/cyborghood-dev/bin/postman:343
msgid "Invalid zone data."
msgstr "Données pour la zone invalides."
#: postman:353
#: /opt/cyborghood-dev/bin/postman:350
msgid "Zone serial is not superior to current serial."
msgstr "Le numéro de série de la zone n'est pas supèrieur à celui actuel."
#: postman:364
#: /opt/cyborghood-dev/bin/postman:361
msgid "Zone updated."
msgstr "Zone mise à jour."
post-clean.rb
# post-clean.rb - setup config generation cleanup
#--
# CyborgHood, a distributed system management software.
# Copyright (c) 2009 Marc Dequènes (Duck) <Duck@DuckCorp.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#++
conffile = "lib/cyborghood/config.rb"
File.unlink(conffile) if FileTest.exists?(conffile)
post-config.rb
# post-config.rb - setup config generation
#--
# CyborgHood, a distributed system management software.
# Copyright (c) 2009 Marc Dequènes (Duck) <Duck@DuckCorp.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#++
# General header.
header = <<HEADER
# config.rb - Coin-diff setup configuration
#--
# CyborgHood, a distributed system management software.
# Copyright (c) 2009 Marc Dequènes (Duck) <Duck@DuckCorp.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#++
# This file is automatically generated by the installer.
# Do not edit by hand.
HEADER
# Generate config.rb containing general compile/setup time configuration
# information (in the CoinDiff::Config module).
File.open('lib/cyborghood/config.rb', 'w') do |file|
file.print header
file.print <<-CONFIG
module CyborgHood
class Config
BIN_DIR = '#{config('bindir')}'
CFG_DIR = '#{File.join(config('sysconfdir'), 'cyborghood')}'
DATA_DIR = '#{File.join(config('datadir'), 'cyborghood')}'
LIB_DIR = '#{config('rbdir')}'
LOG_DIR = '#{File.join(config('localstatedir'), 'log', 'cyborghood')}'
RUN_DIR = '#{File.join(config('localstatedir'), 'run', 'cyborghood')}'
VAR_DIR = '#{File.join(config('localstatedir'), 'lib', 'cyborghood')}'
L10N_DIR = '#{File.join(config('datadir'), 'locale')}'
end
end
CONFIG
end # File.open
post-setup.rb
# post-setup.rb - build extra files
#--
# CyborgHood, a distributed system management software.
# Copyright (c) 2009 Marc Dequènes (Duck) <Duck@DuckCorp.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#++
# build gettext locale files
system("rake i18n:makemo")
postman
#!/usr/bin/ruby -Ku
#--
# CyborgHood, a distributed system management software.
# Copyright (c) 2009 Marc Dequènes (Duck) <Duck@DuckCorp.org>
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#++
# http://www.ruby-doc.org/stdlib/libdoc/net/imap/rdoc/index.html
APP_ROOT = File.dirname(File.expand_path(__FILE__))
Dir.chdir(APP_ROOT)
$: << "./lib"
#require 'socket'
require 'tempfile'
require 'shellwords'
require 'cyborghood/imap'
require 'cyborghood/mail'
require 'cyborghood/objects'
require 'cyborghood/services/dns'
require 'fileutils'
#Socket.gethostname
module CyborgHood
module PostmanHome
include GetText
bindtextdomain("cyborghood_postman", {:path => File.join(APP_ROOT, "locale"), :charset => "UTF-8"})
# not yet ready to be a real Cyborg
class Postman #< Cyborg
include GetText
def initialize
# load config
Config.load(self.human_name.downcase)
@config = Config.instance
ldap_config = @config.ldap
ldap_config.logger = logger
ActiveLdap::Base.establish_connection(ldap_config.marshal_dump)
# setup logs
unless @config.log.nil?
logger.output_level(@config.log.console_level) unless @config.log.console_level.nil?
logger.log_to_file(@config.log.file) unless @config.log.file.nil?
end
@current_thread = Thread.current
@stop_asap = false
@waiting = false
logger.info "Bot '#{self.human_name}' loaded"
end
def run
imap = IMAP.new(@config.imap)
until @stop_asap
t = Time.now.to_i
logger.debug "Starting mail check"
check_mails(imap)
logger.debug "Mail check finished"
t2 = Time.now.to_i
sleep_time = @config.imap.min_check_interval - (t2 - t)
if sleep_time > 0
logger.debug "Having a break before new check..."
@waiting = true
begin
sleep(sleep_time)
rescue
end
@waiting = false
end
end
logger.info "Bot was asked to stop..." if @stop_asap
logger.info "Bot terminating"
end
def ask_to_stop
@stop_asap = true
Thread.critical = true
@current_thread.raise if @waiting
Thread.critical = false
end
private
def check_mails(imap)
imap.check_mail do |msg|
if @stop_asap
logger.info "Bot was asked to stop..."
break
end
mail = Mail.new(msg.content)
logger.info "Received mail with ID '#{mail.message_id}': #{mail.from_addrs} -> #{mail.to_addrs} (#{mail.subject})"
# ignore mails not signed or encrypted
unless mail.is_pgp_signed? or mail.is_pgp_encrypted?
logger.info "Mail not signed/encrypted or not RFC3156 compliant, ignoring..."
msg.delete
next
end
logger.debug "RFC3156 content detected"
begin
order = mail.parse
rescue CyberError => e
case e.severity
when :dangerous
logger.fatal " (#{e.message})"
exit 2
when :unrecoverable
logger.error "Internal processing error, skipping mail (#{e.message})"
next
when :ignorable
end
end
result_tag = order.ok ? "SUCCESS" : "FAILURE"
logger.info "Processing result: #{result_tag} (#{order.message})"
logger.info "Extra processing information: " + order.system_message if order.system_message
if order.user
if order.user.preferredLanguage
logger.debug "User preference for langage: " + order.user.preferredLanguage
set_locale(order.user.preferredLanguage)
else
logger.debug "No user preference for langage, using english"
set_locale("en")
end
else
set_locale("en")
end
unless order.ok
if order.warn_sender
logger.info "Sending reply for rejected message"
mail_reply = mail.create_simple_reject_reply(_("Hello,") + "\n\n" + sprintf(
_("A message (ID: %s), apparently from you, was rejected for the following reason:"),
mail.message_id) + "\n " + _(order.message) + "\n" + mail_signature())
mail_reply.deliver
end
msg.delete
next
end
logger.debug "Message accepted, processing orders..."
result_list = CommandParser.run(order)
# create transcript
logger.debug "Preparing reply"
reply_txt = sprintf(_("Hello %s,"), order.user.cn) + "\n\n"
reply_txt += _(order.message) + "\n\n" if order.message
reply_txt += _("Follows the transcript of your commands:") + "\n"
reply_attachments = []
result_list.each do |result|
reply_txt << "> #{result.cmd}\n"
reply_txt << "#{result.message}\n"
reply_attachments += result.refs unless result.refs.nil?
end
reply_txt << mail_signature()
# create mail
logger.debug "Preparing mail"
mail_reply = mail.create_reply
if reply_attachments.empty?
transcript_part = mail_reply
else
mail_reply.set_content_type("multipart", "mixed", {'boundary' => TMail.new_boundary})
parts = []
p = CyborgHood::Mail.new
transcript_part = p
mail_reply.parts << p
reply_attachments.each do |attachment|
p = CyborgHood::Mail.new
p.set_content_type("text", "plain", {'charset' => "utf-8"})
p.set_disposition("attachment", {'filename' => attachment.filename})
p.quoted_printable_body = attachment.content
mail_reply.parts << p
end
end
# insert transcript
transcript_part.set_content_type("text", "plain", {'charset' => 'utf-8', 'format' => 'flowed'})
transcript_part.set_disposition("inline")
transcript_part.quoted_printable_body = reply_txt
# send reply
logger.debug "Sending mail"
mail_reply.sign_and_crypt(order.user.keyFingerPrint)
mail_reply.deliver
logger.info "Message processed completely, deleting"
msg.delete
end
end
def mail_signature
s = "\n" +
"-- \n" +
"#{CyborgHood::PRODUCT} v#{CyborgHood::VERSION}\n"
s += _("Contact eMail:") + " \"#{@config.contact.name}\" <#{@config.contact.email}>\n" if @config.contact.email
s += _("Contact URL:") + " #{@config.contact.url}\n" if @config.contact.url
s
end
end
class CommandParser
include GetText
def self.run(order)
result_list = []
order.commands.each do |cmdstr|
logger.info "Executing command: #{cmdstr}"
begin
result = execute_cmd(order.user, cmdstr, order.references)
if result.nil?
result = OpenStruct.new
result.cmd = cmdstr
result.ok = false
result.message = _("Command not recognized.")
result.refs = nil
end
rescue CyberError => e
result = OpenStruct.new
result.cmd = cmdstr
result.ok = false
result.message = e.message.capitalize + "."
result.refs = nil
rescue
logger.warn "Command crashed: " + $!
result = OpenStruct.new
result.cmd = cmdstr
result.ok = false
result.message = _("Internal error. Administrator is warned.")
result.refs = nil
end
tag = result.ok ? "SUCCESS" :"FAILURE"
logger.debug "Command result: [#{tag}] #{result.message}"
result_list << result
end
result_list
end
private
def self.execute_cmd(user, cmdstr, refs)
cmdline = Shellwords.shellwords(cmdstr)
subsys = cmdline.shift
result = OpenStruct.new
result.cmd = cmdstr
result.ok = false
ok = true
case subsys.upcase
when "DNS"
return if cmdline.empty?
case cmdline.shift.upcase
when "INFO"
return unless cmdline.empty?
list = CyborgHood::DnsDomain.find_by_manager(user)
txt_list = list.collect{|z| z.cn }.sort.join(", ")
result.ok = true
result.message = sprintf(_("You are manager of the following zones: %s."), txt_list)
when "GET"
return if cmdline.empty?
case cmdline.shift.upcase
when "ZONE"
return if cmdline.empty?
zone = cmdline.shift.downcase
dom = CyborgHood::DnsDomain.new(zone)
unless dom.hosted?
result.message = ("This zone is not hosted here.")
return result
end
unless dom.managed_by? user
result.message = _("You are not allowed to manage this zone.")
... This diff was truncated because it exceeds the maximum size that can be displayed.

Also available in: Unified diff