1# --
2# Copyright (C) 2001-2020 OTRS AG, https://otrs.com/
3# --
4# This software comes with ABSOLUTELY NO WARRANTY. For details, see
5# the enclosed file COPYING for license information (GPL). If you
6# did not receive this file, see https://www.gnu.org/licenses/gpl-3.0.txt.
7# --
8
9package Kernel::System::SysConfig::XML;
10
11use strict;
12use warnings;
13
14our @ObjectDependencies = (
15    'Kernel::System::Log',
16    'Kernel::System::XML::Simple',
17);
18
19use Kernel::System::VariableCheck qw( :all );
20
21=head1 NAME
22
23Kernel::System::SysConfig::XML - Manage system configuration settings in XML.
24
25=head1 PUBLIC INTERFACE
26
27=head2 new()
28
29Create an object. Do not use it directly, instead use:
30
31    use Kernel::System::ObjectManager;
32    local $Kernel::OM = Kernel::System::ObjectManager->new();
33    my $SysConfigXMLObject = $Kernel::OM->Get('Kernel::System::SysConfig::XML');
34
35=cut
36
37sub new {
38    my ( $Type, %Param ) = @_;
39
40    # allocate new hash for object
41    my $Self = {};
42    bless( $Self, $Type );
43
44    return $Self;
45}
46
47=head2 SettingListParse()
48
49Parses XML files into a list of perl structures and meta data.
50
51    my $PerlStructure = $SysConfigXMLObject->SettingListParse(
52        XMLInput => '
53            <?xml version="1.0" encoding="utf-8"?>
54            <otrs_config version="2.0" init="Application">
55                <Setting Name="Test1" Required="1" Valid="1">
56                    <Description Translatable="1">Test 1.</Description>
57                    <Navigation>Core::Ticket</Navigation>
58                    <Value>
59                        <Item ValueType="String" ValueRegex=".*">123</Item>
60                    </Value>
61                </Setting>
62                <Setting Name="Test2" Required="1" Valid="1">
63                    <Description Translatable="1">Test 2.</Description>
64                    <Navigation>Core::Ticket</Navigation>
65                    <Value>
66                        <Item ValueType="File">/usr/bin/gpg</Item>
67                    </Value>
68                </Setting>
69            </otrs_config>
70        ',
71        XMLFilename => 'Test.xml'
72    );
73
74Returns:
75
76    [
77        {
78            XMLContentParsed => {
79                Description => [
80                    {
81                        Content      => 'Test.',
82                        Translatable => '1',
83                    },
84                ],
85                Name  => 'Test',
86                Required => '1',
87                Value => [
88                    {
89                        Item => [
90                            {
91                                ValueRegex => '.*',
92                                ValueType  => 'String',
93                                Content    => '123',
94                            },
95                        ],
96                    },
97                ],
98                Navigation => [
99                    {
100                        Content => 'Core::Ticket',
101                    },
102                ],
103                Valid => '1',
104            },
105            XMLContentRaw => '<Setting Name="Test1" Required="1" Valid="1">
106                <Description Translatable="1">Test 1.</Description>
107                <Navigation>Core::Ticket</Navigation>
108                <Value>
109                    <Item ValueType="String" ValueRegex=".*">123</Item>
110                </Value>
111            </Setting>',
112            XMLFilename => 'Test.xml'
113        },
114    ]
115
116=cut
117
118sub SettingListParse {
119    my ( $Type, %Param ) = @_;
120
121    if ( !IsStringWithData( $Param{XMLInput} ) ) {
122        $Kernel::OM->Get('Kernel::System::Log')->Log(
123            Priority => 'error',
124            Message  => "Parameter XMLInput needs to be a string!",
125        );
126        return;
127    }
128
129    my $XMLSimpleObject = $Kernel::OM->Get('Kernel::System::XML::Simple');
130
131    my $XMLContent = $Param{XMLInput};
132
133    # Remove all lines that starts with comment (#).
134    $XMLContent =~ s{^#.*?$}{}gm;
135
136    # Remove comments <!-- ... -->.
137    $XMLContent =~ s{<!--.*?-->}{}gsm;
138
139    $XMLContent =~ m{otrs_config.*?version="(.*?)"};
140    my $ConfigVersion = $1;
141
142    if ( $ConfigVersion ne '2.0' ) {
143        $Kernel::OM->Get('Kernel::System::Log')->Log(
144            Priority => 'error',
145            Message  => "Invalid XML format found in $Param{XMLFilename} (version must be 2.0)! File skipped.",
146        );
147        return;
148    }
149
150    while ( $XMLContent =~ m{<ConfigItem.*?Name="(.*?)"}smxg ) {
151
152        # Old style ConfigItem detected.
153        my $SettingName = $1;
154
155        $Kernel::OM->Get('Kernel::System::Log')->Log(
156            Priority => 'error',
157            Message  => "Old ConfigItem $SettingName detected in $Param{XMLFilename}!"
158        );
159    }
160
161    # Fetch XML of Setting elements.
162    my @ParsedSettings;
163
164    SETTING:
165    while (
166        $XMLContent =~ m{(?<RawSetting> <Setting[ ]+ .*? Name="(?<SettingName> .*? )" .*? > .*? </Setting> )}smxg
167        )
168    {
169
170        my $RawSetting  = $+{RawSetting};
171        my $SettingName = $+{SettingName};
172
173        next SETTING if !IsStringWithData($RawSetting);
174        next SETTING if !IsStringWithData($SettingName);
175
176        my $PerlStructure = $XMLSimpleObject->XMLIn(
177            XMLInput => $RawSetting,
178            Options  => {
179                KeepRoot     => 1,
180                ForceArray   => 1,
181                ForceContent => 1,
182                ContentKey   => 'Content',
183            },
184        );
185
186        if ( !IsHashRefWithData($PerlStructure) ) {
187            $Kernel::OM->Get('Kernel::System::Log')->Log(
188                Priority => 'error',
189                Message  => "Resulting Perl structure must be a hash reference with data!",
190            );
191            next SETTING;
192        }
193
194        if ( !IsArrayRefWithData( $PerlStructure->{Setting} ) ) {
195            $Kernel::OM->Get('Kernel::System::Log')->Log(
196                Priority => 'error',
197                Message  => "Resulting Perl structure must have Setting elements!",
198            );
199            next SETTING;
200        }
201
202        push @ParsedSettings, {
203            XMLContentParsed => $PerlStructure->{Setting}->[0],
204            XMLContentRaw    => $RawSetting,
205            XMLFilename      => $Param{XMLFilename},
206        };
207    }
208
209    return @ParsedSettings;
210}
211
2121;
213
214=head1 TERMS AND CONDITIONS
215
216This software is part of the OTRS project (L<https://otrs.org/>).
217
218This software comes with ABSOLUTELY NO WARRANTY. For details, see
219the enclosed file COPYING for license information (GPL). If you
220did not receive this file, see L<https://www.gnu.org/licenses/gpl-3.0.txt>.
221
222=cut
223