package com.juick.components.s2s; import com.juick.User; import com.juick.components.XMPPServer; import com.juick.xmpp.Message; import com.juick.xmpp.Presence; import com.juick.xmpp.Stanza; import com.juick.xmpp.extensions.XMPPError; import com.juick.xmpp.extensions.JuickMessage; import org.apache.commons.lang3.StringUtils; import rocks.xmpp.addr.Jid; import javax.inject.Inject; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; /** * * @author ugnich */ public class JuickBot implements StanzaListener { XMPPServer xmpp; @Inject public JuickBot(XMPPServer xmpp) { this.xmpp = xmpp; xmpp.addStanzaListener(this); } 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 boolean incomingPresence(Presence p) { final String username = p.to.getLocal(); final boolean toJuick = username.equals("juick"); if (p.type == null) { Presence reply = new Presence(); reply.from = p.to.asBareJid(); reply.to = p.from.asBareJid(); reply.type = Presence.Type.unsubscribe; xmpp.sendOut(reply); return true; } else if (p.type.equals(Presence.Type.probe)) { int uid_to = 0; if (!toJuick) { uid_to = xmpp.userService.getUIDbyName(username); } if (toJuick || uid_to > 0) { Presence reply = new Presence(); reply.from = p.to.withResource("Juick"); reply.to = p.from; reply.priority = 10; xmpp.sendOut(reply); } else { Presence reply = new Presence(p.to, p.from, Presence.Type.error); reply.id = p.id; reply.addChild(new XMPPError(XMPPError.Type.cancel, "item-not-found")); xmpp.sendOut(reply); return true; } return true; } else if (p.type.equals(Presence.Type.subscribe)) { boolean canSubscribe = false; if (toJuick) { canSubscribe = true; } else { int uid_to = xmpp.userService.getUIDbyName(username); if (uid_to > 0) { xmpp.pmQueriesService.addPMinRoster(uid_to, p.from.asBareJid().toEscapedString()); canSubscribe = true; } } if (canSubscribe) { Presence reply = new Presence(p.to, p.from, Presence.Type.subscribed); xmpp.sendOut(reply); reply.from = reply.from.withResource("Juick"); reply.priority = 10; reply.type = null; xmpp.sendOut(reply); return true; } else { Presence reply = new Presence(p.to, p.from, Presence.Type.error); reply.id = p.id; reply.addChild(new XMPPError(XMPPError.Type.cancel, "item-not-found")); xmpp.sendOut(reply); return true; } } else if (p.type.equals(Presence.Type.unsubscribe)) { if (!toJuick) { int uid_to = xmpp.userService.getUIDbyName(username); if (uid_to > 0) { xmpp.pmQueriesService.removePMinRoster(uid_to, p.from.asBareJid().toEscapedString()); } } Presence reply = new Presence(p.to, p.from, Presence.Type.unsubscribed); xmpp.sendOut(reply); } return false; } public boolean incomingMessage(Message msg) { if (msg.body == null || msg.body.isEmpty()) { return false; } String username = msg.to.getLocal(); User user_from; String signuphash = StringUtils.EMPTY; user_from = xmpp.userService.getUserByJID(msg.from.asBareJid().toEscapedString()); if (user_from == null) { signuphash = xmpp.userService.getSignUpHashByJID(msg.from.asBareJid().toEscapedString()); } 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."; } xmpp.sendOut(reply); return true; } if (username.equals("juick")) { return incomingMessageJuick(user_from, msg); } int uid_to = xmpp.userService.getUIDbyName(username); if (uid_to == 0) { Message reply = new Message(msg.to, msg.from, Message.Type.error); reply.id = msg.id; reply.addChild(new XMPPError(XMPPError.Type.cancel, "item-not-found")); xmpp.sendOut(reply); return true; } boolean success = false; if (!xmpp.userService.isInBLAny(uid_to, user_from.getUid())) { success = xmpp.pmQueriesService.createPM(user_from.getUid(), uid_to, msg.body); } if (success) { Message m = new Message(); m.from = Jid.of("juick@juick.com"); m.to = Jid.of(Integer.toString(uid_to), "push.juick.com", null); JuickMessage jmsg = new JuickMessage(); jmsg.setUser(user_from); jmsg.setText(msg.body); m.childs.add(jmsg); xmpp.getRouter().sendStanza(m.toString()); m.to = Jid.of(Integer.toString(uid_to), "ws.juick.com", null); xmpp.getRouter().sendStanza(m.toString()); List jids; boolean inroster = false; jids = xmpp.userService.getJIDsbyUID(uid_to); for (String jid : jids) { Message mm = new Message(); mm.to = Jid.of(jid); mm.type = Message.Type.chat; inroster = xmpp.pmQueriesService.havePMinRoster(user_from.getUid(), jid); if (inroster) { mm.from = Jid.of(jmsg.getUser().getName(), "juick.com", "Juick"); mm.body = msg.body; } else { mm.from = Jid.of("juick", "juick.com", "Juick"); mm.body = "Private message from @" + jmsg.getUser().getName() + ":\n" + msg.body; } xmpp.sendOut(mm); } } else { Message reply = new Message(msg.to, msg.from, Message.Type.error); reply.id = msg.id; reply.addChild(new XMPPError(XMPPError.Type.cancel, "not-allowed")); xmpp.sendOut(reply); } return false; } private static Pattern regexPM = Pattern.compile("^\\@(\\S+)\\s+([\\s\\S]+)$"); public 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 void commandPing(Message m) { Presence p = new Presence(xmpp.getJid(), m.from); p.priority = 10; xmpp.sendOut(p); Message reply = new Message(xmpp.getJid(), m.from, Message.Type.chat); reply.body = "PONG"; xmpp.sendOut(reply); } private void commandHelp(Message m) { Message reply = new Message(xmpp.getJid(), m.from, Message.Type.chat); reply.body = HELPTEXT; xmpp.sendOut(reply); } private void commandLogin(Message m, User user_from) { Message reply = new Message(xmpp.getJid(), m.from, Message.Type.chat); reply.body = "http://juick.com/login?" + xmpp.userService.getHashByUID(user_from.getUid()); xmpp.sendOut(reply); } private void commandPM(Message m, User user_from, String user_to, String body) { int ret = 0; int uid_to = 0; List jids_to = null; boolean haveInRoster = false; if (user_to.indexOf('@') > 0) { uid_to = xmpp.userService.getUIDbyJID(user_to); } else { uid_to = xmpp.userService.getUIDbyName(user_to); } if (uid_to > 0) { if (!xmpp.userService.isInBLAny(uid_to, user_from.getUid())) { if (xmpp.pmQueriesService.createPM(user_from.getUid(), uid_to, body)) { jids_to = xmpp.userService.getJIDsbyUID(uid_to); ret = 200; } else { ret = 500; } } else { ret = 403; } } else { ret = 404; } if (ret == 200) { Message msg = new Message(); msg.from = Jid.of("juick", "juick.com", null); msg.to = Jid.of(Integer.toString(uid_to), "push.juick.com", null); JuickMessage jmsg = new JuickMessage(); jmsg.setUser(user_from); jmsg.setText(body); msg.childs.add(jmsg); xmpp.getRouter().sendStanza(msg.toString()); msg.to = Jid.of(Integer.toString(uid_to), "ws.juick.com", null); xmpp.getRouter().sendStanza(msg.toString()); for (String jid : jids_to) { Message mm = new Message(); mm.to = Jid.of(jid); mm.type = Message.Type.chat; haveInRoster = xmpp.pmQueriesService.havePMinRoster(user_from.getUid(), jid); if (haveInRoster) { mm.from = Jid.of(user_from.getName(), "juick.com", "Juick"); mm.body = body; } else { mm.from = Jid.of("juick", "juick.com", "Juick"); mm.body = "Private message from @" + user_from.getName() + ":\n" + body; } xmpp.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; } xmpp.sendOut(reply); } private void commandBLShow(Message m, User user_from) { List blusers = xmpp.userService.getUserBLUsers(user_from.getUid()); List bltags = xmpp.tagService.getUserBLTags(user_from.getUid()); String txt = StringUtils.EMPTY; if (bltags.size() > 0) { for (String bltag : bltags) { txt += "*" + bltag + "\n"; } if (blusers.size() > 0) { txt += "\n"; } } if (blusers.size() > 0) { for (User bluser : blusers) { txt += "@" + bluser.getName() + "\n"; } } if (txt.isEmpty()) { txt = "You don't have any users or tags in your blacklist."; } Message reply = new Message(xmpp.getJid(), m.from, Message.Type.chat); reply.body = txt; xmpp.sendOut(reply); } @Override public void stanzaReceived(String name, Stanza xmlValue) { if (xmlValue instanceof Presence) { Presence p = (Presence) xmlValue; if (p.type == null || !p.type.equals(Presence.Type.error)) { incomingPresence(p); } } else if (xmlValue instanceof Message) { Message msg = (Message) xmlValue; if (!incomingMessage(msg)) { xmpp.getRouter().sendStanza(msg.toString()); } } } }