    001package 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 1706239 2015-10-01 13:18:35Z tv $
    047 */
    048public class BrowserDetector
    049{
    050    /** Internet Explorer */
    051    public static final String MSIE = "MSIE";
    052    /** Opera */
    053    public static final String OPERA = "Opera";
    054    /** Mozilla, Firefox and friends */
    055    public static final String MOZILLA = "Mozilla";
    056
    057    /** Running on Windows */
    058    public static final String WINDOWS = "Windows";
    059    /** Running on Unix */
    060    public static final String UNIX = "Unix";
    061    /** Running on Mac OS X */
    062    public static final String MACINTOSH = "Macintosh";
    063
    064    /** The user agent string. */
    065    private String userAgentString = "";
    066
    067    /** The browser name specified in the user agent string. */
    068    private String browserName = "";
    069
    070    /**
    071     * The browser version specified in the user agent string.  If we
    072     * can't parse the version just assume an old browser.
    073     */
    074    private float browserVersion = (float) 1.0;
    075
    076    /**
    077     * The browser platform specified in the user agent string.
    078     */
    079    private String browserPlatform = "unknown";
    080
    081    /** Whether or not javascript works in this browser. */
    082    private boolean javascriptOK = false;
    083
    084    /** Whether or not CSS works in this browser. */
    085    private boolean cssOK = false;
    086
    087    /** Whether or not file upload works in this browser. */
    088    private boolean fileUploadOK = false;
    089
    090    /**
    091     * Constructor used to initialize this class.
    092     *
    093     * @param userAgentString A String with the user agent field.
    094     */
    095    public BrowserDetector(String userAgentString)
    096    {
    097        this.userAgentString = userAgentString;
    098        parse();
    099    }
    100
    101    /**
    102     * Constructor used to initialize this class.
    103     *
    104     * @param data The Turbine RunData object.
    105     */
    106    public BrowserDetector(RunData data)
    107    {
    108        this.userAgentString = data.getUserAgent();
    109        parse();
    110    }
    111
    112    /**
    113     * Whether or not CSS works in this browser.
    114     *
    115     * @return True if CSS works in this browser.
    116     */
    117    public boolean isCssOK()
    118    {
    119        return cssOK;
    120    }
    121
    122    /**
    123     * Whether or not file upload works in this browser.
    124     *
    125     * @return True if file upload works in this browser.
    126     */
    127    public boolean isFileUploadOK()
    128    {
    129        return fileUploadOK;
    130    }
    131
    132    /**
    133     * Whether or not Javascript works in this browser.
    134     *
    135     * @return True if Javascript works in this browser.
    136     */
    137    public boolean isJavascriptOK()
    138    {
    139        return javascriptOK;
    140    }
    141
    142    /**
    143     * The browser name specified in the user agent string.
    144     *
    145     * @return A String with the browser name.
    146     */
    147    public String getBrowserName()
    148    {
    149        return browserName;
    150    }
    151
    152    /**
    153     * The browser platform specified in the user agent string.
    154     *
    155     * @return A String with the browser platform.
    156     */
    157    public String getBrowserPlatform()
    158    {
    159        return browserPlatform;
    160    }
    161
    162    /**
    163     * The browser version specified in the user agent string.
    164     *
    165     * @return A String with the browser version.
    166     */
    167    public float getBrowserVersion()
    168    {
    169        return browserVersion;
    170    }
    171
    172    /**
    173     * The user agent string for this class.
    174     *
    175     * @return A String with the user agent.
    176     */
    177    public String getUserAgentString()
    178    {
    179        return userAgentString;
    180    }
    181
    182    /**
    183     * Helper method to initialize this class.
    184     */
    185    private void parse()
    186    {
    187        int versionStartIndex = userAgentString.indexOf("/");
    188        int versionEndIndex = userAgentString.indexOf(" ");
    189
    190        // Get the browser name and version.
    191        browserName = userAgentString.substring(0, versionStartIndex);
    192        try
    193        {
    194            // Not all user agents will have a space in the reported
    195            // string.
    196            String agentSubstring = null;
    197            if (versionEndIndex < 0)
    198            {
    199                agentSubstring
    200                        = userAgentString.substring(versionStartIndex + 1);
    201            }
    202            else
    203            {
    204                agentSubstring = userAgentString
    205                        .substring(versionStartIndex + 1, versionEndIndex);
    206            }
    207            browserVersion = toFloat(agentSubstring);
    208        }
    209        catch (NumberFormatException e)
    210        {
    211            // Just use the default value.
    212        }
    213
    214        // MSIE lies about its name.  Of course...
    215        if (userAgentString.indexOf(MSIE) != -1)
    216        {
    217            // Ex: Mozilla/4.0 (compatible; MSIE 5.0; Windows NT; DigExt)
    218            versionStartIndex = (userAgentString.indexOf(MSIE)
    219                    + MSIE.length() + 1);
    220            versionEndIndex = userAgentString.indexOf(";", versionStartIndex);
    221
    222            browserName = MSIE;
    223            try
    224            {
    225                browserVersion = toFloat(userAgentString
    226                        .substring(versionStartIndex, versionEndIndex));
    227            }
    228            catch (NumberFormatException e)
    229            {
    230                // Just use the default value.
    231            }
    232
    233            // PHP code
    234            // $Browser_Name = "MSIE";
    235            // $Browser_Version = strtok("MSIE");
    236            // $Browser_Version = strtok(" ");
    237            // $Browser_Version = strtok(";");
    238        }
    239
    240        // Opera isn't completely honest, either...
    241        // Modificaton by Chris Mospaw <mospaw@polk-county.com>
    242        if (userAgentString.indexOf(OPERA) != -1)
    243        {
    244            // Ex: Mozilla/4.0 (Windows NT 4.0;US) Opera 3.61  [en]
    245            // Ex: Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; en) Opera 8.02
    246            versionStartIndex = (userAgentString.indexOf(OPERA)
    247                    + OPERA.length() + 1);
    248            versionEndIndex = userAgentString.indexOf(" ", versionStartIndex);
    249            if (versionEndIndex == -1)
    250            {
    251                versionEndIndex = userAgentString.length();
    252            }
    253
    254            browserName = OPERA;
    255            try
    256            {
    257                browserVersion = toFloat(userAgentString
    258                        .substring(versionStartIndex, versionEndIndex));
    259            }
    260            catch (NumberFormatException e)
    261            {
    262                // Just use the default value.
    263            }
    264
    265            // PHP code
    266            // $Browser_Name = "Opera";
    267            // $Browser_Version = strtok("Opera");
    268            // $Browser_Version = strtok("/");
    269            // $Browser_Version = strtok(";");
    270        }
    271
    272
    273        // Try to figure out what platform.
    274        if ((userAgentString.indexOf("Windows") != -1)
    275                || (userAgentString.indexOf("WinNT") != -1)
    276                || (userAgentString.indexOf("Win98") != -1)
    277                || (userAgentString.indexOf("Win95") != -1))
    278        {
    279            browserPlatform = WINDOWS;
    280        }
    281
    282        if (userAgentString.indexOf("Mac") != -1)
    283        {
    284            browserPlatform = MACINTOSH;
    285        }
    286
    287        if (userAgentString.indexOf("X11") != -1)
    288        {
    289            browserPlatform = UNIX;
    290        }
    291
    292        if (browserPlatform == WINDOWS)
    293        {
    294            if (browserName.equals(MOZILLA))
    295            {
    296                if (browserVersion >= 3.0)
    297                {
    298                    javascriptOK = true;
    299                    fileUploadOK = true;
    300                }
    301                if (browserVersion >= 4.0)
    302                {
    303                    cssOK = true;
    304                }
    305            }
    306            else if (browserName == MSIE)
    307            {
    308                if (browserVersion >= 4.0)
    309                {
    310                    javascriptOK = true;
    311                    fileUploadOK = true;
    312                    cssOK = true;
    313                }
    314            }
    315            else if (browserName == OPERA)
    316            {
    317                if (browserVersion >= 3.0)
    318                {
    319                    javascriptOK = true;
    320                    fileUploadOK = true;
    321                    cssOK = true;
    322                }
    323            }
    324        }
    325        else if (browserPlatform == MACINTOSH)
    326        {
    327            if (browserName.equals(MOZILLA))
    328            {
    329                if (browserVersion >= 3.0)
    330                {
    331                    javascriptOK = true;
    332                    fileUploadOK = true;
    333                }
    334                if (browserVersion >= 4.0)
    335                {
    336                    cssOK = true;
    337                }
    338            }
    339            else if (browserName == MSIE)
    340            {
    341                if (browserVersion >= 4.0)
    342                {
    343                    javascriptOK = true;
    344                    fileUploadOK = true;
    345                }
    346                if (browserVersion > 4.0)
    347                {
    348                    cssOK = true;
    349                }
    350            }
    351        }
    352        else if (browserPlatform == UNIX)
    353        {
    354            if (browserName.equals(MOZILLA))
    355            {
    356                if (browserVersion >= 3.0)
    357                {
    358                    javascriptOK = true;
    359                    fileUploadOK = true;
    360                }
    361                if (browserVersion >= 4.0)
    362                {
    363                    cssOK = true;
    364                }
    365            }
    366        }
    367    }
    368
    369    /**
    370     * Helper method to convert String to a float.
    371     *
    372     * @param s A String.
    373     * @return The String converted to float.
    374     */
    375    private static final float toFloat(String s)
    376    {
    377        return Float.valueOf(s).floatValue();
    378    }
    379
    380}