001    /*
002     *  Licensed to the Apache Software Foundation (ASF) under one
003     *  or more contributor license agreements.  See the NOTICE file
004     *  distributed with this work for additional information
005     *  regarding copyright ownership.  The ASF licenses this file
006     *  to you under the Apache License, Version 2.0 (the
007     *  "License"); you may not use this file except in compliance
008     *  with the License.  You may obtain a copy of the License at
009     *  
010     *    http://www.apache.org/licenses/LICENSE-2.0
011     *  
012     *  Unless required by applicable law or agreed to in writing,
013     *  software distributed under the License is distributed on an
014     *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015     *  KIND, either express or implied.  See the License for the
016     *  specific language governing permissions and limitations
017     *  under the License. 
018     *  
019     */
020    package org.apache.directory.shared.ldap.schema.syntaxCheckers;
021    
022    
023    import org.apache.directory.shared.ldap.constants.SchemaConstants;
024    import org.apache.directory.shared.ldap.schema.SyntaxChecker;
025    import org.apache.directory.shared.ldap.util.StringTools;
026    import org.slf4j.Logger;
027    import org.slf4j.LoggerFactory;
028    
029    
030    /**
031     * A SyntaxChecker which verifies that a value is a TeletexTerminalIdentifier according to 
032     * RFC 4517 :
033     * 
034     * teletex-id = ttx-term *(DOLLAR ttx-param)
035     * ttx-term   = PrintableString          ; terminal identifier
036     * ttx-param  = ttx-key COLON ttx-value  ; parameter
037     * ttx-key    = "graphic" | "control" | "misc" | "page" | "private"
038     * ttx-value  = *ttx-value-octet
039     *
040     * ttx-value-octet = %x00-23 | (%x5C "24") | %x25-5B | (%x5C "5C") | %x5D-FF
041     * 
042     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
043     * @version $Rev$
044     */
045    public class TeletexTerminalIdentifierSyntaxChecker extends SyntaxChecker
046    {
047        /** A logger for this class */
048        private static final Logger LOG = LoggerFactory.getLogger( TeletexTerminalIdentifierSyntaxChecker.class );
049    
050        /** The serialVersionUID */
051        private static final long serialVersionUID = 1L;
052    
053        /**
054         * Creates a new instance of TeletexTerminalIdentifier.
055         */
056        public TeletexTerminalIdentifierSyntaxChecker()
057        {
058            super( SchemaConstants.TELETEX_TERMINAL_IDENTIFIER_SYNTAX );
059        }
060        
061        
062        /**
063         * {@inheritDoc}
064         */
065        public boolean isValidSyntax( Object value )
066        {
067            String strValue = null;
068    
069            if ( value == null )
070            {
071                LOG.debug( "Syntax invalid for '{}'", value );
072                return false;
073            }
074            
075            if ( value instanceof String )
076            {
077                strValue = ( String ) value;
078            }
079            else if ( value instanceof byte[] )
080            {
081                strValue = StringTools.utf8ToString( ( byte[] ) value ); 
082            }
083            else
084            {
085                strValue = value.toString();
086            }
087    
088            if ( strValue.length() == 0 )
089            {
090                LOG.debug( "Syntax invalid for '{}'", value );
091                return false;
092            }
093    
094            // Search for the first '$' separator
095            int dollar = strValue.indexOf( '$' );
096            
097            String terminalIdentifier = ( ( dollar == -1 ) ? strValue : strValue.substring( 0, dollar ) );
098            
099            if ( terminalIdentifier.length() == 0 )
100            {
101                // It should not be null
102                LOG.debug( "Syntax invalid for '{}'", value );
103                return false;
104            }
105            
106            if ( !StringTools.isPrintableString( terminalIdentifier ) )
107            {
108                // It's not a valid PrintableString 
109                LOG.debug( "Syntax invalid for '{}'", value );
110                return false;
111            }
112            
113            if ( dollar == -1 )
114            {
115                // No ttx-param : let's get out
116                LOG.debug( "Syntax valid for '{}'", value );
117                return true;
118            }
119            
120            // Ok, now let's deal withh optional ttx-params
121            String[] ttxParams = strValue.substring( dollar + 1 ).split( "\\$" );
122            
123            if ( ttxParams.length == 0 )
124            {
125                LOG.debug( "Syntax invalid for '{}'", value );
126                return false;
127            }
128            
129            for ( String ttxParam:ttxParams )
130            {
131                int colon = ttxParam.indexOf( ':' );
132                
133                if ( colon == -1 )
134                {
135                    // we must have a ':' separator
136                    LOG.debug( "Syntax invalid for '{}'", value );
137                    return false;
138                }
139                
140                String key = ttxParam.substring( 0, colon );
141                
142                if ( key.startsWith( "graphic" ) ||
143                     key.startsWith( "control" ) ||
144                     key.startsWith( "misc" ) ||
145                     key.startsWith( "page" ) ||
146                     key.startsWith( "private" ) )
147                {
148                    if ( colon + 1 == ttxParam.length() )
149                    {
150                        LOG.debug( "Syntax invalid for '{}'", value );
151                        return false;
152                    }
153                    
154                    boolean hasEsc = false;
155                    
156                    for ( byte b:StringTools.getBytesUtf8( ttxParam ) )
157                    {
158                        switch ( b )
159                        {
160                            case 0x24 :
161                                // '$' is not accepted
162                                LOG.debug( "Syntax invalid for '{}'", value );
163                                return false;
164                                
165                            case 0x5c :
166                                if ( hasEsc )
167                                {
168                                    // two following \ are not accepted
169                                    LOG.debug( "Syntax invalid for '{}'", value );
170                                    return false;
171                                }
172                                else
173                                {
174                                    hasEsc = true;
175                                }
176                                
177                                continue;
178                            
179                            case '2' :
180                                continue;
181    
182                            case '4' :
183                                // We have found a "\24"
184                                hasEsc = false;
185                                continue;
186                                
187                            case '5' :
188                                continue;
189    
190                            case 'c' :
191                            case 'C' :
192                                // We have found a "\5c" or a "\5C"
193                                hasEsc = false;
194                                continue;
195                                
196                            default :
197                                if ( hasEsc )
198                                {
199                                    // A \ should be followed by "24" or "5c" or "5C"
200                                    return false;
201                                }
202                                
203                            continue;
204                        }
205                    }
206                }
207                else
208                {
209                    LOG.debug( "Syntax invalid for '{}'", value );
210                    return false;
211                }
212            }
213            
214            LOG.debug( "Syntax valid for '{}'", value );
215            return true;
216        }
217    }