    001    package org.apache.turbine.util;
    002
    003    /*
    004     * Licensed to the Apache Software Foundation (ASF) under one
    005     * or more contributor license agreements.  See the NOTICE file
    006     * distributed with this work for additional information
    007     * regarding copyright ownership.  The ASF licenses this file
    008     * to you under the Apache License, Version 2.0 (the
    009     * "License"); you may not use this file except in compliance
    010     * with the License.  You may obtain a copy of the License at
    011     *
    012     *   http://www.apache.org/licenses/LICENSE-2.0
    013     *
    014     * Unless required by applicable law or agreed to in writing,
    015     * software distributed under the License is distributed on an
    016     * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    017     * KIND, either express or implied.  See the License for the
    018     * specific language governing permissions and limitations
    019     * under the License.
    020     */
    021
    022    /**
    023     * This class parses the user agent string and sets javasciptOK and
    024     * cssOK following the rules described below.  If you want to check
    025     * for specific browsers/versions then use this class to parse the
    026     * user agent string and use the accessor methods in this class.
    027     *
    028     * JavaScriptOK means that the browser understands JavaScript on the
    029     * same level the Navigator 3 does.  Specifically, it can use named
    030     * images.  This allows easier rollovers.  If a browser doesn't do
    031     * this (Nav 2 or MSIE 3), then we just assume it can't do any
    032     * JavaScript.  Referencing images by load order is too hard to
    033     * maintain.
    034     *
    035     * CSSOK is kind of sketchy in that Nav 4 and MSIE work differently,
    036     * but they do seem to have most of the functionality.  MSIE 4 for the
    037     * Mac has buggy CSS support, so we let it do JavaScript, but no CSS.
    038     *
    039     * Ported from Leon's PHP code at
    040     * http://www.working-dogs.com/freetrade by Frank.
    041     *
    042     * @author <a href="mailto:frank.kim@clearink.com">Frank Y. Kim</a>
    043     * @author <a href="mailto:leon@clearink.com">Leon Atkisnon</a>
    044     * @author <a href="mailto:mospaw@polk-county.com">Chris Mospaw</a>
    045     * @author <a href="mailto:bgriffin@cddb.com">Benjamin Elijah Griffin</a>
    046     * @version $Id: BrowserDetector.java 615328 2008-01-25 20:25:05Z tv $
    047     */
    048    public class BrowserDetector
    049    {
    050        public static final String MSIE = "MSIE";
    051        public static final String OPERA = "Opera";
    052        public static final String MOZILLA = "Mozilla";
    053
    054        public static final String WINDOWS = "Windows";
    055        public static final String UNIX = "Unix";
    056        public static final String MACINTOSH = "Macintosh";
    057
    058        /** The user agent string. */
    059        private String userAgentString = "";
    060
    061        /** The browser name specified in the user agent string. */
    062        private String browserName = "";
    063
    064        /**
    065         * The browser version specified in the user agent string.  If we
    066         * can't parse the version just assume an old browser.
    067         */
    068        private float browserVersion = (float) 1.0;
    069
    070        /**
    071         * The browser platform specified in the user agent string.
    072         */
    073        private String browserPlatform = "unknown";
    074
    075        /** Whether or not javascript works in this browser. */
    076        private boolean javascriptOK = false;
    077
    078        /** Whether or not CSS works in this browser. */
    079        private boolean cssOK = false;
    080
    081        /** Whether or not file upload works in this browser. */
    082        private boolean fileUploadOK = false;
    083
    084        /**
    085         * Constructor used to initialize this class.
    086         *
    087         * @param userAgentString A String with the user agent field.
    088         */
    089        public BrowserDetector(String userAgentString)
    090        {
    091            this.userAgentString = userAgentString;
    092            parse();
    093        }
    094
    095        /**
    096         * Constructor used to initialize this class.
    097         *
    098         * @param data The Turbine RunData object.
    099         */
    100        public BrowserDetector(RunData data)
    101        {
    102            this.userAgentString = data.getUserAgent();
    103            parse();
    104        }
    105
    106        /**
    107         * Whether or not CSS works in this browser.
    108         *
    109         * @return True if CSS works in this browser.
    110         */
    111        public boolean isCssOK()
    112        {
    113            return cssOK;
    114        }
    115
    116        /**
    117         * Whether or not file upload works in this browser.
    118         *
    119         * @return True if file upload works in this browser.
    120         */
    121        public boolean isFileUploadOK()
    122        {
    123            return fileUploadOK;
    124        }
    125
    126        /**
    127         * Whether or not Javascript works in this browser.
    128         *
    129         * @return True if Javascript works in this browser.
    130         */
    131        public boolean isJavascriptOK()
    132        {
    133            return javascriptOK;
    134        }
    135
    136        /**
    137         * The browser name specified in the user agent string.
    138         *
    139         * @return A String with the browser name.
    140         */
    141        public String getBrowserName()
    142        {
    143            return browserName;
    144        }
    145
    146        /**
    147         * The browser platform specified in the user agent string.
    148         *
    149         * @return A String with the browser platform.
    150         */
    151        public String getBrowserPlatform()
    152        {
    153            return browserPlatform;
    154        }
    155
    156        /**
    157         * The browser version specified in the user agent string.
    158         *
    159         * @return A String with the browser version.
    160         */
    161        public float getBrowserVersion()
    162        {
    163            return browserVersion;
    164        }
    165
    166        /**
    167         * The user agent string for this class.
    168         *
    169         * @return A String with the user agent.
    170         */
    171        public String getUserAgentString()
    172        {
    173            return userAgentString;
    174        }
    175
    176        /**
    177         * Helper method to initialize this class.
    178         */
    179        private void parse()
    180        {
    181            int versionStartIndex = userAgentString.indexOf("/");
    182            int versionEndIndex = userAgentString.indexOf(" ");
    183
    184            // Get the browser name and version.
    185            browserName = userAgentString.substring(0, versionStartIndex);
    186            try
    187            {
    188                // Not all user agents will have a space in the reported
    189                // string.
    190                String agentSubstring = null;
    191                if (versionEndIndex < 0)
    192                {
    193                    agentSubstring
    194                            = userAgentString.substring(versionStartIndex + 1);
    195                }
    196                else
    197                {
    198                    agentSubstring = userAgentString
    199                            .substring(versionStartIndex + 1, versionEndIndex);
    200                }
    201                browserVersion = toFloat(agentSubstring);
    202            }
    203            catch (NumberFormatException e)
    204            {
    205                // Just use the default value.
    206            }
    207
    208            // MSIE lies about its name.  Of course...
    209            if (userAgentString.indexOf(MSIE) != -1)
    210            {
    211                // Ex: Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)
    212                versionStartIndex = (userAgentString.indexOf(MSIE)
    213                        + MSIE.length() + 1);
    214                versionEndIndex = userAgentString.indexOf(";", versionStartIndex);
    215
    216                browserName = MSIE;
    217                try
    218                {
    219                    browserVersion = toFloat(userAgentString
    220                            .substring(versionStartIndex, versionEndIndex));
    221                }
    222                catch (NumberFormatException e)
    223                {
    224                    // Just use the default value.
    225                }
    226
    227                // PHP code
    228                // $Browser_Name = "MSIE";
    229                // $Browser_Version = strtok("MSIE");
    230                // $Browser_Version = strtok(" ");
    231                // $Browser_Version = strtok(";");
    232            }
    233
    234            // Opera isn't completely honest, either...
    235            // Modificaton by Chris Mospaw <mospaw@polk-county.com>
    236            if (userAgentString.indexOf(OPERA) != -1)
    237            {
    238                // Ex: Mozilla/4.0 (Windows NT 4.0;US) Opera 3.61  [en]
    239                // Ex: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; en) Opera 8.02
    240                versionStartIndex = (userAgentString.indexOf(OPERA)
    241                        + OPERA.length() + 1);
    242                versionEndIndex = userAgentString.indexOf(" ", versionStartIndex);
    243                if (versionEndIndex == -1)
    244                {
    245                    versionEndIndex = userAgentString.length();
    246                }
    247
    248                browserName = OPERA;
    249                try
    250                {
    251                    browserVersion = toFloat(userAgentString
    252                            .substring(versionStartIndex, versionEndIndex));
    253                }
    254                catch (NumberFormatException e)
    255                {
    256                    // Just use the default value.
    257                }
    258
    259                // PHP code
    260                // $Browser_Name = "Opera";
    261                // $Browser_Version = strtok("Opera");
    262                // $Browser_Version = strtok("/");
    263                // $Browser_Version = strtok(";");
    264            }
    265
    266
    267            // Try to figure out what platform.
    268            if ((userAgentString.indexOf("Windows") != -1)
    269                    || (userAgentString.indexOf("WinNT") != -1)
    270                    || (userAgentString.indexOf("Win98") != -1)
    271                    || (userAgentString.indexOf("Win95") != -1))
    272            {
    273                browserPlatform = WINDOWS;
    274            }
    275
    276            if (userAgentString.indexOf("Mac") != -1)
    277            {
    278                browserPlatform = MACINTOSH;
    279            }
    280
    281            if (userAgentString.indexOf("X11") != -1)
    282            {
    283                browserPlatform = UNIX;
    284            }
    285
    286            if (browserPlatform == WINDOWS)
    287            {
    288                if (browserName.equals(MOZILLA))
    289                {
    290                    if (browserVersion >= 3.0)
    291                    {
    292                        javascriptOK = true;
    293                        fileUploadOK = true;
    294                    }
    295                    if (browserVersion >= 4.0)
    296                    {
    297                        cssOK = true;
    298                    }
    299                }
    300                else if (browserName == MSIE)
    301                {
    302                    if (browserVersion >= 4.0)
    303                    {
    304                        javascriptOK = true;
    305                        fileUploadOK = true;
    306                        cssOK = true;
    307                    }
    308                }
    309                else if (browserName == OPERA)
    310                {
    311                    if (browserVersion >= 3.0)
    312                    {
    313                        javascriptOK = true;
    314                        fileUploadOK = true;
    315                        cssOK = true;
    316                    }
    317                }
    318            }
    319            else if (browserPlatform == MACINTOSH)
    320            {
    321                if (browserName.equals(MOZILLA))
    322                {
    323                    if (browserVersion >= 3.0)
    324                    {
    325                        javascriptOK = true;
    326                        fileUploadOK = true;
    327                    }
    328                    if (browserVersion >= 4.0)
    329                    {
    330                        cssOK = true;
    331                    }
    332                }
    333                else if (browserName == MSIE)
    334                {
    335                    if (browserVersion >= 4.0)
    336                    {
    337                        javascriptOK = true;
    338                        fileUploadOK = true;
    339                    }
    340                    if (browserVersion > 4.0)
    341                    {
    342                        cssOK = true;
    343                    }
    344                }
    345            }
    346            else if (browserPlatform == UNIX)
    347            {
    348                if (browserName.equals(MOZILLA))
    349                {
    350                    if (browserVersion >= 3.0)
    351                    {
    352                        javascriptOK = true;
    353                        fileUploadOK = true;
    354                    }
    355                    if (browserVersion >= 4.0)
    356                    {
    357                        cssOK = true;
    358                    }
    359                }
    360            }
    361        }
    362
    363        /**
    364         * Helper method to convert String to a float.
    365         *
    366         * @param s A String.
    367         * @return The String converted to float.
    368         */
    369        private static final float toFloat(String s)
    370        {
    371            return Float.valueOf(s).floatValue();
    372        }
    373
    374    }