# $Id: API.pm,v 1.18 2002/02/28 02:21:00 m-kasahr Exp $
#
# Copyright (c) 2001 Japan Network Information Center.  All rights reserved.
#  
# By using this file, you agree to the terms and conditions set forth bellow.
# 
#                      LICENSE TERMS AND CONDITIONS 
# 
# The following License Terms and Conditions apply, unless a different
# license is obtained from Japan Network Information Center ("JPNIC"),
# a Japanese association, Fuundo Bldg., 1-2 Kanda Ogawamachi, Chiyoda-ku,
# Tokyo, Japan.
# 
# 1. Use, Modification and Redistribution (including distribution of any
#    modified or derived work) in source and/or binary forms is permitted
#    under this License Terms and Conditions.
# 
# 2. Redistribution of source code must retain the copyright notices as they
#    appear in each source code file, this License Terms and Conditions.
# 
# 3. Redistribution in binary form must reproduce the Copyright Notice,
#    this License Terms and Conditions, in the documentation and/or other
#    materials provided with the distribution.  For the purposes of binary
#    distribution the "Copyright Notice" refers to the following language:
#    "Copyright (c) Japan Network Information Center.  All rights reserved."
# 
# 4. Neither the name of JPNIC may be used to endorse or promote products
#    derived from this Software without specific prior written approval of
#    JPNIC.
# 
# 5. Disclaimer/Limitation of Liability: THIS SOFTWARE IS PROVIDED BY JPNIC
#    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
#    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
#    PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL JPNIC BE LIABLE
#    FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
#    CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
#    SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
#    BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
#    WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
#    OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
#    ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.
# 
# 6. Indemnification by Licensee
#    Any person or entities using and/or redistributing this Software under
#    this License Terms and Conditions shall defend indemnify and hold
#    harmless JPNIC from and against any and all judgements damages,
#    expenses, settlement liabilities, cost and other liabilities of any
#    kind as a result of use and redistribution of this Software or any
#    claim, suite, action, litigation or proceeding by any third party
#    arising out of or relates to this License Terms and Conditions.
# 
# 7. Governing Law, Jurisdiction and Venue
#    This License Terms and Conditions shall be governed by and and
#    construed in accordance with the law of Japan. Any person or entities
#    using and/or redistributing this Software under this License Terms and
#    Conditions hereby agrees and consent to the personal and exclusive
#    jurisdiction and venue of Tokyo District Court of Japan.
#
package MDN::API;

use strict;
use Carp;
use vars qw($VERSION @ISA @EXPORT @EXPORT_OK $AUTOLOAD
	    $resconf $error_message $config_file);

use MDN::ResConf;

require Exporter;

@ISA = qw(Exporter);
@EXPORT = qw();
$VERSION = '2.4';

BEGIN {
    $resconf = MDN::ResConf->new()
	or croak "failed to create an MDN::ResConf object";
    if (defined($config_file)) {
	$resconf->load_file($config_file)
	    or croak "cannot load libmdn configuration file";
    } else {
	$resconf->load_file()
	    or croak "cannot load libmdn configuration file";
    }
    $error_message = 'success';
}

sub encode_name {
    my ($package, $from, @actions) = @_;

    push(@actions, 'encode_app') if (@actions == 0);
    my ($localconv, $delimmap, $localmap, $nameprep, $idnconv)
	= (0, 0, 0, 0, 0);

    foreach my $i (@actions) {
	if ($i =~ /^localconv$/i) {
	    $localconv = 1;
	} elsif ($i =~ /^delimmap$/i) {
	    $delimmap = 1;
	} elsif ($i =~ /^localmap$/i) {
	    $localmap = 1;
	} elsif ($i =~ /^nameprep$/i) {
	    $nameprep = 1;
	} elsif ($i =~ /^unascheck$/i) {
	    # ignore
	} elsif ($i =~ /^idnconv$/i) {
	    $idnconv = 1;
	} elsif ($i =~ /^encode_app$/i) {
	    $localconv = 1;
	    $delimmap = 1;
	    $localmap = 1;
	    $nameprep = 1;
	    $idnconv = 1;
	} else {
	    $error_message = "invalid action, $i";
	    return undef;
	}
    }

    my $nameconv_actions = '';
    $nameconv_actions .= 'l' if ($localconv);
    $nameconv_actions .= 'd' if ($delimmap);
    $nameconv_actions .= 'M' if ($localmap);
    $nameconv_actions .= 'N' if ($nameprep);
    $nameconv_actions .= 'I' if ($idnconv);

    my $result = $resconf->nameconv($nameconv_actions, $from);
    $error_message = MDN::ResConf->lasterror() if (!defined($result));

    return $result;
}

sub decode_name {
    my ($package, $from, @actions) = @_;

    push(@actions, 'decode_app') if (@actions == 0);
    my ($idnconv, $nameprep, $localconv) = (0, 0, 0);

    foreach my $i (@actions) {
	if ($i =~ /^idnconv$/i) {
	    $idnconv = 1;
	} elsif ($i =~ /^nameprep$/i) {
	    $nameprep = 1;
	} elsif ($i =~ /^unascheck$/i) {
	    # ignore
	} elsif ($i =~ /^localconv$/i) {
	    $localconv = 1;
	} elsif ($i =~ /^decode_app$/i) {
	    $idnconv = 1;
	    $nameprep = 1;
	    $localconv = 1;
	} else {
	    $error_message = "invalid action, $i";
	    return undef;
	}
    }

    my $nameconv_actions = '';
    $nameconv_actions .= 'i' if ($idnconv);
    $nameconv_actions .= '!N' if ($nameprep);
    $nameconv_actions .= 'L' if ($localconv);

    my $result = $resconf->nameconv($nameconv_actions, $from);
    $error_message = MDN::ResConf->lasterror() if (!defined($result));

    return $result;
}

sub enable {
    my ($package, $on_off) = @_;

    $resconf->enable($on_off);
}

sub lasterror {
    return $error_message;
}

sub local_to_utf8 {
    my ($package, $from) = @_;
    return encode_name($package, $from, 'localconv');
}

sub utf8_to_local {
    my ($package, $from) = @_;
    return decode_name($package, $from, 'localconv');
}

sub delimiter_map {
    my ($package, $from) = @_;
    return encode_name($package, $from, 'delimmap');
}

sub local_map {
    my ($package, $from) = @_;
    return encode_name($package, $from, 'localmap');
}

sub nameprep {
    my ($package, $from) = @_;
    return encode_name($package, $from, 'nameprep');
}

sub nameprep_check {
    my ($package, $from) = @_;
    return decode_name($package, $from, 'nameprep');
}

sub unassigned_check {
    my ($package, $from) = @_;
    return $from;
}

sub utf8_to_idn {
    my ($package, $from) = @_;
    return encode_name($package, $from, 'idnconv');
}

sub idn_to_utf8 {
    my ($package, $from) = @_;
    return decode_name($package, $from, 'idnconv');
}

sub local_to_idn {
    my ($package, $from) = @_;
    return encode_name($package, $from);
}

sub idn_to_local {
    my ($package, $from) = @_;
    return decode_name($package, $from);
}

1;
__END__

=head1 NAME

MDN::API - Perl interface to domain name conversion methods of libmdn

=head1 SYNOPSIS

  use MDN::API;

  $idn_domain_name = MDN::API->encode_name($local_domain_name);
  $local_domain_name = MDN::API->decode_name($idn_domain_name);

=head1 DESCRIPTION

C<MDN::API> provides a Perl object interface to domain name
conversion methods of libmdn, the multilingual domain name library
included in the mDNkit.

This module provides high-level conversion interface to the library.
It can encode or decode a domain name according with libmdn configuration
(e.g. C</usr/local/etc/mdn.conf>).

=head1 CLASS METHODS

Although this module does not provide object interface,
all the functions should be called as class methods,
in order to be consistent with other modules in C<MDN::>.

        MDN::API->encode_name($domain_name);  # OK
        MDN::API::encode_name($domain_name);  # NG

=over 4

=item encode_name($from [, @actions...])

Encodes domain name of C<$from> according with C<@actions>, and returns
the result.

Each element in C<@actions> is a string as follows:

    'localconv'     convert the local encoding string to UTF-8.
    'delimmap'      covnert local delimiters to periods ('.').
    'localmap'      perfrom local mapping.
    'nameprep'      perform NAMEPREP (mapping, normalization,
                    prohibit character check and unassigned
                    codepoint check).
    'idnconv'       convert the UTF-8 string to ACE.

    'encode_app'    perform 'localconv', 'delimmap', 'localmap',
                    'nameprep' and 'idnconv'.  This is the default
                    value of @actions.

Regardless of the order of elements in C<@actions>, the actions are
always performed in the following order; C<'localconv'>, C<'delimmap'>,
C<'localmap'>, C<'nameprep'> and C<'idnconv'>.

If an error occurs, this method returns C<undef>.

=item decode_name($from [, @actions...])

Decodes domain name of C<$from> according with C<@actions>, and returns
the result.  This is the reverse of C<encode_name>.

Each element in C<@actions> is a string as follows:

    'idnconv'       convert the ACE string to UTF-8.
    'nameprep'      inspect if NAMEPREP has been performed to the
                    string.  If hasn't, convert the string to ACE.
    'localconv'     convert the UTF-8 string to the local encoding.

    'decode_app'    perform 'idnconv', 'nameprep' and 'localconv'.
                    This is the default value of @actions.

Regardless of the order of elements in C<@actions>, those actions
are always performed in the following order; C<'idnconv'>,
C<'nameprep'> and C<'localconv'>.

If an error occurs, this method returns C<undef>.

=item enable($on_off)

Enable or disable mulitilingual domain name support provided by
libmdn.
If C<$on_off> is zero, the support is disabled, otherwise enabled.
If this method has not been called, the C<MDN_DISABLE> environment
variabe is used to determine whether mulitilingual domain name
support is enabled.
The support is disabled if that variable is defined, 

In disabled condition, conversion methods (e.g. C<encode_name()>
and C<decode_name()>) simply return a copy of input string as the
result of conversion.

=item lasterror()

Returns the error message string corresponding to the last error
occurred in this module.

=item local_to_utf8($from)

Is equivalent to C<encode_name($from, 'localconv')>.

=item utf8_to_local($from)

Is equivalent to C<decode_name($from, 'localconv')>.

=item delimiter_map($from)

Is equivalent to C<encode_name($from, 'delimmap')>.

=item local_map($from)

Is equivalent to C<encode_name($from, 'localmap')>.

=item nameprep($from)

Is equivalent to C<encode_name($from, 'nameprep')>.

=item nameprep_check($from)

Is equivalent to C<decode_name($from, 'nameprep')>.

=item utf8_to_idn($from)

Is equivalent to C<encode_name($from, 'idnconv')>.

=item idn_to_utf8($from)

Is equivalent to C<decode_name($from, 'idnconv')>.

=item local_to_idn($from)

Is equivalent to C<encode_name($from)>.

=item idn_to_local($from)

Is equivalent to C<decode_name($from)>.

=back

=head1 COMPATIBILITY

Beginning with version 2.4, the action C<'nameprep'> of C<encode_name()>
and C<decode_name()> also performs unassigned codepoint check.
The C<'unascheck'> action and the C<unassigned_check()> method are no
longer supported.

=head1 ISSUE OF HANDLING UNICODE CHARACTERS

See the ``ISSUE OF HANDLING UNICODE CHARACTERS'' section in
L<MDN::UTF8>.

=head1 SEE ALSO

L<mdn.conf(5)>, L<MDN::ResConf>, L<MDN::UTF8>

MDN library specification

=cut
