/* * This file is part of the OdinMS Maple Story Server Copyright (C) 2008 ~ 2010 * Patrick Huy <patrick.huy@frz.cc> Matthias Butz <matze@odinms.de> Jan * Christian Meyer <vimes@odinms.de> * * This program is free software: you can redistribute it and/or modify it under * the terms of the GNU Affero General Public License version 3 as published by * the Free Software Foundation. You may not use, modify or distribute this * program under any other version of the GNU Affero General Public License. * * This program is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more * details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/>. */ package javastory.channel.handling; import java.rmi.RemoteException; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import javastory.channel.ChannelCharacter; import javastory.channel.ChannelClient; import javastory.channel.ChannelServer; import javastory.channel.client.BuddyAddResult; import javastory.channel.client.BuddyList; import javastory.channel.client.BuddyListEntry; import javastory.channel.client.BuddyOperation; import javastory.client.SimpleCharacterInfo; import javastory.db.Database; import javastory.io.PacketFormatException; import javastory.io.PacketReader; import javastory.rmi.ChannelWorldInterface; import javastory.rmi.WorldChannelInterface; import javastory.tools.packets.ChannelPackets; public class BuddyListHandler { private static final class CharacterIdNameBuddyCapacity extends SimpleCharacterInfo { /** * */ private static final long serialVersionUID = -1029822767319859504L; public final int BuddyCapacity; public CharacterIdNameBuddyCapacity(final int id, final String name, final int level, final int job, final int buddyCapacity) { super(id, name, level, job); this.BuddyCapacity = buddyCapacity; } } private static void nextPendingRequest(final ChannelClient c) { final SimpleCharacterInfo request = c.getPlayer().getBuddyList().pollPendingRequest(); if (request != null) { c.write(ChannelPackets.requestBuddylistAdd(request.Id, request.Name, request.Level, request.Job)); } } private static CharacterIdNameBuddyCapacity getCharacterIdAndNameFromDatabase(final String name) throws SQLException { final Connection con = Database.getConnection(); CharacterIdNameBuddyCapacity ret; try (PreparedStatement ps = con.prepareStatement("SELECT * FROM `characters` WHERE `name` LIKE ?")) { ps.setString(1, name); try (ResultSet rs = ps.executeQuery()) { ret = null; if (rs.next()) { if (rs.getInt("gm") == 0) { ret = new CharacterIdNameBuddyCapacity(rs.getInt("id"), rs.getString("name"), rs.getInt("level"), rs.getInt("job"), rs .getInt("buddyCapacity")); } } } } return ret; } public static void handleBuddyOperation(final PacketReader reader, final ChannelClient c) throws PacketFormatException { final int mode = reader.readByte(); final WorldChannelInterface worldInterface = ChannelServer.getWorldInterface(); final ChannelCharacter player = c.getPlayer(); final BuddyList buddylist = player.getBuddyList(); if (mode == 1) { // add final String addName = reader.readLengthPrefixedString(); final String groupName = reader.readLengthPrefixedString(); final BuddyListEntry ble = buddylist.get(addName); if (addName.length() > 13 || groupName.length() > 16) { return; } if (ble != null && !ble.isVisible()) { c.write(ChannelPackets.buddylistMessage((byte) 13)); } else if (buddylist.isFull()) { c.write(ChannelPackets.buddylistMessage((byte) 11)); } else { try { CharacterIdNameBuddyCapacity charWithId = null; int channel; final ChannelCharacter otherChar = ChannelServer.getPlayerStorage().getCharacterByName(addName); if (otherChar != null) { channel = c.getChannelId(); if (!otherChar.isGM() || player.isGM()) { charWithId = new CharacterIdNameBuddyCapacity(otherChar.getId(), otherChar.getName(), otherChar.getLevel(), otherChar.getJobId(), otherChar.getBuddyList().getCapacity()); } } else { channel = worldInterface.find(addName); charWithId = getCharacterIdAndNameFromDatabase(addName); } if (charWithId != null) { BuddyAddResult buddyAddResult = null; if (channel != -1) { final ChannelWorldInterface channelInterface = worldInterface.getChannelInterface(channel); buddyAddResult = channelInterface.requestBuddyAdd(addName, c.getChannelId(), player.getId(), player.getName(), player.getLevel(), player.getJobId()); } else { final Connection con = Database.getConnection(); PreparedStatement ps = con.prepareStatement("SELECT COUNT(*) AS `buddyCount` FROM `buddies` WHERE `characterid` = ? AND `pending` = 0"); ps.setInt(1, charWithId.Id); ResultSet rs = ps.executeQuery(); if (!rs.next()) { ps.close(); rs.close(); throw new RuntimeException("Result set expected"); } else { final int count = rs.getInt("buddyCount"); if (count >= charWithId.BuddyCapacity) { buddyAddResult = BuddyAddResult.BUDDYLIST_FULL; } } rs.close(); ps.close(); ps = con.prepareStatement("SELECT `pending` FROM `buddies` WHERE `characterid` = ? AND `buddyid` = ?"); ps.setInt(1, charWithId.Id); ps.setInt(2, player.getId()); rs = ps.executeQuery(); if (rs.next()) { buddyAddResult = BuddyAddResult.ALREADY_ON_LIST; } rs.close(); ps.close(); } if (buddyAddResult == BuddyAddResult.BUDDYLIST_FULL) { c.write(ChannelPackets.buddylistMessage((byte) 12)); } else { int displayChannel = -1; final int otherCid = charWithId.Id; if (buddyAddResult == BuddyAddResult.ALREADY_ON_LIST && channel != -1) { displayChannel = channel; notifyRemoteChannel(c, channel, otherCid, BuddyOperation.ADDED); } else if (buddyAddResult != BuddyAddResult.ALREADY_ON_LIST && channel == -1) { final Connection con = Database.getConnection(); try (PreparedStatement ps = con .prepareStatement("INSERT INTO `buddies` (`characterid`, `buddyid`, `groupname`, `pending`) VALUES (?, ?, ?, 1)")) { ps.setInt(1, charWithId.Id); ps.setInt(2, player.getId()); ps.setString(3, groupName); ps.executeUpdate(); } } buddylist.put(new BuddyListEntry(charWithId.Name, otherCid, groupName, displayChannel, true, charWithId.Level, charWithId .Job)); c.write(ChannelPackets.updateBuddyList(buddylist.getBuddies())); } } else { c.write(ChannelPackets.buddylistMessage((byte) 15)); } } catch (final RemoteException e) { System.err.println("REMOTE THROW" + e); } catch (final SQLException e) { System.err.println("SQL THROW" + e); } } } else if (mode == 2) { // accept buddy final int otherCid = reader.readInt(); if (!buddylist.isFull()) { try { final int channel = worldInterface.find(otherCid); String otherName = null; int otherLevel = 0, otherJob = 0; final ChannelCharacter otherChar = ChannelServer.getPlayerStorage().getCharacterById(otherCid); if (otherChar == null) { final Connection con = Database.getConnection(); try (PreparedStatement ps = con.prepareStatement("SELECT `name`, `level`, `job` FROM `characters` WHERE `id` = ?")) { ps.setInt(1, otherCid); try (ResultSet rs = ps.executeQuery()) { if (rs.next()) { otherName = rs.getString("name"); otherLevel = rs.getInt("level"); otherJob = rs.getInt("job"); } } } } else { otherName = otherChar.getName(); } if (otherName != null) { buddylist.put(new BuddyListEntry(otherName, otherCid, "ETC", channel, true, otherLevel, otherJob)); c.write(ChannelPackets.updateBuddyList(buddylist.getBuddies())); notifyRemoteChannel(c, channel, otherCid, BuddyOperation.ADDED); } } catch (final RemoteException e) { System.err.println("REMOTE THROW" + e); } catch (final SQLException e) { System.err.println("SQL THROW" + e); } } nextPendingRequest(c); } else if (mode == 3) { // delete final int otherCid = reader.readInt(); if (buddylist.containsVisible(otherCid)) { try { notifyRemoteChannel(c, worldInterface.find(otherCid), otherCid, BuddyOperation.DELETED); } catch (final RemoteException e) { System.err.println("REMOTE THROW" + e); } } buddylist.remove(otherCid); c.write(ChannelPackets.updateBuddyList(player.getBuddyList().getBuddies())); nextPendingRequest(c); } } private static void notifyRemoteChannel(final ChannelClient c, final int remoteChannel, final int otherCid, final BuddyOperation operation) throws RemoteException { final WorldChannelInterface worldInterface = ChannelServer.getWorldInterface(); final ChannelCharacter player = c.getPlayer(); if (remoteChannel != -1) { final ChannelWorldInterface channelInterface = worldInterface.getChannelInterface(remoteChannel); channelInterface.buddyChanged(otherCid, player.getId(), player.getName(), c.getChannelId(), operation, player.getLevel(), player.getJobId()); } } }