# $Id: plugin.rb,v 1.36 2006/09/02 06:36:57 znz Exp $ # Copyright (C) 2002-2003 TAKEUCHI Hitoshi # Copyright (C) 2004-2005 Kazuhiko # # TADA Tadashi holds the copyright of Config class. require 'cgi' require 'uri' require 'hiki/util' module Hiki class PluginError < StandardError; end class Plugin attr_reader :toc_f, :plugin_command attr_accessor :text, :title, :cookies, :user, :data, :session_id TOC_STRING = "\000\000[Table of Contents]" def initialize( options, conf ) @options = options @conf = conf set_tdiary_env @cookies = [] @plugin_method_list = [] @header_procs = [] @update_procs = [] @delete_procs = [] @body_enter_procs = [] @body_leave_procs = [] @page_attribute_procs = [] @footer_procs = [] @edit_procs = [] @form_procs = [] @menu_procs = [] @conf_keys = [] @conf_procs = {} @mode = '' options.each_key do |opt| eval("@#{opt} = options['#{opt}']") unless opt.index('.') end @toc_f = false @context = nil @plugin_command = [] @plugin_menu = [] @text = '' @mode = 'conf' if options['params']['c'][0] == 'admin' @mode = 'saveconf' if options['params']['saveconf'][0] # loading plugins @plugin_files = [] plugin_path = @conf.plugin_path || "#{PATH}/plugin" plugin_file = '' begin Dir::glob( "#{plugin_path}/*.rb" ).sort.each do |file| plugin_file = file load_plugin( file ) @plugin_files << file end rescue Exception raise PluginError, "Plugin error in '#{File::basename( plugin_file )}'.\n#{$!}\n#{$!.backtrace[0]}" end end def block_context? @context == :block end def inline_context? @context == :inline end def block_context( &proc ) in_context( :block, &proc ) end def inline_context( &proc ) in_context( :inline, &proc ) end def cookie_path path = URI.parse(@conf.base_url).path if path[-1] == ?/ path else File.dirname(path) + '/' end end def header_proc r = [] @header_procs.each do |proc| begin r << proc.call rescue Exception r << plugin_error( 'header_proc', $! ) end end r.join.chomp end def update_proc @update_procs.each do |proc| begin proc.call rescue Exception end end end def delete_proc @delete_procs.each do |proc| begin proc.call rescue Exception end end end def body_enter_proc r = [] @body_enter_procs.each do |proc| begin r << proc.call( @date ) rescue Exception r << plugin_error( 'body_enter_proc', $! ) end end r.join end def body_leave_proc r = [] @body_leave_procs.each do |proc| begin r << proc.call( @date ) rescue Exception r << plugin_error( 'body_leave_proc', $! ) end end r.join end def page_attribute_proc r = [] @page_attribute_procs.each do |proc| begin r << proc.call( @date ) rescue Exception r << plugin_error( 'page_attribute_proc', $! ) end end r.join end def footer_proc r = [] @footer_procs.each do |proc| begin r << proc.call rescue Exception r << plugin_error( 'footer_proc', $! ) end end r.join end def edit_proc r = [] @edit_procs.each do |proc| begin r << proc.call rescue Exception r << plugin_error( 'edit_proc', $! ) end end r.join end def form_proc r = [] @form_procs.each do |proc| begin r << proc.call rescue Exception r << plugin_error( 'form_proc', $! ) end end r.join end def menu_proc r = [] @menu_procs.each do |proc| begin r << proc.call rescue Exception r << plugin_error( 'menu_proc', $! ) end end r.compact end def add_cookie( cookie ) @cookies << cookie end def singleton_method_added(name) @defined_method_list.push(name) end def load_file(filename) open(filename) do |src| instance_eval(src.read.untaint, filename, 1) end end def send(name, *args) name = name.intern if name.is_a?(String) if not name.is_a?(Symbol) raise ArgumentError, "#{name.inspect} is not a symbol" end if not @plugin_method_list.include?(name) method_missing(name, *args) else __send__(name, *args) end end def each_conf_key @conf_keys.each do |key| yield key end end def conf_proc( key ) r = '' label, block = @conf_procs[key] r = block.call if block r end def conf_label( key ) label, block = @conf_procs[key] label end def load_plugin( file ) file.untaint @defined_method_list = [] @export_method_list = nil @resource_loaded = false dirname, basename = File.split( file ) [@conf.lang, 'en', 'ja'].uniq.each do |lang| begin load_file( File.join( dirname, lang, basename ) ) @resource_loaded = true break rescue IOError, Errno::ENOENT end end load_file( file ) if @export_method_list @plugin_method_list.concat(@export_method_list) else @plugin_method_list.concat(@defined_method_list) end end def load( page ) @db.load( page ) end def load_backup( page ) @db.load_backup( page ) end def save( page, src, md5, update_timestamp = true ) src.gsub!(/\r/, '') src.sub!(/\A\n*/, '') src.sub!(/\n*\z/, "\n") result = @db.store(page, src, md5, update_timestamp) if result @db.set_attribute( page, :editor => @user ) @db.delete_cache( page ) begin update_proc rescue Exception end end result end def admin? ( @user == @conf.admin_name ) || @conf.password.empty? end def login( name, password ) return if @user return nil unless password name ||= @conf.admin_name if @conf.password.empty? || password.crypt( @conf.password ) == @conf.password && name == @conf.admin_name @user = @conf.admin_name elsif @conf['user.list'] if @conf['user.list'].has_key?(name) && @conf['user.list'][name] == password.crypt(@conf['user.list'][name]) @user = name end end end private def in_context(context) begin @context = context yield ensure @context = nil end end def export_plugin_methods(*names) @export_method_list = names.collect do |name| name = name.intern if name.is_a?(String) if not name.is_a?(Symbol) raise TypeError, "#{name.inspect} is not a symbol" end name end end def add_header_proc( block = Proc::new ) @header_procs << block end def add_footer_proc( block = Proc::new ) @footer_procs << block end def add_update_proc( block = Proc::new ) @update_procs << block end def add_delete_proc( block = Proc::new ) @delete_procs << block end def add_body_enter_proc( block = Proc::new ) @body_enter_procs << block end def add_page_attribute_proc( block = Proc::new ) @page_attribute_procs << block end def add_body_leave_proc( block = Proc::new ) @body_leave_procs << block end def add_edit_proc( block = Proc::new ) @edit_procs << block end def add_form_proc( block = Proc::new ) @form_procs << block end def add_menu_proc( block = Proc::new ) @menu_procs << block end def add_plugin_command(command, display_text, option = {}) @plugin_command << command @plugin_menu << {:command => command, :display_text => display_text, :option => option} if display_text nil end def add_conf_proc( key, label, block = Proc::new ) return unless @mode =~ /^(conf|saveconf)$/ @conf_keys << key unless @conf_keys.index( key ) @conf_procs[key] = [label, block] end def set_tdiary_env @date = Time::now @cookies = [] @options['cache_path'] = @conf.cache_path @options['mode'] = "day" # @options['author_name'] = @conf.author_name || 'anonymous' # @options['author_mail'] = @conf.mail # @options['index_page'] = @conf.index_page # @options['html_title'] = @conf.site_name @options['years'] = {} @options['diaries'] = nil, @options['date'] = Time::now %w(cache_path mode years diaries date).each do |p| eval("@#{p} = @options['#{p}']") end end end end