/** * Copyright (c) 2000-present Liferay, Inc. All rights reserved. * * This library is free software; you can redistribute it and/or modify it under * the terms of the GNU Lesser General Public License as published by the Free * Software Foundation; either version 2.1 of the License, or (at your option) * any later version. * * This library is distributed in the hope that it will be useful, but WITHOUT * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more * details. */ package com.liferay.chat.jabber; import com.liferay.chat.model.Status; import com.liferay.chat.service.StatusLocalServiceUtil; import com.liferay.chat.util.PortletPropsValues; import com.liferay.chat.util.comparator.BuddyComparator; import com.liferay.portal.kernel.log.Log; import com.liferay.portal.kernel.log.LogFactoryUtil; import com.liferay.portal.kernel.model.ContactConstants; import com.liferay.portal.kernel.model.User; import com.liferay.portal.kernel.service.UserLocalServiceUtil; import com.liferay.portal.kernel.util.StringPool; import com.liferay.portal.kernel.util.StringUtil; import com.liferay.portal.kernel.util.Validator; import java.net.InetAddress; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import org.jivesoftware.smack.AccountManager; import org.jivesoftware.smack.Chat; import org.jivesoftware.smack.ChatManager; import org.jivesoftware.smack.ChatManagerListener; import org.jivesoftware.smack.Connection; import org.jivesoftware.smack.ConnectionConfiguration; import org.jivesoftware.smack.MessageListener; import org.jivesoftware.smack.Roster; import org.jivesoftware.smack.RosterEntry; import org.jivesoftware.smack.SmackConfiguration; import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.packet.Presence; /** * @author Bruno Farache */ public class JabberImpl implements Jabber { @Override public void disconnect(long userId) { Connection connection = getConnection(userId); if (connection == null) { return; } connection.disconnect(); _connections.remove(userId); _onlineUserIds.remove(userId); } @Override public String getResource(String jabberId) { String resource = StringUtil.extractLast(jabberId, StringPool.AT); resource = StringUtil.extractLast(resource, StringPool.SLASH); if (resource == null) { return StringPool.BLANK; } return resource; } @Override public String getScreenName(String jabberId) { return StringUtil.extractFirst(jabberId, StringPool.AT); } @Override public List<Object[]> getStatuses( long companyId, long userId, List<Object[]> buddies) { try { Connection connection = getConnection(userId); if (connection == null) { if (_log.isWarnEnabled()) { _log.warn("User " + userId + " is not connected to Jabber"); } return buddies; } List<Object[]> jabberBuddies = new ArrayList<>(); jabberBuddies.addAll(buddies); Roster roster = connection.getRoster(); Collection<RosterEntry> rosterEntries = roster.getEntries(); if (PortletPropsValues.JABBER_IMPORT_USER_ENABLED) { for (Object[] buddy : buddies) { String firstName = (String)buddy[1]; String lastName = (String)buddy[3]; String middleName = (String)buddy[5]; String screenName = (String)buddy[7]; String fullName = ContactConstants.getFullName( firstName, middleName, lastName); String jabberId = getFullJabberId(screenName); if (!roster.contains(jabberId)) { roster.createEntry(jabberId, fullName, null); } } } BuddyComparator buddyComparator = new BuddyComparator(true); for (RosterEntry rosterEntry : rosterEntries) { Presence presence = roster.getPresence(rosterEntry.getUser()); if (!presence.isAvailable()) { continue; } User user = UserLocalServiceUtil.getUserByScreenName( companyId, getScreenName(rosterEntry.getUser())); Object[] jabberBuddy = new Object[10]; jabberBuddy[0] = true; jabberBuddy[1] = user.getFirstName(); jabberBuddy[2] = user.getGroupId(); jabberBuddy[3] = user.getLastName(); jabberBuddy[4] = user.isMale(); jabberBuddy[5] = user.getMiddleName(); jabberBuddy[6] = user.getPortraitId(); jabberBuddy[7] = user.getScreenName(); jabberBuddy[8] = user.getUserId(); jabberBuddy[9] = user.getUserUuid(); if (Collections.binarySearch( jabberBuddies, jabberBuddy, buddyComparator) < 0) { jabberBuddies.add(jabberBuddy); } } Collections.sort(jabberBuddies, buddyComparator); return jabberBuddies; } catch (Exception e) { _log.error("Unable to get Jabber buddies", e); return buddies; } } @Override public void login(long userId, String password) { try { connect(userId, password); } catch (XMPPException xmppe1) { String message1 = xmppe1.getMessage(); if (Validator.isNotNull(message1) && message1.contains("not-authorized")) { if (!PortletPropsValues.JABBER_IMPORT_USER_ENABLED) { if (_log.isDebugEnabled()) { _log.debug( "User " + userId + " cannot connect to Jabber"); } return; } if (_log.isDebugEnabled()) { _log.debug( "Importing user " + userId + " because he cannot connect to Jabber"); } try { importUser(userId, password); connect(userId, password); } catch (XMPPException xmppe2) { String message2 = xmppe2.getMessage(); if (message2.contains("conflict(409)")) { _log.error( "User " + userId + " already exists but password " + "is not synchronized with Jabber"); } } catch (Exception e) { _log.error(e, e); } } } catch (Exception e) { _log.error(e, e); } } @Override public void sendMessage(long fromUserId, long toUserId, String content) { try { if (Validator.isNull(content)) { return; } Connection connection = getConnection(fromUserId); if (connection == null) { if (_log.isWarnEnabled()) { _log.warn( "User " + fromUserId + " is not connected to Jabber " + "and cannot send messages"); } return; } User toUser = UserLocalServiceUtil.getUser(toUserId); Roster roster = connection.getRoster(); String jabberId = getJabberId(toUser.getScreenName()); if (!roster.contains(jabberId)) { return; } Iterator<Presence> presences = roster.getPresences(jabberId); while (presences.hasNext()) { Presence presence = presences.next(); String from = presence.getFrom(); String resource = getResource(from); if (StringUtil.equalsIgnoreCase( resource, PortletPropsValues.JABBER_RESOURCE)) { continue; } ChatManager chatManager = connection.getChatManager(); MessageListener messageListener = new JabberMessageListener( toUser.getCompanyId(), fromUserId); Chat chat = chatManager.createChat(from, messageListener); try { chat.sendMessage(content); } catch (XMPPException xmppe) { if (_log.isWarnEnabled()) { _log.warn( "User " + fromUserId + " could not send message", xmppe); } } } } catch (Exception e) { _log.error(e, e); } } @Override public void updatePassword(long userId, String password) { if (!PortletPropsValues.JABBER_IMPORT_USER_ENABLED || (password == null)) { return; } Connection connection = getConnection(userId); if (connection == null) { return; } try { AccountManager accountManager = connection.getAccountManager(); accountManager.changePassword(password); } catch (XMPPException xmppe) { _log.error("Unable to update user " + userId + " password", xmppe); } } @Override public void updateStatus(long userId, int online) { updateStatus(userId, online, null); } protected Connection connect() throws Exception { long userId = -1; String password = null; return connect(userId, password); } protected Connection connect(long userId, String password) throws Exception { Connection connection = getConnection(userId); if (connection != null) { return connection; } connection = new XMPPConnection(getConnectionConfiguration()); connection.connect(); if (userId < 0) { return connection; } User user = UserLocalServiceUtil.getUserById(userId); connection.login( user.getScreenName(), password, PortletPropsValues.JABBER_RESOURCE); Status status = StatusLocalServiceUtil.getUserStatus(userId); if (status.getOnline()) { updateStatus(userId, 1, connection); } ChatManager chatManager = connection.getChatManager(); ChatManagerListener chatMessageListener = new JabberChatManagerListener( user.getCompanyId(), userId); chatManager.addChatListener(chatMessageListener); _connections.put(userId, connection); return connection; } protected Connection getConnection(long userId) { return _connections.get(userId); } protected ConnectionConfiguration getConnectionConfiguration() throws UnknownHostException { if (_connectionConfiguration != null) { return _connectionConfiguration; } String jabberHost = PortletPropsValues.JABBER_HOST; if (!Validator.isIPAddress(jabberHost)) { InetAddress inetAddress = InetAddress.getByName(jabberHost); jabberHost = inetAddress.getHostAddress(); } _connectionConfiguration = new ConnectionConfiguration( jabberHost, PortletPropsValues.JABBER_PORT, PortletPropsValues.JABBER_SERVICE_NAME); _connectionConfiguration.setSendPresence(false); SmackConfiguration.setLocalSocks5ProxyEnabled( PortletPropsValues.JABBER_SOCK5_PROXY_ENABLED); SmackConfiguration.setLocalSocks5ProxyPort( PortletPropsValues.JABBER_SOCK5_PROXY_PORT); return _connectionConfiguration; } protected String getFullJabberId(String screenName) { String jabberId = getJabberId(screenName); return jabberId.concat(StringPool.SLASH).concat( PortletPropsValues.JABBER_RESOURCE); } protected String getJabberId(String screenName) { return screenName.concat(StringPool.AT).concat( PortletPropsValues.JABBER_SERVICE_NAME); } protected void importUser(long userId, String password) throws Exception { Connection connection = connect(); AccountManager accountManager = connection.getAccountManager(); if (!accountManager.supportsAccountCreation()) { _log.error("Jabber server does not support account creation"); return; } User user = UserLocalServiceUtil.getUserById(userId); Map<String, String> attributes = new HashMap<>(); attributes.put("email", user.getEmailAddress()); attributes.put("first", user.getFirstName()); attributes.put("last", user.getLastName()); attributes.put("name", user.getFullName()); accountManager.createAccount( user.getScreenName(), password, attributes); } protected void updateStatus( long userId, int online, Connection connection) { try { if (connection == null) { connection = getConnection(userId); if (connection == null) { if (_log.isWarnEnabled()) { _log.warn( "User " + userId + " is not connected to Jabber"); } return; } } if ((online == 1) && !_onlineUserIds.contains(userId)) { Presence presence = new Presence(Presence.Type.available); connection.sendPacket(presence); _onlineUserIds.add(userId); } else if ((online == 0) && _onlineUserIds.contains(userId)) { Presence presence = new Presence(Presence.Type.unavailable); connection.sendPacket(presence); _onlineUserIds.remove(userId); } } catch (Exception e) { _log.error(e, e); } } private static Log _log = LogFactoryUtil.getLog(JabberImpl.class); private ConnectionConfiguration _connectionConfiguration; private Map<Long, Connection> _connections = new HashMap<>(); private Set<Long> _onlineUserIds = new HashSet<>(); }