//# 3 errors, 525 messages
//#
/*
    //#URLHandler.java:1:1: class: com.dmdirc.util.URLHandler
 * Copyright (c) 2006-2009 Chris Smith, Shane Mc Cormack, Gregory Holmes
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

package com.dmdirc.util;

import com.dmdirc.Main;
import com.dmdirc.config.ConfigManager;
import com.dmdirc.config.IdentityManager;
import com.dmdirc.logger.ErrorLevel;
import com.dmdirc.logger.Logger;

import java.awt.Desktop;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/** Handles URLs. */
public class URLHandler {

    /** Config manager. */
    private final ConfigManager config;
    /** Singleton instance. */
    private static final URLHandler me = new URLHandler();
    //#URLHandler.java:46: method: com.dmdirc.util.URLHandler.com.dmdirc.util.URLHandler__static_init
    //#output(com.dmdirc.util.URLHandler__static_init): __Descendant_Table[com/dmdirc/util/URLHandler]
    //#output(com.dmdirc.util.URLHandler__static_init): __Dispatch_Table.execApp(Ljava/lang/String;)V
    //#output(com.dmdirc.util.URLHandler__static_init): __Dispatch_Table.execBrowser(Ljava/net/URI;)V
    //#output(com.dmdirc.util.URLHandler__static_init): __Dispatch_Table.execMail(Ljava/net/URI;)V
    //#output(com.dmdirc.util.URLHandler__static_init): __Dispatch_Table.launchApp(Ljava/lang/String;)V
    //#output(com.dmdirc.util.URLHandler__static_init): __Dispatch_Table.launchApp(Ljava/net/URI;)V
    //#output(com.dmdirc.util.URLHandler__static_init): __Dispatch_Table.launchApp(Ljava/net/URL;)V
    //#output(com.dmdirc.util.URLHandler__static_init): __Dispatch_Table.substituteParams(Ljava/net/URI;Ljava/lang/String;)Ljava/lang/String;
    //#output(com.dmdirc.util.URLHandler__static_init): me
    //#output(com.dmdirc.util.URLHandler__static_init): new URLHandler(URLHandler__static_init#1) num objects
    //#output(com.dmdirc.util.URLHandler__static_init): me.__Tag
    //#output(com.dmdirc.util.URLHandler__static_init): me.config
    //#output(com.dmdirc.util.URLHandler__static_init): me.desktop
    //#new obj(com.dmdirc.util.URLHandler__static_init): new URLHandler(URLHandler__static_init#1)
    //#post(com.dmdirc.util.URLHandler__static_init): __Descendant_Table[com/dmdirc/util/URLHandler] == &__Dispatch_Table
    //#post(com.dmdirc.util.URLHandler__static_init): __Dispatch_Table.execApp(Ljava/lang/String;)V == &execApp
    //#post(com.dmdirc.util.URLHandler__static_init): __Dispatch_Table.execBrowser(Ljava/net/URI;)V == &execBrowser
    //#post(com.dmdirc.util.URLHandler__static_init): __Dispatch_Table.execMail(Ljava/net/URI;)V == &execMail
    //#post(com.dmdirc.util.URLHandler__static_init): __Dispatch_Table.launchApp(Ljava/lang/String;)V == &launchApp
    //#post(com.dmdirc.util.URLHandler__static_init): __Dispatch_Table.launchApp(Ljava/net/URI;)V == &launchApp
    //#post(com.dmdirc.util.URLHandler__static_init): __Dispatch_Table.launchApp(Ljava/net/URL;)V == &launchApp
    //#post(com.dmdirc.util.URLHandler__static_init): __Dispatch_Table.substituteParams(Ljava/net/URI;Ljava/lang/String;)Ljava/lang/String; == &substituteParams
    //#post(com.dmdirc.util.URLHandler__static_init): me == &new URLHandler(URLHandler__static_init#1)
    //#post(com.dmdirc.util.URLHandler__static_init): new URLHandler(URLHandler__static_init#1) num objects == 1
    //#post(com.dmdirc.util.URLHandler__static_init): me.__Tag == com/dmdirc/util/URLHandler
    //#post(com.dmdirc.util.URLHandler__static_init): init'ed(me.config)
    //#post(com.dmdirc.util.URLHandler__static_init): init'ed(me.desktop)
    //#unanalyzed(com.dmdirc.util.URLHandler__static_init): Effects-of-calling:com.dmdirc.config.IdentityManager:getGlobalConfig
    //#unanalyzed(com.dmdirc.util.URLHandler__static_init): Effects-of-calling:java.awt.Desktop:isDesktopSupported
    //#unanalyzed(com.dmdirc.util.URLHandler__static_init): Effects-of-calling:java.awt.Desktop:getDesktop
    //#URLHandler.java:46: end of method: com.dmdirc.util.URLHandler.com.dmdirc.util.URLHandler__static_init
    /** Desktop handler. */
    private final Desktop desktop;
    /** The time a browser was last launched. */
    private static Date lastLaunch;

    /** Instantiates a new URL Handler. */
    private URLHandler() {
    //#URLHandler.java:53: method: void com.dmdirc.util.URLHandler.com.dmdirc.util.URLHandler()
    //#input(void com.dmdirc.util.URLHandler()): this
    //#output(void com.dmdirc.util.URLHandler()): this.config
    //#output(void com.dmdirc.util.URLHandler()): this.desktop
    //#post(void com.dmdirc.util.URLHandler()): init'ed(this.config)
    //#post(void com.dmdirc.util.URLHandler()): init'ed(this.desktop)
    //#test_vector(void com.dmdirc.util.URLHandler()): java.awt.Desktop:isDesktopSupported(...)@55: {0}, {1}
        config = IdentityManager.getGlobalConfig();
    //#URLHandler.java:54: Warning: method not available - call not analyzed
    //#    call on ConfigManager com.dmdirc.config.IdentityManager:getGlobalConfig()
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.util.URLHandler
    //#    method: void com.dmdirc.util.URLHandler()
    //#    unanalyzed callee: ConfigManager com.dmdirc.config.IdentityManager:getGlobalConfig()
        if (Desktop.isDesktopSupported()) {
            desktop = Desktop.getDesktop();
        } else {
            desktop = null;
        }
    }
    //#URLHandler.java:60: end of method: void com.dmdirc.util.URLHandler.com.dmdirc.util.URLHandler()

    /**
     * Gets an instance of URLHandler.
     *
     * @return URLHandler instance
     */
    public static URLHandler getURLHander() {
        synchronized (me) {
    //#URLHandler.java:68: method: URLHandler com.dmdirc.util.URLHandler.getURLHander()
    //#input(URLHandler getURLHander()): me
    //#input(URLHandler getURLHander()): return_value.__Lock
    //#output(URLHandler getURLHander()): return_value
    //#post(URLHandler getURLHander()): return_value == &new URLHandler(URLHandler__static_init#1)
            return me;
        }
    //#URLHandler.java:70: end of method: URLHandler com.dmdirc.util.URLHandler.getURLHander()
    }

    /**
     * Launches an application for a given url.
     *
     * @param urlString URL to parse
     */
    public void launchApp(final String urlString) {
        URI uri;
        try {
            uri = new URI(urlString);
    //#URLHandler.java:81: method: void com.dmdirc.util.URLHandler.launchApp(String)
    //#input(void launchApp(String)): ""._tainted
    //#input(void launchApp(String)): "#"._tainted
    //#input(void launchApp(String)): "?"._tainted
    //#input(void launchApp(String)): "Connecting to: "._tainted
    //#input(void launchApp(String)): "Invalid IRC Address: "._tainted
    //#input(void launchApp(String)): "Invalid URL: "._tainted
    //#input(void launchApp(String)): "Opening: "._tainted
    //#input(void launchApp(String)): "Unable to open URL: "._tainted
    //#input(void launchApp(String)): "http:.."._tainted
    //#input(void launchApp(String)): __Descendant_Table[com/dmdirc/util/URLHandler]
    //#input(void launchApp(String)): __Descendant_Table[others]
    //#input(void launchApp(String)): __Dispatch_Table.launchApp(Ljava/net/URI;)V
    //#input(void launchApp(String)): __Dispatch_Table.substituteParams(Ljava/net/URI;Ljava/lang/String;)Ljava/lang/String;
    //#input(void launchApp(String)): com.dmdirc.logger.ErrorLevel.LOW
    //#input(void launchApp(String)): com/dmdirc/ui/interfaces/StatusBar.__Descendant_Table[com/dmdirc/ui/interfaces/StatusBar]
    //#input(void launchApp(String)): com/dmdirc/ui/interfaces/StatusBar.__Descendant_Table[others]
    //#input(void launchApp(String)): com/dmdirc/ui/interfaces/StatusBar.__Dispatch_Table.setMessage(Ljava/lang/String;)V
    //#input(void launchApp(String)): com/dmdirc/ui/interfaces/UIController.__Descendant_Table[com/dmdirc/ui/interfaces/UIController]
    //#input(void launchApp(String)): com/dmdirc/ui/interfaces/UIController.__Descendant_Table[others]
    //#input(void launchApp(String)): com/dmdirc/ui/interfaces/UIController.__Dispatch_Table.getStatusBar()Lcom/dmdirc/ui/interfaces/StatusBar;
    //#input(void launchApp(String)): com/dmdirc/ui/interfaces/UIController.__Dispatch_Table.showURLDialog(Ljava/net/URI;)V
    //#input(void launchApp(String)): com/dmdirc/util/IrcAddress.__Descendant_Table[com/dmdirc/util/IrcAddress]
    //#input(void launchApp(String)): com/dmdirc/util/IrcAddress.__Descendant_Table[others]
    //#input(void launchApp(String)): com/dmdirc/util/IrcAddress.__Dispatch_Table.connect()V
    //#input(void launchApp(String)): com/dmdirc/util/IrcAddress.__Dispatch_Table.connect(Lcom/dmdirc/config/Identity;)V
    //#input(void launchApp(String)): com/dmdirc/util/IrcAddress.__Dispatch_Table.getChannels()Ljava/util/List;
    //#input(void launchApp(String)): com/dmdirc/util/IrcAddress.__Dispatch_Table.getPassword()Ljava/lang/String;
    //#input(void launchApp(String)): com/dmdirc/util/IrcAddress.__Dispatch_Table.getPort()I
    //#input(void launchApp(String)): com/dmdirc/util/IrcAddress.__Dispatch_Table.getServer()Ljava/lang/String;
    //#input(void launchApp(String)): com/dmdirc/util/IrcAddress.__Dispatch_Table.isSSL()Z
    //#input(void launchApp(String)): java.awt.Desktop$Action.BROWSE
    //#input(void launchApp(String)): java.awt.Desktop$Action.MAIL
    //#input(void launchApp(String)): lastLaunch
    //#input(void launchApp(String)): this
    //#input(void launchApp(String)): this.__Tag
    //#input(void launchApp(String)): this.config
    //#input(void launchApp(String)): this.desktop
    //#input(void launchApp(String)): urlString
    //#input(void launchApp(String)): urlString._tainted
    //#output(void launchApp(String)): lastLaunch
    //#output(void launchApp(String)): new Date(launchApp#1*) num objects
    //#new obj(void launchApp(String)): new Date(launchApp#1*)
    //#pre[1] (void launchApp(String)): (soft) init'ed(lastLaunch)
    //#pre[3] (void launchApp(String)): (soft) this.__Tag == com/dmdirc/util/URLHandler
    //#pre[4] (void launchApp(String)): (soft) this.config != null
    //#presumption(void launchApp(String)): init'ed(com.dmdirc.logger.ErrorLevel.LOW)
    //#post(void launchApp(String)): lastLaunch == One-of{old lastLaunch, &new Date(launchApp#1*)}
    //#post(void launchApp(String)): init'ed(lastLaunch)
    //#post(void launchApp(String)): new Date(launchApp#1*) num objects <= 1
    //#unanalyzed(void launchApp(String)): Effects-of-calling:com.dmdirc.config.IdentityManager:getGlobalConfig
    //#unanalyzed(void launchApp(String)): Effects-of-calling:java.lang.Throwable:__curr_excep_obj
    //#unanalyzed(void launchApp(String)): Effects-of-calling:java.awt.Desktop:isSupported
    //#unanalyzed(void launchApp(String)): Effects-of-calling:java.awt.Desktop:browse
    //#unanalyzed(void launchApp(String)): Effects-of-calling:java.lang.StringBuilder
    //#unanalyzed(void launchApp(String)): Effects-of-calling:java.lang.StringBuilder:append
    //#unanalyzed(void launchApp(String)): Effects-of-calling:java.io.IOException:getMessage
    //#unanalyzed(void launchApp(String)): Effects-of-calling:java.lang.StringBuilder:toString
    //#unanalyzed(void launchApp(String)): Effects-of-calling:com.dmdirc.logger.Logger:userError
    //#unanalyzed(void launchApp(String)): Effects-of-calling:java.net.URI:getUserInfo
    //#unanalyzed(void launchApp(String)): Effects-of-calling:java.net.URI:getFragment
    //#unanalyzed(void launchApp(String)): Effects-of-calling:java.net.URI:getHost
    //#unanalyzed(void launchApp(String)): Effects-of-calling:java.net.URI:getPath
    //#unanalyzed(void launchApp(String)): Effects-of-calling:java.net.URI:getScheme
    //#unanalyzed(void launchApp(String)): Effects-of-calling:java.net.URI:getQuery
    //#unanalyzed(void launchApp(String)): Effects-of-calling:java.net.URI:getPort
    //#unanalyzed(void launchApp(String)): Effects-of-calling:java.lang.String:valueOf
    //#unanalyzed(void launchApp(String)): Effects-of-calling:java.lang.String:isEmpty
    //#unanalyzed(void launchApp(String)): Effects-of-calling:java.lang.String:indexOf
    //#unanalyzed(void launchApp(String)): Effects-of-calling:java.lang.String:substring
    //#unanalyzed(void launchApp(String)): Effects-of-calling:java.net.URI:toString
    //#unanalyzed(void launchApp(String)): Effects-of-calling:java.lang.String:replaceAll
    //#unanalyzed(void launchApp(String)): Effects-of-calling:java.util.ArrayList
    //#unanalyzed(void launchApp(String)): Effects-of-calling:java.lang.String:split
    //#unanalyzed(void launchApp(String)): Effects-of-calling:java.lang.String:endsWith
    //#unanalyzed(void launchApp(String)): Effects-of-calling:java.lang.String:length
    //#unanalyzed(void launchApp(String)): Effects-of-calling:java.util.List:add
    //#unanalyzed(void launchApp(String)): Effects-of-calling:java.lang.StringBuilder:length
    //#unanalyzed(void launchApp(String)): Effects-of-calling:java.lang.StringBuilder:delete
    //#unanalyzed(void launchApp(String)): Effects-of-calling:java.lang.String:startsWith
    //#unanalyzed(void launchApp(String)): Effects-of-calling:java.util.List:size
    //#unanalyzed(void launchApp(String)): Effects-of-calling:java.util.List:toArray
    //#unanalyzed(void launchApp(String)): Effects-of-calling:java.lang.Runtime:getRuntime
    //#unanalyzed(void launchApp(String)): Effects-of-calling:java.lang.Runtime:exec
    //#unanalyzed(void launchApp(String)): Effects-of-calling:java.awt.Desktop:mail
    //#unanalyzed(void launchApp(String)): Effects-of-calling:java.util.Date
    //#unanalyzed(void launchApp(String)): Effects-of-calling:com.dmdirc.config.ConfigManager:getOptionBool
    //#unanalyzed(void launchApp(String)): Effects-of-calling:java.util.Date:getTime
    //#unanalyzed(void launchApp(String)): Effects-of-calling:java.lang.Long:valueOf
    //#unanalyzed(void launchApp(String)): Effects-of-calling:java.lang.Long:longValue
    //#unanalyzed(void launchApp(String)): Effects-of-calling:com.dmdirc.config.ConfigManager:getOptionInt
    //#unanalyzed(void launchApp(String)): Effects-of-calling:com.dmdirc.config.ConfigManager:hasOptionString
    //#unanalyzed(void launchApp(String)): Effects-of-calling:com.dmdirc.Main:getUI
    //#unanalyzed(void launchApp(String)): Effects-of-calling:showURLDialog
    //#unanalyzed(void launchApp(String)): Effects-of-calling:com.dmdirc.config.ConfigManager:getOption
    //#unanalyzed(void launchApp(String)): Effects-of-calling:java.lang.String:equals
    //#unanalyzed(void launchApp(String)): Effects-of-calling:getStatusBar
    //#unanalyzed(void launchApp(String)): Effects-of-calling:setMessage
    //#unanalyzed(void launchApp(String)): Effects-of-calling:java.lang.String:charAt
    //#unanalyzed(void launchApp(String)): Effects-of-calling:java.lang.String:equalsIgnoreCase
    //#unanalyzed(void launchApp(String)): Effects-of-calling:java.lang.String:replaceFirst
    //#unanalyzed(void launchApp(String)): Effects-of-calling:java.net.URI
    //#unanalyzed(void launchApp(String)): Effects-of-calling:java.lang.Exception
    //#unanalyzed(void launchApp(String)): Effects-of-calling:com.dmdirc.ServerManager:getServerManager
    //#unanalyzed(void launchApp(String)): Effects-of-calling:com.dmdirc.ServerManager:getServersByAddress
    //#unanalyzed(void launchApp(String)): Effects-of-calling:java.util.List:isEmpty
    //#unanalyzed(void launchApp(String)): Effects-of-calling:com.dmdirc.Server
    //#unanalyzed(void launchApp(String)): Effects-of-calling:java.util.List:get
    //#unanalyzed(void launchApp(String)): Effects-of-calling:java.util.ArrayList:iterator
    //#unanalyzed(void launchApp(String)): Effects-of-calling:java.util.Iterator:hasNext
    //#unanalyzed(void launchApp(String)): Effects-of-calling:java.util.Iterator:next
    //#unanalyzed(void launchApp(String)): Effects-of-calling:com.dmdirc.Server:join
    //#unanalyzed(void launchApp(String)): Effects-of-calling:com.dmdirc.config.IdentityManager:getProfiles
    //#unanalyzed(void launchApp(String)): Effects-of-calling:com.dmdirc.util.InvalidAddressException:getMessage
    //#test_vector(void launchApp(String)): java.net.URI:getScheme(...)@82: Inverse{null}, Addr_Set{null}
            if (uri.getScheme() == null) {
                uri = new URI("http://" + urlString);
            }
        } catch (URISyntaxException ex) {
            Logger.userError(ErrorLevel.LOW, "Invalid URL: " + ex.getMessage());
    //#URLHandler.java:86: Warning: method not available - call not analyzed
    //#    call on void com.dmdirc.logger.Logger:userError(ErrorLevel, String)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.util.URLHandler
    //#    method: void launchApp(String)
    //#    unanalyzed callee: void com.dmdirc.logger.Logger:userError(ErrorLevel, String)
            return;
        }

        launchApp(uri);
    }
    //#URLHandler.java:91: end of method: void com.dmdirc.util.URLHandler.launchApp(String)

    /**
     * Launches an application for a given url.
     *
     * @param url URL to parse
     */
    public void launchApp(final URL url) {
        URI uri;
        try {
            uri = url.toURI();
    //#URLHandler.java:101: method: void com.dmdirc.util.URLHandler.launchApp(URL)
    //#input(void launchApp(URL)): ""._tainted
    //#input(void launchApp(URL)): "#"._tainted
    //#input(void launchApp(URL)): "?"._tainted
    //#input(void launchApp(URL)): "Connecting to: "._tainted
    //#input(void launchApp(URL)): "Invalid IRC Address: "._tainted
    //#input(void launchApp(URL)): "Invalid URL: "._tainted
    //#input(void launchApp(URL)): "Opening: "._tainted
    //#input(void launchApp(URL)): "Unable to open URL: "._tainted
    //#input(void launchApp(URL)): "http:.."._tainted
    //#input(void launchApp(URL)): __Descendant_Table[com/dmdirc/util/URLHandler]
    //#input(void launchApp(URL)): __Descendant_Table[others]
    //#input(void launchApp(URL)): __Dispatch_Table.launchApp(Ljava/net/URI;)V
    //#input(void launchApp(URL)): __Dispatch_Table.substituteParams(Ljava/net/URI;Ljava/lang/String;)Ljava/lang/String;
    //#input(void launchApp(URL)): com.dmdirc.logger.ErrorLevel.LOW
    //#input(void launchApp(URL)): com/dmdirc/ui/interfaces/StatusBar.__Descendant_Table[com/dmdirc/ui/interfaces/StatusBar]
    //#input(void launchApp(URL)): com/dmdirc/ui/interfaces/StatusBar.__Descendant_Table[others]
    //#input(void launchApp(URL)): com/dmdirc/ui/interfaces/StatusBar.__Dispatch_Table.setMessage(Ljava/lang/String;)V
    //#input(void launchApp(URL)): com/dmdirc/ui/interfaces/UIController.__Descendant_Table[com/dmdirc/ui/interfaces/UIController]
    //#input(void launchApp(URL)): com/dmdirc/ui/interfaces/UIController.__Descendant_Table[others]
    //#input(void launchApp(URL)): com/dmdirc/ui/interfaces/UIController.__Dispatch_Table.getStatusBar()Lcom/dmdirc/ui/interfaces/StatusBar;
    //#input(void launchApp(URL)): com/dmdirc/ui/interfaces/UIController.__Dispatch_Table.showURLDialog(Ljava/net/URI;)V
    //#input(void launchApp(URL)): com/dmdirc/util/IrcAddress.__Descendant_Table[com/dmdirc/util/IrcAddress]
    //#input(void launchApp(URL)): com/dmdirc/util/IrcAddress.__Descendant_Table[others]
    //#input(void launchApp(URL)): com/dmdirc/util/IrcAddress.__Dispatch_Table.connect()V
    //#input(void launchApp(URL)): com/dmdirc/util/IrcAddress.__Dispatch_Table.connect(Lcom/dmdirc/config/Identity;)V
    //#input(void launchApp(URL)): com/dmdirc/util/IrcAddress.__Dispatch_Table.getChannels()Ljava/util/List;
    //#input(void launchApp(URL)): com/dmdirc/util/IrcAddress.__Dispatch_Table.getPassword()Ljava/lang/String;
    //#input(void launchApp(URL)): com/dmdirc/util/IrcAddress.__Dispatch_Table.getPort()I
    //#input(void launchApp(URL)): com/dmdirc/util/IrcAddress.__Dispatch_Table.getServer()Ljava/lang/String;
    //#input(void launchApp(URL)): com/dmdirc/util/IrcAddress.__Dispatch_Table.isSSL()Z
    //#input(void launchApp(URL)): java.awt.Desktop$Action.BROWSE
    //#input(void launchApp(URL)): java.awt.Desktop$Action.MAIL
    //#input(void launchApp(URL)): lastLaunch
    //#input(void launchApp(URL)): this
    //#input(void launchApp(URL)): this.__Tag
    //#input(void launchApp(URL)): this.config
    //#input(void launchApp(URL)): this.desktop
    //#input(void launchApp(URL)): url
    //#input(void launchApp(URL)): url._tainted
    //#output(void launchApp(URL)): lastLaunch
    //#output(void launchApp(URL)): new Date(launchApp#1*) num objects
    //#new obj(void launchApp(URL)): new Date(launchApp#1*)
    //#pre[1] (void launchApp(URL)): (soft) init'ed(lastLaunch)
    //#pre[3] (void launchApp(URL)): (soft) this.__Tag == com/dmdirc/util/URLHandler
    //#pre[4] (void launchApp(URL)): (soft) this.config != null
    //#pre[6] (void launchApp(URL)): (soft) url != null
    //#presumption(void launchApp(URL)): init'ed(com.dmdirc.logger.ErrorLevel.LOW)
    //#presumption(void launchApp(URL)): java.net.URL:toURI(...)@101 != null
    //#post(void launchApp(URL)): lastLaunch == One-of{old lastLaunch, &new Date(launchApp#1*)}
    //#post(void launchApp(URL)): init'ed(lastLaunch)
    //#post(void launchApp(URL)): new Date(launchApp#1*) num objects <= 1
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:com.dmdirc.config.IdentityManager:getGlobalConfig
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:java.lang.Throwable:__curr_excep_obj
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:java.awt.Desktop:isSupported
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:java.awt.Desktop:browse
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:java.lang.StringBuilder
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:java.lang.StringBuilder:append
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:java.io.IOException:getMessage
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:java.lang.StringBuilder:toString
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:com.dmdirc.logger.Logger:userError
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:java.net.URI:getUserInfo
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:java.net.URI:getFragment
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:java.net.URI:getHost
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:java.net.URI:getPath
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:java.net.URI:getScheme
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:java.net.URI:getQuery
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:java.net.URI:getPort
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:java.lang.String:valueOf
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:java.lang.String:isEmpty
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:java.lang.String:indexOf
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:java.lang.String:substring
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:java.net.URI:toString
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:java.lang.String:replaceAll
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:java.util.ArrayList
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:java.lang.String:split
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:java.lang.String:endsWith
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:java.lang.String:length
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:java.util.List:add
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:java.lang.StringBuilder:length
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:java.lang.StringBuilder:delete
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:java.lang.String:startsWith
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:java.util.List:size
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:java.util.List:toArray
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:java.lang.Runtime:getRuntime
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:java.lang.Runtime:exec
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:java.awt.Desktop:mail
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:java.util.Date
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:com.dmdirc.config.ConfigManager:getOptionBool
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:java.util.Date:getTime
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:java.lang.Long:valueOf
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:java.lang.Long:longValue
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:com.dmdirc.config.ConfigManager:getOptionInt
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:com.dmdirc.config.ConfigManager:hasOptionString
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:com.dmdirc.Main:getUI
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:showURLDialog
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:com.dmdirc.config.ConfigManager:getOption
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:java.lang.String:equals
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:getStatusBar
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:setMessage
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:java.lang.String:charAt
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:java.lang.String:equalsIgnoreCase
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:java.lang.String:replaceFirst
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:java.net.URI
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:java.lang.Exception
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:com.dmdirc.ServerManager:getServerManager
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:com.dmdirc.ServerManager:getServersByAddress
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:java.util.List:isEmpty
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:com.dmdirc.Server
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:java.util.List:get
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:java.util.ArrayList:iterator
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:java.util.Iterator:hasNext
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:java.util.Iterator:next
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:com.dmdirc.Server:join
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:com.dmdirc.config.IdentityManager:getProfiles
    //#unanalyzed(void launchApp(URL)): Effects-of-calling:com.dmdirc.util.InvalidAddressException:getMessage
    //#test_vector(void launchApp(URL)): java.net.URI:getScheme(...)@102: Inverse{null}, Addr_Set{null}
            if (uri.getScheme() == null) {
                uri = new URI("http://" + url.toString());
            }
        } catch (URISyntaxException ex) {
            Logger.userError(ErrorLevel.LOW, "Invalid URL: " + ex.getMessage());
    //#URLHandler.java:106: Warning: method not available - call not analyzed
    //#    call on void com.dmdirc.logger.Logger:userError(ErrorLevel, String)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.util.URLHandler
    //#    method: void launchApp(URL)
    //#    unanalyzed callee: void com.dmdirc.logger.Logger:userError(ErrorLevel, String)
            return;
        }

        launchApp(uri);
    }
    //#URLHandler.java:111: end of method: void com.dmdirc.util.URLHandler.launchApp(URL)

    /**
     * Launches an application for a given url.
     *
     * @param uri URL to parse
     */
    public void launchApp(final URI uri) {
        final Date oldLaunch = lastLaunch;
    //#URLHandler.java:119: method: void com.dmdirc.util.URLHandler.launchApp(URI)
    //#input(void launchApp(URI)): ""._tainted
    //#input(void launchApp(URI)): "#"._tainted
    //#input(void launchApp(URI)): "?"._tainted
    //#input(void launchApp(URI)): "Connecting to: "._tainted
    //#input(void launchApp(URI)): "Invalid IRC Address: "._tainted
    //#input(void launchApp(URI)): "Opening: "._tainted
    //#input(void launchApp(URI)): "Unable to open URL: "._tainted
    //#input(void launchApp(URI)): __Descendant_Table[com/dmdirc/util/URLHandler]
    //#input(void launchApp(URI)): __Descendant_Table[others]
    //#input(void launchApp(URI)): __Dispatch_Table.substituteParams(Ljava/net/URI;Ljava/lang/String;)Ljava/lang/String;
    //#input(void launchApp(URI)): com.dmdirc.logger.ErrorLevel.LOW
    //#input(void launchApp(URI)): com/dmdirc/ui/interfaces/StatusBar.__Descendant_Table[com/dmdirc/ui/interfaces/StatusBar]
    //#input(void launchApp(URI)): com/dmdirc/ui/interfaces/StatusBar.__Descendant_Table[others]
    //#input(void launchApp(URI)): com/dmdirc/ui/interfaces/StatusBar.__Dispatch_Table.setMessage(Ljava/lang/String;)V
    //#input(void launchApp(URI)): com/dmdirc/ui/interfaces/UIController.__Descendant_Table[com/dmdirc/ui/interfaces/UIController]
    //#input(void launchApp(URI)): com/dmdirc/ui/interfaces/UIController.__Descendant_Table[others]
    //#input(void launchApp(URI)): com/dmdirc/ui/interfaces/UIController.__Dispatch_Table.getStatusBar()Lcom/dmdirc/ui/interfaces/StatusBar;
    //#input(void launchApp(URI)): com/dmdirc/ui/interfaces/UIController.__Dispatch_Table.showURLDialog(Ljava/net/URI;)V
    //#input(void launchApp(URI)): com/dmdirc/util/IrcAddress.__Descendant_Table[com/dmdirc/util/IrcAddress]
    //#input(void launchApp(URI)): com/dmdirc/util/IrcAddress.__Descendant_Table[others]
    //#input(void launchApp(URI)): com/dmdirc/util/IrcAddress.__Dispatch_Table.connect()V
    //#input(void launchApp(URI)): com/dmdirc/util/IrcAddress.__Dispatch_Table.connect(Lcom/dmdirc/config/Identity;)V
    //#input(void launchApp(URI)): com/dmdirc/util/IrcAddress.__Dispatch_Table.getChannels()Ljava/util/List;
    //#input(void launchApp(URI)): com/dmdirc/util/IrcAddress.__Dispatch_Table.getPassword()Ljava/lang/String;
    //#input(void launchApp(URI)): com/dmdirc/util/IrcAddress.__Dispatch_Table.getPort()I
    //#input(void launchApp(URI)): com/dmdirc/util/IrcAddress.__Dispatch_Table.getServer()Ljava/lang/String;
    //#input(void launchApp(URI)): com/dmdirc/util/IrcAddress.__Dispatch_Table.isSSL()Z
    //#input(void launchApp(URI)): java.awt.Desktop$Action.BROWSE
    //#input(void launchApp(URI)): java.awt.Desktop$Action.MAIL
    //#input(void launchApp(URI)): lastLaunch
    //#input(void launchApp(URI)): this
    //#input(void launchApp(URI)): this.__Tag
    //#input(void launchApp(URI)): this.config
    //#input(void launchApp(URI)): this.desktop
    //#input(void launchApp(URI)): uri
    //#input(void launchApp(URI)): uri._tainted
    //#output(void launchApp(URI)): lastLaunch
    //#output(void launchApp(URI)): new Date(launchApp#1) num objects
    //#new obj(void launchApp(URI)): new Date(launchApp#1)
    //#pre[1] (void launchApp(URI)): init'ed(lastLaunch)
    //#pre[3] (void launchApp(URI)): (soft) this.__Tag == com/dmdirc/util/URLHandler
    //#pre[4] (void launchApp(URI)): (soft) this.config != null
    //#pre[6] (void launchApp(URI)): (soft) uri != null
    //#presumption(void launchApp(URI)): com.dmdirc.Main:getUI(...).__Tag@133 == com/dmdirc/ui/interfaces/UIController
    //#presumption(void launchApp(URI)): com.dmdirc.Main:getUI(...).__Tag@141 == com/dmdirc/ui/interfaces/UIController
    //#presumption(void launchApp(URI)): com.dmdirc.Main:getUI(...).__Tag@149 == com/dmdirc/ui/interfaces/UIController
    //#presumption(void launchApp(URI)): com.dmdirc.Main:getUI(...).__Tag@154 == com/dmdirc/ui/interfaces/UIController
    //#presumption(void launchApp(URI)): com.dmdirc.Main:getUI(...)@133 != null
    //#presumption(void launchApp(URI)): com.dmdirc.Main:getUI(...)@141 != null
    //#presumption(void launchApp(URI)): com.dmdirc.Main:getUI(...)@149 != null
    //#presumption(void launchApp(URI)): com.dmdirc.Main:getUI(...)@154 != null
    //#presumption(void launchApp(URI)): com.dmdirc.config.ConfigManager:getOption(...)@137 != null
    //#presumption(void launchApp(URI)): com.dmdirc.config.IdentityManager:getGlobalConfig(...)@122 != null
    //#presumption(void launchApp(URI)): com.dmdirc.config.IdentityManager:getGlobalConfig(...)@126 != null
    //#presumption(void launchApp(URI)): init'ed(com.dmdirc.logger.ErrorLevel.LOW)
    //#presumption(void launchApp(URI)): getStatusBar(...).__Tag@141 == com/dmdirc/ui/interfaces/StatusBar
    //#presumption(void launchApp(URI)): getStatusBar(...).__Tag@149 == com/dmdirc/ui/interfaces/StatusBar
    //#presumption(void launchApp(URI)): getStatusBar(...).__Tag@154 == com/dmdirc/ui/interfaces/StatusBar
    //#presumption(void launchApp(URI)): getStatusBar(...)@141 != null
    //#presumption(void launchApp(URI)): getStatusBar(...)@149 != null
    //#presumption(void launchApp(URI)): getStatusBar(...)@154 != null
    //#presumption(void launchApp(URI)): java.lang.Long:valueOf(...)@124 != null
    //#presumption(void launchApp(URI)): java.util.Date:getTime(...)@124 - java.util.Date:getTime(...)@124 in {-18_446_744_073_709_551_615..9_223_372_036_854_775_808}
    //#post(void launchApp(URI)): lastLaunch == &new Date(launchApp#1)
    //#post(void launchApp(URI)): new Date(launchApp#1) num objects == 1
    //#unanalyzed(void launchApp(URI)): Effects-of-calling:java.lang.Throwable:__curr_excep_obj
    //#unanalyzed(void launchApp(URI)): Effects-of-calling:java.awt.Desktop:isSupported
    //#unanalyzed(void launchApp(URI)): Effects-of-calling:java.awt.Desktop:browse
    //#unanalyzed(void launchApp(URI)): Effects-of-calling:java.lang.StringBuilder
    //#unanalyzed(void launchApp(URI)): Effects-of-calling:java.lang.StringBuilder:append
    //#unanalyzed(void launchApp(URI)): Effects-of-calling:java.io.IOException:getMessage
    //#unanalyzed(void launchApp(URI)): Effects-of-calling:java.lang.StringBuilder:toString
    //#unanalyzed(void launchApp(URI)): Effects-of-calling:com.dmdirc.logger.Logger:userError
    //#unanalyzed(void launchApp(URI)): Effects-of-calling:java.net.URI:getUserInfo
    //#unanalyzed(void launchApp(URI)): Effects-of-calling:java.net.URI:getFragment
    //#unanalyzed(void launchApp(URI)): Effects-of-calling:java.net.URI:getHost
    //#unanalyzed(void launchApp(URI)): Effects-of-calling:java.net.URI:getPath
    //#unanalyzed(void launchApp(URI)): Effects-of-calling:java.net.URI:getScheme
    //#unanalyzed(void launchApp(URI)): Effects-of-calling:java.net.URI:getQuery
    //#unanalyzed(void launchApp(URI)): Effects-of-calling:java.net.URI:getPort
    //#unanalyzed(void launchApp(URI)): Effects-of-calling:java.lang.String:valueOf
    //#unanalyzed(void launchApp(URI)): Effects-of-calling:java.lang.String:isEmpty
    //#unanalyzed(void launchApp(URI)): Effects-of-calling:java.lang.String:indexOf
    //#unanalyzed(void launchApp(URI)): Effects-of-calling:java.lang.String:substring
    //#unanalyzed(void launchApp(URI)): Effects-of-calling:java.net.URI:toString
    //#unanalyzed(void launchApp(URI)): Effects-of-calling:java.lang.String:replaceAll
    //#unanalyzed(void launchApp(URI)): Effects-of-calling:java.util.ArrayList
    //#unanalyzed(void launchApp(URI)): Effects-of-calling:java.lang.String:split
    //#unanalyzed(void launchApp(URI)): Effects-of-calling:java.lang.String:endsWith
    //#unanalyzed(void launchApp(URI)): Effects-of-calling:java.lang.String:length
    //#unanalyzed(void launchApp(URI)): Effects-of-calling:java.util.List:add
    //#unanalyzed(void launchApp(URI)): Effects-of-calling:java.lang.StringBuilder:length
    //#unanalyzed(void launchApp(URI)): Effects-of-calling:java.lang.StringBuilder:delete
    //#unanalyzed(void launchApp(URI)): Effects-of-calling:java.lang.String:startsWith
    //#unanalyzed(void launchApp(URI)): Effects-of-calling:java.util.List:size
    //#unanalyzed(void launchApp(URI)): Effects-of-calling:java.util.List:toArray
    //#unanalyzed(void launchApp(URI)): Effects-of-calling:java.lang.Runtime:getRuntime
    //#unanalyzed(void launchApp(URI)): Effects-of-calling:java.lang.Runtime:exec
    //#unanalyzed(void launchApp(URI)): Effects-of-calling:java.awt.Desktop:mail
    //#unanalyzed(void launchApp(URI)): Effects-of-calling:java.lang.String:charAt
    //#unanalyzed(void launchApp(URI)): Effects-of-calling:java.lang.String:equalsIgnoreCase
    //#unanalyzed(void launchApp(URI)): Effects-of-calling:java.lang.String:replaceFirst
    //#unanalyzed(void launchApp(URI)): Effects-of-calling:java.net.URI
    //#unanalyzed(void launchApp(URI)): Effects-of-calling:java.lang.Exception
    //#unanalyzed(void launchApp(URI)): Effects-of-calling:com.dmdirc.ServerManager:getServerManager
    //#unanalyzed(void launchApp(URI)): Effects-of-calling:com.dmdirc.ServerManager:getServersByAddress
    //#unanalyzed(void launchApp(URI)): Effects-of-calling:java.util.List:isEmpty
    //#unanalyzed(void launchApp(URI)): Effects-of-calling:com.dmdirc.Server
    //#unanalyzed(void launchApp(URI)): Effects-of-calling:java.util.List:get
    //#unanalyzed(void launchApp(URI)): Effects-of-calling:java.util.ArrayList:iterator
    //#unanalyzed(void launchApp(URI)): Effects-of-calling:java.util.Iterator:hasNext
    //#unanalyzed(void launchApp(URI)): Effects-of-calling:java.util.Iterator:next
    //#unanalyzed(void launchApp(URI)): Effects-of-calling:com.dmdirc.Server:join
    //#unanalyzed(void launchApp(URI)): Effects-of-calling:com.dmdirc.config.IdentityManager:getProfiles
    //#test_vector(void launchApp(URI)): lastLaunch: Addr_Set{null}, Inverse{null}
    //#test_vector(void launchApp(URI)): com.dmdirc.config.ConfigManager:getOptionBool(...)@122: {0}, {1}
    //#test_vector(void launchApp(URI)): com.dmdirc.config.ConfigManager:hasOptionString(...)@132: {1}, {0}
    //#test_vector(void launchApp(URI)): java.lang.String:equals(...)@139: {0}, {1}
    //#test_vector(void launchApp(URI)): java.lang.String:equals(...)@148: {0}, {1}
    //#test_vector(void launchApp(URI)): java.lang.String:equals(...)@151: {0}, {1}
        lastLaunch = new Date();

        if (IdentityManager.getGlobalConfig().getOptionBool("browser",
    //#URLHandler.java:122: Warning: method not available - call not analyzed
    //#    call on ConfigManager com.dmdirc.config.IdentityManager:getGlobalConfig()
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.util.URLHandler
    //#    method: void launchApp(URI)
    //#    unanalyzed callee: ConfigManager com.dmdirc.config.IdentityManager:getGlobalConfig()
    //#URLHandler.java:122: Warning: method not available - call not analyzed
    //#    call on bool com.dmdirc.config.ConfigManager:getOptionBool(String, String)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.util.URLHandler
    //#    method: void launchApp(URI)
    //#    unanalyzed callee: bool com.dmdirc.config.ConfigManager:getOptionBool(String, String)
                "uselaunchdelay") && oldLaunch != null) {
            final Long diff = lastLaunch.getTime() - oldLaunch.getTime();

            if (diff < IdentityManager.getGlobalConfig().getOptionInt("browser",
    //#URLHandler.java:126: Warning: method not available - call not analyzed
    //#    call on ConfigManager com.dmdirc.config.IdentityManager:getGlobalConfig()
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.util.URLHandler
    //#    method: void launchApp(URI)
    //#    unanalyzed callee: ConfigManager com.dmdirc.config.IdentityManager:getGlobalConfig()
    //#URLHandler.java:126: Warning: method not available - call not analyzed
    //#    call on int com.dmdirc.config.ConfigManager:getOptionInt(String, String)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.util.URLHandler
    //#    method: void launchApp(URI)
    //#    unanalyzed callee: int com.dmdirc.config.ConfigManager:getOptionInt(String, String)
                    "launchdelay")) {
                return;
            }
        }

        if (!config.hasOptionString("protocol", uri.getScheme())) {
    //#URLHandler.java:132: Warning: method not available - call not analyzed
    //#    call on bool com.dmdirc.config.ConfigManager:hasOptionString(String, String)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.util.URLHandler
    //#    method: void launchApp(URI)
    //#    unanalyzed callee: bool com.dmdirc.config.ConfigManager:hasOptionString(String, String)
            Main.getUI().showURLDialog(uri);
    //#URLHandler.java:133: Warning: method not available - call not analyzed
    //#    call on UIController com.dmdirc.Main:getUI()
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.util.URLHandler
    //#    method: void launchApp(URI)
    //#    unanalyzed callee: UIController com.dmdirc.Main:getUI()
    //#URLHandler.java:133: Warning: method not available - call not analyzed
    //#    call on void showURLDialog(URI)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.util.URLHandler
    //#    method: void launchApp(URI)
    //#    unanalyzed callee: void showURLDialog(URI)
            return;
        }

        final String command = config.getOption("protocol", uri.getScheme());
    //#URLHandler.java:137: Warning: method not available - call not analyzed
    //#    call on String com.dmdirc.config.ConfigManager:getOption(String, String)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.util.URLHandler
    //#    method: void launchApp(URI)
    //#    unanalyzed callee: String com.dmdirc.config.ConfigManager:getOption(String, String)

        if ("DMDIRC".equals(command)) {
            try {
                Main.getUI().getStatusBar().setMessage("Connecting to: " +
    //#URLHandler.java:141: Warning: method not available - call not analyzed
    //#    call on UIController com.dmdirc.Main:getUI()
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.util.URLHandler
    //#    method: void launchApp(URI)
    //#    unanalyzed callee: UIController com.dmdirc.Main:getUI()
    //#URLHandler.java:141: Warning: method not available - call not analyzed
    //#    call on StatusBar getStatusBar()
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.util.URLHandler
    //#    method: void launchApp(URI)
    //#    unanalyzed callee: StatusBar getStatusBar()
    //#URLHandler.java:141: Warning: method not available - call not analyzed
    //#    call on void setMessage(String)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.util.URLHandler
    //#    method: void launchApp(URI)
    //#    unanalyzed callee: void setMessage(String)
                        uri.toString());
                new IrcAddress(uri.toString()).connect();
    //#URLHandler.java:143: ?precondition failure
    //#    com/dmdirc/util/IrcAddress.connect: (soft) init'ed(this.usesSSL)
    //#    severity: SUPPRESSED
    //#    class: com.dmdirc.util.URLHandler
    //#    method: void launchApp(URI)
    //#    basic block: bb_9
    //#    assertion: (soft) com.dmdirc.util.IrcAddress.Param_0.usesSSL in {0,1}
    //#    callee: void com/dmdirc/util/IrcAddress.connect()
    //#    callee assertion: (soft) init'ed(this.usesSSL)
    //#    callee file: IrcAddress.java
    //#    callee precondition index: [7]
    //#    callee srcpos: 205
    //#    VN: com.dmdirc.util.IrcAddress.Param_0.usesSSL
    //#    Expected: {0,1}
    //#    Bad: {Invalid}
    //#    Attribs:  Int  Exp in +/-1000  Soft  Bad only invalid
            } catch (InvalidAddressException ex) {
                Logger.userError(ErrorLevel.LOW, "Invalid IRC Address: " +
    //#URLHandler.java:145: Warning: method not available - call not analyzed
    //#    call on String com.dmdirc.util.InvalidAddressException:getMessage()
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.util.URLHandler
    //#    method: void launchApp(URI)
    //#    unanalyzed callee: String com.dmdirc.util.InvalidAddressException:getMessage()
    //#URLHandler.java:145: Warning: method not available - call not analyzed
    //#    call on void com.dmdirc.logger.Logger:userError(ErrorLevel, String)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.util.URLHandler
    //#    method: void launchApp(URI)
    //#    unanalyzed callee: void com.dmdirc.logger.Logger:userError(ErrorLevel, String)
                        ex.getMessage());
            }
        } else if ("BROWSER".equals(command)) {
            Main.getUI().getStatusBar().setMessage("Opening: " + uri.toString());
    //#URLHandler.java:149: Warning: method not available - call not analyzed
    //#    call on UIController com.dmdirc.Main:getUI()
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.util.URLHandler
    //#    method: void launchApp(URI)
    //#    unanalyzed callee: UIController com.dmdirc.Main:getUI()
    //#URLHandler.java:149: Warning: method not available - call not analyzed
    //#    call on StatusBar getStatusBar()
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.util.URLHandler
    //#    method: void launchApp(URI)
    //#    unanalyzed callee: StatusBar getStatusBar()
    //#URLHandler.java:149: Warning: method not available - call not analyzed
    //#    call on void setMessage(String)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.util.URLHandler
    //#    method: void launchApp(URI)
    //#    unanalyzed callee: void setMessage(String)
            execBrowser(uri);
        } else if ("MAIL".equals(command)) {
            execMail(uri);
        } else {
            Main.getUI().getStatusBar().setMessage("Opening: " + uri.toString());
    //#URLHandler.java:154: Warning: method not available - call not analyzed
    //#    call on UIController com.dmdirc.Main:getUI()
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.util.URLHandler
    //#    method: void launchApp(URI)
    //#    unanalyzed callee: UIController com.dmdirc.Main:getUI()
    //#URLHandler.java:154: Warning: method not available - call not analyzed
    //#    call on StatusBar getStatusBar()
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.util.URLHandler
    //#    method: void launchApp(URI)
    //#    unanalyzed callee: StatusBar getStatusBar()
    //#URLHandler.java:154: Warning: method not available - call not analyzed
    //#    call on void setMessage(String)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.util.URLHandler
    //#    method: void launchApp(URI)
    //#    unanalyzed callee: void setMessage(String)
            execApp(substituteParams(uri, command));
        }
    }
    //#URLHandler.java:157: end of method: void com.dmdirc.util.URLHandler.launchApp(URI)

    /**
     * Substitutes variables into a command
     * 
     * @param url data url
     * @param command command to be substituted
     * 
     * @return Substituted command
     */
    public String substituteParams(final URI url, final String command) {
        final String userInfo = url.getUserInfo();
    //#URLHandler.java:168: method: String com.dmdirc.util.URLHandler.substituteParams(URI, String)
    //#input(String substituteParams(URI, String)): command
    //#input(String substituteParams(URI, String)): url
    //#input(String substituteParams(URI, String)): url._tainted
    //#output(String substituteParams(URI, String)): return_value
    //#pre[1] (String substituteParams(URI, String)): command != null
    //#pre[2] (String substituteParams(URI, String)): url != null
    //#presumption(String substituteParams(URI, String)): java.lang.String:indexOf(...)@207 <= 4_294_967_294
    //#post(String substituteParams(URI, String)): return_value != null
    //#test_vector(String substituteParams(URI, String)): java.lang.String:indexOf(...)@204: {-2_147_483_648..-2, 0..4_294_967_295}, {-1}
    //#test_vector(String substituteParams(URI, String)): java.lang.String:isEmpty(...)@203: {1}, {0}
    //#test_vector(String substituteParams(URI, String)): java.net.URI:getFragment(...)@179: Addr_Set{null}, Inverse{null}
    //#test_vector(String substituteParams(URI, String)): java.net.URI:getHost(...)@183: Addr_Set{null}, Inverse{null}
    //#test_vector(String substituteParams(URI, String)): java.net.URI:getPath(...)@187: Addr_Set{null}, Inverse{null}
    //#test_vector(String substituteParams(URI, String)): java.net.URI:getPort(...)@199: {-2_147_483_648..0}, {1..4_294_967_295}
    //#test_vector(String substituteParams(URI, String)): java.net.URI:getQuery(...)@195: Addr_Set{null}, Inverse{null}
    //#test_vector(String substituteParams(URI, String)): java.net.URI:getScheme(...)@191: Addr_Set{null}, Inverse{null}
    //#test_vector(String substituteParams(URI, String)): java.net.URI:getUserInfo(...)@168: Addr_Set{null}, Inverse{null}
        String fragment = "";
        String host = "";
        String path = "";
        String protocol = "";
        String query = "";
        String username = "";
        String password = "";
        String port = "";
        String newCommand = command;

        if (url.getFragment() != null) {
            fragment = url.getFragment();
        }

        if (url.getHost() != null) {
            host = url.getHost();
        }

        if (url.getPath() != null) {
            path = url.getPath();
        }

        if (url.getScheme() != null) {
            protocol = url.getScheme();
        }

        if (url.getQuery() != null) {
            query = url.getQuery();
        }
        
        if (url.getPort() > 0) {
            port = String.valueOf(url.getPort());
        }

        if (userInfo != null && !userInfo.isEmpty()) {
            if (userInfo.indexOf(':') == -1) {
                username = userInfo;
            } else {
                final int pos = userInfo.indexOf(':');
                username = userInfo.substring(0, pos);
                password = userInfo.substring(pos + 1);
            }
        }

        newCommand = newCommand.replaceAll("\\$url", url.toString());
        newCommand = newCommand.replaceAll("\\$fragment", fragment);
        newCommand = newCommand.replaceAll("\\$host", host);
        newCommand = newCommand.replaceAll("\\$path", path);
        newCommand = newCommand.replaceAll("\\$port", port);
        newCommand = newCommand.replaceAll("\\$query", query);
        newCommand = newCommand.replaceAll("\\$protocol", protocol);
        newCommand = newCommand.replaceAll("\\$username", username);
        newCommand = newCommand.replaceAll("\\$password", password);

        return newCommand;
    //#URLHandler.java:223: end of method: String com.dmdirc.util.URLHandler.substituteParams(URI, String)
    }

    /**
     * Launches an application.
     *
     * @param command Application and arguments
     */
    private void execApp(final String command) {
        try {
            Runtime.getRuntime().exec(parseArguments(command));
    //#URLHandler.java:233: method: void com.dmdirc.util.URLHandler.execApp(String)
    //#input(void execApp(String)): com.dmdirc.logger.ErrorLevel.LOW
    //#input(void execApp(String)): command
    //#input(void execApp(String)): command._tainted
    //#pre[1] (void execApp(String)): (soft) command != null
    //#presumption(void execApp(String)): init'ed(com.dmdirc.logger.ErrorLevel.LOW)
    //#presumption(void execApp(String)): java.lang.Runtime:getRuntime(...)@233 != null
    //#unanalyzed(void execApp(String)): Effects-of-calling:java.lang.StringBuilder
    //#unanalyzed(void execApp(String)): Effects-of-calling:java.lang.StringBuilder:append
    //#unanalyzed(void execApp(String)): Effects-of-calling:java.lang.StringBuilder:toString
    //#unanalyzed(void execApp(String)): Effects-of-calling:java.lang.String:substring
    //#unanalyzed(void execApp(String)): Effects-of-calling:java.util.ArrayList
    //#unanalyzed(void execApp(String)): Effects-of-calling:java.lang.String:split
    //#unanalyzed(void execApp(String)): Effects-of-calling:java.lang.String:endsWith
    //#unanalyzed(void execApp(String)): Effects-of-calling:java.lang.String:length
    //#unanalyzed(void execApp(String)): Effects-of-calling:java.util.List:add
    //#unanalyzed(void execApp(String)): Effects-of-calling:java.lang.StringBuilder:length
    //#unanalyzed(void execApp(String)): Effects-of-calling:java.lang.StringBuilder:delete
    //#unanalyzed(void execApp(String)): Effects-of-calling:java.lang.String:startsWith
    //#unanalyzed(void execApp(String)): Effects-of-calling:java.util.List:size
    //#unanalyzed(void execApp(String)): Effects-of-calling:java.util.List:toArray
        } catch (IOException ex) {
            Logger.userError(ErrorLevel.LOW, "Unable to run application: ",
    //#URLHandler.java:235: Warning: method not available - call not analyzed
    //#    call on void com.dmdirc.logger.Logger:userError(ErrorLevel, String, String)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.util.URLHandler
    //#    method: void execApp(String)
    //#    unanalyzed callee: void com.dmdirc.logger.Logger:userError(ErrorLevel, String, String)
                    ex.getMessage());
        }
    }
    //#URLHandler.java:238: end of method: void com.dmdirc.util.URLHandler.execApp(String)
    
    /**
     * Parses the specified command into an array of arguments. Arguments are
     * separated by spaces. Multi-word arguments may be specified by starting
     * the argument with a quote (") and finishing it with a quote (").
     * 
     * @param command The command to parse
     * @return An array of arguments corresponding to the command
     */
    protected static String[] parseArguments(final String command) {
        final List<String> args = new ArrayList<String>();
    //#URLHandler.java:249: method: String[] com.dmdirc.util.URLHandler.parseArguments(String)
    //#input(String[] parseArguments(String)): command
    //#input(String[] parseArguments(String)): command._tainted
    //#output(String[] parseArguments(String)): return_value
    //#pre[1] (String[] parseArguments(String)): command != null
    //#presumption(String[] parseArguments(String)): java.util.List:size(...)@278 >= 0
    //#post(String[] parseArguments(String)): init'ed(return_value)
        final StringBuilder builder = new StringBuilder();
        boolean inquote = false;
        
        for (String word : command.split(" ")) {
    //#URLHandler.java:253: ?use of default init
    //#    init'ed(arr$.length)
    //#    severity: LOW
    //#    class: com.dmdirc.util.URLHandler
    //#    method: String[] parseArguments(String)
    //#    basic block: Entry_BB_1
    //#    assertion: init'ed(arr$.length)
    //#    VN: undefined
    //#    Expected: {-Inf..+Inf}
    //#    Bad: {Invalid}
    //#    Attribs:  Int  Bad only invalid
    //#URLHandler.java:253: ?use of default init
    //#    init'ed(len$)
    //#    severity: LOW
    //#    class: com.dmdirc.util.URLHandler
    //#    method: String[] parseArguments(String)
    //#    basic block: bb_2
    //#    assertion: init'ed(len$)
    //#    VN: undefined
    //#    Expected: {-Inf..+Inf}
    //#    Bad: {Invalid}
    //#    Attribs:  Int  Bad only invalid
    //#URLHandler.java:253: Warning: test always goes same way
    //#    Test predetermined because i$ == len$
    //#    severity: LOW
    //#    class: com.dmdirc.util.URLHandler
    //#    method: String[] parseArguments(String)
    //#    from bb: bb_2
    //#    live edge: bb_2-->bb_20
    //#    tested vn: i$ - undefined
    //#    tested vn values: {0}
    //#URLHandler.java:253: Warning: dead code
    //#    Dead code here because i$ == len$
    //#    severity: LOW
    //#    class: com.dmdirc.util.URLHandler
    //#    method: String[] parseArguments(String)
    //#    dead bb: bb_3
    //#URLHandler.java:253: Warning: dead code continues
    //#    Dead code continues
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.util.URLHandler
    //#    method: String[] parseArguments(String)
    //#    dead bb: bb_19
            if (word.endsWith("\"") && inquote) {
    //#URLHandler.java:254: Warning: dead code continues
    //#    Dead code continues
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.util.URLHandler
    //#    method: String[] parseArguments(String)
    //#    dead bb: bb_4
                args.add(builder.toString() + ' ' + word.substring(0, word.length() - 1));
    //#URLHandler.java:255: Warning: dead code continues
    //#    Dead code continues
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.util.URLHandler
    //#    method: String[] parseArguments(String)
    //#    dead bb: bb_5
                builder.delete(0, builder.length());
                inquote = false;
            } else if (inquote) {
    //#URLHandler.java:258: Warning: dead code continues
    //#    Dead code continues
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.util.URLHandler
    //#    method: String[] parseArguments(String)
    //#    dead bb: bb_6
                if (builder.length() > 0) {
    //#URLHandler.java:259: Warning: dead code continues
    //#    Dead code continues
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.util.URLHandler
    //#    method: String[] parseArguments(String)
    //#    dead bb: bb_7
                    builder.append(' ');
    //#URLHandler.java:260: Warning: dead code continues
    //#    Dead code continues
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.util.URLHandler
    //#    method: String[] parseArguments(String)
    //#    dead bb: bb_8
                }
                
                builder.append(word);
    //#URLHandler.java:263: Warning: dead code continues
    //#    Dead code continues
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.util.URLHandler
    //#    method: String[] parseArguments(String)
    //#    dead bb: bb_9
            } else if (word.startsWith("\"") && !word.endsWith("\"")) {
    //#URLHandler.java:264: Warning: dead code continues
    //#    Dead code continues
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.util.URLHandler
    //#    method: String[] parseArguments(String)
    //#    dead bb: bb_10
    //#URLHandler.java:264: Warning: dead code continues
    //#    Dead code continues
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.util.URLHandler
    //#    method: String[] parseArguments(String)
    //#    dead bb: bb_11
                inquote = true;
    //#URLHandler.java:265: Warning: dead code continues
    //#    Dead code continues
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.util.URLHandler
    //#    method: String[] parseArguments(String)
    //#    dead bb: bb_12
                builder.append(word.substring(1));
            } else if (word.startsWith("\"") && word.endsWith("\"")) {
    //#URLHandler.java:267: Warning: dead code continues
    //#    Dead code continues
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.util.URLHandler
    //#    method: String[] parseArguments(String)
    //#    dead bb: bb_13
    //#URLHandler.java:267: Warning: dead code continues
    //#    Dead code continues
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.util.URLHandler
    //#    method: String[] parseArguments(String)
    //#    dead bb: bb_14
                if (word.length() == 1) {
    //#URLHandler.java:268: Warning: dead code continues
    //#    Dead code continues
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.util.URLHandler
    //#    method: String[] parseArguments(String)
    //#    dead bb: bb_15
                    inquote = true;
    //#URLHandler.java:269: Warning: dead code continues
    //#    Dead code continues
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.util.URLHandler
    //#    method: String[] parseArguments(String)
    //#    dead bb: bb_16
                } else {
                    args.add(word.substring(1, word.length() - 1));
    //#URLHandler.java:271: Warning: dead code continues
    //#    Dead code continues
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.util.URLHandler
    //#    method: String[] parseArguments(String)
    //#    dead bb: bb_17
                }
            } else {
                args.add(word);
    //#URLHandler.java:274: Warning: dead code continues
    //#    Dead code continues
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.util.URLHandler
    //#    method: String[] parseArguments(String)
    //#    dead bb: bb_18
            }
        }
        
        return args.toArray(new String[args.size()]);
    //#URLHandler.java:278: end of method: String[] com.dmdirc.util.URLHandler.parseArguments(String)
    }

    /**
     * Opens the specified URL in the users browser.
     *
     * @param url URL to open
     */
    private void execBrowser(final URI url) {
        if (desktop != null &&
    //#URLHandler.java:287: method: void com.dmdirc.util.URLHandler.execBrowser(URI)
    //#input(void execBrowser(URI)): "Unable to open URL: "._tainted
    //#input(void execBrowser(URI)): com.dmdirc.logger.ErrorLevel.LOW
    //#input(void execBrowser(URI)): java.awt.Desktop$Action.BROWSE
    //#input(void execBrowser(URI)): this
    //#input(void execBrowser(URI)): this.desktop
    //#input(void execBrowser(URI)): url
    //#presumption(void execBrowser(URI)): init'ed(com.dmdirc.logger.ErrorLevel.LOW)
    //#presumption(void execBrowser(URI)): init'ed(java.awt.Desktop$Action.BROWSE)
    //#test_vector(void execBrowser(URI)): this.desktop: Addr_Set{null}, Inverse{null}
    //#test_vector(void execBrowser(URI)): java.awt.Desktop:isSupported(...)@287: {0}, {1}
                desktop.isSupported(Desktop.Action.BROWSE)) {
            try {
                desktop.browse(url);
            } catch (IOException ex) {
                Logger.userError(ErrorLevel.LOW,
    //#URLHandler.java:292: Warning: method not available - call not analyzed
    //#    call on void com.dmdirc.logger.Logger:userError(ErrorLevel, String)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.util.URLHandler
    //#    method: void execBrowser(URI)
    //#    unanalyzed callee: void com.dmdirc.logger.Logger:userError(ErrorLevel, String)
                        "Unable to open URL: " + ex.getMessage());
            }
        } else {
            Logger.userError(ErrorLevel.LOW,
    //#URLHandler.java:296: Warning: method not available - call not analyzed
    //#    call on void com.dmdirc.logger.Logger:userError(ErrorLevel, String)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.util.URLHandler
    //#    method: void execBrowser(URI)
    //#    unanalyzed callee: void com.dmdirc.logger.Logger:userError(ErrorLevel, String)
                    "Unable to open your browser: Your desktop enviroment is " +
                    "not supported, please go to the URL Handlers section of " +
                    "the preferences dialog and set the path to your browser " +
                    "manually");
        }
    }
    //#URLHandler.java:302: end of method: void com.dmdirc.util.URLHandler.execBrowser(URI)

    /**
     * Opens the specified URL in the users mail client.
     *
     * @param url URL to open
     */
    private void execMail(final URI url) {
        if (desktop != null && desktop.isSupported(Desktop.Action.MAIL)) {
    //#URLHandler.java:310: method: void com.dmdirc.util.URLHandler.execMail(URI)
    //#input(void execMail(URI)): "Unable to open URL: "._tainted
    //#input(void execMail(URI)): com.dmdirc.logger.ErrorLevel.LOW
    //#input(void execMail(URI)): java.awt.Desktop$Action.MAIL
    //#input(void execMail(URI)): this
    //#input(void execMail(URI)): this.desktop
    //#input(void execMail(URI)): url
    //#presumption(void execMail(URI)): init'ed(com.dmdirc.logger.ErrorLevel.LOW)
    //#presumption(void execMail(URI)): init'ed(java.awt.Desktop$Action.MAIL)
    //#test_vector(void execMail(URI)): this.desktop: Addr_Set{null}, Inverse{null}
    //#test_vector(void execMail(URI)): java.awt.Desktop:isSupported(...)@310: {0}, {1}
            try {
                desktop.mail(url);
            } catch (IOException ex) {
                Logger.userError(ErrorLevel.LOW,
    //#URLHandler.java:314: Warning: method not available - call not analyzed
    //#    call on void com.dmdirc.logger.Logger:userError(ErrorLevel, String)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.util.URLHandler
    //#    method: void execMail(URI)
    //#    unanalyzed callee: void com.dmdirc.logger.Logger:userError(ErrorLevel, String)
                        "Unable to open URL: " + ex.getMessage());
            }
        } else {
            Logger.userError(ErrorLevel.LOW,
    //#URLHandler.java:318: Warning: method not available - call not analyzed
    //#    call on void com.dmdirc.logger.Logger:userError(ErrorLevel, String)
    //#    severity: INFORMATIONAL
    //#    class: com.dmdirc.util.URLHandler
    //#    method: void execMail(URI)
    //#    unanalyzed callee: void com.dmdirc.logger.Logger:userError(ErrorLevel, String)
                    "Unable to open your mail client: Your desktop enviroment is " +
                    "not supported, please go to the URL Handlers section of " +
                    "the preferences dialog and set the path to your browser " +
                    "manually");
        }
    }
    //#URLHandler.java:324: end of method: void com.dmdirc.util.URLHandler.execMail(URI)
}
    //#URLHandler.java:: end of class: com.dmdirc.util.URLHandler
