/* OrpheusMS: MapleStory Private Server based on OdinMS Copyright (C) 2012 Aaron Weiss <aaron@deviant-core.net> 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 as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. 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 net.server.handlers.channel; import static client.BuddyList.BuddyOperation.ADDED; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import client.BuddyList; import client.BuddylistEntry; import client.CharacterNameAndId; import client.MapleCharacter; import client.MapleClient; import client.BuddyList.BuddyAddResult; import client.BuddyList.BuddyOperation; import tools.DatabaseConnection; import net.AbstractMaplePacketHandler; import net.server.World; import tools.MaplePacketCreator; import tools.data.input.SeekableLittleEndianAccessor; public class BuddylistModifyHandler extends AbstractMaplePacketHandler { private static class CharacterIdNameBuddyCapacity extends CharacterNameAndId { private int buddyCapacity; public CharacterIdNameBuddyCapacity(int id, String name, int buddyCapacity) { super(id, name); this.buddyCapacity = buddyCapacity; } public int getBuddyCapacity() { return buddyCapacity; } } private void nextPendingRequest(MapleClient c) { CharacterNameAndId pendingBuddyRequest = c.getPlayer().getBuddylist().pollPendingRequest(); if (pendingBuddyRequest != null) { c.announce(MaplePacketCreator.requestBuddylistAdd(pendingBuddyRequest.getId(), c.getPlayer().getId(), pendingBuddyRequest.getName())); } } private CharacterIdNameBuddyCapacity getCharacterIdAndNameFromDatabase(String name) throws SQLException { Connection con = DatabaseConnection.getConnection(); PreparedStatement ps = con.prepareStatement("SELECT id, name, buddyCapacity FROM characters WHERE name LIKE ?"); ps.setString(1, name); ResultSet rs = ps.executeQuery(); CharacterIdNameBuddyCapacity ret = null; if (rs.next()) { ret = new CharacterIdNameBuddyCapacity(rs.getInt("id"), rs.getString("name"), rs.getInt("buddyCapacity")); } rs.close(); ps.close(); return ret; } @Override public void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) { int mode = slea.readByte(); MapleCharacter player = c.getPlayer(); BuddyList buddylist = player.getBuddylist(); if (mode == 1) { // add String addName = slea.readMapleAsciiString(); String group = slea.readMapleAsciiString(); if (group.length() > 16 || addName.length() < 4 || addName.length() > 13) { return; // hax. } BuddylistEntry ble = buddylist.get(addName); if (ble != null && !ble.isVisible() && group.equals(ble.getGroup())) { c.announce(MaplePacketCreator.serverNotice(1, "You already have \"" + ble.getName() + "\" on your Buddylist")); } else if (buddylist.isFull() && ble == null) { c.announce(MaplePacketCreator.serverNotice(1, "Your buddylist is already full")); } else if (ble == null) { try { World world = c.getWorldServer(); CharacterIdNameBuddyCapacity charWithId = null; byte channel; MapleCharacter otherChar = c.getChannelServer().getPlayerStorage().getCharacterByName(addName); if (otherChar != null) { channel = c.getChannel(); charWithId = new CharacterIdNameBuddyCapacity(otherChar.getId(), otherChar.getName(), otherChar.getBuddylist().getCapacity()); } else { channel = world.find(addName); charWithId = getCharacterIdAndNameFromDatabase(addName); } if (charWithId != null) { BuddyAddResult buddyAddResult = null; if (channel != -1) { buddyAddResult = world.requestBuddyAdd(addName, c.getChannel(), player.getId(), player.getName()); } else { Connection con = DatabaseConnection.getConnection(); PreparedStatement ps = con.prepareStatement("SELECT COUNT(*) as buddyCount FROM buddies WHERE characterid = ? AND pending = 0"); ps.setInt(1, charWithId.getId()); ResultSet rs = ps.executeQuery(); if (!rs.next()) { throw new RuntimeException("Result set expected"); } else if (rs.getInt("buddyCount") >= charWithId.getBuddyCapacity()) { buddyAddResult = BuddyAddResult.BUDDYLIST_FULL; } rs.close(); ps.close(); ps = con.prepareStatement("SELECT pending FROM buddies WHERE characterid = ? AND buddyid = ?"); ps.setInt(1, charWithId.getId()); 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.announce(MaplePacketCreator.serverNotice(1, "\"" + addName + "\"'s Buddylist is full")); } else { byte displayChannel = -1; int otherCid = charWithId.getId(); if (buddyAddResult == BuddyAddResult.ALREADY_ON_LIST && channel != -1) { displayChannel = channel; notifyRemoteChannel(c, channel, otherCid, ADDED); } else if (buddyAddResult != BuddyAddResult.ALREADY_ON_LIST && channel == -1) { Connection con = DatabaseConnection.getConnection(); PreparedStatement ps = con.prepareStatement("INSERT INTO buddies (characterid, `buddyid`, `pending`) VALUES (?, ?, 1)"); ps.setInt(1, charWithId.getId()); ps.setInt(2, player.getId()); ps.executeUpdate(); ps.close(); } buddylist.put(new BuddylistEntry(charWithId.getName(), group, otherCid, displayChannel, true)); c.announce(MaplePacketCreator.updateBuddylist(buddylist.getBuddies())); } } else { c.announce(MaplePacketCreator.serverNotice(1, "A character called \"" + addName + "\" does not exist")); } } catch (SQLException e) { } } else { ble.changeGroup(group); c.announce(MaplePacketCreator.updateBuddylist(buddylist.getBuddies())); } } else if (mode == 2) { // accept buddy int otherCid = slea.readInt(); if (!buddylist.isFull()) { try { byte channel = c.getWorldServer().find(otherCid);// worldInterface.find(otherCid); String otherName = null; MapleCharacter otherChar = c.getChannelServer().getPlayerStorage().getCharacterById(otherCid); if (otherChar == null) { Connection con = DatabaseConnection.getConnection(); PreparedStatement ps = con.prepareStatement("SELECT name FROM characters WHERE id = ?"); ps.setInt(1, otherCid); ResultSet rs = ps.executeQuery(); if (rs.next()) { otherName = rs.getString("name"); } rs.close(); ps.close(); } else { otherName = otherChar.getName(); } if (otherName != null) { buddylist.put(new BuddylistEntry(otherName, "Default Group", otherCid, channel, true)); c.announce(MaplePacketCreator.updateBuddylist(buddylist.getBuddies())); notifyRemoteChannel(c, channel, otherCid, ADDED); } } catch (SQLException e) { } } nextPendingRequest(c); } else if (mode == 3) { // delete int otherCid = slea.readInt(); if (buddylist.containsVisible(otherCid)) { notifyRemoteChannel(c, c.getWorldServer().find(otherCid), otherCid, BuddyOperation.DELETED); } buddylist.remove(otherCid); c.announce(MaplePacketCreator.updateBuddylist(player.getBuddylist().getBuddies())); nextPendingRequest(c); } } private void notifyRemoteChannel(MapleClient c, int remoteChannel, int otherCid, BuddyOperation operation) { MapleCharacter player = c.getPlayer(); if (remoteChannel != -1) { c.getWorldServer().buddyChanged(otherCid, player.getId(), player.getName(), c.getChannel(), operation); } } }