package clientside; import constants.ServerConstants; import database.DatabaseConnection; import database.DatabaseException; import handling.cashshop.CashShopServer; import handling.channel.ChannelServer; import handling.login.LoginServer; import handling.world.MapleMessengerCharacter; import handling.world.MapleParty; import handling.world.MaplePartyCharacter; import handling.world.PartyOperation; import handling.world.World; import handling.world.family.MapleFamilyCharacter; import handling.world.guild.MapleGuildCharacter; import java.io.Serializable; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Timestamp; import java.util.Calendar; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; import javax.script.ScriptEngine; import org.apache.mina.core.session.IoSession; import server.CharacterCardFactory; import server.Timer; import server.maps.MapleMap; import server.quest.MapleQuest; import server.shops.IMaplePlayerShop; import tools.FileoutputUtil; import tools.MapleAESOFB; import tools.Pair; import tools.packet.LoginPacket; public class MapleClient implements Serializable { private static final long serialVersionUID = 9179541993413738569L; public static final byte LOGIN_NOTLOGGEDIN = 0; public static final byte LOGIN_SERVER_TRANSITION = 1; public static final byte LOGIN_LOGGEDIN = 2; public static final byte CHANGE_CHANNEL = 3; public static final int DEFAULT_CHARSLOT = 6; public static final String CLIENT_KEY = "CLIENT"; public static byte unbanaccs(String accname) { try { Connection con = DatabaseConnection.getConnection(); PreparedStatement ps = con.prepareStatement("SELECT id from accounts where name = ?"); ps.setString(1, accname); ResultSet rs = ps.executeQuery(); if (!rs.next()) { rs.close(); ps.close(); return -1; } final int accid = rs.getInt(1); rs.close(); ps.close(); ps = con.prepareStatement("UPDATE accounts SET banned = 0, points = 0, vpoints = 0, nxprepaid = 0, mPoints = 0, nxcredit = 0, banreason = '' WHERE id = ?"); ps.setInt(1, accid); ps.executeUpdate(); ps.close(); } catch (SQLException e) { System.err.println("Error while unbanning" + e); return -2; } return 0; } public static byte unbanbyAccId(String accname) { try { Connection con = DatabaseConnection.getConnection(); PreparedStatement ps = con.prepareStatement("SELECT * FROM accounts WHERE name = ?"); ps.setString(1, accname); ResultSet rs = ps.executeQuery(); if (!rs.next()) { rs.close(); ps.close(); return -1; } String sessionIP = rs.getString("sessionIP"); String macs = rs.getString("macs"); rs.close(); ps.close(); byte ret = 0; if (sessionIP != null) { try (PreparedStatement psa = con.prepareStatement("DELETE FROM ipbans WHERE ip like ?")) { psa.setString(1, sessionIP); psa.execute(); } ret++; } if (macs != null) { String[] macz = macs.split(", "); for (String mac : macz) { if (!mac.equals("")) { try (PreparedStatement psa = con.prepareStatement("DELETE FROM macbans WHERE mac = ?")) { psa.setString(1, mac); psa.execute(); } } } ret++; } return ret; } catch (SQLException e) { System.err.println("Error while unbanning" + e); return -2; } } private transient MapleAESOFB send; private transient MapleAESOFB receive; private transient IoSession session; private MapleCharacter player; private int channel = 1; private int accId = -1; private int world; private int birthday; private int charslots = 15; private boolean loggedIn = false; private boolean serverTransition = false; private transient Calendar tempban = null; private String accountName; private transient long lastPong = 0L; private transient long lastPing = 0L; private boolean monitored = false; private boolean receiving = true; private boolean gm; private byte greason = 1; private byte gender = -1; public transient short loginAttempt = 0; private transient List<Integer> allowedChar = new LinkedList(); private transient Set<String> macs = new HashSet(); private transient Map<String, ScriptEngine> engines = new HashMap(); private transient ScheduledFuture<?> idleTask = null; private transient String secondPassword; private transient String salt2; private transient String tempIP = ""; private final transient Lock mutex = new ReentrantLock(true); private final transient Lock npc_mutex = new ReentrantLock(); private long lastNpcClick = 0L; private static final Lock login_mutex = new ReentrantLock(true); private Map<Integer, Pair<Short, Short>> charInfo = new LinkedHashMap(); public MapleClient(MapleAESOFB send, MapleAESOFB receive, IoSession session) { this.send = send; this.receive = receive; this.session = session; } public final MapleAESOFB getReceiveCrypto() { return this.receive; } public final MapleAESOFB getSendCrypto() { return this.send; } public final IoSession getSession() { return this.session; } public final Lock getLock() { return this.mutex; } public final Lock getNPCLock() { return this.npc_mutex; } public MapleCharacter getPlayer() { return this.player; } public void setPlayer(MapleCharacter player) { this.player = player; } public void createdChar(int id) { this.allowedChar.add(Integer.valueOf(id)); } public final boolean login_Auth(int id) { return this.allowedChar.contains(Integer.valueOf(id)); } public final List<MapleCharacter> loadCharacters(int serverId) { List chars = new LinkedList(); Map cardss = CharacterCardFactory.getInstance().loadCharacterCards(this.accId, serverId); for (CharNameAndId cni : loadCharactersInternal(serverId)) { MapleCharacter chr = MapleCharacter.loadCharFromDB(cni.id, this, false, cardss); chars.add(chr); this.charInfo.put(Integer.valueOf(chr.getId()), new Pair(Short.valueOf(chr.getLevel()), Short.valueOf(chr.getJob()))); if (!login_Auth(chr.getId())) { this.allowedChar.add(Integer.valueOf(chr.getId())); } } return chars; } /* */ public final void updateCharacterCards(Map<Integer, Integer> cids) { /* 167 */ if (this.charInfo.isEmpty()) { return; } /* */ try /* */ { /* 171 */ Connection con = DatabaseConnection.getConnection(); try (PreparedStatement ps = con.prepareStatement("DELETE FROM `character_cards` WHERE `accid` = ?")) { ps.setInt(1, this.accId); /* 174 */ ps.executeUpdate(); } try (PreparedStatement psu = con.prepareStatement("INSERT INTO `character_cards` (accid, worldid, characterid, position) VALUES (?, ?, ?, ?)")) { for (Map.Entry ii : cids.entrySet()) { /* 179 */ Pair info = (Pair) this.charInfo.get(ii.getValue()); // /* 180 */ if ((info == null) || (((Integer) ii.getValue()).intValue() == 0) || (!CharacterCardFactory.getInstance().canHaveCard(((Short) info.getLeft()).shortValue(), ((Short) info.getRight()).shortValue()))) { // System.out.println("lele"); // /* // */ continue; // // /* */ } /* 183 */ psu.setInt(1, this.accId); /* 184 */ psu.setInt(2, this.world); /* 185 */ psu.setInt(3, ((Integer) ii.getValue()).intValue()); /* 186 */ psu.setInt(4, ((Integer) ii.getKey()).intValue()); /* 187 */ psu.executeUpdate(); /* */ } } } catch (SQLException sqlE) { /* 191 */ System.out.println(new StringBuilder().append("Failed to update character cards. Reason: ").append(sqlE.toString()).toString()); /* */ } /* */ } public boolean canMakeCharacter(int serverId) { return loadCharactersSize(serverId) < getCharacterSlots(); } public List<String> loadCharacterNames(int serverId) { List chars = new LinkedList(); for (CharNameAndId cni : loadCharactersInternal(serverId)) { chars.add(cni.name); } return chars; } private List<CharNameAndId> loadCharactersInternal(int serverId) { List chars = new LinkedList(); try { Connection con = DatabaseConnection.getConnection(); PreparedStatement ps = con.prepareStatement("SELECT id, name, gm FROM characters WHERE accountid = ? AND world = ?"); ps.setInt(1, this.accId); ps.setInt(2, serverId); ResultSet rs = ps.executeQuery(); while (rs.next()) { chars.add(new CharNameAndId(rs.getString("name"), rs.getInt("id"))); LoginServer.getLoginAuth(rs.getInt("id")); } rs.close(); ps.close(); } catch (SQLException e) { System.err.println("error loading characters internal"); e.printStackTrace(); } return chars; } private int loadCharactersSize(int serverId) { int chars = 0; try { Connection con = DatabaseConnection.getConnection(); PreparedStatement ps = con.prepareStatement("SELECT count(*) FROM characters WHERE accountid = ? AND world = ?"); ps.setInt(1, this.accId); ps.setInt(2, serverId); ResultSet rs = ps.executeQuery(); if (rs.next()) { chars = rs.getInt(1); } rs.close(); ps.close(); } catch (SQLException e) { System.err.println("error loading characters internal"); e.printStackTrace(); } return chars; } public boolean isLoggedIn() { return (this.loggedIn) && (this.accId >= 0); } private Calendar getTempBanCalendar(ResultSet rs) throws SQLException { Calendar lTempban = Calendar.getInstance(); if (rs.getLong("tempban") == 0L) { lTempban.setTimeInMillis(0L); return lTempban; } Calendar today = Calendar.getInstance(); lTempban.setTimeInMillis(rs.getTimestamp("tempban").getTime()); if (today.getTimeInMillis() < lTempban.getTimeInMillis()) { return lTempban; } lTempban.setTimeInMillis(0L); return lTempban; } public Calendar getTempBanCalendar() { return this.tempban; } public byte getBanReason() { return this.greason; } public boolean hasProxyBan() { boolean ret = false; try { Connection con = DatabaseConnection.getConnection(); try (PreparedStatement ps = con.prepareStatement("SELECT COUNT(*) FROM proxyip WHERE ? LIKE CONCAT(proxyip, '%')")) { ps.setString(1, getSessionIPAddress()); try (ResultSet rs = ps.executeQuery()) { rs.next(); if (rs.getInt(1) > 0) { ret = true; } } } } catch (SQLException ex) { System.err.println("Error checking proxy bans" + ex); } return ret; } public boolean hasBannedIP() { boolean ret = false; try { Connection con = DatabaseConnection.getConnection(); PreparedStatement ps = con.prepareStatement("SELECT COUNT(*) FROM ipbans WHERE ? LIKE CONCAT(ip, '%')"); ps.setString(1, getSessionIPAddress()); ResultSet rs = ps.executeQuery(); rs.next(); if (rs.getInt(1) > 0) { ret = true; } rs.close(); ps.close(); } catch (SQLException ex) { System.err.println(new StringBuilder().append("Error checking ip bans").append(ex).toString()); } return ret; } public boolean hasBannedMac() { if (this.macs.isEmpty()) { return false; } boolean ret = false; int i = 0; try { Connection con = DatabaseConnection.getConnection(); StringBuilder sql = new StringBuilder("SELECT COUNT(*) FROM macbans WHERE mac IN ("); for (i = 0; i < this.macs.size(); i++) { sql.append("?"); if (i != this.macs.size() - 1) { sql.append(", "); } } sql.append(")"); PreparedStatement ps = con.prepareStatement(sql.toString()); i = 0; for (String mac : this.macs) { i++; ps.setString(i, mac); } ResultSet rs = ps.executeQuery(); rs.next(); if (rs.getInt(1) > 0) { ret = true; } rs.close(); ps.close(); } catch (SQLException ex) { System.err.println(new StringBuilder().append("Error checking mac bans").append(ex).toString()); } return ret; } private void loadMacsIfNescessary() throws SQLException { if (this.macs.isEmpty()) { Connection con = DatabaseConnection.getConnection(); PreparedStatement ps = con.prepareStatement("SELECT macs FROM accounts WHERE id = ?"); ps.setInt(1, this.accId); ResultSet rs = ps.executeQuery(); if (rs.next()) { if (rs.getString("macs") != null) { String[] macData = rs.getString("macs").split(", "); for (String mac : macData) { if (!mac.equals("")) { this.macs.add(mac); } } } } else { rs.close(); ps.close(); throw new RuntimeException("No valid account associated with this client."); } rs.close(); ps.close(); } } public void loginData(String login) { try { Connection con = DatabaseConnection.getConnection(); PreparedStatement ps = con.prepareStatement("SELECT * FROM accounts WHERE name = ?"); ps.setString(1, login); ResultSet rs = ps.executeQuery(); if (rs.next()) { accountName = login; accId = rs.getInt("id"); secondPassword = rs.getString("2ndpassword"); salt2 = rs.getString("salt2"); gm = rs.getInt("gm") > 0; greason = rs.getByte("greason"); tempban = getTempBanCalendar(rs); gender = rs.getByte("gender"); } if (secondPassword != null && salt2 != null) { secondPassword = LoginCrypto.rand_r(secondPassword); } ps.close(); loggedIn = true; } catch (SQLException e) { System.err.println("ERROR" + e); } } public void banMacs() { try { loadMacsIfNescessary(); if (this.macs.size() > 0) { String[] macBans = new String[this.macs.size()]; int z = 0; for (String mac : this.macs) { macBans[z] = mac; z++; } banMacs(macBans); } } catch (SQLException e) { e.printStackTrace(); } } public static final void banMacs(String[] macs) { Connection con = DatabaseConnection.getConnection(); try { List<String> filtered = new LinkedList(); PreparedStatement ps = con.prepareStatement("SELECT filter FROM macfilters"); ResultSet rs = ps.executeQuery(); while (rs.next()) { filtered.add(rs.getString("filter")); } rs.close(); ps.close(); ps = con.prepareStatement("INSERT INTO macbans (mac) VALUES (?)"); for (String mac : macs) { boolean matched = false; for (String filter : filtered) { if (mac.matches(filter)) { matched = true; break; } } if (!matched) { ps.setString(1, mac); try { ps.executeUpdate(); } catch (SQLException e) { } } } ps.close(); } catch (SQLException e) { System.err.println(new StringBuilder().append("Error banning MACs").append(e).toString()); } } public int finishLogin() { login_mutex.lock(); try { final byte state = getLoginState(); if (state > MapleClient.LOGIN_NOTLOGGEDIN) { // already loggedin loggedIn = false; return 7; } updateLoginState(MapleClient.LOGIN_LOGGEDIN, getSessionIPAddress()); } finally { login_mutex.unlock(); } return 0; } public void clearInformation() { this.accountName = null; this.accId = -1; this.secondPassword = null; this.salt2 = null; this.gm = false; this.loggedIn = false; this.greason = 1; this.tempban = null; this.gender = -1; this.charInfo.clear(); } public int login(String login, String pwd, boolean ipMacBanned) { String password = pwd; int loginok = 5; try { Connection con = DatabaseConnection.getConnection(); PreparedStatement ps = con.prepareStatement("SELECT * FROM accounts WHERE name = ?"); ps.setString(1, login); ResultSet rs = ps.executeQuery(); if (rs.next()) { int banned = rs.getInt("banned"); String passhash = rs.getString("password"); String salt = rs.getString("salt"); String oldSession = rs.getString("SessionIP"); this.accountName = login; this.accId = rs.getInt("id"); this.secondPassword = rs.getString("2ndpassword"); this.salt2 = rs.getString("salt2"); this.gm = (rs.getInt("gm") > 0); this.greason = rs.getByte("greason"); this.tempban = getTempBanCalendar(rs); this.gender = rs.getByte("gender"); boolean admin = rs.getInt("gm") > 1; if ((this.secondPassword != null) && (this.salt2 != null)) { this.secondPassword = LoginCrypto.rand_r(this.secondPassword); } ps.close(); if ((banned > 0) && (!this.gm)) { loginok = 3; } else { if (banned == -1) { unban(); } byte loginstate = getLoginState(); if (loginstate > MapleClient.LOGIN_NOTLOGGEDIN) { // already loggedin loggedIn = false; loginok = 7; } else if ((passhash == null) || (passhash.isEmpty())) { if ((oldSession != null) && (!oldSession.isEmpty())) { this.loggedIn = getSessionIPAddress().equals(oldSession); loginok = this.loggedIn ? 0 : 4; } else { loginok = 4; this.loggedIn = false; } } else if (password.equals(passhash)) { loginok = 0; //} else if (LoginCrypto.checkSaltedSha512Hash(passhash, pwd, salt)) { // loginok = 0; this.loggedIn = true; } else { this.loggedIn = false; this.session.close(true); System.out.println("Attempted to login: " + login + " Pass:" + pwd + "IP:" + session.getRemoteAddress()); loginok = 4; } } } rs.close(); ps.close(); } catch (SQLException e) { System.err.println(new StringBuilder().append("ERROR").append(e).toString()); } return loginok; } public int getAccountIdByLogin(String name) { Connection con = DatabaseConnection.getConnection(); int accid = 0; try { PreparedStatement ps = con.prepareStatement("SELECT id FROM accounts WHERE name = ? LIMIT 1"); ps.setString(1, name); ResultSet rs = ps.executeQuery(); while (rs.next()) { accid = rs.getInt("id"); } ps.close(); rs.close(); } catch (SQLException ex) { System.out.println(ex); } return accid; } public boolean CheckSecondPassword(String in) { boolean allow = false; boolean updatePasswordHash = false; if ((LoginCryptoLegacy.isLegacyPassword(this.secondPassword)) && (LoginCryptoLegacy.checkPassword(in, this.secondPassword))) { allow = true; updatePasswordHash = true; } else if ((this.salt2 == null) && (LoginCrypto.checkSha1Hash(this.secondPassword, in))) { allow = true; updatePasswordHash = true; } else if (LoginCrypto.checkSaltedSha512Hash(this.secondPassword, in, this.salt2)) { allow = true; } if (updatePasswordHash) { Connection con = DatabaseConnection.getConnection(); try { PreparedStatement ps = con.prepareStatement("UPDATE `accounts` SET `2ndpassword` = ?, `salt2` = ? WHERE id = ?"); String newSalt = LoginCrypto.makeSalt(); ps.setString(1, LoginCrypto.rand_s(LoginCrypto.makeSaltedSha512Hash(in, newSalt))); ps.setString(2, newSalt); ps.setInt(3, this.accId); ps.executeUpdate(); ps.close(); } catch (SQLException e) { return false; } } return allow; } private void unban() { try { Connection con = DatabaseConnection.getConnection(); PreparedStatement ps = con.prepareStatement("UPDATE accounts SET banned = 0, banreason = '' WHERE id = ?"); ps.setInt(1, this.accId); ps.executeUpdate(); ps.close(); } catch (SQLException e) { System.err.println(new StringBuilder().append("Error while unbanning").append(e).toString()); } } public static final byte unban(String charname) { try { Connection con = DatabaseConnection.getConnection(); PreparedStatement ps = con.prepareStatement("SELECT accountid from characters where name = ?"); ps.setString(1, charname); ResultSet rs = ps.executeQuery(); if (!rs.next()) { rs.close(); ps.close(); return -1; } int accid = rs.getInt(1); rs.close(); ps.close(); ps = con.prepareStatement("UPDATE accounts SET banned = 0, banreason = '' WHERE id = ?"); ps.setInt(1, accid); ps.executeUpdate(); ps.close(); } catch (SQLException e) { System.err.println(new StringBuilder().append("Error while unbanning").append(e).toString()); return -2; } return 0; } public void updateMacs(String macData) { for (String mac : macData.split(", ")) { this.macs.add(mac); } StringBuilder newMacData = new StringBuilder(); Iterator iter = this.macs.iterator(); while (iter.hasNext()) { newMacData.append((String) iter.next()); if (iter.hasNext()) { newMacData.append(", "); } } try { Connection con = DatabaseConnection.getConnection(); PreparedStatement ps = con.prepareStatement("UPDATE accounts SET macs = ? WHERE id = ?"); ps.setString(1, newMacData.toString()); ps.setInt(2, this.accId); ps.executeUpdate(); ps.close(); } catch (SQLException e) { System.err.println(new StringBuilder().append("Error saving MACs").append(e).toString()); } } public void setAccID(int id) { this.accId = id; } public int getAccID() { return this.accId; } public final void updateLoginState(final int newstate, final String SessionID) { // TODO hide? try { Connection con = DatabaseConnection.getConnection(); try (PreparedStatement ps = con.prepareStatement("UPDATE accounts SET loggedin = ?, SessionIP = ?, lastlogin = CURRENT_TIMESTAMP() WHERE id = ?")) { ps.setInt(1, newstate); ps.setString(2, SessionID); ps.setInt(3, getAccID()); ps.executeUpdate(); } } catch (SQLException e) { System.err.println("error updating login state" + e); } if (newstate == MapleClient.LOGIN_NOTLOGGEDIN) { loggedIn = false; serverTransition = false; } else { serverTransition = (newstate == MapleClient.LOGIN_SERVER_TRANSITION || newstate == MapleClient.CHANGE_CHANNEL); loggedIn = !serverTransition; } } public final void updateSecondPassword() { try { Connection con = DatabaseConnection.getConnection(); PreparedStatement ps = con.prepareStatement("UPDATE `accounts` SET `2ndpassword` = ?, `salt2` = ? WHERE id = ?"); String newSalt = LoginCrypto.makeSalt(); ps.setString(1, LoginCrypto.rand_s(LoginCrypto.makeSaltedSha512Hash(this.secondPassword, newSalt))); ps.setString(2, newSalt); ps.setInt(3, this.accId); ps.executeUpdate(); ps.close(); } catch (SQLException e) { System.err.println(new StringBuilder().append("error updating login state").append(e).toString()); } } public final byte getLoginState() { // TODO hide? Connection con = DatabaseConnection.getConnection(); try { PreparedStatement ps; ps = con.prepareStatement("SELECT loggedin, lastlogin, banned, `birthday` + 0 AS `bday` FROM accounts WHERE id = ?"); ps.setInt(1, getAccID()); byte state; try (ResultSet rs = ps.executeQuery()) { if (!rs.next() || rs.getInt("banned") > 0) { ps.close(); rs.close(); session.close(true); throw new DatabaseException("Account doesn't exist or is banned"); } birthday = rs.getInt("bday"); state = rs.getByte("loggedin"); if (state == MapleClient.LOGIN_SERVER_TRANSITION || state == MapleClient.CHANGE_CHANNEL) { if (rs.getTimestamp("lastlogin").getTime() + 20000 < System.currentTimeMillis()) { // connecting to chanserver timeout state = MapleClient.LOGIN_NOTLOGGEDIN; updateLoginState(state, getSessionIPAddress()); } } } ps.close(); if (state == MapleClient.LOGIN_LOGGEDIN) { loggedIn = true; } else { loggedIn = false; } return state; } catch (SQLException e) { loggedIn = false; throw new DatabaseException("error getting login state", e); } } public final boolean checkBirthDate(int date) { return this.birthday == date; } public final void removalTask(boolean shutdown) { try { this.player.cancelAllBuffs_(); this.player.cancelAllDebuffs(); if (this.player.getMarriageId() > 0) { MapleQuestStatus stat1 = this.player.getQuestNoAdd(MapleQuest.getInstance(160001)); MapleQuestStatus stat2 = this.player.getQuestNoAdd(MapleQuest.getInstance(160002)); if ((stat1 != null) && (stat1.getCustomData() != null) && ((stat1.getCustomData().equals("2_")) || (stat1.getCustomData().equals("2")))) { if ((stat2 != null) && (stat2.getCustomData() != null)) { stat2.setCustomData("0"); } stat1.setCustomData("3"); } } if (this.player.getMapId() == 910310300) { MapleQuestStatus stat1 = this.player.getQuestNAdd(MapleQuest.getInstance(123455)); MapleQuestStatus stat2 = this.player.getQuestNAdd(MapleQuest.getInstance(123456)); if (stat1.getCustomData() == null) { stat1.setCustomData(String.valueOf(System.currentTimeMillis())); } else if (stat2.getCustomData() == null) { stat2.setCustomData("0"); } else { int seconds = Integer.parseInt(stat2.getCustomData()) - (int) ((System.currentTimeMillis() - Long.parseLong(stat1.getCustomData())) / 1000L); if (seconds < 0) { seconds = 0; } stat2.setCustomData(String.valueOf(seconds)); } } this.player.changeRemoval(true); if (this.player.getEventInstance() != null) { this.player.getEventInstance().playerDisconnected(this.player, this.player.getId()); } IMaplePlayerShop shop = this.player.getPlayerShop(); if (shop != null) { shop.removeVisitor(this.player); if (shop.isOwner(this.player)) { if ((shop.getShopType() == 1) && (shop.isAvailable()) && (!shutdown)) { shop.setOpen(true); } else { shop.closeShop(true, !shutdown); } } } this.player.setMessenger(null); if (this.player.getMap() != null) { if ((shutdown) || ((getChannelServer() != null) && (getChannelServer().isShutdown()))) { int questID = -1; switch (this.player.getMapId()) { case 240060200: questID = 160100; break; case 240060201: questID = 160103; break; case 280030000: questID = 160101; break; case 280030001: questID = 160102; break; case 270050100: questID = 160101; break; case 105100300: case 105100400: questID = 160106; break; case 211070000: case 211070100: case 211070101: case 211070110: questID = 160107; break; case 551030200: questID = 160108; break; case 271040100: questID = 160109; break; case 262030000: case 262031300: questID = 160110; break; case 272030400: questID = 160111; } if (questID > 0) { this.player.getQuestNAdd(MapleQuest.getInstance(questID)).setCustomData("0"); } } else if (this.player.isAlive()) { switch (this.player.getMapId()) { case 220080001: case 541010100: case 541020800: this.player.getMap().addDisconnected(this.player.getId()); } } this.player.getMap().removePlayer(this.player); } } catch (Throwable e) { FileoutputUtil.outputFileError("Log_AccountStuck.rtf", e); } } public final void disconnect(boolean RemoveInChannelServer, boolean fromCS) { disconnect(RemoveInChannelServer, fromCS, false); } public final void disconnect(boolean RemoveInChannelServer, boolean fromCS, boolean shutdown) { if (this.player != null) { MapleMap map = this.player.getMap(); MapleParty party = this.player.getParty(); boolean clone = this.player.isClone(); String namez = this.player.getName(); int idz = this.player.getId(); int messengerid = this.player.getMessenger() == null ? 0 : this.player.getMessenger().getId(); int gid = this.player.getGuildId(); int fid = this.player.getFamilyId(); BuddyList bl = this.player.getBuddylist(); MaplePartyCharacter chrp = new MaplePartyCharacter(this.player); MapleMessengerCharacter chrm = new MapleMessengerCharacter(this.player); MapleGuildCharacter chrg = this.player.getMGC(); MapleFamilyCharacter chrf = this.player.getMFC(); removalTask(shutdown); LoginServer.getLoginAuth(this.player.getId()); this.player.saveToDB(true, fromCS); if (shutdown) { this.player = null; this.receiving = false; return; } if (!fromCS) { ChannelServer ch = ChannelServer.getInstance(map == null ? this.channel : map.getChannel()); int chz = World.Find.findChannel(idz); if (chz < -1) { disconnect(RemoveInChannelServer, true); return; } try { if ((chz == -1) || (ch == null) || (clone) || (ch.isShutdown())) { this.player = null; return; } if (messengerid > 0) { World.Messenger.leaveMessenger(messengerid, chrm); } if (party != null) { chrp.setOnline(false); World.Party.updateParty(party.getId(), PartyOperation.LOG_ONOFF, chrp); if ((map != null) && (party.getLeader().getId() == idz)) { MaplePartyCharacter lchr = null; for (MaplePartyCharacter pchr : party.getMembers()) { if ((pchr != null) && (map.getCharacterById(pchr.getId()) != null) && ((lchr == null) || (lchr.getLevel() < pchr.getLevel()))) { lchr = pchr; } } if (lchr != null) { World.Party.updateParty(party.getId(), PartyOperation.CHANGE_LEADER_DC, lchr); } } } if (bl != null) { if (!this.serverTransition) { World.Buddy.loggedOff(namez, idz, this.channel, bl.getBuddyIds()); } else { World.Buddy.loggedOn(namez, idz, this.channel, bl.getBuddyIds()); } } if ((gid > 0) && (chrg != null)) { World.Guild.setGuildMemberOnline(chrg, false, -1); } if ((fid > 0) && (chrf != null)) { World.Family.setFamilyMemberOnline(chrf, false, -1); } } catch (Exception e) { e.printStackTrace(); FileoutputUtil.outputFileError("Log_AccountStuck.rtf", e); System.err.println(new StringBuilder().append(getLogMessage(this, "ERROR")).append(e).toString()); } finally { if ((RemoveInChannelServer) && (ch != null)) { ch.removePlayer(idz, namez); } this.player = null; } } else { int ch = World.Find.findChannel(idz); if (ch > 0) { disconnect(RemoveInChannelServer, false); return; } try { if (party != null) { chrp.setOnline(false); World.Party.updateParty(party.getId(), PartyOperation.LOG_ONOFF, chrp); } if (!serverTransition) { World.Buddy.loggedOff(namez, idz, this.channel, bl.getBuddyIds()); } else { World.Buddy.loggedOn(namez, idz, this.channel, bl.getBuddyIds()); } if ((gid > 0) && (chrg != null)) { World.Guild.setGuildMemberOnline(chrg, false, -1); } if ((fid > 0) && (chrf != null)) { World.Family.setFamilyMemberOnline(chrf, false, -1); } if (player != null) { player.setMessenger(null); } } catch (Exception e) { e.printStackTrace(); FileoutputUtil.outputFileError("Log_AccountStuck.rtf", e); System.err.println(new StringBuilder().append(getLogMessage(this, "ERROR")).append(e).toString()); } finally { CashShopServer.getPlayerStorage().deregisterPlayer(idz, namez); player = null; } } } if ((!this.serverTransition) && (isLoggedIn())) { updateLoginState(0, getSessionIPAddress()); } this.engines.clear(); } public final String getSessionIPAddress() { return this.session.getRemoteAddress().toString().split(":")[0]; } public final boolean CheckIPAddress() { if (this.accId < 0) { return false; } try { PreparedStatement ps = DatabaseConnection.getConnection().prepareStatement("SELECT SessionIP, banned FROM accounts WHERE id = ?"); ps.setInt(1, this.accId); ResultSet rs = ps.executeQuery(); boolean canlogin = false; if (rs.next()) { String sessionIP = rs.getString("SessionIP"); if (sessionIP != null) { canlogin = getSessionIPAddress().equals(sessionIP.split(":")[0]); } if (rs.getInt("banned") > 0) { canlogin = false; } } rs.close(); ps.close(); return canlogin; } catch (SQLException e) { System.out.println("Failed in checking IP address for client."); } return true; } public final void DebugMessage(StringBuilder sb) { sb.append(getSession().getRemoteAddress()); sb.append("Connected: "); sb.append(getSession().isConnected()); sb.append(" Closing: "); sb.append(getSession().isClosing()); sb.append(" ClientKeySet: "); sb.append(getSession().getAttribute("CLIENT") != null); sb.append(" loggedin: "); sb.append(isLoggedIn()); sb.append(" has char: "); sb.append(getPlayer() != null); } public final int getChannel() { return this.channel; } public final ChannelServer getChannelServer() { return ChannelServer.getInstance(this.channel); } public final int deleteCharacter(int cid) { try { Connection con = DatabaseConnection.getConnection(); PreparedStatement ps = con.prepareStatement("SELECT guildid, guildrank, familyid, name FROM characters WHERE id = ? AND accountid = ?"); ps.setInt(1, cid); ps.setInt(2, this.accId); ResultSet rs = ps.executeQuery(); if (!rs.next()) { rs.close(); ps.close(); return 9; } if (rs.getInt("guildid") > 0) { if (rs.getInt("guildrank") == 1) { rs.close(); ps.close(); return 22; } World.Guild.deleteGuildCharacter(rs.getInt("guildid"), cid); } if ((rs.getInt("familyid") > 0) && (World.Family.getFamily(rs.getInt("familyid")) != null)) { World.Family.getFamily(rs.getInt("familyid")).leaveFamily(cid); } rs.close(); ps.close(); MapleCharacter.deleteWhereCharacterId(con, "DELETE FROM characters WHERE id = ?", cid); MapleCharacter.deleteWhereCharacterId(con, "DELETE FROM hiredmerch WHERE characterid = ?", cid); MapleCharacter.deleteWhereCharacterId(con, "DELETE FROM mts_cart WHERE characterid = ?", cid); MapleCharacter.deleteWhereCharacterId(con, "DELETE FROM mts_items WHERE characterid = ?", cid); MapleCharacter.deleteWhereCharacterId(con, "DELETE FROM mountdata WHERE characterid = ?", cid); MapleCharacter.deleteWhereCharacterId(con, "DELETE FROM inventoryitems WHERE characterid = ?", cid); MapleCharacter.deleteWhereCharacterId(con, "DELETE FROM famelog WHERE characterid = ?", cid); MapleCharacter.deleteWhereCharacterId(con, "DELETE FROM famelog WHERE characterid_to = ?", cid); MapleCharacter.deleteWhereCharacterId(con, "DELETE FROM dueypackages WHERE RecieverId = ?", cid); MapleCharacter.deleteWhereCharacterId(con, "DELETE FROM wishlist WHERE characterid = ?", cid); MapleCharacter.deleteWhereCharacterId(con, "DELETE FROM buddies WHERE characterid = ?", cid); MapleCharacter.deleteWhereCharacterId(con, "DELETE FROM buddies WHERE buddyid = ?", cid); MapleCharacter.deleteWhereCharacterId(con, "DELETE FROM keymap WHERE characterid = ?", cid); MapleCharacter.deleteWhereCharacterId(con, "DELETE FROM trocklocations WHERE characterid = ?", cid); MapleCharacter.deleteWhereCharacterId(con, "DELETE FROM regrocklocations WHERE characterid = ?", cid); MapleCharacter.deleteWhereCharacterId(con, "DELETE FROM hyperrocklocations WHERE characterid = ?", cid); MapleCharacter.deleteWhereCharacterId(con, "DELETE FROM savedlocations WHERE characterid = ?", cid); MapleCharacter.deleteWhereCharacterId(con, "DELETE FROM skills WHERE characterid = ?", cid); MapleCharacter.deleteWhereCharacterId(con, "DELETE FROM familiars WHERE characterid = ?", cid); MapleCharacter.deleteWhereCharacterId(con, "DELETE FROM mountdata WHERE characterid = ?", cid); MapleCharacter.deleteWhereCharacterId(con, "DELETE FROM skillmacros WHERE characterid = ?", cid); MapleCharacter.deleteWhereCharacterId(con, "DELETE FROM trocklocations WHERE characterid = ?", cid); MapleCharacter.deleteWhereCharacterId(con, "DELETE FROM queststatus WHERE characterid = ?", cid); MapleCharacter.deleteWhereCharacterId(con, "DELETE FROM inventoryslot WHERE characterid = ?", cid); MapleCharacter.deleteWhereCharacterId(con, "DELETE FROM extendedslots WHERE characterid = ?", cid); return 0; } catch (Exception e) { FileoutputUtil.outputFileError("Log_Packet_Except.txt", e); e.printStackTrace(); } return 10; } public final byte getGender() { return this.gender; } public final void setGender(byte gender) { this.gender = gender; } public final String getSecondPassword() { return this.secondPassword; } public final void setSecondPassword(String secondPassword) { this.secondPassword = secondPassword; } public final String getAccountName() { return this.accountName; } public final void setAccountName(String accountName) { this.accountName = accountName; } public final void setChannel(int channel) { this.channel = channel; } public final int getWorld() { return this.world; } public final void setWorld(int world) { this.world = world; } public final int getLatency() { return (int) (this.lastPong - this.lastPing); } public final long getLastPong() { return this.lastPong; } public final long getLastPing() { return this.lastPing; } public final void pongReceived() { this.lastPong = System.currentTimeMillis(); } public final void sendPing() { this.lastPing = System.currentTimeMillis(); this.session.write(LoginPacket.getPing()); Timer.PingTimer.getInstance().schedule(new Runnable() { public void run() { try { if (MapleClient.this.getLatency() < 0) { MapleClient.this.disconnect(true, false); if (MapleClient.this.getSession().isConnected()) { MapleClient.this.getSession().close(true); } } } catch (NullPointerException e) { } } }, 60000L); } public static final String getLogMessage(MapleClient cfor, String message) { return getLogMessage(cfor, message, new Object[0]); } public static final String getLogMessage(MapleCharacter cfor, String message) { return getLogMessage(cfor == null ? null : cfor.getClient(), message); } public static final String getLogMessage(MapleCharacter cfor, String message, Object[] parms) { return getLogMessage(cfor == null ? null : cfor.getClient(), message, parms); } public static final String getLogMessage(MapleClient cfor, String message, Object[] parms) { StringBuilder builder = new StringBuilder(); if (cfor != null) { if (cfor.getPlayer() != null) { builder.append("<"); builder.append(MapleCharacterUtil.makeMapleReadable(cfor.getPlayer().getName())); builder.append(" (cid: "); builder.append(cfor.getPlayer().getId()); builder.append(")> "); } if (cfor.getAccountName() != null) { builder.append("(Account: "); builder.append(cfor.getAccountName()); builder.append(") "); } } builder.append(message); for (Object parm : parms) { int start = builder.indexOf("{}"); builder.replace(start, start + 2, parm.toString()); } return builder.toString(); } public static final int findAccIdForCharacterName(String charName) { try { Connection con = DatabaseConnection.getConnection(); PreparedStatement ps = con.prepareStatement("SELECT accountid FROM characters WHERE name = ?"); ps.setString(1, charName); ResultSet rs = ps.executeQuery(); int ret = -1; if (rs.next()) { ret = rs.getInt("accountid"); } rs.close(); ps.close(); return ret; } catch (SQLException e) { System.err.println("findAccIdForCharacterName SQL error"); } return -1; } public final Set<String> getMacs() { return Collections.unmodifiableSet(this.macs); } public final boolean isGm() { return this.gm; } public final void setScriptEngine(String name, ScriptEngine e) { this.engines.put(name, e); } public final ScriptEngine getScriptEngine(String name) { return (ScriptEngine) this.engines.get(name); } public final void removeScriptEngine(String name) { this.engines.remove(name); } public final ScheduledFuture<?> getIdleTask() { return this.idleTask; } public final void setIdleTask(ScheduledFuture<?> idleTask) { this.idleTask = idleTask; } public int getCharacterSlots() { // if (isGm()) { return 15; // } /* try { Connection con = DatabaseConnection.getConnection(); PreparedStatement ps = con.prepareStatement("SELECT * FROM character_slots WHERE accid = ? AND worldid = ?"); ps.setInt(1, this.accId); ps.setInt(2, this.world); ResultSet rs = ps.executeQuery(); if (rs.next()) { this.charslots = rs.getInt("charslots"); } else { PreparedStatement psu = con.prepareStatement("INSERT INTO character_slots (accid, worldid, charslots) VALUES (?, ?, ?)"); psu.setInt(1, this.accId); psu.setInt(2, this.world); psu.setInt(3, this.charslots); psu.executeUpdate(); psu.close(); } rs.close(); ps.close(); } catch (SQLException sqlE) { sqlE.printStackTrace(); } return this.charslots;*/ } public boolean gainCharacterSlot() { if (getCharacterSlots() >= 15) { return false; } this.charslots += 1; try { Connection con = DatabaseConnection.getConnection(); PreparedStatement ps = con.prepareStatement("UPDATE character_slots SET charslots = ? WHERE worldid = ? AND accid = ?"); ps.setInt(1, this.charslots); ps.setInt(2, this.world); ps.setInt(3, this.accId); ps.executeUpdate(); ps.close(); } catch (SQLException sqlE) { sqlE.printStackTrace(); return false; } return true; } public static final byte unbanIPMacs(String charname) { try { Connection con = DatabaseConnection.getConnection(); PreparedStatement ps = con.prepareStatement("SELECT accountid from characters where name = ?"); ps.setString(1, charname); ResultSet rs = ps.executeQuery(); if (!rs.next()) { rs.close(); ps.close(); return -1; } int accid = rs.getInt(1); rs.close(); ps.close(); ps = con.prepareStatement("SELECT * FROM accounts WHERE id = ?"); ps.setInt(1, accid); rs = ps.executeQuery(); if (!rs.next()) { rs.close(); ps.close(); return -1; } String sessionIP = rs.getString("sessionIP"); String macs = rs.getString("macs"); rs.close(); ps.close(); byte ret = 0; if (sessionIP != null) { PreparedStatement psa = con.prepareStatement("DELETE FROM ipbans WHERE ip like ?"); psa.setString(1, sessionIP); psa.execute(); psa.close(); ret = (byte) (ret + 1); } if (macs != null) { String[] macz = macs.split(", "); for (String mac : macz) { if (!mac.equals("")) { PreparedStatement psa = con.prepareStatement("DELETE FROM macbans WHERE mac = ?"); psa.setString(1, mac); psa.execute(); psa.close(); } } } return (byte) (ret + 1); } catch (SQLException e) { System.err.println(new StringBuilder().append("Error while unbanning").append(e).toString()); } return -2; } public static final byte unHellban(String charname) { try { Connection con = DatabaseConnection.getConnection(); PreparedStatement ps = con.prepareStatement("SELECT accountid from characters where name = ?"); ps.setString(1, charname); ResultSet rs = ps.executeQuery(); if (!rs.next()) { rs.close(); ps.close(); return -1; } int accid = rs.getInt(1); rs.close(); ps.close(); ps = con.prepareStatement("SELECT * FROM accounts WHERE id = ?"); ps.setInt(1, accid); rs = ps.executeQuery(); if (!rs.next()) { rs.close(); ps.close(); return -1; } String sessionIP = rs.getString("sessionIP"); String email = rs.getString("email"); rs.close(); ps.close(); ps = con.prepareStatement(new StringBuilder().append("UPDATE accounts SET banned = 0, banreason = '' WHERE email = ?").append(sessionIP == null ? "" : " OR sessionIP = ?").toString()); ps.setString(1, email); if (sessionIP != null) { ps.setString(2, sessionIP); } ps.execute(); ps.close(); return 0; } catch (SQLException e) { System.err.println(new StringBuilder().append("Error while unbanning").append(e).toString()); } return -2; } public boolean isMonitored() { return this.monitored; } public void setMonitored(boolean m) { this.monitored = m; } public boolean isReceiving() { return this.receiving; } public void setReceiving(boolean m) { this.receiving = m; } public boolean canClickNPC() { return this.lastNpcClick + 500L < System.currentTimeMillis(); } public void setClickedNPC() { this.lastNpcClick = System.currentTimeMillis(); } public void removeClickedNPC() { this.lastNpcClick = 0L; } public final Timestamp getCreated() { Connection con = DatabaseConnection.getConnection(); try { PreparedStatement ps = con.prepareStatement("SELECT createdat FROM accounts WHERE id = ?"); ps.setInt(1, getAccID()); ResultSet rs = ps.executeQuery(); if (!rs.next()) { rs.close(); ps.close(); return null; } Timestamp ret = rs.getTimestamp("createdat"); rs.close(); ps.close(); return ret; } catch (SQLException e) { throw new DatabaseException("error getting create", e); } } public String getTempIP() { return this.tempIP; } public void setTempIP(String s) { this.tempIP = s; } public boolean isLocalhost() { return ServerConstants.Use_Localhost; } protected static final class CharNameAndId { public final String name; public final int id; public CharNameAndId(String name, int id) { this.name = name; this.id = id; } } }