Commit a4f117fe authored by Holger Just's avatar Holger Just

Merge branch 'release-v2.5.0' into stable

parents ee543489 7104a245
......@@ -18,6 +18,10 @@ group :test do
platforms :mri_19, :mingw_19 do gem 'ruby-debug19', :require => 'ruby-debug' end
end
group :ldap do
gem "net-ldap", '~> 0.2.2'
end
group :openid do
gem "ruby-openid", '~> 2.1.4', :require => 'openid'
end
......
......@@ -16,8 +16,8 @@ class UsersController < ApplicationController
layout 'admin'
before_filter :require_admin, :except => :show
before_filter :find_user, :only => [:show, :edit, :update, :edit_membership, :destroy_membership]
accept_key_auth :index, :show, :create, :update
before_filter :find_user, :only => [:show, :edit, :update, :destroy, :edit_membership, :destroy_membership]
accept_key_auth :index, :show, :create, :update, :destroy
include SortHelper
include CustomFieldsHelper
......@@ -178,6 +178,24 @@ class UsersController < ApplicationController
redirect_to :controller => 'users', :action => 'edit', :id => @user
end
verify :method => :delete, :only => :destroy, :render => {:nothing => true, :status => :method_not_allowed }
def destroy
# Only allow to delete users with STATUS_REGISTERED for now
# It is assumed that these users are not yet references in any way
# from other objects.
return render_403 unless @user.deletable?
@user.destroy
respond_to do |format|
format.html {
flash[:notice] = l(:notice_successful_delete)
redirect_back_or_default(:action => 'index')
}
format.api { head :ok }
end
end
def edit_membership
@membership = Member.edit_membership(params[:membership_id], params[:membership], @user)
@membership.save if request.post?
......
......@@ -413,7 +413,7 @@ module ApplicationHelper
title = []
title << h(@project.name) if @project
title += @html_title if @html_title
title << Setting.app_title
title << h(Setting.app_title)
title.select {|t| !t.blank? }.join(' - ')
else
@html_title ||= []
......
......@@ -37,13 +37,26 @@ module UsersHelper
def change_status_link(user)
url = {:controller => 'users', :action => 'update', :id => user, :page => params[:page], :status => params[:status], :tab => nil}
links = []
if user.locked?
link_to l(:button_unlock), url.merge(:user => {:status => User::STATUS_ACTIVE}), :method => :put, :class => 'icon icon-unlock'
links << link_to(l(:button_unlock), url.merge(:user => {:status => User::STATUS_ACTIVE}), :method => :put, :class => 'icon icon-unlock')
elsif user.registered?
link_to l(:button_activate), url.merge(:user => {:status => User::STATUS_ACTIVE}), :method => :put, :class => 'icon icon-unlock'
links << link_to(l(:button_activate), url.merge(:user => {:status => User::STATUS_ACTIVE}), :method => :put, :class => 'icon icon-unlock')
elsif user != User.current
link_to l(:button_lock), url.merge(:user => {:status => User::STATUS_LOCKED}), :method => :put, :class => 'icon icon-lock'
links << link_to(l(:button_lock), url.merge(:user => {:status => User::STATUS_LOCKED}), :method => :put, :class => 'icon icon-lock')
end
if user.deletable?
links << link_to(
l(:button_delete), {:controller => 'users', :action => 'destroy', :id => user},
:method => :delete,
:confirm => l(:text_are_you_sure),
:title => l(:button_delete),
:class => 'icon icon-del'
)
end
links.join(" ")
end
def user_settings_tabs
......
......@@ -108,7 +108,7 @@ class Journal < ActiveRecord::Base
## => Try the journaled object with the same method and arguments
## => On error, call super
def method_missing(method, *args, &block)
return super if attributes[method.to_s]
return super if respond_to?(method) || attributes[method.to_s]
journaled.send(method, *args, &block)
rescue NoMethodError => e
e.name == method ? super : raise(e)
......
......@@ -396,8 +396,8 @@ class Mailer < ActionMailer::Base
# if he doesn't want to receive notifications about what he does
@author ||= User.current
if @author.pref[:no_self_notified]
recipients.delete(@author.mail) if recipients
cc.delete(@author.mail) if cc
recipients((recipients.is_a?(Array) ? recipients : [recipients]) - [@author.mail]) if recipients.present?
cc((cc.is_a?(Array) ? cc : [cc]) - [@author.mail]) if cc.present?
end
notified_users = [recipients, cc].flatten.compact.uniq
......
......@@ -70,6 +70,7 @@ class User < Principal
validates_length_of :mail, :maximum => 60, :allow_nil => true
validates_confirmation_of :password, :allow_nil => true
validates_inclusion_of :mail_notification, :in => MAIL_NOTIFICATION_OPTIONS.collect(&:first), :allow_blank => true
validates_inclusion_of :status, :in => [STATUS_ANONYMOUS, STATUS_ACTIVE, STATUS_REGISTERED, STATUS_LOCKED]
named_scope :in_group, lambda {|group|
group_id = group.is_a?(Group) ? group.id : group.to_i
......@@ -207,6 +208,11 @@ class User < Principal
update_attribute(:status, STATUS_LOCKED)
end
def deletable?
registered? && last_login_on.nil?
end
# Returns true if +clear_password+ is the correct user's password, otherwise false
def check_password?(clear_password)
if auth_source_id.present?
......@@ -526,6 +532,24 @@ class User < Principal
if !password.nil? && password.size < Setting.password_min_length.to_i
errors.add(:password, :too_short, :count => Setting.password_min_length.to_i)
end
# Status
if !new_record? && status_changed?
case status_was
when nil
# initial setting is always save
true
when STATUS_ANONYMOUS
# never allow a state change of the anonymous user
false
when STATUS_REGISTERED
[STATUS_ACTIVE, STATUS_LOCKED].include? status
when STATUS_ACTIVE
[STATUS_LOCKED].include? status
when STATUS_LOCKED
[STATUS_ACTIVE].include? status
end || errors.add(:status, :inclusion)
end
end
private
......
......@@ -104,7 +104,12 @@ class WikiContent < ActiveRecord::Base
def text
@text ||= case changes["compression"]
when "gzip"
Zlib::Inflate.inflate(changes["data"])
data = Zlib::Inflate.inflate(changes["data"])
if data.respond_to? :force_encoding
data.force_encoding("UTF-8")
else
data
end
else
# uncompressed data
changes["data"]
......
......@@ -15,7 +15,7 @@
<%= render :partial => (@edit_allowed ? 'form' : 'form_update'), :locals => {:f => f} %>
</fieldset>
<% end %>
<% if authorize_for('timelog', 'edit') %>
<% if User.current.allowed_to?(:log_time, @project) %>
<fieldset class="tabular"><legend><%= l(:button_log_time) %></legend>
<% fields_for :time_entry, @time_entry, { :builder => TabularFormBuilder, :lang => current_language} do |time_entry| %>
<div class="splitcontentleft">
......
......@@ -2,7 +2,7 @@
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title><%=h html_title %></title>
<title><%= html_title %></title>
<meta name="description" content="<%= Redmine::Info.app_name %>" />
<meta name="keywords" content="issue,bug,tracker" />
<%= csrf_meta_tag %>
......
......@@ -8,10 +8,13 @@
<%= link_to(l(:label_overall_spent_time), { :controller => 'time_entries' }) + ' |' if User.current.allowed_to?(:view_time_entries, nil, :global => true) %>
<%= link_to(l(:label_news_view_all), { :controller => 'news' }) + ' |' if User.current.allowed_to?(:view_news, nil, :global => true) %>
<%= link_to l(:label_overall_activity), { :controller => 'activities', :action => 'index' }%>
<%= call_hook(:view_projects_show_contextual) %>
</div>
<h2><%=l(:label_project_plural)%></h2>
<%= call_hook(:view_projects_show_top) %>
<%= render_project_hierarchy(@projects)%>
<% if User.current.logged? %>
......
......@@ -97,11 +97,11 @@ Event.observe(document,"dom:loaded", apply_filters_observer);
</select>
<%= link_to_function image_tag('bullet_toggle_plus.png'), "toggle_multi_select('#{field}');", :style => "vertical-align: bottom;" %>
<% when :date, :date_past %>
<%= text_field_tag "v[#{field}][]", query.values_for(field), :id => "values_#{field}", :size => 3, :class => "select-small" %> <%= l(:label_day_plural) %>
<%= text_field_tag "v[#{field}][]", query.values_for(field).try(:first), :id => "values_#{field}", :size => 3, :class => "select-small" %> <%= l(:label_day_plural) %>
<% when :string, :text %>
<%= text_field_tag "v[#{field}][]", query.values_for(field), :id => "values_#{field}", :size => 30, :class => "select-small" %>
<%= text_field_tag "v[#{field}][]", query.values_for(field).try(:first), :id => "values_#{field}", :size => 30, :class => "select-small" %>
<% when :integer %>
<%= text_field_tag "v[#{field}][]", query.values_for(field), :id => "values_#{field}", :size => 3, :class => "select-small" %>
<%= text_field_tag "v[#{field}][]", query.values_for(field).try(:first), :id => "values_#{field}", :size => 3, :class => "select-small" %>
<% end %>
</div>
<script type="text/javascript">toggle_filter('<%= field %>');</script>
......
......@@ -960,26 +960,26 @@ bg:
field_effective_date: Дата
text_default_encoding: "По подразбиране: UTF-8"
text_git_repo_example: a bare and local repository (e.g. /gitrepo, c:\gitrepo)
label_notify_member_plural: Email issue updates
label_notify_member_plural: Изпращане на e-mail при промени в задачите
label_path_encoding: Кодиране на пътищата
text_mercurial_repo_example: локално хранилище (например /hgrepo, c:\hgrepo)
label_diff: diff
setting_issue_startdate_is_adddate: Use current date as start date for new issues
description_search: Searchfield
description_user_mail_notification: Mail notification settings
description_date_range_list: Choose range from list
description_date_to: Enter end date
description_query_sort_criteria_attribute: Sort attribute
description_message_content: Message content
description_wiki_subpages_reassign: Choose new parent page
description_available_columns: Available Columns
description_selected_columns: Selected Columns
description_date_range_interval: Choose range by selecting start and end date
description_project_scope: Search scope
description_issue_category_reassign: Choose issue category
description_query_sort_criteria_direction: Sort direction
description_notes: Notes
description_filter: Filter
description_choose_project: Projects
description_date_from: Enter start date
label_deleted_custom_field: (deleted custom field)
setting_issue_startdate_is_adddate: Използване на текущата дата като начална дата за нови задачи
description_search: Търсене
description_user_mail_notification: Конфигурация известията по пощата
description_date_range_list: Изберете диапазон от списъка
description_date_to: Въведете крайна дата
description_query_sort_criteria_attribute: Атрибут на сортиране
description_message_content: Съдържание на съобщението
description_wiki_subpages_reassign: Изберете нова родителска страница
description_available_columns: Налични колони
description_selected_columns: Избрани колони
description_date_range_interval: Изберете диапазон чрез задаване на начална и крайна дати
description_project_scope: Обхват на търсенето
description_issue_category_reassign: Изберете категория
description_query_sort_criteria_direction: Посока на сортиране
description_notes: Бележки
description_filter: Филтър
description_choose_project: Проекти
description_date_from: Въведете начална дата
label_deleted_custom_field: (изтрито потребителско поле)
......@@ -19,9 +19,9 @@ rescue LoadError
raise "Could not load the bundler gem. Install it with `gem install bundler`."
end
if Gem::Version.new(Bundler::VERSION) <= Gem::Version.new("0.9.24")
raise RuntimeError, "Your bundler version is too old for Rails 2.3." +
"Run `gem install bundler` to upgrade."
if Gem::Version.new(Bundler::VERSION) < Gem::Version.new("1.0.6")
raise RuntimeError, "Your bundler version is too old. We require " +
"at least version 1.0.6. Run `gem install bundler` to upgrade."
end
begin
......@@ -29,6 +29,6 @@ begin
ENV["BUNDLE_GEMFILE"] = File.expand_path("../../Gemfile", __FILE__)
Bundler.setup
rescue Bundler::GemNotFound
raise RuntimeError, "Bundler couldn't find some gems." +
raise RuntimeError, "Bundler couldn't find some gems. " +
"Did you run `bundle install`?"
end
......@@ -137,8 +137,7 @@ ActionController::Routing::Routes.draw do |map|
map.resources :users, :member => {
:edit_membership => :post,
:destroy_membership => :post
},
:except => [:destroy]
}
# For nice "roadmap" in the url for the index action
map.connect 'projects/:project_id/roadmap', :controller => 'versions', :action => 'index'
......
This diff is collapsed.
......@@ -438,10 +438,12 @@ sub is_member {
my $pass_digest = Digest::SHA1::sha1_hex($redmine_pass);
my $access_mode = request_is_read_only($r) ? "R" : "W";
my $cfg = Apache2::Module::get_config(__PACKAGE__, $r->server, $r->per_dir_config);
my $usrprojpass;
if ($cfg->{RedmineCacheCredsMax}) {
$usrprojpass = $cfg->{RedmineCacheCreds}->get($redmine_user.":".$project_id);
$usrprojpass = $cfg->{RedmineCacheCreds}->get($redmine_user.":".$project_id.":".$access_mode);
return 1 if (defined $usrprojpass and ($usrprojpass eq $pass_digest));
}
my $query = $cfg->{RedmineQuery};
......@@ -485,10 +487,10 @@ sub is_member {
if ($cfg->{RedmineCacheCredsMax} and $ret) {
if (defined $usrprojpass) {
$cfg->{RedmineCacheCreds}->set($redmine_user.":".$project_id, $pass_digest);
$cfg->{RedmineCacheCreds}->set($redmine_user.":".$project_id.":".$access_mode, $pass_digest);
} else {
if ($cfg->{RedmineCacheCredsCount} < $cfg->{RedmineCacheCredsMax}) {
$cfg->{RedmineCacheCreds}->set($redmine_user.":".$project_id, $pass_digest);
$cfg->{RedmineCacheCreds}->set($redmine_user.":".$project_id.":".$access_mode, $pass_digest);
$cfg->{RedmineCacheCredsCount}++;
} else {
$cfg->{RedmineCacheCreds}->clear();
......
......@@ -21,5 +21,19 @@ module ChiliProject
Journal.included_modules.include?(Redmine::Acts::Journalized)
end
# Is any jQuery version available on all pages?
#
# This does not take modifications into account, that may be performed by
# plugins.
#
# Released: ChiliProject 2.5.0
def self.using_jquery?
false
end
# Catch-all to be overwritten be future compatibility checks.
def self.method_missing(method, *args)
method.to_s.ends_with?('?') ? false : super
end
end
end
......@@ -18,7 +18,7 @@ module ChiliProject
module VERSION #:nodoc:
MAJOR = 2
MINOR = 4
MINOR = 5
PATCH = 0
TINY = PATCH # Redmine compat
......
......@@ -100,10 +100,10 @@ Redmine::AccessControl.map do |map|
end
map.project_module :time_tracking do |map|
map.permission :log_time, {:timelog => [:new, :create, :edit, :update]}, :require => :loggedin
map.permission :log_time, {:timelog => [:new, :create]}, :require => :loggedin
map.permission :view_time_entries, :timelog => [:index, :show], :time_entry_reports => [:report]
map.permission :edit_time_entries, {:timelog => [:new, :create, :edit, :update, :destroy]}, :require => :member
map.permission :edit_own_time_entries, {:timelog => [:new, :create, :edit, :update, :destroy]}, :require => :loggedin
map.permission :edit_time_entries, {:timelog => [:edit, :update, :destroy]}, :require => :member
map.permission :edit_own_time_entries, {:timelog => [:edit, :update, :destroy]}, :require => :loggedin
map.permission :manage_project_activities, {:project_enumerations => [:update, :destroy]}, :require => :member
end
......
......@@ -22,7 +22,7 @@ class TabularFormBuilder < ActionView::Helpers::FormBuilder
super
end
(field_helpers - %w(radio_button hidden_field fields_for) + %w(date_select)).each do |selector|
(field_helpers.map(&:to_s) - %w(radio_button hidden_field fields_for) + %w(date_select)).each do |selector|
src = <<-END_SRC
def #{selector}(field, options = {})
label_for_field(field, options) + super
......
......@@ -781,6 +781,22 @@ class IssuesControllerTest < ActionController::TestCase
assert_tag :input, :attributes => { :name => 'time_entry[comments]', :value => 'test_get_edit_with_params' }
end
def test_get_edit_should_display_the_time_entry_form_with_log_time_permission
@request.session[:user_id] = 2
Role.find_by_name('Manager').update_attribute :permissions, [:view_issues, :edit_issues, :log_time]
get :edit, :id => 1
assert_tag 'input', :attributes => {:name => 'time_entry[hours]'}
end
def test_get_edit_should_not_display_the_time_entry_form_without_log_time_permission
@request.session[:user_id] = 2
Role.find_by_name('Manager').remove_permission! :log_time
get :edit, :id => 1
assert_no_tag 'input', :attributes => {:name => 'time_entry[hours]'}
end
def test_update_edit_form
@request.session[:user_id] = 2
xhr :post, :new, :project_id => 1,
......
......@@ -111,6 +111,18 @@ class TimelogControllerTest < ActionController::TestCase
assert_equal 3, t.user_id
end
def test_create_without_log_time_permission_should_be_denied
@request.session[:user_id] = 2
Role.find_by_name('Manager').remove_permission! :log_time
post :create, :project_id => 1,
:time_entry => {:activity_id => '11',
:issue_id => '',
:spent_on => '2008-03-14',
:hours => '7.3'}
assert_response 403
end
def test_update
entry = TimeEntry.find(1)
assert_equal 1, entry.issue_id
......
......@@ -270,6 +270,31 @@ class UsersControllerTest < ActionController::TestCase
assert u.check_password?('newpass')
end
def test_destroy
u = User.new(:firstname => 'Death', :lastname => 'Row', :mail => 'death.row@example.com', :language => 'en')
u.login = 'death.row'
u.status = User::STATUS_REGISTERED
u.save!
delete :destroy, :id => u.id
assert_redirected_to :action => 'index'
# make sure that the user was actually destroyed
assert_raises(ActiveRecord::RecordNotFound) { u.reload }
end
def test_failing_destroy
u = User.new(:firstname => 'Surviving', :lastname => 'Patient', :mail => 'surviving.patient@example.com', :language => 'en')
u.login = 'surviving.patient'
u.status = User::STATUS_ACTIVE
u.save!
delete :destroy, :id => u.id
assert_response :forbidden
# make sure the user is still around
assert !u.reload.destroyed?
end
def test_edit_membership
post :edit_membership, :id => 2, :membership_id => 1,
:membership => { :role_ids => [2]}
......
......@@ -241,26 +241,52 @@ class ApiTest::UsersTest < ActionController::IntegrationTest
end
end
end
end
context "DELETE /users/2" do
context "DELETE /users/:temp:" do
context ".xml" do
should "not be allowed" do
assert_no_difference('User.count') do
delete '/users/2.xml'
should "delete the user" do
u = User.new(:firstname => 'Death', :lastname => 'Row', :mail => 'death.row@example.com', :language => 'en')
u.login = 'death.row'
u.status = User::STATUS_REGISTERED
u.save!
assert_difference('User.count',-1) do
delete "/users/#{u.id}.xml", {}, :authorization => credentials('admin')
end
assert_response :success
assert_nil User.find_by_id(u.id)
end
assert_response :method_not_allowed
should "not delete active user" do
assert_difference('User.count',0) do
delete "/users/2.xml", {}, :authorization => credentials('jsmith')
end
assert_response :forbidden
end
end
context ".json" do
should "not be allowed" do
assert_no_difference('User.count') do
delete '/users/2.json'
should "delete the user" do
u = User.new(:firstname => 'Death', :lastname => 'Row', :mail => 'death.row@example.com', :language => 'en')
u.login = 'death.row'
u.status = User::STATUS_REGISTERED
u.save!
assert_difference('User.count',-1) do
delete "/users/#{u.id}.json", {}, :authorization => credentials('admin')
end
assert_response :success
assert_nil User.find_by_id(u.id)
end
assert_response :method_not_allowed
should "not delete active user" do
assert_difference('User.count',0) do
delete "/users/2.json", {}, :authorization => credentials('jsmith')
end
assert_response :forbidden
end
end
end
......
......@@ -60,4 +60,15 @@ class LayoutTest < ActionController::IntegrationTest
:attributes => {:src => %r{^/javascripts/jstoolbar/textile.js}},
:parent => {:tag => 'head'}
end
test "page titles should be properly escaped" do
project = Project.generate(:name => "C&A")
with_settings :app_title => '<3' do
get "/projects/#{project.to_param}"
assert_select "title", /C&amp;A/
assert_select "title", /&lt;3/
end
end
end
......@@ -174,6 +174,14 @@ class UserTest < ActiveSupport::TestCase
assert_equal nil, user
end
def test_error_on_active_to_registered
user = User.try_to_login("jsmith", "jsmith")
assert_equal @jsmith, user
@jsmith.status = User::STATUS_REGISTERED
assert !@jsmith.save
end
context ".try_to_login" do
context "with good credentials" do
should "return the user" do
......
This diff is collapsed.
= Net::LDAP Changelog
== Net::LDAP 0.0.4: August 15, 2006
* Undeprecated Net::LDAP#modify. Thanks to Justin Forder for
providing the rationale for this.
* Added a much-expanded set of special characters to the parser
for RFC-2254 filters. Thanks to Andre Nathan.
* Changed Net::LDAP#search so you can pass it a filter in string form.
The conversion to a Net::LDAP::Filter now happens automatically.
* Implemented Net::LDAP#bind_as (preliminary and subject to change).
Thanks for Simon Claret for valuable suggestions and for helping test.
* Fixed bug in Net::LDAP#open that was preventing #open from being
called more than one on a given Net::LDAP object.
== Net::LDAP 0.0.3: July 26, 2006
* Added simple TLS encryption.
Thanks to Garett Shulman for suggestions and for helping test.
== Net::LDAP 0.0.2: July 12, 2006
* Fixed malformation in distro tarball and gem.
* Improved documentation.
* Supported "paged search control."
* Added a range of API improvements.
* Thanks to Andre Nathan, andre@digirati.com.br, for valuable
suggestions.
* Added support for LE and GE search filters.
* Added support for Search referrals.
* Fixed a regression with openldap 2.2.x and higher caused
by the introduction of RFC-2696 controls. Thanks to Andre
Nathan for reporting the problem.
* Added support for RFC-2254 filter syntax.
== Net::LDAP 0.0.1: May 1, 2006
* Initial release.
* Client functionality is near-complete, although the APIs
are not guaranteed and may change depending on feedback
from the community.
* We're internally working on a Ruby-based implementation
of a full-featured, production-quality LDAP server,
which will leverage the underlying LDAP and BER functionality
in Net::LDAP.
* Please tell us if you would be interested in seeing a public
release of the LDAP server.
* Grateful acknowledgement to Austin Ziegler, who reviewed
this code and provided the release framework, including
minitar.
#--
# Net::LDAP for Ruby.
# http://rubyforge.org/projects/net-ldap/
# Copyright (C) 2006 by Francis Cianfrocca
#
# Available under the same terms as Ruby. See LICENCE in the main
# distribution for full licensing information.
#
# $Id: ChangeLog,v 1.17.2.4 2005/09/09 12:36:42 austin Exp $
#++
# vim: sts=2 sw=2 ts=4 et ai tw=77
Net::LDAP is copyrighted free software by Francis Cianfrocca
<garbagecat10@gmail.com>. You can redistribute it and/or modify it under either
the terms of the GPL (see the file COPYING), or the conditions below:
1. You may make and give away verbatim copies of the source form of the
software without restriction, provided that you duplicate all of the
original copyright notices and associated disclaimers.
2. You may modify your copy of the software in any way, provided that you do
at least ONE of the following:
a) place your modifications in the Public Domain or otherwise make them
Freely Available, such as by posting said modifications to Usenet or
an equivalent medium, or by allowing the author to include your
modifications in the software.
b) use the modified software only within your corporation or
organization.
c) rename any non-standard executables so the names do not conflict with
standard executables, which must also be provided.
d) make other distribution arrangements with the author.
3. You may distribute the software in object code or executable form,
provided that you do at least ONE of the following:
a) distribute the executables and library files of the software, together
with instructions (in the manual page or equivalent) on where to get
the original distribution.
b) accompany the distribution with the machine-readable source of the
software.
c) give non-standard executables non-standard names, with instructions on
where to get the original software distribution.
d) make other distribution arrangements with the author.
4. You may modify and include the part of the software into any other
software (possibly commercial). But some files in the distribution are
not written by the author, so that they are not under this terms.
They are gc.c(partly), utils.c(partly), regex.[ch], st.[ch] and some
files under the ./missing directory. See each file for the copying
condition.
5. The scripts and library files supplied as input to or produced as output
from the software do not automatically fall under the copyright of the
software, but belong to whomever generated them, and may be sold
commercially, and may be aggregated with this software.
6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED
WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
= Net::LDAP for Ruby
Net::LDAP is an LDAP support library written in pure Ruby. It supports all
LDAP client features, and a subset of server features as well.
Homepage:: http://rubyforge.org/projects/net-ldap/
Copyright:: (C) 2006 by Francis Cianfrocca
Original developer: Francis Cianfrocca
Contributions by Austin Ziegler gratefully acknowledged.
== LICENCE NOTES
Please read the file LICENCE for licensing restrictions on this library. In