From 9dc82bc92186d9313be8d7d570bd9716bb374fdc Mon Sep 17 00:00:00 2001 From: Alexander Ivanov Date: Sat, 27 Aug 2016 17:57:46 +0500 Subject: [PATCH 1/5] Added types of message in messageListeners --- .gitignore | 30 ++++ pom.xml | 8 +- src/main/java/fr/delthas/skype/Constants.java | 14 ++ .../delthas/skype/GroupMessageListener.java | 45 ++++- .../fr/delthas/skype/MessageListener.java | 12 ++ .../java/fr/delthas/skype/NotifConnector.java | 169 +++++++++++------- src/main/java/fr/delthas/skype/Skype.java | 46 ++++- .../fr/delthas/skype/UserMessageListener.java | 19 +- .../skype/message/AbstractMessage.java | 68 +++++++ .../delthas/skype/message/ContactMessage.java | 16 ++ .../fr/delthas/skype/message/FileMessage.java | 14 ++ .../fr/delthas/skype/message/Message.java | 16 ++ .../fr/delthas/skype/message/MessageType.java | 57 ++++++ .../fr/delthas/skype/message/MojiMessage.java | 16 ++ .../delthas/skype/message/PictureMessage.java | 16 ++ .../fr/delthas/skype/message/TextMessage.java | 14 ++ .../delthas/skype/message/UnknownMessage.java | 16 ++ .../delthas/skype/message/VideoMessage.java | 16 ++ .../java/fr/delthas/skype/TestListeners.java | 66 +++++++ .../fr/delthas/skype/message/TestMessage.java | 74 ++++++++ .../fr/delthas/skype/message/contact.xml | 3 + .../fr/delthas/skype/message/file.xml | 12 ++ .../fr/delthas/skype/message/moji.xml | 11 ++ .../fr/delthas/skype/message/picture.xml | 10 ++ .../resources/fr/delthas/skype/message/ss.xml | 1 + .../fr/delthas/skype/message/video.xml | 10 ++ 26 files changed, 702 insertions(+), 77 deletions(-) create mode 100644 src/main/java/fr/delthas/skype/Constants.java create mode 100644 src/main/java/fr/delthas/skype/MessageListener.java create mode 100644 src/main/java/fr/delthas/skype/message/AbstractMessage.java create mode 100644 src/main/java/fr/delthas/skype/message/ContactMessage.java create mode 100644 src/main/java/fr/delthas/skype/message/FileMessage.java create mode 100644 src/main/java/fr/delthas/skype/message/Message.java create mode 100644 src/main/java/fr/delthas/skype/message/MessageType.java create mode 100644 src/main/java/fr/delthas/skype/message/MojiMessage.java create mode 100644 src/main/java/fr/delthas/skype/message/PictureMessage.java create mode 100644 src/main/java/fr/delthas/skype/message/TextMessage.java create mode 100644 src/main/java/fr/delthas/skype/message/UnknownMessage.java create mode 100644 src/main/java/fr/delthas/skype/message/VideoMessage.java create mode 100644 src/test/java/fr/delthas/skype/TestListeners.java create mode 100644 src/test/java/fr/delthas/skype/message/TestMessage.java create mode 100644 src/test/resources/fr/delthas/skype/message/contact.xml create mode 100644 src/test/resources/fr/delthas/skype/message/file.xml create mode 100644 src/test/resources/fr/delthas/skype/message/moji.xml create mode 100644 src/test/resources/fr/delthas/skype/message/picture.xml create mode 100644 src/test/resources/fr/delthas/skype/message/ss.xml create mode 100644 src/test/resources/fr/delthas/skype/message/video.xml diff --git a/.gitignore b/.gitignore index f2ecff4..cf41fd0 100644 --- a/.gitignore +++ b/.gitignore @@ -3,6 +3,8 @@ *.class hs_err_pid* *.jar +*.war +*.ear # maven files @@ -13,6 +15,7 @@ pom.xml.versionsBackup pom.xml.next release.properties repo/.locks +dependency-reduced-pom.xml # eclipse files @@ -30,3 +33,30 @@ local.properties *.launch .classpath .target + +# NetBeans +nbproject/ +build/ +nbbuild/ +dist/ +nbdist/ +nbactions.xml +nb-configuration.xml + +# IntelliJ IDEA +*.iml +*.ipr +*.iws +.idea/ + +# Windows +Thumbs.db +ehthumbs.db +Desktop.ini +$RECYCLE.BIN/ + +# Linux +.* +!.gitattributes +!.gitignore +*~ \ No newline at end of file diff --git a/pom.xml b/pom.xml index b8064bd..301bc16 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 fr.delthas javaskype - 1.0.14 + 1.0.14.1-SNAPSHOT JavaSkype https://github.com/delthas/javaskype @@ -69,6 +69,12 @@ 4.12 test + + commons-io + commons-io + 2.4 + test + diff --git a/src/main/java/fr/delthas/skype/Constants.java b/src/main/java/fr/delthas/skype/Constants.java new file mode 100644 index 0000000..43c9b12 --- /dev/null +++ b/src/main/java/fr/delthas/skype/Constants.java @@ -0,0 +1,14 @@ +package fr.delthas.skype; + +/** + * Constants + */ +public class Constants { + public static String HEADER_TEXT = "Text"; + public static String HEADER_RICH_TEXT = "RichText"; + public static String HEADER_PICTURE = "RichText/UriObject"; + public static String HEADER_FILE = "RichText/Media_GenericFile"; + public static String HEADER_VIDEO = "RichText/Media_Video"; + public static String HEADER_CONTACT = "RichText/Contacts"; + public static String HEADER_MOJI = "RichText/Media_FlikMsg"; +} diff --git a/src/main/java/fr/delthas/skype/GroupMessageListener.java b/src/main/java/fr/delthas/skype/GroupMessageListener.java index 64e0426..25d2242 100644 --- a/src/main/java/fr/delthas/skype/GroupMessageListener.java +++ b/src/main/java/fr/delthas/skype/GroupMessageListener.java @@ -1,19 +1,52 @@ package fr.delthas.skype; +import fr.delthas.skype.message.Message; /** * A listener for new messages sent to a Skype account. - * */ -public interface GroupMessageListener { +public interface GroupMessageListener extends MessageListener { /** * Called when a message is sent from a user to a group the Skype account is in while it is connected. * - * @param group The group in which the message has been sent. - * @param sender The sender of the message. - * @param message The message sent. + * @param group The group in which the message has been sent. + * @param sender The sender of the message. + * @param message The text of message sent. */ - public void messageReceived(Group group, User sender, String message); + @Deprecated + default void messageReceived(Group group, User sender, String message) { + } + + /** + * Called when a message is sent from a user to a group the Skype account is in while it is connected. + * + * @param group The group in which the message has been sent. + * @param sender The sender of the message. + * @param message The object of message sent. + */ + default void messageReceived(Group group, User sender, Message message) { + } + + /** + * Called when a message is edited by a user in a group the Skype account is in while it is connected. + * + * @param group The group in which the message has been edit. + * @param sender The sender of the message. + * @param message The object of message sent. + */ + default void messageEdited(Group group, User sender, Message message) { + } + + /** + * Called when a message is removed by a user in a group the Skype account is in while it is connected. + * + * @param group The group in which the message has been remove. + * @param sender The sender of the message. + * @param message The object of message sent. + */ + default void messageRemoved(Group group, User sender, Message message) { + } + } diff --git a/src/main/java/fr/delthas/skype/MessageListener.java b/src/main/java/fr/delthas/skype/MessageListener.java new file mode 100644 index 0000000..e682b54 --- /dev/null +++ b/src/main/java/fr/delthas/skype/MessageListener.java @@ -0,0 +1,12 @@ +package fr.delthas.skype; + +/** + * A root listener for new messages sent to a Skype account. + */ +public interface MessageListener { + enum MessageEventType { + RECEIVED, + EDITED, + REMOVED + } +} diff --git a/src/main/java/fr/delthas/skype/NotifConnector.java b/src/main/java/fr/delthas/skype/NotifConnector.java index 2ceb61d..dae26c4 100644 --- a/src/main/java/fr/delthas/skype/NotifConnector.java +++ b/src/main/java/fr/delthas/skype/NotifConnector.java @@ -1,10 +1,19 @@ package fr.delthas.skype; -import java.io.BufferedInputStream; -import java.io.BufferedWriter; -import java.io.IOException; -import java.io.OutputStreamWriter; -import java.io.StringReader; +import fr.delthas.skype.MessageListener.MessageEventType; +import fr.delthas.skype.message.*; +import org.jsoup.Jsoup; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +import javax.net.ssl.SSLSocketFactory; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import java.io.*; import java.net.Socket; import java.nio.charset.StandardCharsets; import java.security.GeneralSecurityException; @@ -18,17 +27,8 @@ import java.util.regex.Pattern; import java.util.stream.Collectors; -import javax.net.ssl.SSLSocketFactory; -import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; - -import org.jsoup.Jsoup; -import org.w3c.dom.Document; -import org.w3c.dom.Node; -import org.w3c.dom.NodeList; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; +import static fr.delthas.skype.Constants.HEADER_RICH_TEXT; +import static fr.delthas.skype.Constants.HEADER_TEXT; class NotifConnector { @@ -183,56 +183,103 @@ private void processPacket(Packet packet) throws IOException { } Object sender = parseEntity(formatted.sender); Object receiver = parseEntity(formatted.receiver); - switch (messageType) { - case "Text": - case "RichText": - if (!(sender instanceof User)) { - logger.fine("Received " + messageType + " message sent from " + sender + " which isn't a user"); - break; - } - if (receiver instanceof Group) { - skype.groupMessageReceived((Group) receiver, (User) sender, getPlaintext(formatted.body)); - } else { - skype.userMessageReceived((User) sender, getPlaintext(formatted.body)); - } - break; - case "ThreadActivity/AddMember": - List usernames = getXMLFields(formatted.body, "target"); - skype.usersAddedToGroup(usernames.stream().map(username -> (User) parseEntity(username)).collect(Collectors.toList()), (Group) sender); - break; - case "ThreadActivity/DeleteMember": - usernames = getXMLFields(formatted.body, "target"); - skype.usersAddedToGroup(usernames.stream().map(username -> (User) parseEntity(username)).collect(Collectors.toList()), (Group) sender); + if (messageType.startsWith(HEADER_RICH_TEXT) || messageType.startsWith(HEADER_TEXT)) { + // work with messages + if (!(sender instanceof User)) { + logger.fine("Received " + messageType + " message sent from " + sender + " which isn't a user"); break; - case "ThreadActivity/TopicUpdate": - skype.groupTopicChanged((Group) sender, getPlaintext(getXMLField(formatted.body, "value"))); + } + boolean isRemoved = false; + + String isMe = formatted.headers.get("Skype-EmoteOffset"); + String messageId = formatted.headers.get("Client-Message-ID"); + String editId = formatted.headers.get("Skype-EditedId"); + String html = formatted.body; + if (isMe != null) { + html = formatted.body.substring(Integer.parseInt(isMe)); + } + if (editId != null) { + html = html.replaceAll("", ""); + isRemoved = html.isEmpty(); + } + String id = messageId != null ? messageId : editId; + Message message = null; + MessageType type = MessageType.getTypeByHeaderType((messageType)); + if (type == null) { break; - case "ThreadActivity/RoleUpdate": - Document doc = getDocument(formatted.body); - NodeList targetNodes = doc.getElementsByTagName("target"); - List> roles = new ArrayList<>(targetNodes.getLength()); - for (int i = 0; i < targetNodes.getLength(); i++) { - Node targetNode = targetNodes.item(i); - User user = null; - Role role = null; - for (int j = 0; j < targetNode.getChildNodes().getLength(); j++) { - Node targetPropertyNode = targetNode.getChildNodes().item(j); - if (targetPropertyNode.getNodeName().equals("id")) { - user = (User) parseEntity(targetPropertyNode.getTextContent()); - skype.updateUser(user); - } else if (targetPropertyNode.getNodeName().equals("role")) { - role = Role.getRole(targetPropertyNode.getTextContent()); + } + switch (type) { + case TEXT: + message = new TextMessage(id, html, isMe != null); + break; + case PICTURE: + message = new PictureMessage(id, html); + break; + case FILE: + message = new FileMessage(id, html); + break; + case VIDEO: + message = new VideoMessage(id, html); + break; + case CONTACT: + message = new ContactMessage(id, html); + break; + case MOJI: + message = new MojiMessage(id, html); + break; + case UNKNOWN: + message = new UnknownMessage(id, html); + break; + default: + break; + } + MessageEventType eventType = editId == null ? MessageEventType.RECEIVED : isRemoved ? MessageEventType.REMOVED : MessageEventType.EDITED; + if (receiver instanceof Group) { + skype.doGroupMessageEvent(eventType, (Group) receiver, (User) sender, message); + } else { + skype.doUserMessageEvent(eventType, (User) sender, message); + } + } else { + switch (messageType) { + case "ThreadActivity/AddMember": + List usernames = getXMLFields(formatted.body, "target"); + skype.usersAddedToGroup(usernames.stream().map(username -> (User) parseEntity(username)).collect(Collectors.toList()), (Group) sender); + break; + case "ThreadActivity/DeleteMember": + usernames = getXMLFields(formatted.body, "target"); + skype.usersAddedToGroup(usernames.stream().map(username -> (User) parseEntity(username)).collect(Collectors.toList()), (Group) sender); + break; + case "ThreadActivity/TopicUpdate": + skype.groupTopicChanged((Group) sender, getPlaintext(getXMLField(formatted.body, "value"))); + break; + case "ThreadActivity/RoleUpdate": + Document doc = getDocument(formatted.body); + NodeList targetNodes = doc.getElementsByTagName("target"); + List> roles = new ArrayList<>(targetNodes.getLength()); + for (int i = 0; i < targetNodes.getLength(); i++) { + Node targetNode = targetNodes.item(i); + User user = null; + Role role = null; + for (int j = 0; j < targetNode.getChildNodes().getLength(); j++) { + Node targetPropertyNode = targetNode.getChildNodes().item(j); + if (targetPropertyNode.getNodeName().equals("id")) { + user = (User) parseEntity(targetPropertyNode.getTextContent()); + skype.updateUser(user); + } else if (targetPropertyNode.getNodeName().equals("role")) { + role = Role.getRole(targetPropertyNode.getTextContent()); + } + } + if (user != null && role != null) { + roles.add(new Pair<>(user, role)); } } - if (user != null && role != null) { - roles.add(new Pair<>(user, role)); - } - } - skype.usersRolesChanged((Group) sender, roles); - break; - default: - break; + skype.usersRolesChanged((Group) sender, roles); + break; + default: + break; + } } + } break; case "NFY": diff --git a/src/main/java/fr/delthas/skype/Skype.java b/src/main/java/fr/delthas/skype/Skype.java index 9bbc451..3b1af93 100644 --- a/src/main/java/fr/delthas/skype/Skype.java +++ b/src/main/java/fr/delthas/skype/Skype.java @@ -1,5 +1,8 @@ package fr.delthas.skype; +import fr.delthas.skype.MessageListener.MessageEventType; +import fr.delthas.skype.message.Message; + import java.io.IOException; import java.nio.file.Path; import java.util.ArrayList; @@ -27,7 +30,6 @@ * LF which will be replaced with CRLF if needed. *

* If you want to report a bug, please enable debug/logs with {@link Skype#setDebug(Path)}, before using {@link #connect()}. - * */ public final class Skype { @@ -78,9 +80,8 @@ public Skype(String username, String password) { /** * Calls {@code connect(Presence.CONNECTED)}. * - * @throws IOException If an error is thrown while connecting. + * @throws IOException If an error is thrown while connecting. * @throws InterruptedException If the connection is interrupted. - * * @see #connect(Presence) */ public void connect() throws IOException, InterruptedException { @@ -92,8 +93,7 @@ public void connect() throws IOException, InterruptedException { * Connects the Skype interface. Will block until connected. * * @param presence The initial presence of the Skype account after connection. Cannot be {@link Presence#OFFLINE}. - * - * @throws IOException If an error is thrown while connecting. + * @throws IOException If an error is thrown while connecting. * @throws InterruptedException If the connection is interrupted. */ public void connect(Presence presence) throws IOException, InterruptedException { @@ -438,6 +438,7 @@ void changeGroupTopic(Group group, String topic) { // --- Listeners call methods --- // + @Deprecated void userMessageReceived(User sender, String message) { updateUser(sender); logger.finer("Received message: " + message + " from user: " + sender); @@ -446,6 +447,24 @@ void userMessageReceived(User sender, String message) { } } + void doUserMessageEvent(MessageEventType event, User sender, T message) { + logger.finer("Event: " + event + ", message('" + message.getType().getName() + "'): " + message + " from user: " + sender); + for (UserMessageListener listener : userMessageListeners) { + switch (event) { + case RECEIVED: + listener.messageReceived(sender, message); + break; + case EDITED: + listener.messageEdited(sender, message); + break; + case REMOVED: + listener.messageRemoved(sender, message); + break; + } + } + } + + @Deprecated void groupMessageReceived(Group group, User sender, String message) { logger.finer("Received group message: " + message + " from user: " + sender + " in group: " + group); for (GroupMessageListener listener : groupMessageListeners) { @@ -453,6 +472,23 @@ void groupMessageReceived(Group group, User sender, String message) { } } + void doGroupMessageEvent(MessageEventType event, Group group, User sender, T message) { + logger.finer("Event: " + event + ", message('" + message.getType().getName() + "'): " + message + " from user: " + sender + " in group: " + group); + for (GroupMessageListener listener : groupMessageListeners) { + switch (event) { + case RECEIVED: + listener.messageReceived(group, sender, message); + break; + case EDITED: + listener.messageEdited(group, sender, message); + break; + case REMOVED: + listener.messageRemoved(group, sender, message); + break; + } + } + } + void userPresenceChanged(User user, Presence oldPresence, Presence presence) { logger.finer("User: " + user + " changed presence from: " + oldPresence + " to: " + presence); for (UserPresenceListener listener : userPresenceListeners) { diff --git a/src/main/java/fr/delthas/skype/UserMessageListener.java b/src/main/java/fr/delthas/skype/UserMessageListener.java index 01c9ce5..732e8f2 100644 --- a/src/main/java/fr/delthas/skype/UserMessageListener.java +++ b/src/main/java/fr/delthas/skype/UserMessageListener.java @@ -1,18 +1,29 @@ package fr.delthas.skype; +import fr.delthas.skype.message.Message; + /** * A listener for new messages sent to a Skype account. - * */ -public interface UserMessageListener { +public interface UserMessageListener extends MessageListener { /** * Called when a message is sent from a user to the Skype account while it is connected. * - * @param sender The sender of the message. + * @param sender The sender of the message. * @param message The message sent. */ - public void messageReceived(User sender, String message); + @Deprecated + default void messageReceived(User sender, String message) { + } + + default void messageReceived(User sender, Message message) { + } + + default void messageEdited(User sender, Message message) { + } + default void messageRemoved(User sender, Message message) { + } } diff --git a/src/main/java/fr/delthas/skype/message/AbstractMessage.java b/src/main/java/fr/delthas/skype/message/AbstractMessage.java new file mode 100644 index 0000000..6154220 --- /dev/null +++ b/src/main/java/fr/delthas/skype/message/AbstractMessage.java @@ -0,0 +1,68 @@ +package fr.delthas.skype.message; + +import org.jsoup.Jsoup; + +/** + * Abstract class for all type of message with all common field and methods + */ +public abstract class AbstractMessage implements Message { + + private String id; + private MessageType type; + private String html; + private String text; + private boolean isMe; + + public AbstractMessage(String id, String html) { + this.id = id; + this.html = html; + this.text = Jsoup.parseBodyFragment(html, "").text(); + this.type = MessageType.getTypeByClass(getClass().getSimpleName()); + } + + public AbstractMessage(String id, String html, boolean isMe) { + this(id, html); + this.isMe = isMe; + } + + @Override + public String getId() { + return id; + } + + @Override + public MessageType getType() { + return type; + } + + protected void setType(MessageType type) { + this.type = type; + } + + public String getHtml() { + return html; + } + + public void setHtml(String html) { + this.html = html; + } + + public String getText() { + return text; + } + + public boolean isMe() { + return isMe; + } + + @Override + public String toString() { + return getClass().getSimpleName() + " {" + + "id='" + id + '\'' + + ", type=" + type + + ", html='" + html + '\'' + + ", text='" + text + '\'' + + ", isMe=" + isMe + + '}'; + } +} diff --git a/src/main/java/fr/delthas/skype/message/ContactMessage.java b/src/main/java/fr/delthas/skype/message/ContactMessage.java new file mode 100644 index 0000000..e798be9 --- /dev/null +++ b/src/main/java/fr/delthas/skype/message/ContactMessage.java @@ -0,0 +1,16 @@ +package fr.delthas.skype.message; + +/** + * Message with contact + */ +public class ContactMessage extends AbstractMessage { + + public ContactMessage(String id, String html) { + super(id, html); + } + + public ContactMessage(String id, String html, boolean isMe) { + super(id, html, isMe); + } + +} diff --git a/src/main/java/fr/delthas/skype/message/FileMessage.java b/src/main/java/fr/delthas/skype/message/FileMessage.java new file mode 100644 index 0000000..82a22b1 --- /dev/null +++ b/src/main/java/fr/delthas/skype/message/FileMessage.java @@ -0,0 +1,14 @@ +package fr.delthas.skype.message; + +/** + * Message with file + */ +public class FileMessage extends AbstractMessage { + public FileMessage(String id, String html) { + super(id, html); + } + + public FileMessage(String id, String html, boolean isMe) { + super(id, html, isMe); + } +} diff --git a/src/main/java/fr/delthas/skype/message/Message.java b/src/main/java/fr/delthas/skype/message/Message.java new file mode 100644 index 0000000..2b339b1 --- /dev/null +++ b/src/main/java/fr/delthas/skype/message/Message.java @@ -0,0 +1,16 @@ +package fr.delthas.skype.message; + +/** + * Interface for messages` + */ +public interface Message { + + public static String X_URL_THUMBNAIL = "/URIObject/@url_thumbnail"; + public static String X_URL = "/URIObject/@uri"; + public static String X_TYPE = "/URIObject/@type"; + public static String X_ORIGINAL_NAME = "/URIObject/OriginalName/@v"; + + String getId(); + + MessageType getType(); +} diff --git a/src/main/java/fr/delthas/skype/message/MessageType.java b/src/main/java/fr/delthas/skype/message/MessageType.java new file mode 100644 index 0000000..3668550 --- /dev/null +++ b/src/main/java/fr/delthas/skype/message/MessageType.java @@ -0,0 +1,57 @@ +package fr.delthas.skype.message; + +import static fr.delthas.skype.Constants.*; + +/** + * Skype message types + */ +public enum MessageType { + TEXT("Text", HEADER_RICH_TEXT, TextMessage.class), + PICTURE("Picture", HEADER_PICTURE, PictureMessage.class), + FILE("File", HEADER_FILE, FileMessage.class), + VIDEO("Video", HEADER_VIDEO, VideoMessage.class), + CONTACT("Contact", HEADER_CONTACT, ContactMessage.class), + MOJI("Moji", HEADER_MOJI, MojiMessage.class), + UNKNOWN("Unknown", "Unknown", UnknownMessage.class); + + private String name; + private String headerType; + private Class clazz; + + MessageType(String name, String headerType, Class clazz) { + this.name = name; + this.headerType = headerType; + this.clazz = clazz; + } + + public String getHeaderType() { + return headerType; + } + + public String getName() { + return name; + } + + public Class getClazz() { + return clazz; + } + + public static MessageType getTypeByClass(String className) { + for (MessageType type : MessageType.values()) { + if (type.getClazz().getSimpleName().equals(className)) { + return type; + } + } + return UNKNOWN; + } + + public static MessageType getTypeByHeaderType(String headerType) { + if (HEADER_TEXT.equals(headerType)) return TEXT; + for (MessageType type : MessageType.values()) { + if (type.getHeaderType().equals(headerType)) { + return type; + } + } + return UNKNOWN; + } +} diff --git a/src/main/java/fr/delthas/skype/message/MojiMessage.java b/src/main/java/fr/delthas/skype/message/MojiMessage.java new file mode 100644 index 0000000..e6e34b4 --- /dev/null +++ b/src/main/java/fr/delthas/skype/message/MojiMessage.java @@ -0,0 +1,16 @@ +package fr.delthas.skype.message; + +/** + * Message with moji + */ +public class MojiMessage extends AbstractMessage { + + public MojiMessage(String id, String html) { + super(id, html); + } + + public MojiMessage(String id, String html, boolean isMe) { + super(id, html, isMe); + } + +} diff --git a/src/main/java/fr/delthas/skype/message/PictureMessage.java b/src/main/java/fr/delthas/skype/message/PictureMessage.java new file mode 100644 index 0000000..b159504 --- /dev/null +++ b/src/main/java/fr/delthas/skype/message/PictureMessage.java @@ -0,0 +1,16 @@ +package fr.delthas.skype.message; + +/** + * Message with picture + */ +public class PictureMessage extends AbstractMessage { + + public PictureMessage(String id, String html) { + super(id, html); + } + + public PictureMessage(String id, String html, boolean isMe) { + super(id, html, isMe); + } + +} diff --git a/src/main/java/fr/delthas/skype/message/TextMessage.java b/src/main/java/fr/delthas/skype/message/TextMessage.java new file mode 100644 index 0000000..32b085b --- /dev/null +++ b/src/main/java/fr/delthas/skype/message/TextMessage.java @@ -0,0 +1,14 @@ +package fr.delthas.skype.message; + +/** + * Simple text message + */ +public class TextMessage extends AbstractMessage { + public TextMessage(String id, String html) { + super(id, html); + } + + public TextMessage(String id, String html, boolean isMe) { + super(id, html, isMe); + } +} diff --git a/src/main/java/fr/delthas/skype/message/UnknownMessage.java b/src/main/java/fr/delthas/skype/message/UnknownMessage.java new file mode 100644 index 0000000..9fad2ae --- /dev/null +++ b/src/main/java/fr/delthas/skype/message/UnknownMessage.java @@ -0,0 +1,16 @@ +package fr.delthas.skype.message; + +/** + * Message with unknown type + */ +public class UnknownMessage extends AbstractMessage { + + public UnknownMessage(String id, String html) { + super(id, html); + } + + public UnknownMessage(String id, String html, boolean isMe) { + super(id, html, isMe); + } + +} diff --git a/src/main/java/fr/delthas/skype/message/VideoMessage.java b/src/main/java/fr/delthas/skype/message/VideoMessage.java new file mode 100644 index 0000000..140f679 --- /dev/null +++ b/src/main/java/fr/delthas/skype/message/VideoMessage.java @@ -0,0 +1,16 @@ +package fr.delthas.skype.message; + +/** + * Message with video + */ +public class VideoMessage extends AbstractMessage { + + public VideoMessage(String id, String html) { + super(id, html); + } + + public VideoMessage(String id, String html, boolean isMe) { + super(id, html, isMe); + } + +} diff --git a/src/test/java/fr/delthas/skype/TestListeners.java b/src/test/java/fr/delthas/skype/TestListeners.java new file mode 100644 index 0000000..460c767 --- /dev/null +++ b/src/test/java/fr/delthas/skype/TestListeners.java @@ -0,0 +1,66 @@ +package fr.delthas.skype; + +import fr.delthas.skype.message.Message; +import org.junit.Assert; + +import java.util.logging.Logger; + +@SuppressWarnings({"javadoc", "static-method"}) +public class TestListeners { + + public static Logger logger = Logger.getLogger("TestConnect"); + + public void testConnect() { + Skype skype = new Skype("username", "password"); + try { + logger.info("Starting..."); + skype.connect(); + logger.info("Started"); + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(e.getMessage()); + } + skype.setErrorListener(e -> { + e.printStackTrace(); + Assert.fail(e.getMessage()); + }); + skype.addGroupMessageListener(new GroupMessageListener() { + @Override + public void messageReceived(Group group, User sender, Message message) { + logger.info("Received " + message); + } + + @Override + public void messageEdited(Group group, User sender, Message message) { + logger.info("Edited " + message); + } + + @Override + public void messageRemoved(Group group, User sender, Message message) { + logger.info("Removed " + message); + } + }); + + skype.addUserMessageListener(new UserMessageListener() { + @Override + public void messageReceived(User sender, Message message) { + logger.info("Received " + message); + } + + @Override + public void messageEdited(User sender, Message message) { + logger.info("Edited " + message); + } + + @Override + public void messageRemoved(User sender, Message message) { + logger.info("Removed " + message); + } + }); + } + + public static void main(String... strings) { + new TestListeners().testConnect(); + } + +} diff --git a/src/test/java/fr/delthas/skype/message/TestMessage.java b/src/test/java/fr/delthas/skype/message/TestMessage.java new file mode 100644 index 0000000..c135de5 --- /dev/null +++ b/src/test/java/fr/delthas/skype/message/TestMessage.java @@ -0,0 +1,74 @@ +package fr.delthas.skype.message; + +import fr.delthas.skype.ParseException; +import org.apache.commons.io.IOUtils; +import org.jsoup.Jsoup; +import org.jsoup.nodes.Document; +import org.junit.Test; +import org.w3c.dom.NodeList; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; + +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import java.io.IOException; +import java.io.StringReader; +import java.util.ArrayList; +import java.util.List; + +/** + * Class of fr.delthas.skype + * + * @author aivanov + */ +public class TestMessage { + + private DocumentBuilder documentBuilder; + + + @Test + public void test() throws Exception { + documentBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + + String xml = getXml("fr/delthas/skype/message/picture.xml"); + System.out.println(getXMLField(xml, "URIObject")); + } + + private static Document getPlaintext(String string) { + return Jsoup.parseBodyFragment(string); + } + + public static String getXml(String path) throws IOException { + return IOUtils.toString(ClassLoader.getSystemResourceAsStream(path), "UTF-8"); + } + + + private org.w3c.dom.Document getDocument(String XML) throws ParseException { + try { + return documentBuilder.parse(new InputSource(new StringReader(XML))); + } catch (IOException | SAXException e) { + throw new ParseException(e); + } + } + + private List getXMLFields(String XML, String fieldName) throws ParseException { + NodeList nodes = getDocument(XML).getElementsByTagName(fieldName); + List fields = new ArrayList<>(nodes.getLength()); + for (int i = 0; i < nodes.getLength(); i++) { + fields.add(nodes.item(i).getTextContent()); + } + return fields; + } + + private String getXMLField(String XML, String fieldName) throws ParseException { + List fields = getXMLFields(XML, fieldName); + if (fields.size() > 1) { + throw new ParseException(); + } + if (fields.size() == 0) { + return null; + } + return fields.get(0); + } + +} diff --git a/src/test/resources/fr/delthas/skype/message/contact.xml b/src/test/resources/fr/delthas/skype/message/contact.xml new file mode 100644 index 0000000..85d61bf --- /dev/null +++ b/src/test/resources/fr/delthas/skype/message/contact.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/src/test/resources/fr/delthas/skype/message/file.xml b/src/test/resources/fr/delthas/skype/message/file.xml new file mode 100644 index 0000000..3c574b2 --- /dev/null +++ b/src/test/resources/fr/delthas/skype/message/file.xml @@ -0,0 +1,12 @@ + + + To view this shared file, go to: + hosts + hosts + + https://login.skype.com/login/sso?go=webclient.xmm&docid=0-weu-d1-39307d971c65d7d697876272123304e4 + + + + diff --git a/src/test/resources/fr/delthas/skype/message/moji.xml b/src/test/resources/fr/delthas/skype/message/moji.xml new file mode 100644 index 0000000..65a2ec6 --- /dev/null +++ b/src/test/resources/fr/delthas/skype/message/moji.xml @@ -0,0 +1,11 @@ + + + + Moji + + https://login.skype.com/login/sso?go=xmmfallback&2b3bd2ed622e443c8ff98c5df55b4e31 + + + + diff --git a/src/test/resources/fr/delthas/skype/message/picture.xml b/src/test/resources/fr/delthas/skype/message/picture.xml new file mode 100644 index 0000000..ee1559f --- /dev/null +++ b/src/test/resources/fr/delthas/skype/message/picture.xml @@ -0,0 +1,10 @@ + +To view this shared + photo, go to: + + https://login.skype.com/login/sso?go=xmmfallback?pic=0-weu-d1-347eba640ba729af0d46f4acb3deffce + + + + diff --git a/src/test/resources/fr/delthas/skype/message/ss.xml b/src/test/resources/fr/delthas/skype/message/ss.xml new file mode 100644 index 0000000..e86667d --- /dev/null +++ b/src/test/resources/fr/delthas/skype/message/ss.xml @@ -0,0 +1 @@ +(goldmedal) \ No newline at end of file diff --git a/src/test/resources/fr/delthas/skype/message/video.xml b/src/test/resources/fr/delthas/skype/message/video.xml new file mode 100644 index 0000000..b01f189 --- /dev/null +++ b/src/test/resources/fr/delthas/skype/message/video.xml @@ -0,0 +1,10 @@ +To view this video +message, go to: +Video Message +Video Message + + https://login.skype.com/login/sso?go=xmmfallback&vim=0-neu-d1-d22932af94c973a48a944f983da278cd + + + \ No newline at end of file From dbc5d10f9281e737972f46a7a5328ffb655cf857 Mon Sep 17 00:00:00 2001 From: Alexander Ivanov Date: Sun, 28 Aug 2016 14:20:54 +0500 Subject: [PATCH 2/5] new actions to send/edit/remove message. Send/edit don't work with not text message types. --- pom.xml | 2 +- src/main/java/fr/delthas/skype/Chat.java | 61 +++++++++++++++++++ src/main/java/fr/delthas/skype/Group.java | 33 +++++++++- .../fr/delthas/skype/MessageListener.java | 2 +- .../java/fr/delthas/skype/NotifConnector.java | 55 ++++++++++++++++- src/main/java/fr/delthas/skype/Skype.java | 57 +++++++++++++++-- src/main/java/fr/delthas/skype/User.java | 38 ++++++++++-- .../skype/message/AbstractMessage.java | 9 +++ .../fr/delthas/skype/message/MessageType.java | 8 +++ .../java/fr/delthas/skype/TestListeners.java | 16 +++++ 10 files changed, 264 insertions(+), 17 deletions(-) create mode 100644 src/main/java/fr/delthas/skype/Chat.java diff --git a/pom.xml b/pom.xml index 301bc16..45ffa03 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 fr.delthas javaskype - 1.0.14.1-SNAPSHOT + 1.0.14.2-SNAPSHOT JavaSkype https://github.com/delthas/javaskype diff --git a/src/main/java/fr/delthas/skype/Chat.java b/src/main/java/fr/delthas/skype/Chat.java new file mode 100644 index 0000000..1123929 --- /dev/null +++ b/src/main/java/fr/delthas/skype/Chat.java @@ -0,0 +1,61 @@ +package fr.delthas.skype; + +import fr.delthas.skype.message.Message; + +/** + * Interface for chats + */ +public interface Chat { + + /** + * Get Skype client + * + * @return skype object + */ + Skype getSkype(); + + /** + * Get identity of a chat + * + * @return string + */ + String getIdentity(); + + /** + * Type of chat + * + * @return ChatType enum item + */ + ChatType getType(); + + /** + * Send message to chat + * + * @param message object of one of messages types + */ + void sendMessage(Message message); + + /** + * Edit message to chat. + * + * Work only with text message. + * + * @param message object of one of messages types + */ + void editMessage(Message message); + + /** + * Remove message to chat + * + * @param message object of one of messages types + */ + void removeMessage(Message message); + + /** + * ChatType enum + */ + public enum ChatType { + GROUP, + USER + } +} diff --git a/src/main/java/fr/delthas/skype/Group.java b/src/main/java/fr/delthas/skype/Group.java index b56b473..b41ff3a 100644 --- a/src/main/java/fr/delthas/skype/Group.java +++ b/src/main/java/fr/delthas/skype/Group.java @@ -1,5 +1,7 @@ package fr.delthas.skype; +import fr.delthas.skype.message.Message; + import java.util.Collections; import java.util.Iterator; import java.util.List; @@ -12,7 +14,7 @@ * All information will be updated as updates are received (this object is NOT an immutable view/snapshot of a group). * */ -public class Group { +public class Group implements Chat{ private final Skype skype; private final String id; @@ -31,14 +33,27 @@ public class Group { * * @param message The message to send. */ + @Deprecated public void sendMessage(String message) { skype.sendGroupMessage(this, message); } + public void sendMessage(Message message) { + skype.doMessageAction(this, message, Skype.MessageAction.SEND); + } + + public void editMessage(Message message) { + skype.doMessageAction(this, message, Skype.MessageAction.EDIT); + } + + public void removeMessage(Message message) { + skype.doMessageAction(this, message, Skype.MessageAction.REMOVE); + } + /** * The id of a group is a special String used by Skype to uniquely identify groups. *

- * In case you know about network IDs and the like: if a group "adress" is "19:xxx@thread.skype", its id is "xxx". + * In case you know about network IDs and the like: if a group "address" is "19:xxx@thread.skype", its id is "xxx". * * @return The id of the group. */ @@ -213,4 +228,18 @@ public String toString() { return "Group: " + getId(); } + @Override + public Skype getSkype() { + return skype; + } + + @Override + public String getIdentity() { + return id; + } + + @Override + public ChatType getType() { + return ChatType.GROUP; + } } diff --git a/src/main/java/fr/delthas/skype/MessageListener.java b/src/main/java/fr/delthas/skype/MessageListener.java index e682b54..bd52c80 100644 --- a/src/main/java/fr/delthas/skype/MessageListener.java +++ b/src/main/java/fr/delthas/skype/MessageListener.java @@ -4,7 +4,7 @@ * A root listener for new messages sent to a Skype account. */ public interface MessageListener { - enum MessageEventType { + enum MessageEvent { RECEIVED, EDITED, REMOVED diff --git a/src/main/java/fr/delthas/skype/NotifConnector.java b/src/main/java/fr/delthas/skype/NotifConnector.java index dae26c4..7fbd5ba 100644 --- a/src/main/java/fr/delthas/skype/NotifConnector.java +++ b/src/main/java/fr/delthas/skype/NotifConnector.java @@ -1,6 +1,6 @@ package fr.delthas.skype; -import fr.delthas.skype.MessageListener.MessageEventType; +import fr.delthas.skype.MessageListener.MessageEvent; import fr.delthas.skype.message.*; import org.jsoup.Jsoup; import org.w3c.dom.Document; @@ -18,6 +18,7 @@ import java.nio.charset.StandardCharsets; import java.security.GeneralSecurityException; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import java.util.Random; import java.util.concurrent.CountDownLatch; @@ -233,7 +234,7 @@ private void processPacket(Packet packet) throws IOException { default: break; } - MessageEventType eventType = editId == null ? MessageEventType.RECEIVED : isRemoved ? MessageEventType.REMOVED : MessageEventType.EDITED; + MessageEvent eventType = editId == null ? MessageEvent.RECEIVED : isRemoved ? MessageEvent.REMOVED : MessageEvent.EDITED; if (receiver instanceof Group) { skype.doGroupMessageEvent(eventType, (Group) receiver, (User) sender, message); } else { @@ -541,10 +542,25 @@ public void connect() throws IOException, InterruptedException { pingThread.start(); } + public void sendMessage(Chat chat, Message message) throws IOException { + String entity = ""; + switch (chat.getType()) { + case GROUP: + entity = "19:" + chat.getIdentity() + "@thread.skype"; + break; + case USER: + entity = "8:" + chat.getIdentity(); + break; + } + sendMessage(entity, message); + } + + @Deprecated public void sendUserMessage(User user, String message) throws IOException { sendMessage("8:" + user.getUsername(), getSanitized(message)); } + @Deprecated public void sendGroupMessage(Group group, String message) throws IOException { sendMessage("19:" + group.getId() + "@thread.skype", getSanitized(message)); } @@ -580,12 +596,47 @@ public void changePresence(Presence presence) throws IOException { sendPacket("PUT", "MSGR\\PRESENCE", formattedPublicationMessage); } + @Deprecated private void sendMessage(String entity, String message) throws IOException { String body = FormattedMessage.format("8:" + username + ";epid={" + EPID + "}", entity, "Messaging: 2.0", message, "Content-Type: application/user+xml", "Message-Type: RichText"); sendPacket("SDG", "MSGR", body); } + private void sendMessage(String entity, Message message) throws IOException { + List headers = new ArrayList<>(Arrays.asList("Content-Type: application/user+xml", "Message-Type: " + MessageType.getTypeByClass(message).getHeaderType())); + if (message.getId() != null) { + headers.add("Skype-EditedId: " + message.getId()); + } + AbstractMessage abstractMessage = (AbstractMessage) message; + String body = ""; + switch (message.getType()) { + case TEXT: + TextMessage textMessage = (TextMessage) message; + body = FormattedMessage.format("8:" + username + ";epid={" + EPID + "}", entity, "Messaging: 2.0", getSanitized(textMessage.getHtml()), + headers.toArray(new String[headers.size()])); + sendPacket("SDG", "MSGR", body); + break; + case PICTURE: + case FILE: + case VIDEO: + case CONTACT: + case MOJI: + if (abstractMessage.isEmpty()) { + body = FormattedMessage.format("8:" + username + ";epid={" + EPID + "}", entity, "Messaging: 2.0", "", + headers.toArray(new String[headers.size()])); + sendPacket("SDG", "MSGR", body); + } else { + //Send this type of message not implemented yet; + } + break; + case UNKNOWN: + logger.warning("Strange UNKNOWN message has been tried to send."); + break; + } + + } + public synchronized void disconnect() { logger.finer("Stopping notification connector"); try { diff --git a/src/main/java/fr/delthas/skype/Skype.java b/src/main/java/fr/delthas/skype/Skype.java index 3b1af93..a53cd0c 100644 --- a/src/main/java/fr/delthas/skype/Skype.java +++ b/src/main/java/fr/delthas/skype/Skype.java @@ -1,6 +1,7 @@ package fr.delthas.skype; -import fr.delthas.skype.MessageListener.MessageEventType; +import fr.delthas.skype.MessageListener.MessageEvent; +import fr.delthas.skype.message.AbstractMessage; import fr.delthas.skype.message.Message; import java.io.IOException; @@ -172,7 +173,6 @@ public User getSelf() { /** * @return The current list of contacts of the account (snapshot, won't be updated). - * */ public List getContacts() { ensureConnected(); @@ -211,9 +211,8 @@ public boolean isConnected() { * Enables or disables debug of the Skype library (globally). (By default logs are disabled.) *

* If enabled, debug information and logs will be written to a log file at the specified path. If the path is null, the debug will be disabled. - * + * * @param path The path at which to write debugging information, or null to disable logging. - * * @throws IOException may be thrown when adding a file handler to the logger */ public static void setDebug(Path path) throws IOException { @@ -376,6 +375,7 @@ void declineContactRequest(ContactRequest contactRequest) { // --- Package-private methods that simply call the notification connector --- // + @Deprecated void sendUserMessage(User user, String message) { ensureConnected(); try { @@ -386,6 +386,51 @@ void sendUserMessage(User user, String message) { } } + public enum MessageAction { + SEND, + EDIT, + REMOVE + } + + /** + * Execute action with message. + * Message can be send, edit and removed + * + * @param chat where will be send action + * @param message object of some message type + * @param action send, edit or removed + */ + void doMessageAction(Chat chat, Message message, MessageAction action) { + ensureConnected(); + try { + logger.finer("Do " + action.name() + "-action in chat: " + chat + " message: " + message); + switch (action) { + case SEND: + notifConnector.sendMessage(chat, message); + break; + case EDIT: + if (message.getId() != null) { + notifConnector.sendMessage(chat, message); + } else { + logger.warning("Message has not id. Can't edit message: " + message); + } + break; + case REMOVE: + if (message.getId() != null) { + AbstractMessage abstractMessage = (AbstractMessage) message; + abstractMessage.setHtml(""); + notifConnector.sendMessage(chat, message); + } else { + logger.warning("Message has not id. Can't remove message: " + message); + } + break; + } + } catch (IOException e) { + error(e); + } + } + + @Deprecated void sendGroupMessage(Group group, String message) { ensureConnected(); try { @@ -447,7 +492,7 @@ void userMessageReceived(User sender, String message) { } } - void doUserMessageEvent(MessageEventType event, User sender, T message) { + void doUserMessageEvent(MessageEvent event, User sender, T message) { logger.finer("Event: " + event + ", message('" + message.getType().getName() + "'): " + message + " from user: " + sender); for (UserMessageListener listener : userMessageListeners) { switch (event) { @@ -472,7 +517,7 @@ void groupMessageReceived(Group group, User sender, String message) { } } - void doGroupMessageEvent(MessageEventType event, Group group, User sender, T message) { + void doGroupMessageEvent(MessageEvent event, Group group, User sender, T message) { logger.finer("Event: " + event + ", message('" + message.getType().getName() + "'): " + message + " from user: " + sender + " in group: " + group); for (GroupMessageListener listener : groupMessageListeners) { switch (event) { diff --git a/src/main/java/fr/delthas/skype/User.java b/src/main/java/fr/delthas/skype/User.java index da31e7a..9d651e3 100644 --- a/src/main/java/fr/delthas/skype/User.java +++ b/src/main/java/fr/delthas/skype/User.java @@ -1,13 +1,14 @@ package fr.delthas.skype; +import fr.delthas.skype.message.Message; + /** * A Skype account. *

* All information will be updated as updates are received (this object is NOT an immutable view/snapshot of a user account). - * */ -public class User { +public class User implements Chat { private final Skype skype; private final String username; @@ -26,7 +27,6 @@ public class User { /** * Blocks this user (without reporting the account). - * */ public void block() { skype.block(this); @@ -34,7 +34,6 @@ public void block() { /** * Unblocks this user. - * */ public void unblock() { skype.unblock(this); @@ -51,7 +50,6 @@ public void sendContactRequest(String greeting) { /** * Removes this user from the list of contacts of the Skype account. If the user isn't a contact, nothing happens. - * */ public void removeFromContacts() { skype.removeFromContacts(this); @@ -62,10 +60,26 @@ public void removeFromContacts() { * * @param message The message to send to this user. */ + @Deprecated public void sendMessage(String message) { skype.sendUserMessage(this, message); } + @Override + public void sendMessage(Message message) { + skype.doMessageAction(this, message, Skype.MessageAction.SEND); + } + + @Override + public void editMessage(Message message) { + skype.doMessageAction(this, message, Skype.MessageAction.EDIT); + } + + @Override + public void removeMessage(Message message) { + skype.doMessageAction(this, message, Skype.MessageAction.REMOVE); + } + /** * @return The username of this user. */ @@ -228,4 +242,18 @@ public String toString() { return "User: " + getUsername(); } + @Override + public Skype getSkype() { + return skype; + } + + @Override + public String getIdentity() { + return username; + } + + @Override + public ChatType getType() { + return ChatType.USER; + } } diff --git a/src/main/java/fr/delthas/skype/message/AbstractMessage.java b/src/main/java/fr/delthas/skype/message/AbstractMessage.java index 6154220..80c3a12 100644 --- a/src/main/java/fr/delthas/skype/message/AbstractMessage.java +++ b/src/main/java/fr/delthas/skype/message/AbstractMessage.java @@ -45,6 +45,7 @@ public String getHtml() { public void setHtml(String html) { this.html = html; + this.text = Jsoup.parseBodyFragment(html, "").text(); } public String getText() { @@ -55,6 +56,14 @@ public boolean isMe() { return isMe; } + public void empty() { + setHtml(""); + } + + public boolean isEmpty() { + return html.isEmpty(); + } + @Override public String toString() { return getClass().getSimpleName() + " {" + diff --git a/src/main/java/fr/delthas/skype/message/MessageType.java b/src/main/java/fr/delthas/skype/message/MessageType.java index 3668550..7480d83 100644 --- a/src/main/java/fr/delthas/skype/message/MessageType.java +++ b/src/main/java/fr/delthas/skype/message/MessageType.java @@ -45,6 +45,14 @@ public static MessageType getTypeByClass(String className) { return UNKNOWN; } + public static MessageType getTypeByClass(Message message) { + if (message != null) { + String className = message.getClass().getSimpleName(); + return getTypeByClass(className); + } + return UNKNOWN; + } + public static MessageType getTypeByHeaderType(String headerType) { if (HEADER_TEXT.equals(headerType)) return TEXT; for (MessageType type : MessageType.values()) { diff --git a/src/test/java/fr/delthas/skype/TestListeners.java b/src/test/java/fr/delthas/skype/TestListeners.java index 460c767..943b707 100644 --- a/src/test/java/fr/delthas/skype/TestListeners.java +++ b/src/test/java/fr/delthas/skype/TestListeners.java @@ -1,5 +1,6 @@ package fr.delthas.skype; +import fr.delthas.skype.message.AbstractMessage; import fr.delthas.skype.message.Message; import org.junit.Assert; @@ -28,6 +29,20 @@ public void testConnect() { @Override public void messageReceived(Group group, User sender, Message message) { logger.info("Received " + message); + AbstractMessage abstractMessage = (AbstractMessage) message; + abstractMessage.setHtml("Edited"); + try { + Thread.sleep(5000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + group.editMessage(abstractMessage); + try { + Thread.sleep(5000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + group.removeMessage(abstractMessage); } @Override @@ -57,6 +72,7 @@ public void messageRemoved(User sender, Message message) { logger.info("Removed " + message); } }); + } public static void main(String... strings) { From 9fabd788d4cde3b6448d26499f7629068111b60e Mon Sep 17 00:00:00 2001 From: Alexander Ivanov Date: Mon, 29 Aug 2016 22:55:20 +0500 Subject: [PATCH 3/5] support for new @p2p.thread.skype type of groups. Now ids of group is like 19:xxx@(p2p.)?thread.skype instead of xxx --- pom.xml | 2 +- src/main/java/fr/delthas/skype/Group.java | 12 ++---- .../java/fr/delthas/skype/NotifConnector.java | 37 ++++++------------- src/main/java/fr/delthas/skype/Skype.java | 10 ++--- .../java/fr/delthas/skype/WebConnector.java | 8 ++-- .../java/fr/delthas/skype/TestListeners.java | 16 +++----- 6 files changed, 30 insertions(+), 55 deletions(-) diff --git a/pom.xml b/pom.xml index 45ffa03..7de1d88 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 fr.delthas javaskype - 1.0.14.2-SNAPSHOT + 1.0.14.3-SNAPSHOT JavaSkype https://github.com/delthas/javaskype diff --git a/src/main/java/fr/delthas/skype/Group.java b/src/main/java/fr/delthas/skype/Group.java index b41ff3a..217683c 100644 --- a/src/main/java/fr/delthas/skype/Group.java +++ b/src/main/java/fr/delthas/skype/Group.java @@ -12,9 +12,8 @@ * A conversation between some Skype users. *

* All information will be updated as updates are received (this object is NOT an immutable view/snapshot of a group). - * */ -public class Group implements Chat{ +public class Group implements Chat { private final Skype skype; private final String id; @@ -53,8 +52,8 @@ public void removeMessage(Message message) { /** * The id of a group is a special String used by Skype to uniquely identify groups. *

- * In case you know about network IDs and the like: if a group "address" is "19:xxx@thread.skype", its id is "xxx". - * + * In case you know about network IDs and the like: if a group "address" is "19:xxx@thread.skype", its id is "19:xxx@thread.skype" or "19:xxx@p2p.thread.skype" . + * * @return The id of the group. */ public String getId() { @@ -104,7 +103,6 @@ void setUsers(List> users) { * * @param user The user to add to this group. * @param role The role of the newly added user. - * * @return true if the user wasn't in the group, and the Skype account has group admin rights if needed. */ public boolean addUser(User user, Role role) { @@ -126,9 +124,7 @@ public boolean addUser(User user, Role role) { * Removes a user from this group. Group admin rights are needed. * * @param user The user to remove from this group. - * * @return true if the Skype account has admin rights, and the user was in the group. - * * @see #isSelfAdmin() */ public boolean removeUser(User user) { @@ -153,9 +149,7 @@ public boolean removeUser(User user) { * * @param user The user whose role is to be changed * @param role The new role of the user. - * * @return true if the Skype account has admin rights, and the user was in the group and didn't have this role already. - * * @see #isSelfAdmin() */ public boolean changeUserRole(User user, Role role) { diff --git a/src/main/java/fr/delthas/skype/NotifConnector.java b/src/main/java/fr/delthas/skype/NotifConnector.java index 7fbd5ba..fc2c2f1 100644 --- a/src/main/java/fr/delthas/skype/NotifConnector.java +++ b/src/main/java/fr/delthas/skype/NotifConnector.java @@ -103,7 +103,8 @@ private void processPacket(Packet packet) throws IOException { case "recentconversations-response": NodeList conversationNodes = doc.getElementsByTagName("conversation"); List threadIds = new ArrayList<>(); - outer: for (int i = 0; i < conversationNodes.getLength(); i++) { + outer: + for (int i = 0; i < conversationNodes.getLength(); i++) { Node conversation = conversationNodes.item(i); String id = null; boolean isThread = false; @@ -147,7 +148,7 @@ private void processPacket(Packet packet) throws IOException { sb.delete(0, sb.length()); sb.append(""); } - sb.append("19:").append(threadId).append("@thread.skype"); + sb.append("").append(threadId).append(""); } String body = sb.append("").toString(); sendPacket("GET", "MSGR\\THREADS", body); @@ -546,7 +547,7 @@ public void sendMessage(Chat chat, Message message) throws IOException { String entity = ""; switch (chat.getType()) { case GROUP: - entity = "19:" + chat.getIdentity() + "@thread.skype"; + entity = chat.getIdentity(); break; case USER: entity = "8:" + chat.getIdentity(); @@ -562,29 +563,29 @@ public void sendUserMessage(User user, String message) throws IOException { @Deprecated public void sendGroupMessage(Group group, String message) throws IOException { - sendMessage("19:" + group.getId() + "@thread.skype", getSanitized(message)); + sendMessage(group.getId(), getSanitized(message)); } public void addUserToGroup(User user, Role role, Group group) throws IOException { - String body = String.format("19:%s@thread.skype8:%s%s", + String body = String.format("%s8:%s%s", group.getId(), user.getUsername(), role.getRoleString()); sendPacket("PUT", "MSGR\\THREAD", body); } public void removeUserFromGroup(User user, Group group) throws IOException { - String body = String.format("19:%s@thread.skype8:%s", group.getId(), + String body = String.format("%s8:%s", group.getId(), user.getUsername()); sendPacket("DEL", "MSGR\\THREAD", body); } public void changeGroupTopic(Group group, String topic) throws IOException { String body = - String.format("19:%s@thread.skype%s", group.getId(), getSanitized(topic)); + String.format("%s%s", group.getId(), getSanitized(topic)); sendPacket("PUT", "MSGR\\THREAD", body); } public void changeUserRole(User user, Role role, Group group) throws IOException { - String body = String.format("19:%s@thread.skype8:%s%s", + String body = String.format("%s8:%s%s", group.getId(), user.getUsername(), role.getRoleString()); sendPacket("PUT", "MSGR\\THREAD", body); } @@ -737,25 +738,11 @@ private Object parseEntity(String rawEntity) { logger.finest("Parsing entity " + rawEntity); int senderBegin = rawEntity.indexOf(':'); int network = Integer.parseInt(rawEntity.substring(0, senderBegin)); - int end0 = rawEntity.indexOf('@'); - int end1 = rawEntity.indexOf(';'); - if (end0 == -1) { - end0 = Integer.MAX_VALUE; - } - if (end1 == -1) { - end1 = Integer.MAX_VALUE; - } - int senderEnd = Math.min(end0, end1); - String name; - if (senderEnd == Integer.MAX_VALUE) { - name = rawEntity.substring(senderBegin + 1); - } else { - name = rawEntity.substring(senderBegin + 1, senderEnd); - } if (network == 8) { - return skype.getUser(name); + int i = rawEntity.indexOf(';'); + return skype.getUser(rawEntity.substring(2, i == -1 ? rawEntity.length() : i)); } else if (network == 19) { - return skype.getGroup(name); + return skype.getGroup(rawEntity); } else { logger.warning("Error while parsing entity " + rawEntity + ": unknown network:" + network); throw new IllegalArgumentException(); diff --git a/src/main/java/fr/delthas/skype/Skype.java b/src/main/java/fr/delthas/skype/Skype.java index a53cd0c..d39cabc 100644 --- a/src/main/java/fr/delthas/skype/Skype.java +++ b/src/main/java/fr/delthas/skype/Skype.java @@ -14,11 +14,7 @@ import java.util.List; import java.util.Map; import java.util.Set; -import java.util.logging.FileHandler; -import java.util.logging.Handler; -import java.util.logging.Level; -import java.util.logging.Logger; -import java.util.logging.SimpleFormatter; +import java.util.logging.*; import java.util.stream.Collectors; /** @@ -396,9 +392,9 @@ public enum MessageAction { * Execute action with message. * Message can be send, edit and removed * - * @param chat where will be send action + * @param chat where will be send action * @param message object of some message type - * @param action send, edit or removed + * @param action send, edit or removed */ void doMessageAction(Chat chat, Message message, MessageAction action) { ensureConnected(); diff --git a/src/main/java/fr/delthas/skype/WebConnector.java b/src/main/java/fr/delthas/skype/WebConnector.java index c69b722..02e8036 100644 --- a/src/main/java/fr/delthas/skype/WebConnector.java +++ b/src/main/java/fr/delthas/skype/WebConnector.java @@ -115,9 +115,11 @@ private User updateUser(JSONObject userJSON, boolean newContactType) throws Pars } else { userUsername = userJSON.getString("id"); userDisplayName = userJSON.optString("display_name", null); - JSONObject nameJSON = userJSON.getJSONObject("name"); - userFirstName = nameJSON.optString("first", null); - userLastName = nameJSON.optString("surname", null); + if (userJSON.optString("type", "skype").equals("skype")) { + JSONObject nameJSON = userJSON.getJSONObject("name"); + userFirstName = nameJSON.optString("first", null); + userLastName = nameJSON.optString("surname", null); + } userMood = userJSON.optString("mood", null); if (userJSON.has("locations")) { JSONObject locationJSON = userJSON.optJSONArray("locations").optJSONObject(0); diff --git a/src/test/java/fr/delthas/skype/TestListeners.java b/src/test/java/fr/delthas/skype/TestListeners.java index 943b707..e07631e 100644 --- a/src/test/java/fr/delthas/skype/TestListeners.java +++ b/src/test/java/fr/delthas/skype/TestListeners.java @@ -1,7 +1,7 @@ package fr.delthas.skype; -import fr.delthas.skype.message.AbstractMessage; import fr.delthas.skype.message.Message; +import fr.delthas.skype.message.TextMessage; import org.junit.Assert; import java.util.logging.Logger; @@ -29,20 +29,16 @@ public void testConnect() { @Override public void messageReceived(Group group, User sender, Message message) { logger.info("Received " + message); - AbstractMessage abstractMessage = (AbstractMessage) message; - abstractMessage.setHtml("Edited"); - try { - Thread.sleep(5000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - group.editMessage(abstractMessage); + try { Thread.sleep(5000); } catch (InterruptedException e) { e.printStackTrace(); } - group.removeMessage(abstractMessage); + + TextMessage textMessage = new TextMessage(null, "hello"); + group.sendMessage(textMessage); + logger.info("Send " + textMessage); } @Override From 159dc1bfac6b7e13e1df306d756dc6ac37f5c0c7 Mon Sep 17 00:00:00 2001 From: Alexander Ivanov Date: Tue, 30 Aug 2016 23:45:19 +0500 Subject: [PATCH 4/5] add editoffset. Move isMe to textMessage. some commented code for quotes --- pom.xml | 2 +- .../java/fr/delthas/skype/NotifConnector.java | 14 ++++++++++- .../skype/message/AbstractMessage.java | 12 +--------- .../delthas/skype/message/ContactMessage.java | 4 ---- .../fr/delthas/skype/message/FileMessage.java | 4 ---- .../fr/delthas/skype/message/MojiMessage.java | 4 ---- .../delthas/skype/message/PictureMessage.java | 5 ---- .../fr/delthas/skype/message/TextMessage.java | 23 ++++++++++++++++++- .../delthas/skype/message/UnknownMessage.java | 5 ---- .../delthas/skype/message/VideoMessage.java | 5 ---- 10 files changed, 37 insertions(+), 41 deletions(-) diff --git a/pom.xml b/pom.xml index 7de1d88..cde6c43 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 fr.delthas javaskype - 1.0.14.3-SNAPSHOT + 1.0.14.4-SNAPSHOT JavaSkype https://github.com/delthas/javaskype diff --git a/src/main/java/fr/delthas/skype/NotifConnector.java b/src/main/java/fr/delthas/skype/NotifConnector.java index fc2c2f1..5935f7a 100644 --- a/src/main/java/fr/delthas/skype/NotifConnector.java +++ b/src/main/java/fr/delthas/skype/NotifConnector.java @@ -201,6 +201,11 @@ private void processPacket(Packet packet) throws IOException { html = formatted.body.substring(Integer.parseInt(isMe)); } if (editId != null) { + String editOffset = formatted.headers.get("Skype-EditOffset"); + if (editOffset != null) { + Integer offset = Integer.parseInt(editOffset); + html = html.substring(offset); + } html = html.replaceAll("", ""); isRemoved = html.isEmpty(); } @@ -212,7 +217,14 @@ private void processPacket(Packet packet) throws IOException { } switch (type) { case TEXT: - message = new TextMessage(id, html, isMe != null); + String quote = null; +// Pattern quotes = Pattern.compile(".*(.*)<\\/legacyquote>(.*).*<\\/quote>(.*)", DOTALL); +// Matcher matcher = quotes.matcher(html); +// if (matcher.matches()) { +// quote = matcher.group(1) + matcher.group(2); +// html = matcher.group(3); +// } + message = new TextMessage(id, html, isMe != null, quote); break; case PICTURE: message = new PictureMessage(id, html); diff --git a/src/main/java/fr/delthas/skype/message/AbstractMessage.java b/src/main/java/fr/delthas/skype/message/AbstractMessage.java index 80c3a12..65c6b13 100644 --- a/src/main/java/fr/delthas/skype/message/AbstractMessage.java +++ b/src/main/java/fr/delthas/skype/message/AbstractMessage.java @@ -11,7 +11,7 @@ public abstract class AbstractMessage implements Message { private MessageType type; private String html; private String text; - private boolean isMe; + public AbstractMessage(String id, String html) { this.id = id; @@ -20,11 +20,6 @@ public AbstractMessage(String id, String html) { this.type = MessageType.getTypeByClass(getClass().getSimpleName()); } - public AbstractMessage(String id, String html, boolean isMe) { - this(id, html); - this.isMe = isMe; - } - @Override public String getId() { return id; @@ -52,10 +47,6 @@ public String getText() { return text; } - public boolean isMe() { - return isMe; - } - public void empty() { setHtml(""); } @@ -71,7 +62,6 @@ public String toString() { ", type=" + type + ", html='" + html + '\'' + ", text='" + text + '\'' + - ", isMe=" + isMe + '}'; } } diff --git a/src/main/java/fr/delthas/skype/message/ContactMessage.java b/src/main/java/fr/delthas/skype/message/ContactMessage.java index e798be9..a97abd6 100644 --- a/src/main/java/fr/delthas/skype/message/ContactMessage.java +++ b/src/main/java/fr/delthas/skype/message/ContactMessage.java @@ -9,8 +9,4 @@ public ContactMessage(String id, String html) { super(id, html); } - public ContactMessage(String id, String html, boolean isMe) { - super(id, html, isMe); - } - } diff --git a/src/main/java/fr/delthas/skype/message/FileMessage.java b/src/main/java/fr/delthas/skype/message/FileMessage.java index 82a22b1..e07c5ae 100644 --- a/src/main/java/fr/delthas/skype/message/FileMessage.java +++ b/src/main/java/fr/delthas/skype/message/FileMessage.java @@ -7,8 +7,4 @@ public class FileMessage extends AbstractMessage { public FileMessage(String id, String html) { super(id, html); } - - public FileMessage(String id, String html, boolean isMe) { - super(id, html, isMe); - } } diff --git a/src/main/java/fr/delthas/skype/message/MojiMessage.java b/src/main/java/fr/delthas/skype/message/MojiMessage.java index e6e34b4..4893530 100644 --- a/src/main/java/fr/delthas/skype/message/MojiMessage.java +++ b/src/main/java/fr/delthas/skype/message/MojiMessage.java @@ -9,8 +9,4 @@ public MojiMessage(String id, String html) { super(id, html); } - public MojiMessage(String id, String html, boolean isMe) { - super(id, html, isMe); - } - } diff --git a/src/main/java/fr/delthas/skype/message/PictureMessage.java b/src/main/java/fr/delthas/skype/message/PictureMessage.java index b159504..44a08ff 100644 --- a/src/main/java/fr/delthas/skype/message/PictureMessage.java +++ b/src/main/java/fr/delthas/skype/message/PictureMessage.java @@ -8,9 +8,4 @@ public class PictureMessage extends AbstractMessage { public PictureMessage(String id, String html) { super(id, html); } - - public PictureMessage(String id, String html, boolean isMe) { - super(id, html, isMe); - } - } diff --git a/src/main/java/fr/delthas/skype/message/TextMessage.java b/src/main/java/fr/delthas/skype/message/TextMessage.java index 32b085b..4a653c8 100644 --- a/src/main/java/fr/delthas/skype/message/TextMessage.java +++ b/src/main/java/fr/delthas/skype/message/TextMessage.java @@ -4,11 +4,32 @@ * Simple text message */ public class TextMessage extends AbstractMessage { + private boolean isMe; + private String quote; + public TextMessage(String id, String html) { super(id, html); } public TextMessage(String id, String html, boolean isMe) { - super(id, html, isMe); + this(id, html); + this.isMe = isMe; + } + + public TextMessage(String id, String html, boolean isMe, String quote) { + this(id, html, isMe); + this.quote = quote; + } + + public String getQuote() { + return quote; + } + + public void setQuote(String quote) { + this.quote = quote; + } + + public boolean isMe() { + return isMe; } } diff --git a/src/main/java/fr/delthas/skype/message/UnknownMessage.java b/src/main/java/fr/delthas/skype/message/UnknownMessage.java index 9fad2ae..89cc9cc 100644 --- a/src/main/java/fr/delthas/skype/message/UnknownMessage.java +++ b/src/main/java/fr/delthas/skype/message/UnknownMessage.java @@ -8,9 +8,4 @@ public class UnknownMessage extends AbstractMessage { public UnknownMessage(String id, String html) { super(id, html); } - - public UnknownMessage(String id, String html, boolean isMe) { - super(id, html, isMe); - } - } diff --git a/src/main/java/fr/delthas/skype/message/VideoMessage.java b/src/main/java/fr/delthas/skype/message/VideoMessage.java index 140f679..5b88d76 100644 --- a/src/main/java/fr/delthas/skype/message/VideoMessage.java +++ b/src/main/java/fr/delthas/skype/message/VideoMessage.java @@ -8,9 +8,4 @@ public class VideoMessage extends AbstractMessage { public VideoMessage(String id, String html) { super(id, html); } - - public VideoMessage(String id, String html, boolean isMe) { - super(id, html, isMe); - } - } From afd26733654704a4f12259afc42b84534b70ce71 Mon Sep 17 00:00:00 2001 From: Alexander Ivanov Date: Wed, 31 Aug 2016 23:17:47 +0500 Subject: [PATCH 5/5] flag is message has quotes --- pom.xml | 2 +- .../java/fr/delthas/skype/NotifConnector.java | 11 +++------- .../fr/delthas/skype/message/TextMessage.java | 22 +++++++++++++------ .../java/fr/delthas/skype/TestListeners.java | 10 --------- 4 files changed, 19 insertions(+), 26 deletions(-) diff --git a/pom.xml b/pom.xml index cde6c43..f435c7b 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ 4.0.0 fr.delthas javaskype - 1.0.14.4-SNAPSHOT + 1.0.14.5-SNAPSHOT JavaSkype https://github.com/delthas/javaskype diff --git a/src/main/java/fr/delthas/skype/NotifConnector.java b/src/main/java/fr/delthas/skype/NotifConnector.java index 5935f7a..213bb6f 100644 --- a/src/main/java/fr/delthas/skype/NotifConnector.java +++ b/src/main/java/fr/delthas/skype/NotifConnector.java @@ -217,14 +217,9 @@ private void processPacket(Packet packet) throws IOException { } switch (type) { case TEXT: - String quote = null; -// Pattern quotes = Pattern.compile(".*(.*)<\\/legacyquote>(.*).*<\\/quote>(.*)", DOTALL); -// Matcher matcher = quotes.matcher(html); -// if (matcher.matches()) { -// quote = matcher.group(1) + matcher.group(2); -// html = matcher.group(3); -// } - message = new TextMessage(id, html, isMe != null, quote); + String singleRow = html.replaceAll("\r", "").replaceAll("\n", ""); + Boolean isHasQuotes = Pattern.compile(".*.*<\\/quote>.*").matcher(singleRow).matches(); + message = new TextMessage(id, html, isMe != null, isHasQuotes); break; case PICTURE: message = new PictureMessage(id, html); diff --git a/src/main/java/fr/delthas/skype/message/TextMessage.java b/src/main/java/fr/delthas/skype/message/TextMessage.java index 4a653c8..1da6db0 100644 --- a/src/main/java/fr/delthas/skype/message/TextMessage.java +++ b/src/main/java/fr/delthas/skype/message/TextMessage.java @@ -5,7 +5,7 @@ */ public class TextMessage extends AbstractMessage { private boolean isMe; - private String quote; + private boolean hasQuotes; public TextMessage(String id, String html) { super(id, html); @@ -16,20 +16,28 @@ public TextMessage(String id, String html, boolean isMe) { this.isMe = isMe; } - public TextMessage(String id, String html, boolean isMe, String quote) { + public TextMessage(String id, String html, boolean isMe, boolean hasQuotes) { this(id, html, isMe); - this.quote = quote; + this.hasQuotes = hasQuotes; } - public String getQuote() { - return quote; + public boolean hasQuotes() { + return hasQuotes; } - public void setQuote(String quote) { - this.quote = quote; + public void setHasQuotes(boolean hasQuotes) { + this.hasQuotes = hasQuotes; } public boolean isMe() { return isMe; } + + @Override + public String toString() { + return "TextMessage{" + + "isMe=" + isMe + + ", hasQuotes=" + hasQuotes + + "} " + super.toString(); + } } diff --git a/src/test/java/fr/delthas/skype/TestListeners.java b/src/test/java/fr/delthas/skype/TestListeners.java index e07631e..7617b45 100644 --- a/src/test/java/fr/delthas/skype/TestListeners.java +++ b/src/test/java/fr/delthas/skype/TestListeners.java @@ -29,16 +29,6 @@ public void testConnect() { @Override public void messageReceived(Group group, User sender, Message message) { logger.info("Received " + message); - - try { - Thread.sleep(5000); - } catch (InterruptedException e) { - e.printStackTrace(); - } - - TextMessage textMessage = new TextMessage(null, "hello"); - group.sendMessage(textMessage); - logger.info("Send " + textMessage); } @Override