/** * 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.request; import java.util.ArrayList; import java.util.regex.Matcher; import java.util.regex.Pattern; import net.java.dev.spellcast.utilities.LockableListModel; import net.sourceforge.kolmafia.KoLConstants; import net.sourceforge.kolmafia.KoLConstants.MafiaState; import net.sourceforge.kolmafia.KoLmafia; import net.sourceforge.kolmafia.persistence.ProfileSnapshot; import net.sourceforge.kolmafia.session.ClanManager; import net.sourceforge.kolmafia.session.ContactManager; import net.sourceforge.kolmafia.utilities.StringUtilities; public class ClanMembersRequest extends GenericRequest { private static final Pattern MEMBER_PATTERN = Pattern.compile( "<a class=nounder href=\"showplayer\\.php\\?who=(\\d+)\">([^<]+)</a></b> </td><td class=small>([^<]*?) </td><td class=small>(\\d+).*?</td>" ); private static final Pattern RANK_PATTERN = Pattern.compile( "<select name=level.*?</select>" ); private static final Pattern OPTION_PATTERN = Pattern.compile( "<option.*?>(.*?)</option>" ); private static final Pattern ROW_PATTERN = Pattern.compile( "<tr>(.*?)</tr>", Pattern.DOTALL ); private static final Pattern CELL_PATTERN = Pattern.compile( "<td.*?>(.*?)</td>", Pattern.DOTALL ); private final boolean isLookup; private final boolean isDetailLookup; private final LockableListModel<String> rankList; public ClanMembersRequest( final boolean isDetailLookup ) { super( isDetailLookup ? "clan_detailedroster.php" : "showclan.php" ); this.isLookup = true; this.isDetailLookup = isDetailLookup; this.rankList = null; } public ClanMembersRequest( final LockableListModel<String> rankList ) { super( "clan_members.php" ); this.isLookup = false; this.isDetailLookup = false; this.rankList = rankList; } public ClanMembersRequest( final Object[] titleChange, final Object[] newTitles, final Object[] boots ) { super( "clan_members.php" ); this.isLookup = false; this.isDetailLookup = false; this.rankList = new LockableListModel<String>(); this.addFormField( "action", "modify" ); ArrayList<String> fields = new ArrayList<String>(); String currentId; for ( int i = 0; i < titleChange.length; ++i ) { currentId = ContactManager.getPlayerId( (String) titleChange[ i ] ); this.addFormField( "title" + currentId, (String) newTitles[ i ] ); if ( !fields.contains( currentId ) ) { fields.add( currentId ); } } for ( int i = 0; i < boots.length; ++i ) { currentId = ContactManager.getPlayerId( (String) boots[ i ] ); ClanManager.unregisterMember( currentId ); this.addFormField( "boot" + currentId, "on" ); if ( !fields.contains( currentId ) ) { fields.add( currentId ); } } String[] changedIds = new String[ fields.size() ]; fields.toArray( changedIds ); for ( int i = 0; i < changedIds.length; ++i ) { this.addFormField( "pids[]", changedIds[ i ], true ); } } @Override protected boolean retryOnTimeout() { return true; } @Override public void run() { if ( !this.isLookup || this.isDetailLookup ) { KoLmafia.updateDisplay( "Retrieving clan member list..." ); super.run(); return; } int clanId = ClanManager.getClanId(); if ( clanId == 0 ) { KoLmafia.updateDisplay( MafiaState.ERROR, "Your character does not belong to a clan." ); } KoLmafia.updateDisplay( "Retrieving clan member list..." ); int page = 0; do { this.responseText = null; this.constructURLString( "showclan.php?whichclan=" + clanId + "&page=" + (page++), false ); super.run(); } while ( this.responseText != null && this.responseText.indexOf( "next page >>" ) != -1 ); } @Override public void processResults() { if ( !this.isLookup ) { this.parseRanks(); } else if ( this.isDetailLookup ) { this.parseDetail(); } else { this.parseSparse(); } } private void parseRanks() { this.rankList.clear(); Matcher ranklistMatcher = ClanMembersRequest.RANK_PATTERN.matcher( this.responseText ); if ( ranklistMatcher.find() ) { Matcher rankMatcher = ClanMembersRequest.OPTION_PATTERN.matcher( ranklistMatcher.group() ); while ( rankMatcher.find() ) { this.rankList.add( rankMatcher.group( 1 ).toLowerCase() ); } } } private void parseDetail() { Matcher rowMatcher = ClanMembersRequest.ROW_PATTERN.matcher( this.responseText.substring( this.responseText.lastIndexOf( "clan_detailedroster.php" ) ) ); String currentRow; String currentName; Matcher dataMatcher; while ( rowMatcher.find() ) { currentRow = rowMatcher.group( 1 ); if ( currentRow.equals( "<td height=4></td>" ) ) { continue; } dataMatcher = ClanMembersRequest.CELL_PATTERN.matcher( currentRow ); // The name of the player occurs in the first // field of the table. Use this to index the // roster map. dataMatcher.find(); currentName = dataMatcher.group( 1 ); currentName = KoLConstants.ANYTAG_PATTERN.matcher( currentName ).replaceAll( "" ); currentName = StringUtilities.globalStringDelete( currentName, " " ).trim(); ProfileSnapshot.addToRoster( currentName, currentRow ); } } private void parseSparse() { int lastMatchIndex = 0; Matcher memberMatcher = ClanMembersRequest.MEMBER_PATTERN.matcher( this.responseText ); while ( memberMatcher.find( lastMatchIndex ) ) { lastMatchIndex = memberMatcher.end(); String id = memberMatcher.group( 1 ); String name = memberMatcher.group( 2 ); String level = memberMatcher.group( 4 ); String title = memberMatcher.group( 3 ); ContactManager.registerPlayerId( name, id ); ClanManager.registerMember( name, level, title ); } } }