/** * Copyright (c) 2005-2017, KoLmafia development team * http://kolmafia.sourceforge.net/ * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * [1] Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * [2] Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * [3] Neither the name "KoLmafia" nor the names of its contributors may * be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ package net.sourceforge.kolmafia.swingui.listener; import java.util.regex.Matcher; import java.util.regex.Pattern; import javax.swing.event.HyperlinkEvent; import javax.swing.event.HyperlinkListener; import net.sourceforge.kolmafia.RequestThread; import net.sourceforge.kolmafia.swingui.widget.RequestPane; import net.sourceforge.kolmafia.utilities.InputFieldUtilities; import net.sourceforge.kolmafia.utilities.StringUtilities; import net.sourceforge.kolmafia.webui.RelayLoader; public class HyperlinkAdapter implements HyperlinkListener { private static final Pattern[] ACTION_PATTERNS = new Pattern[ 3 ]; private static final Pattern[] NAME_PATTERNS = new Pattern[ 3 ]; private static final Pattern[] VALUE_PATTERNS = new Pattern[ 3 ]; static { HyperlinkAdapter.ACTION_PATTERNS[ 0 ] = Pattern.compile( "action=\"(.*?)\"" ); HyperlinkAdapter.NAME_PATTERNS[ 0 ] = Pattern.compile( "name=\"(.*?)\"" ); HyperlinkAdapter.VALUE_PATTERNS[ 0 ] = Pattern.compile( "value=\"(.*?)\"" ); HyperlinkAdapter.ACTION_PATTERNS[ 1 ] = Pattern.compile( "action=\'(.*?)\'" ); HyperlinkAdapter.NAME_PATTERNS[ 1 ] = Pattern.compile( "name=\'(.*?)\'" ); HyperlinkAdapter.VALUE_PATTERNS[ 1 ] = Pattern.compile( "value=\'(.*?)\'" ); HyperlinkAdapter.ACTION_PATTERNS[ 2 ] = Pattern.compile( "action=([^\\s]*?)" ); HyperlinkAdapter.NAME_PATTERNS[ 2 ] = Pattern.compile( "name=([^\\s]*?)" ); HyperlinkAdapter.VALUE_PATTERNS[ 2 ] = Pattern.compile( "value=([^\\s]*?)" ); } public void hyperlinkUpdate( final HyperlinkEvent e ) { if ( e.getEventType() != HyperlinkEvent.EventType.ACTIVATED ) { return; } RequestPane requestPane = (RequestPane) e.getSource(); String location = e.getDescription(); RequestThread.runInParallel( new HyperlinkUpdateRunnable( requestPane, location ) ); } private class HyperlinkUpdateRunnable implements Runnable { private RequestPane requestPane; private String location; private HyperlinkUpdateRunnable( RequestPane requestPane, String location ) { this.requestPane = requestPane; this.location = location; } public void run() { if ( location.indexOf( "pics.communityofloathing.com" ) != -1 ) { HyperlinkAdapter.this.handleInternalLink( location ); return; } else if ( location.startsWith( "http://" ) || location.startsWith( "https://" ) ) { RelayLoader.openSystemBrowser( location ); return; } else if ( location.startsWith( "javascript:" ) && ( location.indexOf( "submit()" ) == -1 || location.indexOf( "messageform" ) != -1 ) ) { InputFieldUtilities.alert( "Ironically, Java does not support Javascript." ); return; } else if ( location.indexOf( "submit()" ) == -1 ) { HyperlinkAdapter.this.handleInternalLink( location ); return; } // If it's an attempt to submit an adventure form, // examine the location string to see which form is // being submitted and submit it manually. String[] locationSplit = location.split( "\\." ); String formId = "\"" + locationSplit[ locationSplit.length - 2 ] + "\""; String editorText = requestPane.getText(); int formIndex = editorText.indexOf( formId ); String locationText = editorText.substring( editorText.lastIndexOf( "<form", formIndex ), editorText.toLowerCase().indexOf( "</form>", formIndex ) ); Matcher inputMatcher = Pattern.compile( "<input.*?>" ).matcher( locationText ); String lastInput; int patternIndex; Matcher actionMatcher, nameMatcher, valueMatcher; StringBuffer inputString = new StringBuffer(); // Determine the action associated with the // form -- this is used for the URL. patternIndex = 0; do { actionMatcher = HyperlinkAdapter.ACTION_PATTERNS[ patternIndex ].matcher( locationText ); } while ( !actionMatcher.find() && ++patternIndex < 3 ); // Figure out which inputs need to be submitted. // This is determined through the existing HTML, // looking at preset values only. while ( inputMatcher.find() ) { lastInput = inputMatcher.group(); // Each input has a name associated with it. // This should be determined first. patternIndex = 0; do { nameMatcher = HyperlinkAdapter.NAME_PATTERNS[ patternIndex ].matcher( lastInput ); } while ( !nameMatcher.find() && ++patternIndex < 3 ); // Each input has a name associated with it. // This should be determined next. patternIndex = 0; do { valueMatcher = HyperlinkAdapter.VALUE_PATTERNS[ patternIndex ].matcher( lastInput ); } while ( !valueMatcher.find() && ++patternIndex < 3 ); // Append the latest input's name and value to // the complete input string. inputString.append( inputString.length() == 0 ? '?' : '&' ); inputString.append( StringUtilities.getURLEncode( nameMatcher.group( 1 ) ) ); inputString.append( '=' ); inputString.append( StringUtilities.getURLEncode( valueMatcher.group( 1 ) ) ); } // Now that the entire form string is known, handle // the appropriate internal link. String targetLocation = actionMatcher.group( 1 ) + inputString.toString(); HyperlinkAdapter.this.handleInternalLink( targetLocation ); } } public void handleInternalLink( String location ) { RelayLoader.openSystemBrowser( location ); } }