/*
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 java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import client.MapleCharacter;
import client.MapleClient;
import tools.DatabaseConnection;
import tools.Output;
import net.AbstractMaplePacketHandler;
import tools.MaplePacketCreator;
import tools.data.input.SeekableLittleEndianAccessor;
public final class BBSOperationHandler extends AbstractMaplePacketHandler {
private String correctLength(String in, int maxSize) {
return in.length() > maxSize ? in.substring(0, maxSize) : in;
}
public final void handlePacket(SeekableLittleEndianAccessor slea, MapleClient c) {
if (c.getPlayer().getGuildId() < 1) {
return;
}
byte mode = slea.readByte();
int localthreadid = 0;
switch (mode) {
case 0:
boolean bEdit = slea.readByte() == 1;
if (bEdit) {
localthreadid = slea.readInt();
}
boolean bNotice = slea.readByte() == 1;
String title = correctLength(slea.readMapleAsciiString(), 25);
String text = correctLength(slea.readMapleAsciiString(), 600);
int icon = slea.readInt();
if (icon >= 0x64 && icon <= 0x6a) {
if (c.getPlayer().getItemQuantity(5290000 + icon - 0x64, false) > 0) {
return;
}
} else if (icon < 0 || icon > 3) {
return;
}
if (!bEdit) {
newBBSThread(c, title, text, icon, bNotice);
} else {
editBBSThread(c, title, text, icon, localthreadid);
}
break;
case 1:
localthreadid = slea.readInt();
deleteBBSThread(c, localthreadid);
break;
case 2:
int start = slea.readInt();
listBBSThreads(c, start * 10);
break;
case 3: // list thread + reply, followed by id (int)
localthreadid = slea.readInt();
displayThread(c, localthreadid);
break;
case 4: // reply
localthreadid = slea.readInt();
text = correctLength(slea.readMapleAsciiString(), 25);
newBBSReply(c, localthreadid, text);
break;
case 5: // delete reply
localthreadid = slea.readInt(); // we don't use this
int replyid = slea.readInt();
deleteBBSReply(c, replyid);
break;
default:
Output.print("Unhandled BBS mode: " + slea.toString());
}
}
private static void listBBSThreads(MapleClient c, int start) {
try {
PreparedStatement ps = DatabaseConnection.getConnection().prepareStatement("SELECT * FROM bbs_threads WHERE guildid = ? ORDER BY localthreadid DESC");
ps.setInt(1, c.getPlayer().getGuildId());
ResultSet rs = ps.executeQuery();
c.announce(MaplePacketCreator.BBSThreadList(rs, start));
rs.close();
ps.close();
} catch (SQLException se) {
se.printStackTrace();
}
}
private static void newBBSReply(MapleClient c, int localthreadid, String text) {
if (c.getPlayer().getGuildId() <= 0) {
return;
}
Connection con = DatabaseConnection.getConnection();
try {
PreparedStatement ps = con.prepareStatement("SELECT threadid FROM bbs_threads WHERE guildid = ? AND localthreadid = ?");
ps.setInt(1, c.getPlayer().getGuildId());
ps.setInt(2, localthreadid);
ResultSet threadRS = ps.executeQuery();
if (!threadRS.next()) {
threadRS.close();
ps.close();
return;
}
int threadid = threadRS.getInt("threadid");
threadRS.close();
ps.close();
ps = con.prepareStatement("INSERT INTO bbs_replies " + "(`threadid`, `postercid`, `timestamp`, `content`) VALUES " + "(?, ?, ?, ?)");
ps.setInt(1, threadid);
ps.setInt(2, c.getPlayer().getId());
ps.setLong(3, System.currentTimeMillis());
ps.setString(4, text);
ps.execute();
ps.close();
ps = con.prepareStatement("UPDATE bbs_threads SET replycount = replycount + 1 WHERE threadid = ?");
ps.setInt(1, threadid);
ps.execute();
ps.close();
displayThread(c, localthreadid);
} catch (SQLException se) {
se.printStackTrace();
}
}
private static void editBBSThread(MapleClient client, String title, String text, int icon, int localthreadid) {
MapleCharacter c = client.getPlayer();
if (c.getGuildId() < 1) {
return;
}
try {
PreparedStatement ps = DatabaseConnection.getConnection().prepareStatement("UPDATE bbs_threads SET `name` = ?, `timestamp` = ?, " + "`icon` = ?, " + "`startpost` = ? WHERE guildid = ? AND localthreadid = ? AND (postercid = ? OR ?)");
ps.setString(1, title);
ps.setLong(2, System.currentTimeMillis());
ps.setInt(3, icon);
ps.setString(4, text);
ps.setInt(5, c.getGuildId());
ps.setInt(6, localthreadid);
ps.setInt(7, c.getId());
ps.setBoolean(8, c.getGuildRank() < 3);
ps.execute();
ps.close();
displayThread(client, localthreadid);
} catch (SQLException se) {
se.printStackTrace();
}
}
private static void newBBSThread(MapleClient client, String title, String text, int icon, boolean bNotice) {
MapleCharacter c = client.getPlayer();
if (c.getGuildId() <= 0) {
return;
}
int nextId = 0;
try {
Connection con = DatabaseConnection.getConnection();
PreparedStatement ps;
if (!bNotice) {
ps = con.prepareStatement("SELECT MAX(localthreadid) AS lastLocalId FROM bbs_threads WHERE guildid = ?");
ps.setInt(1, c.getGuildId());
ResultSet rs = ps.executeQuery();
rs.next();
nextId = rs.getInt("lastLocalId") + 1;
rs.close();
ps.close();
}
ps = con.prepareStatement("INSERT INTO bbs_threads " + "(`postercid`, `name`, `timestamp`, `icon`, `startpost`, " + "`guildid`, `localthreadid`) " + "VALUES(?, ?, ?, ?, ?, ?, ?)");
ps.setInt(1, c.getId());
ps.setString(2, title);
ps.setLong(3, System.currentTimeMillis());
ps.setInt(4, icon);
ps.setString(5, text);
ps.setInt(6, c.getGuildId());
ps.setInt(7, nextId);
ps.execute();
ps.close();
displayThread(client, nextId);
} catch (SQLException se) {
se.printStackTrace();
}
}
public static void deleteBBSThread(MapleClient client, int localthreadid) {
MapleCharacter mc = client.getPlayer();
if (mc.getGuildId() <= 0) {
return;
}
Connection con = DatabaseConnection.getConnection();
try {
PreparedStatement ps = con.prepareStatement("SELECT threadid, postercid FROM bbs_threads WHERE guildid = ? AND localthreadid = ?");
ps.setInt(1, mc.getGuildId());
ps.setInt(2, localthreadid);
ResultSet threadRS = ps.executeQuery();
if (!threadRS.next()) {
threadRS.close();
ps.close();
return;
}
if (mc.getId() != threadRS.getInt("postercid") && mc.getGuildRank() > 2) {
threadRS.close();
ps.close();
return;
}
int threadid = threadRS.getInt("threadid");
ps.close();
ps = con.prepareStatement("DELETE FROM bbs_replies WHERE threadid = ?");
ps.setInt(1, threadid);
ps.execute();
ps.close();
ps = con.prepareStatement("DELETE FROM bbs_threads WHERE threadid = ?");
ps.setInt(1, threadid);
ps.execute();
threadRS.close();
ps.close();
} catch (SQLException se) {
se.printStackTrace();
}
}
public static void deleteBBSReply(MapleClient client, int replyid) {
MapleCharacter mc = client.getPlayer();
if (mc.getGuildId() <= 0) {
return;
}
int threadid;
Connection con = DatabaseConnection.getConnection();
try {
PreparedStatement ps = con.prepareStatement("SELECT postercid, threadid FROM bbs_replies WHERE replyid = ?");
ps.setInt(1, replyid);
ResultSet rs = ps.executeQuery();
if (!rs.next()) {
rs.close();
ps.close();
return;
}
if (mc.getId() != rs.getInt("postercid") && mc.getGuildRank() > 2) {
rs.close();
ps.close();
return;
}
threadid = rs.getInt("threadid");
rs.close();
ps.close();
ps = con.prepareStatement("DELETE FROM bbs_replies WHERE replyid = ?");
ps.setInt(1, replyid);
ps.execute();
ps.close();
ps = con.prepareStatement("UPDATE bbs_threads SET replycount = replycount - 1 WHERE threadid = ?");
ps.setInt(1, threadid);
ps.execute();
ps.close();
displayThread(client, threadid, false);
} catch (SQLException se) {
se.printStackTrace();
}
}
public static void displayThread(MapleClient client, int threadid) {
displayThread(client, threadid, true);
}
public static void displayThread(MapleClient client, int threadid, boolean bIsThreadIdLocal) {
MapleCharacter mc = client.getPlayer();
if (mc.getGuildId() <= 0) {
return;
}
Connection con = DatabaseConnection.getConnection();
try {
PreparedStatement ps = con.prepareStatement("SELECT * FROM bbs_threads WHERE guildid = ? AND " + (bIsThreadIdLocal ? "local" : "") + "threadid = ?");
ps.setInt(1, mc.getGuildId());
ps.setInt(2, threadid);
ResultSet threadRS = ps.executeQuery();
if (!threadRS.next()) {
threadRS.close();
ps.close();
return;
}
ResultSet repliesRS = null;
PreparedStatement ps2 = null;
if (threadRS.getInt("replycount") >= 0) {
ps2 = con.prepareStatement("SELECT * FROM bbs_replies WHERE threadid = ?");
ps2.setInt(1, !bIsThreadIdLocal ? threadid : threadRS.getInt("threadid"));
repliesRS = ps2.executeQuery();
}
client.announce(MaplePacketCreator.showThread(bIsThreadIdLocal ? threadid : threadRS.getInt("localthreadid"), threadRS, repliesRS));
repliesRS.close();
ps.close();
if (ps2 != null) {
ps2.close();
}
} catch (SQLException se) {
se.printStackTrace();
} catch (RuntimeException re) {// btw we get this everytime for some
// reason, but replies work!
re.printStackTrace();
Output.print("The number of reply rows does not match the replycount in thread.");
}
}
}