├── .gitignore ├── src └── main │ ├── openfire │ ├── logo_large.gif │ ├── logo_small.gif │ ├── plugin.xml │ ├── changelog.html │ └── readme.html │ ├── webapp │ ├── images │ │ └── success-16x16.gif │ └── apns.jsp │ ├── database │ └── apns_mysql.sql │ └── java │ └── com │ └── wecapslabs │ └── openfire │ └── plugin │ └── apns │ ├── ApnsIQHandler.java │ ├── PushMessage.java │ ├── ApnsDBHandler.java │ └── ApnsPlugin.java ├── README.md └── pom.xml /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | -------------------------------------------------------------------------------- /src/main/openfire/logo_large.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xinminlabs/openfire-apns-plugin/HEAD/src/main/openfire/logo_large.gif -------------------------------------------------------------------------------- /src/main/openfire/logo_small.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xinminlabs/openfire-apns-plugin/HEAD/src/main/openfire/logo_small.gif -------------------------------------------------------------------------------- /src/main/webapp/images/success-16x16.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/xinminlabs/openfire-apns-plugin/HEAD/src/main/webapp/images/success-16x16.gif -------------------------------------------------------------------------------- /src/main/database/apns_mysql.sql: -------------------------------------------------------------------------------- 1 | # $Revision$ 2 | # $Date$ 3 | 4 | INSERT INTO ofVersion (name, version) VALUES ('apns', 1); 5 | 6 | CREATE TABLE ofAPNS ( 7 | JID VARCHAR(200) NOT NULL, 8 | devicetoken CHAR(64) NOT NULL, 9 | PRIMARY KEY (JID) 10 | ); 11 | -------------------------------------------------------------------------------- /src/main/openfire/plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | com.wecapslabs.openfire.plugin.apns.ApnsPlugin 5 | ${pom.name} 6 | ${pom.description} 7 | ${pom.organization.name} 8 | ${pom.version} 9 | ${openfire-plugin.build.date} 10 | 3.3.0 11 | apns 12 | 0 13 | gpl 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /src/main/openfire/changelog.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Openfire Apns Changelog 6 | 40 | 41 | 42 | 43 |

44 | Openfire Apns Plugin Changelog 45 |

46 | 47 |

1.0 -- Sep 29, 2013

48 | 49 | 52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Building 2 | --- 3 | Pre-requisite: Use Maven 2.2.1 4 | --- 5 | 1. Install maven-openfire-plugin from https://github.com/srt/maven-openfire-plugin 6 | 2. Obtain a copy of `openfire.jar` and install it into maven. There are serveral ways you can do it, here are two of them: 7 | * Option 1. Download source code of the version of openfire you need at http://www.igniterealtime.org/downloads/source.jsp 8 | 9 | Then set `$OPENFIRE_PATH` and `$OPENFIRE_VERSION` environment variables according to source code path and version and run: 10 | ```bash 11 | cd $OPENFIRE_PATH/build 12 | ant 13 | mvn install:install-file -DgroupId=org.igniterealtime.openfire -DartifactId=openfire -Dversion=$OPENFIRE_VERSION -Dpackaging=jar -DgeneratePom=true -Dfile=$OPENFIRE_PATH/target/openfire/lib/openfire.jar 14 | ``` 15 | * Option 2. If you installed openfire using `openfire*.deb` package on ubuntu, you can find `openfire.jar` inside `/usr/share/openfire/lib`: 16 | 17 | Because this directory is read protected from regular users, you would first have to copy it to somewhere in your home directory and change it's read permissions using sudo, e.g by running: 18 | 19 | ```bash 20 | sudo cp /usr/share/openfire/lib/openfire.jar . 21 | sudo chmod a+r openfire.jar 22 | ``` 23 | 24 | Now you can install it into maven by running: 25 | 26 | ```bash 27 | mvn install:install-file -DgroupId=org.igniterealtime.openfire -DartifactId=openfire -Dversion=$OPENFIRE_VERSION -Dpackaging=jar -DgeneratePom=true -Dfile=openfire.jar 28 | ``` 29 | 3. Inside openfire-apns-plugin directory run: `mvn clean install` 30 | 4. If the build was successfull `openfire-apns.jar` should appear in `target` directory. 31 | -------------------------------------------------------------------------------- /src/main/openfire/readme.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Openfire Apns Plugin Readme 6 | 50 | 51 | 52 | 53 |

54 | Openfire Apns Plugin Readme 55 |

56 | 57 |

Overview

58 | 59 |

60 | The apns plugin is used to integrate Apple Push Notification Service. 61 |

62 | 63 |

Installation

64 | 65 |

Copy openfire-apns.jar into the plugins directory of your Openfire installation. The 66 | plugin will then be automatically deployed. To upgrade to a new version, copy the new 67 | openfire-apns.jar file over the existing file or upgrade from the admin console.

68 | 69 |

Configuration

70 | 71 | 72 |

Using the Plugin

73 | 74 | 75 | 76 | 77 | -------------------------------------------------------------------------------- /src/main/java/com/wecapslabs/openfire/plugin/apns/ApnsIQHandler.java: -------------------------------------------------------------------------------- 1 | package com.wecapslabs.openfire.plugin.apns; 2 | 3 | import org.jivesoftware.openfire.IQHandlerInfo; 4 | import org.jivesoftware.openfire.auth.UnauthorizedException; 5 | import org.jivesoftware.openfire.handler.IQHandler; 6 | import org.dom4j.DocumentHelper; 7 | import org.dom4j.Element; 8 | import org.dom4j.QName; 9 | import org.xmpp.packet.IQ; 10 | import org.xmpp.packet.JID; 11 | import org.xmpp.packet.PacketError; 12 | 13 | public class ApnsIQHandler extends IQHandler { 14 | 15 | private IQHandlerInfo info; 16 | 17 | private ApnsDBHandler dbManager; 18 | 19 | public ApnsIQHandler() { 20 | super("Apns IQ Handler"); 21 | info = new IQHandlerInfo("query","urn:xmpp:apns"); 22 | dbManager = new ApnsDBHandler(); 23 | } 24 | 25 | @Override 26 | public IQHandlerInfo getInfo() { 27 | return info; 28 | } 29 | 30 | @Override 31 | public IQ handleIQ(IQ packet) throws UnauthorizedException { 32 | IQ result = IQ.createResultIQ(packet); 33 | 34 | JID from = packet.getFrom(); 35 | IQ.Type type = packet.getType(); 36 | 37 | if (type.equals(IQ.Type.get)) { 38 | Element responseElement = DocumentHelper.createElement(QName.get("query", "urn:xmpp:apns")); 39 | responseElement.addElement("token").setText(dbManager.getDeviceToken(from)); 40 | 41 | result.setChildElement(responseElement); 42 | } else if (type.equals(IQ.Type.set)) { 43 | Element receivedPacket = packet.getElement(); 44 | 45 | String token = receivedPacket.element("query").elementText("token"); 46 | if (token.length() == 64) { 47 | if (dbManager.insertDeviceToken(from, token)) { 48 | Element responseElement = DocumentHelper.createElement(QName.get("query", "urn:xmpp:apns")); 49 | responseElement.addElement("token").setText(token); 50 | 51 | result.setChildElement(responseElement); 52 | } else { 53 | result.setChildElement(packet.getChildElement().createCopy()); 54 | result.setError(PacketError.Condition.internal_server_error); 55 | } 56 | } else { 57 | result.setChildElement(packet.getChildElement().createCopy()); 58 | result.setError(PacketError.Condition.not_acceptable); 59 | } 60 | } else { 61 | result.setChildElement(packet.getChildElement().createCopy()); 62 | result.setError(PacketError.Condition.not_acceptable); 63 | } 64 | 65 | return result; 66 | } 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/main/java/com/wecapslabs/openfire/plugin/apns/PushMessage.java: -------------------------------------------------------------------------------- 1 | package com.wecapslabs.openfire.plugin.apns; 2 | 3 | import javapns.Push; 4 | import javapns.notification.PushedNotification; 5 | import javapns.notification.PushedNotifications; 6 | import javapns.notification.ResponsePacket; 7 | import javapns.communication.exceptions.KeystoreException; 8 | import javapns.communication.exceptions.CommunicationException; 9 | 10 | import org.slf4j.Logger; 11 | import org.slf4j.LoggerFactory; 12 | 13 | class PushMessage extends Thread { 14 | 15 | private static final Logger Log = LoggerFactory.getLogger(ApnsPlugin.class); 16 | 17 | private ApnsDBHandler dbManager; 18 | 19 | private String message; 20 | private int badge; 21 | private String sound; 22 | private Object keystore; 23 | private String password; 24 | private boolean production; 25 | private Object devices; 26 | 27 | public PushMessage(String message, int badge, String sound, Object keystore, String password, boolean production, Object devices) { 28 | this.message = message; 29 | this.badge = badge; 30 | this.sound = sound; 31 | this.keystore = keystore; 32 | this.password = password; 33 | this.production = production; 34 | this.devices = devices; 35 | 36 | dbManager = new ApnsDBHandler(); 37 | } 38 | 39 | public void run() { 40 | try { 41 | PushedNotifications notifications = Push.combined(message, badge, sound, keystore, password, production, devices); 42 | 43 | for (PushedNotification notification : notifications) { 44 | if (notification.isSuccessful()) { 45 | /* Apple accepted the notification and should deliver it */ 46 | Log.info("Push notification sent successfully to: " + notification.getDevice().getToken()); 47 | /* Still need to query the Feedback Service regularly */ 48 | } else { 49 | String invalidToken = notification.getDevice().getToken(); 50 | dbManager.deleteDeviceToken(invalidToken); 51 | 52 | /* Find out more about what the problem was */ 53 | Exception theProblem = notification.getException(); 54 | Log.error(theProblem.getMessage(), theProblem); 55 | 56 | /* If the problem was an error-response packet returned by Apple, get it */ 57 | ResponsePacket theErrorResponse = notification.getResponse(); 58 | if (theErrorResponse != null) { 59 | Log.info(theErrorResponse.getMessage()); 60 | } 61 | } 62 | } 63 | } catch (KeystoreException e) { 64 | /* A critical problem occurred while trying to use your keystore */ 65 | Log.error(e.getMessage(), e); 66 | } catch (CommunicationException e) { 67 | /* A critical communication error occurred while trying to contact Apple servers */ 68 | Log.error(e.getMessage(), e); 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 3 | 4.0.0 4 | com.wecapslabs.openfire.plugin 5 | apns 6 | 1.0.0 7 | openfire-plugin 8 | APNS Service 9 | openfire-apns-plugin is used to integrate Apple Push Notification Service to Openfire. 10 | https://github.com/wecapslabs/openfire-apns-plugin 11 | 12 | Wecaps Labs 13 | 14 | 15 | 16 | clojars.org 17 | http://clojars.org/repo 18 | 19 | 20 | 21 | 22 | org.igniterealtime.openfire 23 | openfire 24 | 3.10 25 | provided 26 | 27 | 28 | org.clojars.aaroniba 29 | javapns 30 | 2.2 31 | 32 | 33 | javax.servlet 34 | servlet-api 35 | 2.5 36 | provided 37 | 38 | 39 | commons-fileupload 40 | commons-fileupload 41 | 1.2.2 42 | 43 | 44 | commons-io 45 | commons-io 46 | 2.4 47 | 48 | 49 | 50 | openfire-apns 51 | 52 | 53 | maven-compiler-plugin 54 | 55 | 1.5 56 | 1.5 57 | 58 | 3.6.1 59 | 60 | 61 | com.reucon.maven.plugins 62 | maven-openfire-plugin 63 | true 64 | 65 | UTF-8 66 | 67 | 1.0.2-SNAPSHOT 68 | 69 | 70 | 71 | 72 | 73 | GNU General Public License (GPL) v3 74 | http://www.gnu.org/licenses/gpl.txt 75 | 76 | 77 | 78 | 79 | flyerhzm 80 | Richard Huang 81 | flyerhzm@gmail.com 82 | 83 | Main contributor 84 | 85 | 86 | 87 | 88 | UTF-8 89 | 90 | 91 | -------------------------------------------------------------------------------- /src/main/webapp/apns.jsp: -------------------------------------------------------------------------------- 1 | <%@ page import="java.io.File, 2 | java.util.List, 3 | org.jivesoftware.openfire.XMPPServer, 4 | org.jivesoftware.util.*, 5 | com.wecapslabs.openfire.plugin.apns.ApnsPlugin, 6 | org.apache.commons.fileupload.FileItem, 7 | org.apache.commons.fileupload.disk.DiskFileItemFactory, 8 | org.apache.commons.fileupload.servlet.ServletFileUpload, 9 | org.apache.commons.fileupload.FileUploadException" 10 | errorPage="error.jsp" 11 | %> 12 | 13 | <% // Get parameters 14 | boolean save = request.getParameter("save") != null; 15 | boolean success = request.getParameter("success") != null; 16 | boolean error = request.getParameter("error") != null; 17 | String password = ParamUtils.getParameter(request, "password"); 18 | String badge = ParamUtils.getParameter(request, "badge"); 19 | String sound = ParamUtils.getParameter(request, "sound"); 20 | String production = ParamUtils.getParameter(request, "production"); 21 | 22 | ApnsPlugin plugin = (ApnsPlugin) XMPPServer.getInstance().getPluginManager().getPlugin("openfire-apns"); 23 | 24 | // Handle a save 25 | if (save) { 26 | plugin.setPassword(password); 27 | plugin.setBadge(badge); 28 | plugin.setSound(sound); 29 | plugin.setProduction(production); 30 | 31 | try { 32 | List multiparts = new ServletFileUpload(new DiskFileItemFactory()).parseRequest(request); 33 | 34 | for (FileItem item : multiparts) { 35 | if (!item.isFormField()) { 36 | String filename = item.getName(); 37 | item.write(new File(ApnsPlugin.keystorePath())); 38 | } 39 | } 40 | response.sendRedirect("apns.jsp?success=true"); 41 | return; 42 | } catch (Exception e) { 43 | response.sendRedirect("apns.jsp?error=true"); 44 | return; 45 | } 46 | 47 | } 48 | 49 | password = plugin.getPassword(); 50 | badge = Integer.toString(plugin.getBadge()); 51 | sound = plugin.getSound(); 52 | production = plugin.getProduction() ? "true" : "false"; 53 | %> 54 | 55 | 56 | 57 | APNS Settings Properties 58 | 59 | 60 | 61 | 62 | <% if (success) { %> 63 |
64 | 65 | 66 | 67 | 70 | 71 |
68 | APNS certificate updated successfully. 69 |
72 |

73 | <% } %> 74 | 75 |
76 | 77 |
APNS certificate
78 |
79 | 80 | 81 |
82 | 83 | 84 | 85 |
86 | 87 | 88 | 89 |
90 | 91 | 92 | 93 |
94 | 95 | 96 | >Sandbox 97 | >Production 98 |
99 | 100 |
101 | 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /src/main/java/com/wecapslabs/openfire/plugin/apns/ApnsDBHandler.java: -------------------------------------------------------------------------------- 1 | package com.wecapslabs.openfire.plugin.apns; 2 | 3 | import java.sql.Connection; 4 | import java.sql.PreparedStatement; 5 | import java.sql.ResultSet; 6 | import java.sql.SQLException; 7 | 8 | import java.util.List; 9 | import java.util.ArrayList; 10 | 11 | import org.jivesoftware.database.DbConnectionManager; 12 | 13 | import org.xmpp.packet.JID; 14 | 15 | import org.slf4j.Logger; 16 | import org.slf4j.LoggerFactory; 17 | 18 | public class ApnsDBHandler { 19 | 20 | private static final Logger Log = LoggerFactory.getLogger(ApnsPlugin.class); 21 | 22 | private static final String LOAD_TOKEN = "SELECT devicetoken FROM ofAPNS WHERE JID=?"; 23 | private static final String INSERT_TOKEN = "INSERT INTO ofAPNS VALUES(?, ?) ON DUPLICATE KEY UPDATE devicetoken = ?"; 24 | private static final String DELETE_TOKEN = "DELETE FROM ofAPNS WHERE devicetoken = ?"; 25 | private static final String LOAD_TOKENS = "SELECT devicetoken FROM ofAPNS LEFT JOIN ofMucMember ON ofAPNS.JID = ofMucMember.jid LEFT JOIN ofMucRoom ON ofMucMember.roomID = ofMucRoom.roomID WHERE ofMucRoom.name = ?"; 26 | 27 | public boolean insertDeviceToken(JID targetJID, String token) { 28 | Connection con = null; 29 | PreparedStatement pstmt = null; 30 | ResultSet rs = null; 31 | boolean isCompleted = false; 32 | try { 33 | con = DbConnectionManager.getConnection(); 34 | pstmt = con.prepareStatement(INSERT_TOKEN); 35 | pstmt.setString(1, targetJID.toBareJID()); 36 | pstmt.setString(2, token); 37 | pstmt.setString(3, token); 38 | pstmt.executeUpdate(); 39 | pstmt.close(); 40 | 41 | isCompleted = true; 42 | } catch (SQLException sqle) { 43 | Log.error(sqle.getMessage(), sqle); 44 | isCompleted = false; 45 | } finally { 46 | DbConnectionManager.closeConnection(rs, pstmt, con); 47 | } 48 | return isCompleted; 49 | } 50 | 51 | public boolean deleteDeviceToken(String token) { 52 | Connection con = null; 53 | PreparedStatement pstmt = null; 54 | ResultSet rs = null; 55 | boolean isCompleted = false; 56 | try { 57 | con = DbConnectionManager.getConnection(); 58 | pstmt = con.prepareStatement(DELETE_TOKEN); 59 | pstmt.setString(1, token); 60 | pstmt.executeUpdate(); 61 | pstmt.close(); 62 | 63 | isCompleted = true; 64 | } catch (SQLException sqle) { 65 | Log.error(sqle.getMessage(), sqle); 66 | isCompleted = false; 67 | } finally { 68 | DbConnectionManager.closeConnection(rs, pstmt, con); 69 | } 70 | return isCompleted; 71 | } 72 | 73 | public String getDeviceToken(JID targetJID) { 74 | Connection con = null; 75 | PreparedStatement pstmt = null; 76 | ResultSet rs = null; 77 | 78 | String returnToken = null; 79 | try { 80 | con = DbConnectionManager.getConnection(); 81 | pstmt = con.prepareStatement(LOAD_TOKEN); 82 | pstmt.setString(1, targetJID.toBareJID()); 83 | rs = pstmt.executeQuery(); 84 | if (rs.next()) { 85 | returnToken = rs.getString(1); 86 | } 87 | rs.close(); 88 | pstmt.close(); 89 | } catch (SQLException sqle) { 90 | Log.error(sqle.getMessage(), sqle); 91 | returnToken = sqle.getMessage(); 92 | } finally { 93 | DbConnectionManager.closeConnection(rs, pstmt, con); 94 | } 95 | return returnToken; 96 | } 97 | 98 | public List getDeviceTokens(String roomName) { 99 | Connection con = null; 100 | PreparedStatement pstmt = null; 101 | ResultSet rs = null; 102 | 103 | List returnTokens = new ArrayList(); 104 | try { 105 | con = DbConnectionManager.getConnection(); 106 | pstmt = con.prepareStatement(LOAD_TOKENS); 107 | pstmt.setString(1, roomName); 108 | rs = pstmt.executeQuery(); 109 | while (rs.next()) { 110 | returnTokens.add(rs.getString(1)); 111 | } 112 | rs.close(); 113 | pstmt.close(); 114 | } catch (SQLException sqle) { 115 | Log.error(sqle.getMessage(), sqle); 116 | } finally { 117 | DbConnectionManager.closeConnection(rs, pstmt, con); 118 | } 119 | return returnTokens; 120 | } 121 | } 122 | -------------------------------------------------------------------------------- /src/main/java/com/wecapslabs/openfire/plugin/apns/ApnsPlugin.java: -------------------------------------------------------------------------------- 1 | package com.wecapslabs.openfire.plugin.apns; 2 | 3 | import java.io.File; 4 | import java.util.List; 5 | 6 | import org.jivesoftware.openfire.XMPPServer; 7 | import org.jivesoftware.openfire.container.Plugin; 8 | import org.jivesoftware.openfire.container.PluginManager; 9 | import org.jivesoftware.openfire.session.Session; 10 | import org.jivesoftware.openfire.handler.IQHandler; 11 | import org.jivesoftware.openfire.IQRouter; 12 | import org.jivesoftware.openfire.interceptor.InterceptorManager; 13 | import org.jivesoftware.openfire.interceptor.PacketInterceptor; 14 | import org.jivesoftware.openfire.interceptor.PacketRejectedException; 15 | 16 | import org.jivesoftware.util.JiveGlobals; 17 | 18 | import org.xmpp.packet.JID; 19 | import org.xmpp.packet.Message; 20 | import org.xmpp.packet.Packet; 21 | 22 | import org.slf4j.Logger; 23 | import org.slf4j.LoggerFactory; 24 | 25 | 26 | public class ApnsPlugin implements Plugin, PacketInterceptor { 27 | 28 | private static final Logger Log = LoggerFactory.getLogger(ApnsPlugin.class); 29 | 30 | private InterceptorManager interceptorManager; 31 | private ApnsDBHandler dbManager; 32 | 33 | public ApnsPlugin() { 34 | interceptorManager = InterceptorManager.getInstance(); 35 | dbManager = new ApnsDBHandler(); 36 | } 37 | 38 | public static String keystorePath() { 39 | return "./keystore.p12"; 40 | } 41 | 42 | public void setPassword(String password) { 43 | JiveGlobals.setProperty("plugin.apns.password", password); 44 | } 45 | 46 | public String getPassword() { 47 | return JiveGlobals.getProperty("plugin.apns.password", ""); 48 | } 49 | 50 | public void setBadge(String badge) { 51 | JiveGlobals.setProperty("plugin.apns.badge", badge); 52 | } 53 | 54 | public int getBadge() { 55 | return Integer.parseInt(JiveGlobals.getProperty("plugin.apns.badge", "1")); 56 | } 57 | 58 | public void setSound(String sound) { 59 | JiveGlobals.setProperty("plugin.apns.sound", sound); 60 | } 61 | 62 | public String getSound() { 63 | return JiveGlobals.getProperty("plugin.apns.sound", "default"); 64 | } 65 | 66 | public void setProduction(String production) { 67 | JiveGlobals.setProperty("plugin.apns.production", production); 68 | } 69 | 70 | public boolean getProduction() { 71 | return Boolean.parseBoolean(JiveGlobals.getProperty("plugin.apns.badge", "false")); 72 | } 73 | 74 | public void initializePlugin(PluginManager pManager, File pluginDirectory) { 75 | interceptorManager.addInterceptor(this); 76 | 77 | IQHandler myHandler = new ApnsIQHandler(); 78 | IQRouter iqRouter = XMPPServer.getInstance().getIQRouter(); 79 | iqRouter.addHandler(myHandler); 80 | } 81 | 82 | public void destroyPlugin() { 83 | interceptorManager.removeInterceptor(this); 84 | } 85 | 86 | public void interceptPacket(Packet packet, Session session, boolean read, boolean processed) throws PacketRejectedException { 87 | 88 | if (isValidTargetPacket(packet, read, processed)) { 89 | Packet original = packet; 90 | 91 | if(original instanceof Message) { 92 | Message receivedMessage = (Message) original; 93 | 94 | if (receivedMessage.getType() == Message.Type.chat) { 95 | JID targetJID = receivedMessage.getTo(); 96 | 97 | String user = targetJID.getNode(); 98 | String body = receivedMessage.getBody(); 99 | String payloadString = user + ": " + body; 100 | 101 | String deviceToken = dbManager.getDeviceToken(targetJID); 102 | if (deviceToken == null) return; 103 | 104 | new PushMessage(payloadString, getBadge(), getSound(), ApnsPlugin.keystorePath(), getPassword(), getProduction(), deviceToken).start(); 105 | } else if (receivedMessage.getType() == Message.Type.groupchat) { 106 | JID sourceJID = receivedMessage.getFrom(); 107 | JID targetJID = receivedMessage.getTo(); 108 | 109 | String user = sourceJID.getNode(); 110 | String body = receivedMessage.getBody(); 111 | String payloadString = user + ": " + body; 112 | String roomName = targetJID.getNode(); 113 | 114 | List deviceTokens = dbManager.getDeviceTokens(roomName); 115 | if (deviceTokens.isEmpty()) return; 116 | 117 | new PushMessage(payloadString, getBadge(), getSound(), ApnsPlugin.keystorePath(), getPassword(), getProduction(), deviceTokens).start(); 118 | } 119 | } 120 | } 121 | } 122 | 123 | private boolean isValidTargetPacket(Packet packet, boolean read, boolean processed) { 124 | return !processed && read && packet instanceof Message; 125 | } 126 | } 127 | --------------------------------------------------------------------------------