package com.juick.xmpp.s2s; import com.juick.User; import com.juick.server.PMQueries; import com.juick.server.TagQueries; import com.juick.server.UserQueries; import com.juick.xmpp.JID; import com.juick.xmpp.Message; import com.juick.xmpp.Presence; import com.juick.xmpp.extensions.Error; import com.juick.xmpp.extensions.JuickMessage; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * * @author ugnich */ public class JuickBot { public static final JID JuickJID = new JID("juick", "juick.com", "Juick"); private static final String HELPTEXT = "@username text - Send private message\n" + "*tagname Blah-blah-blah - Post a message with tag 'tagname'\n" + "#1234 Blah-blah-blah - Answer to message #1234\n" + "#1234/5 Blah - Answer to reply #1234/5\n" + "! #1234 - Recommend post\n" + "\n" + "# - Show last messages from your feed (## - second page, ...)\n" + "@ - Show recomendations and popular personal blogs\n" + "* - Show your tags\n" + "#1234 - Show message\n" + "#1234+ - Show message with replies\n" + "@username - Show user's info\n" + "@username+ - Show user's info and last 10 messages\n" + "@username *tag - User's messages with this tag\n" + "*tag - Show last 10 messages with this tag\n" + "? blah - Search posts for 'blah'\n" + "? @username blah - Searching among user\'s posts for 'blah'\n" + "D #123 - Delete message\n" + "D #123/45 - Delete reply\n" + "DL - Delete last message/reply\n" + "S - Show your subscriptions\n" + "S #123 - Subscribe to message replies\n" + "S @username - Subscribe to user's blog\n" + "U #123 - Unsubscribe from comments\n" + "U @username - Unsubscribe from user's blog\n" + "BL - Show your blacklist\n" + "BL @username - Add/delete user to/from your blacklist\n" + "BL *tag - Add/delete tag to/from your blacklist\n" + "ON / OFF - Enable/disable subscriptions delivery\n" + "PING - Pong\n" + "\n" + "Read more: http://juick.com/help/"; public static boolean incomingPresence(Presence p) { final String username = p.to.Username.toLowerCase(); final boolean toJuick = username.equals("juick"); if (p.type == null) { Presence reply = new Presence(); reply.from = new JID(p.to.Username, p.to.Host, null); reply.to = new JID(p.from.Username, p.from.Host, null); reply.type = Presence.Type.unsubscribe; XMPPComponent.sendOut(reply); return true; } else if (p.type.equals(Presence.Type.probe)) { int uid_to = 0; if (!toJuick) { synchronized (XMPPComponent.sqlSync) { uid_to = UserQueries.getUIDbyName(XMPPComponent.sql, username); } } if (toJuick || uid_to > 0) { Presence reply = new Presence(); reply.from = p.to; reply.from.Resource = "Juick"; reply.to = p.from; reply.priority = 10; XMPPComponent.sendOut(reply); } else { Presence reply = new Presence(p.to, p.from, Presence.Type.error); reply.id = p.id; reply.addChild(new Error(Error.Type.cancel, "item-not-found")); XMPPComponent.sendOut(reply); return true; } return true; } else if (p.type.equals(Presence.Type.subscribe)) { boolean canSubscribe = false; if (toJuick) { canSubscribe = true; } else { synchronized (XMPPComponent.sqlSync) { int uid_to = UserQueries.getUIDbyName(XMPPComponent.sql, username); if (uid_to > 0) { PMQueries.addPMinRoster(XMPPComponent.sql, uid_to, p.from.Bare()); canSubscribe = true; } } } if (canSubscribe) { Presence reply = new Presence(p.to, p.from, Presence.Type.subscribed); XMPPComponent.sendOut(reply); reply.from.Resource = "Juick"; reply.priority = 10; reply.type = null; XMPPComponent.sendOut(reply); return true; } else { Presence reply = new Presence(p.to, p.from, Presence.Type.error); reply.id = p.id; reply.addChild(new Error(Error.Type.cancel, "item-not-found")); XMPPComponent.sendOut(reply); return true; } } else if (p.type.equals(Presence.Type.unsubscribe)) { if (!toJuick) { synchronized (XMPPComponent.sqlSync) { int uid_to = UserQueries.getUIDbyName(XMPPComponent.sql, username); if (uid_to > 0) { PMQueries.removePMinRoster(XMPPComponent.sql, uid_to, p.from.Bare()); } } } Presence reply = new Presence(p.to, p.from, Presence.Type.unsubscribed); XMPPComponent.sendOut(reply); } return false; } public static boolean incomingMessage(Message msg) { if (msg.body == null || msg.body.isEmpty()) { return true; } String username = msg.to.Username.toLowerCase(); User user_from = null; String signuphash = ""; synchronized (XMPPComponent.sqlSync) { user_from = UserQueries.getUserByJID(XMPPComponent.sql, msg.from.Bare()); if (user_from == null) { signuphash = UserQueries.getSignUpHashByJID(XMPPComponent.sql, msg.from.Bare()); } } if (user_from == null) { Message reply = new Message(msg.to, msg.from, Message.Type.chat); if (username.equals("juick")) { reply.body = "Для того, чтобы начать пользоваться сервисом, пожалуйста пройдите быструю регистрацию: http://juick.com/signup?type=xmpp&hash=" + signuphash + "\nЕсли у вас уже есть учетная запись на Juick, вы сможете присоединить этот JabberID к ней.\n\nTo start using Juick, please sign up: http://juick.com/signup?type=xmpp&hash=" + signuphash + "\nIf you already have an account on Juick, you will be proposed to attach this JabberID to your existing account."; } else { reply.body = "Внимание, системное сообщение!\nВаш JabberID не обнаружен в списке доверенных. Для того, чтобы отправить сообщение пользователю " + username + "@juick.com, пожалуйста зарегистрируйте свой JabberID в системе: http://juick.com/signup?type=xmpp&hash=" + signuphash + "\nЕсли у вас уже есть учетная запись на Juick, вы сможете присоединить этот JabberID к ней.\n\nWarning, system message!\nYour JabberID is not found in our server's white list. To send a message to " + username + "@juick.com, please sign up: http://juick.com/signup?type=xmpp&hash=" + signuphash + "\nIf you already have an account on Juick, you will be proposed to attach this JabberID to your existing account."; } XMPPComponent.sendOut(reply); return true; } if (username.equals("juick")) { return incomingMessageJuick(user_from, msg); } int uid_to = 0; synchronized (XMPPComponent.sqlSync) { uid_to = UserQueries.getUIDbyName(XMPPComponent.sql, username); } if (uid_to == 0) { Message reply = new Message(msg.to, msg.from, Message.Type.error); reply.id = msg.id; reply.addChild(new Error(Error.Type.cancel, "item-not-found")); XMPPComponent.sendOut(reply); return true; } boolean success = false; synchronized (XMPPComponent.sqlSync) { if (!UserQueries.isInBLAny(XMPPComponent.sql, uid_to, user_from.getUID())) { success = PMQueries.createPM(XMPPComponent.sql, user_from.getUID(), uid_to, msg.body); } } if (success) { Message m = new Message(); m.from = new JID("juick", "juick.com", null); m.to = new JID(Integer.toString(uid_to), "push.juick.com", null); JuickMessage jmsg = new JuickMessage(); synchronized (XMPPComponent.sqlSync) { jmsg.setUser(UserQueries.getUserByUID(XMPPComponent.sql, user_from.getUID())); } jmsg.setText(msg.body); m.childs.add(jmsg); XMPPComponent.connRouter.sendStanza(m.toString()); m.to.Host = "ws.juick.com"; XMPPComponent.connRouter.sendStanza(m.toString()); String jid; boolean inroster = false; synchronized (XMPPComponent.sqlSync) { jid = UserQueries.getJIDbyUID(XMPPComponent.sql, uid_to); if (jid != null) { inroster = PMQueries.havePMinRoster(XMPPComponent.sql, user_from.getUID(), jid); } } if (jid != null) { Message mm = new Message(); mm.to = new JID(jid); mm.type = Message.Type.chat; if (inroster) { mm.from = new JID(jmsg.getUser().getUName(), "juick.com", "Juick"); mm.body = msg.body; } else { mm.from = new JID("juick", "juick.com", "Juick"); mm.body = "Private message from @" + jmsg.getUser().getUName() + ":\n" + msg.body; } XMPPComponent.sendOut(mm); } } else { Message reply = new Message(msg.to, msg.from, Message.Type.error); reply.id = msg.id; reply.addChild(new Error(Error.Type.cancel, "not-allowed")); XMPPComponent.sendOut(reply); } return true; } private static Pattern regexPM = Pattern.compile("^\\@(\\S+)\\s+([\\s\\S]+)$"); public static boolean incomingMessageJuick(User user_from, Message msg) { String command = msg.body.trim(); int commandlen = command.length(); // COMPATIBILITY if (commandlen > 7 && command.substring(0, 3).equalsIgnoreCase("PM ")) { command = command.substring(3).trim(); commandlen = command.length(); } if (commandlen == 4) { if (command.equalsIgnoreCase("PING")) { commandPing(msg); return true; } else if (command.equalsIgnoreCase("HELP")) { commandHelp(msg); return true; } } else if (commandlen == 5 && command.equalsIgnoreCase("LOGIN")) { commandLogin(msg, user_from); return true; } else if (command.charAt(0) == '@') { Matcher matchPM = regexPM.matcher(command); if (matchPM.find()) { String user_to = matchPM.group(1); String msgtxt = matchPM.group(2); commandPM(msg, user_from, user_to, msgtxt); return true; } } else if (commandlen == 2 && command.equalsIgnoreCase("BL")) { commandBLShow(msg, user_from); return true; } return false; } private static void commandPing(Message m) { Presence p = new Presence(JuickJID, m.from); p.priority = 10; XMPPComponent.sendOut(p); Message reply = new Message(JuickJID, m.from, Message.Type.chat); reply.body = "PONG"; XMPPComponent.sendOut(reply); } private static void commandHelp(Message m) { Message reply = new Message(JuickJID, m.from, Message.Type.chat); reply.body = HELPTEXT; XMPPComponent.sendOut(reply); } private static void commandLogin(Message m, User user_from) { Message reply = new Message(JuickJID, m.from, Message.Type.chat); reply.body = "http://juick.com/login?" + UserQueries.getHashByUID(XMPPComponent.sql, user_from.getUID()); XMPPComponent.sendOut(reply); } private static void commandPM(Message m, User user_from, String user_to, String body) { int ret = 0; int uid_to = 0; String jid_to = null; boolean haveInRoster = false; synchronized (XMPPComponent.sqlSync) { if (user_to.indexOf('@') > 0) { uid_to = UserQueries.getUIDbyJID(XMPPComponent.sql, user_to); } else { uid_to = UserQueries.getUIDbyName(XMPPComponent.sql, user_to); } if (uid_to > 0) { if (!UserQueries.isInBLAny(XMPPComponent.sql, uid_to, user_from.getUID())) { if (PMQueries.createPM(XMPPComponent.sql, user_from.getUID(), uid_to, body)) { jid_to = UserQueries.getJIDbyUID(XMPPComponent.sql, uid_to); if (jid_to != null) { haveInRoster = PMQueries.havePMinRoster(XMPPComponent.sql, user_from.getUID(), jid_to); } ret = 200; } else { ret = 500; } } else { ret = 403; } } else { ret = 404; } } if (ret == 200) { Message msg = new Message(); msg.from = new JID("juick", "juick.com", null); msg.to = new JID(Integer.toString(uid_to), "push.juick.com", null); JuickMessage jmsg = new JuickMessage(); jmsg.setUser(user_from); jmsg.setText(body); msg.childs.add(jmsg); XMPPComponent.connRouter.sendStanza(msg.toString()); msg.to.Host = "ws.juick.com"; XMPPComponent.connRouter.sendStanza(msg.toString()); if (jid_to != null) { Message mm = new Message(); mm.to = new JID(jid_to); mm.type = Message.Type.chat; if (haveInRoster) { mm.from = new JID(user_from.getUName(), "juick.com", "Juick"); mm.body = body; } else { mm.from = new JID("juick", "juick.com", "Juick"); mm.body = "Private message from @" + user_from.getUName() + ":\n" + body; } XMPPComponent.sendOut(mm); } } Message reply = new Message(m.to, m.from); if (ret == 200) { reply.type = m.type; reply.body = "Private message sent"; } else { reply.type = Message.Type.error; reply.body = "Error " + ret; } XMPPComponent.sendOut(reply); } private static void commandBLShow(Message m, User user_from) { List blusers; List bltags; synchronized (XMPPComponent.sqlSync) { blusers = UserQueries.getUserBLUsers(XMPPComponent.sql, user_from.getUID()); bltags = TagQueries.getUserBLTags(XMPPComponent.sql, user_from.getUID()); } String txt = ""; if (bltags.size() > 0) { for (int i = 0; i < bltags.size(); i++) { txt += "*" + bltags.get(i) + "\n"; } if (blusers.size() > 0) { txt += "\n"; } } if (blusers.size() > 0) { for (int i = 0; i < blusers.size(); i++) { txt += "@" + blusers.get(i).getUName() + "\n"; } } if (txt.isEmpty()) { txt = "You don't have any users or tags in your blacklist."; } Message reply = new Message(JuickJID, m.from, Message.Type.chat); reply.body = txt; XMPPComponent.sendOut(reply); } }