mirror of
https://github.com/igniterealtime/Spark.git
synced 2025-10-29 11:47:01 +00:00
Compare commits
7 Commits
7705a3e72c
...
6294835844
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6294835844 | ||
|
|
20a5264c95 | ||
|
|
87b614f32c | ||
|
|
d2181c486d | ||
|
|
eaa5e42819 | ||
|
|
27e1d35bce | ||
|
|
90defcc4bb |
@ -203,20 +203,29 @@ public class Default {
|
||||
// Otherwise, load and add to cache.
|
||||
try {
|
||||
final URL imageURL = getURL(imageName);
|
||||
if (imageURL == null) {
|
||||
Log.debug(imageName + " not found.");
|
||||
return null;
|
||||
}
|
||||
|
||||
final ImageIcon icon = new ImageIcon(imageURL);
|
||||
cache.put(imageName, icon);
|
||||
return icon;
|
||||
}
|
||||
catch (Exception e) {
|
||||
Log.warning(imageName + " not found.", e);
|
||||
Log.warning("Unable to load " + imageName, e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static URL getURL(String propertyName) {
|
||||
URL pluginUrl = PluginRes.getDefaultURL(propertyName);
|
||||
return pluginUrl != null ? pluginUrl : cl.getResource(getString(propertyName));
|
||||
if (pluginUrl != null) return pluginUrl;
|
||||
String resourceName = getString(propertyName);
|
||||
if (resourceName == null) {
|
||||
return null;
|
||||
}
|
||||
return cl.getResource(resourceName);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ -956,7 +956,9 @@ public class ChatContainer extends SparkTabbedPane implements MessageListener, C
|
||||
-> {
|
||||
for (final ChatRoomListener listener : chatRoomListeners) {
|
||||
try {
|
||||
listener.userHasJoined(room, userid.toString());
|
||||
if (userid != null) {
|
||||
listener.userHasJoined(room, userid.toString());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.error("A ChatRoomListener (" + listener + ") threw an exception while processing a 'user joined' event for user '" + userid + "' in room: " + room, e);
|
||||
}
|
||||
|
||||
@ -15,16 +15,27 @@
|
||||
*/
|
||||
package org.jivesoftware.spark.ui;
|
||||
|
||||
import org.apache.hc.client5.http.config.RequestConfig;
|
||||
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
|
||||
import org.apache.hc.client5.http.impl.classic.HttpClients;
|
||||
import org.apache.hc.core5.http.ClassicHttpRequest;
|
||||
import org.apache.hc.core5.http.HttpEntity;
|
||||
import org.apache.hc.core5.http.io.support.ClassicRequestBuilder;
|
||||
import org.jivesoftware.smack.SmackConfiguration;
|
||||
import org.jivesoftware.spark.util.log.Log;
|
||||
import org.jivesoftware.sparkimpl.plugin.emoticons.EmoticonManager;
|
||||
import org.jivesoftware.sparkimpl.settings.local.SettingsManager;
|
||||
import org.jivesoftware.sparkimpl.updater.AcceptAllCertsConnectionManager;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.swing.*;
|
||||
import javax.swing.text.*;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static javax.swing.text.StyleConstants.Foreground;
|
||||
|
||||
@ -41,11 +52,11 @@ import static javax.swing.text.StyleConstants.Foreground;
|
||||
public class MessageEntry extends TimeStampedEntry
|
||||
{
|
||||
public static final List<Character> DIRECTIVE_CHARS = Arrays.asList( '*', '_', '~', '`' );
|
||||
private final String prefix;
|
||||
private final Color prefixColor;
|
||||
private final String message;
|
||||
private final Color messageColor;
|
||||
private final Color backgroundColor;
|
||||
protected final String prefix;
|
||||
protected final Color prefixColor;
|
||||
protected final String message;
|
||||
protected final Color messageColor;
|
||||
protected final Color backgroundColor;
|
||||
|
||||
/**
|
||||
* Creates a new entry using the default background color (white/transparent).
|
||||
@ -216,9 +227,10 @@ public class MessageEntry extends TimeStampedEntry
|
||||
}
|
||||
|
||||
protected void insertFragment(ChatArea chatArea, String fragment, MutableAttributeSet style) throws BadLocationException {
|
||||
if (insertPicture(chatArea, fragment, style)) return;
|
||||
if (insertLink(chatArea.getDocument(), fragment, style)) return;
|
||||
if (insertAddress(chatArea.getDocument(), fragment, style)) return;
|
||||
if (insertImage(chatArea, fragment)) return;
|
||||
if (insertEmoticon(chatArea, fragment)) return;
|
||||
chatArea.getDocument().insertString(chatArea.getDocument().getLength(), fragment, style);
|
||||
}
|
||||
|
||||
@ -349,6 +361,108 @@ public class MessageEntry extends TimeStampedEntry
|
||||
return style;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a picture into the current document.
|
||||
*
|
||||
* @param url - the link to the content to insert( ex. http://example.org/hello.gif )
|
||||
* @throws BadLocationException if the location is not available for insertion.
|
||||
*/
|
||||
public boolean insertPicture(ChatArea chatArea, String url, MutableAttributeSet messageStyle) throws BadLocationException
|
||||
{
|
||||
// FIXME: this is unsafe. Do not blindly accept anything that looks like an URL (check if it is a valid URL).
|
||||
// TODO: instead of operating on message text content, operate on message stanza metadata.
|
||||
// TODO: do not download each time. Cache downloaded data.
|
||||
// TODO: make resized image clickable (open in unresized size).
|
||||
if (url.startsWith("http://") ||
|
||||
url.startsWith("https://")) {
|
||||
|
||||
try (final CloseableHttpClient httpClient =
|
||||
HttpClients.custom()
|
||||
.setConnectionManager(AcceptAllCertsConnectionManager.getInstance()) // FIXME: do not use acceptallcdertsconnectionmanager! It is unsafe. Only use trusted certificates!
|
||||
.setDefaultRequestConfig(RequestConfig.custom().setResponseTimeout(SmackConfiguration.getDefaultReplyTimeout()/10, TimeUnit.MILLISECONDS).build())
|
||||
.build()
|
||||
) {
|
||||
final ClassicHttpRequest request = ClassicRequestBuilder.get(url)
|
||||
.setHeader("Content-Type", "image/*")
|
||||
.setHeader("User-Agent", "Spark HttpFileUpload")
|
||||
.build();
|
||||
|
||||
BufferedImage img = httpClient.execute(request, httpResponse -> {
|
||||
HttpEntity entity = httpResponse.getEntity();
|
||||
try {
|
||||
return ImageIO.read(entity.getContent());
|
||||
} catch (Throwable t) {
|
||||
Log.warning("Unable to load picture from " + url, t);
|
||||
return null;
|
||||
}
|
||||
});
|
||||
|
||||
if (img != null) {
|
||||
SimpleAttributeSet center = new SimpleAttributeSet();
|
||||
StyleConstants.setAlignment(center, StyleConstants.ALIGN_CENTER);
|
||||
SimpleAttributeSet left = new SimpleAttributeSet();
|
||||
StyleConstants.setAlignment(left, StyleConstants.ALIGN_LEFT);
|
||||
|
||||
final StyledDocument doc = (StyledDocument) chatArea.getDocument();
|
||||
|
||||
doc.insertString( doc.getLength(), "\n", messageStyle );
|
||||
|
||||
final int width = Math.max(60, Math.round(chatArea.getParent().getWidth()*0.70f));
|
||||
final int height = Math.max(60, Math.round(chatArea.getParent().getHeight()*0.40f));
|
||||
ImageIcon image = scaleImage(new ImageIcon(img), width, height);
|
||||
|
||||
int start = doc.getLength();
|
||||
|
||||
MutableAttributeSet inputAttributes = chatArea.getInputAttributes();
|
||||
inputAttributes.removeAttributes(inputAttributes);
|
||||
StyleConstants.setIcon(inputAttributes, image);
|
||||
chatArea.getDocument().insertString(doc.getLength(), " ", chatArea.getInputAttributes());
|
||||
inputAttributes.removeAttributes(inputAttributes);
|
||||
doc.insertString(doc.getLength(), "\n", messageStyle);
|
||||
|
||||
final MutableAttributeSet linkStyle = new SimpleAttributeSet( messageStyle.copyAttributes() );
|
||||
insertLink(doc, url, linkStyle);
|
||||
int end = doc.getLength();
|
||||
final int length = end-start+1;
|
||||
doc.setParagraphAttributes(start, length, center, false);
|
||||
|
||||
// No longer center.
|
||||
//System.out.println("text: " + doc.getText(start, length));
|
||||
doc.setParagraphAttributes(doc.getLength()+2, 0, left,false);
|
||||
return true;
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
Log.warning( "Unable to download content from " + url, e );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public static ImageIcon scaleImage(ImageIcon icon, int w, int h)
|
||||
{
|
||||
try {
|
||||
int nw = icon.getIconWidth();
|
||||
int nh = icon.getIconHeight();
|
||||
|
||||
if (icon.getIconWidth() > w) {
|
||||
nw = w;
|
||||
nh = (nw * icon.getIconHeight()) / icon.getIconWidth();
|
||||
}
|
||||
|
||||
if (nh > h) {
|
||||
nh = h;
|
||||
nw = (icon.getIconWidth() * nh) / icon.getIconHeight();
|
||||
}
|
||||
|
||||
return new ImageIcon(icon.getImage().getScaledInstance(nw, nh, Image.SCALE_DEFAULT));
|
||||
} catch (Exception e) {
|
||||
Log.warning("Unable to scale an image", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts a link into the current document.
|
||||
*
|
||||
@ -403,7 +517,7 @@ public class MessageEntry extends TimeStampedEntry
|
||||
* @param imageKey - the smiley representation of the image.( ex. :) )
|
||||
* @return true if the image was found, otherwise false.
|
||||
*/
|
||||
public boolean insertImage( ChatArea chatArea, String imageKey )
|
||||
public boolean insertEmoticon(ChatArea chatArea, String imageKey )
|
||||
{
|
||||
if ( !chatArea.getForceEmoticons() && !SettingsManager.getLocalPreferences().areEmoticonsEnabled() || !chatArea.emoticonsAvailable )
|
||||
{
|
||||
|
||||
@ -27,6 +27,7 @@ import org.jivesoftware.spark.SparkManager;
|
||||
import org.jivesoftware.spark.plugin.ContextMenuListener;
|
||||
import org.jivesoftware.spark.ui.history.HistoryWindow;
|
||||
import org.jivesoftware.spark.util.ModelUtil;
|
||||
import org.jivesoftware.spark.util.TaskEngine;
|
||||
import org.jivesoftware.spark.util.log.Log;
|
||||
import org.jivesoftware.sparkimpl.plugin.manager.Enterprise;
|
||||
import org.jivesoftware.sparkimpl.plugin.emoticons.EmoticonManager;
|
||||
@ -105,37 +106,50 @@ public class TranscriptWindow extends ChatArea implements ContextMenuListener
|
||||
|
||||
}
|
||||
|
||||
// Guarded by 'this'
|
||||
boolean isReordingScheduled = false;
|
||||
|
||||
private synchronized void reOrder() {
|
||||
// Clear and refill the UI component.
|
||||
try
|
||||
{
|
||||
entries.sort( Comparator.comparing(TranscriptWindowEntry::isDelayed).thenComparing( TranscriptWindowEntry::getTimestamp ) );
|
||||
clear();
|
||||
for ( TranscriptWindowEntry e : entries )
|
||||
{
|
||||
e.addTo( this );
|
||||
}
|
||||
}
|
||||
catch ( BadLocationException ex )
|
||||
{
|
||||
Log.error( "An exception prevented chat content to be redrawn in the user interface!", ex );
|
||||
}
|
||||
finally
|
||||
{
|
||||
isReordingScheduled = false;
|
||||
}
|
||||
}
|
||||
|
||||
protected synchronized void add( TranscriptWindowEntry entry )
|
||||
{
|
||||
final TranscriptWindow transcriptWindow = this;
|
||||
//boolean reorderEverything = false;
|
||||
if ( !entries.isEmpty() )
|
||||
{
|
||||
if ( entry.getTimestamp().isBefore( entries.getLast().getTimestamp() ) && !(entries.getLast() instanceof CustomTextEntry) )
|
||||
{
|
||||
Log.warning( "A chat entry appears to have been delivered out of order. The transcript window must be reordered!" );
|
||||
//reorderEverything = true;
|
||||
Log.debug( "A chat entry appears to have been delivered out of order. The transcript window must be reordered!" );
|
||||
if (!isReordingScheduled) {
|
||||
Log.warning( "Scheduling new re-ordering of entries in the transcript window." );
|
||||
isReordingScheduled = true;
|
||||
TaskEngine.getInstance().schedule(new TimerTask()
|
||||
{
|
||||
@Override
|
||||
|
||||
// This is an alternative approach to the 'reorderEverything boolean + routine. The idea behind using the
|
||||
// SwingUtilities is to schedule redrawing after all currently queued messages (loads of which are
|
||||
// probably also out of order), are processed, which should reduce the amount of redraws.
|
||||
SwingUtilities.invokeLater( () ->
|
||||
{
|
||||
// Clear and refill the UI component.
|
||||
try
|
||||
{
|
||||
entries.sort( Comparator.comparing(TranscriptWindowEntry::isDelayed).thenComparing( TranscriptWindowEntry::getTimestamp ) );
|
||||
clear();
|
||||
for ( TranscriptWindowEntry e : entries )
|
||||
{
|
||||
e.addTo( transcriptWindow );
|
||||
}
|
||||
}
|
||||
catch ( BadLocationException ex )
|
||||
{
|
||||
Log.error( "An exception prevented chat content to be redrawn in the user interface!", ex );
|
||||
}
|
||||
} );
|
||||
public void run()
|
||||
{
|
||||
SwingUtilities.invokeLater(() -> reOrder());
|
||||
}
|
||||
}, 250);
|
||||
}
|
||||
}
|
||||
if ( !entry.getTimestamp().withZoneSameInstant( ZoneId.systemDefault() ).toLocalDate().isEqual( entries.getLast().getTimestamp().withZoneSameInstant( ZoneId.systemDefault() ).toLocalDate() ) )
|
||||
{
|
||||
@ -153,20 +167,7 @@ public class TranscriptWindow extends ChatArea implements ContextMenuListener
|
||||
|
||||
try
|
||||
{
|
||||
// if ( reorderEverything )
|
||||
// {
|
||||
// // Clear and refill the UI component.
|
||||
// entries.sort( Comparator.comparing( TranscriptWindowEntry::getTimestamp ) );
|
||||
// clear();
|
||||
// for ( TranscriptWindowEntry e : entries )
|
||||
// {
|
||||
// e.addTo( this );
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
{
|
||||
entry.addTo( this );
|
||||
}
|
||||
entry.addTo( this );
|
||||
}
|
||||
catch ( BadLocationException ex )
|
||||
{
|
||||
|
||||
@ -128,7 +128,7 @@ public class ChatRoomImpl extends ChatRoom {
|
||||
this.participantNickname = participantNickname;
|
||||
|
||||
// Loads the current history for this user.
|
||||
loadHistory();
|
||||
SwingUtilities.invokeLater(this::loadHistory);
|
||||
|
||||
// Register StanzaListeners
|
||||
final StanzaFilter directFilter = new AndFilter(
|
||||
|
||||
@ -735,7 +735,7 @@ public class GroupChatRoom extends ChatRoom
|
||||
{
|
||||
UIManager.put( "OptionPane.okButtonText", Res.getString( "ok" ) );
|
||||
JOptionPane.showMessageDialog( this,
|
||||
Res.getString( "message.room.destroyed", destroy.getReason() ),
|
||||
(destroy.getReason() != null ? Res.getString( "message.room.destroyed", destroy.getReason() ) : Res.getString( "message.room.destroyed.no.reason" )),
|
||||
Res.getString( "title.room.destroyed" ),
|
||||
JOptionPane.INFORMATION_MESSAGE );
|
||||
leaveChatRoom();
|
||||
@ -782,7 +782,11 @@ public class GroupChatRoom extends ChatRoom
|
||||
@Override
|
||||
public void kicked( EntityFullJid participant, Jid actor, String reason )
|
||||
{
|
||||
insertText( Res.getString( "message.user.kicked.from.room", participant.getResourcepart(), actor, reason ) );
|
||||
if (reason == null || reason.isEmpty()) {
|
||||
insertText(Res.getString("message.user.kicked.from.room.no.reason", participant.getResourcepart(), actor));
|
||||
} else {
|
||||
insertText(Res.getString("message.user.kicked.from.room", participant.getResourcepart(), actor, reason));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -800,7 +804,11 @@ public class GroupChatRoom extends ChatRoom
|
||||
@Override
|
||||
public void banned( EntityFullJid participant, Jid actor, String reason )
|
||||
{
|
||||
insertText( Res.getString( "message.user.banned", participant.getResourcepart(), reason ) );
|
||||
if (reason == null || reason.isEmpty()) {
|
||||
insertText(Res.getString("message.user.banned.no.reason", participant.getResourcepart()));
|
||||
} else {
|
||||
insertText(Res.getString("message.user.banned", participant.getResourcepart(), reason));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@ -15,6 +15,7 @@
|
||||
*/
|
||||
package org.jivesoftware.sparkimpl.updater;
|
||||
|
||||
import org.apache.hc.client5.http.config.ConnectionConfig;
|
||||
import org.apache.hc.client5.http.impl.io.BasicHttpClientConnectionManager;
|
||||
import org.apache.hc.client5.http.socket.ConnectionSocketFactory;
|
||||
import org.apache.hc.client5.http.socket.PlainConnectionSocketFactory;
|
||||
@ -22,13 +23,16 @@ import org.apache.hc.client5.http.ssl.NoopHostnameVerifier;
|
||||
import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory;
|
||||
import org.apache.hc.core5.http.config.Registry;
|
||||
import org.apache.hc.core5.http.config.RegistryBuilder;
|
||||
import org.apache.hc.core5.http.io.SocketConfig;
|
||||
import org.apache.hc.core5.ssl.SSLContexts;
|
||||
import org.apache.hc.core5.ssl.TrustStrategy;
|
||||
import org.jivesoftware.smack.SmackConfiguration;
|
||||
|
||||
import javax.net.ssl.SSLContext;
|
||||
import java.security.KeyManagementException;
|
||||
import java.security.KeyStoreException;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
/**
|
||||
* A HTTP Client connection manager that knowingly by-passes all verification of TLS certificates.
|
||||
@ -68,6 +72,9 @@ public class AcceptAllCertsConnectionManager extends BasicHttpClientConnectionMa
|
||||
.register("http", new PlainConnectionSocketFactory())
|
||||
.build();
|
||||
|
||||
return new BasicHttpClientConnectionManager(socketFactoryRegistry);
|
||||
final BasicHttpClientConnectionManager result = new BasicHttpClientConnectionManager(socketFactoryRegistry);
|
||||
result.setSocketConfig(SocketConfig.custom().setSoTimeout(SmackConfiguration.getDefaultReplyTimeout(), TimeUnit.MILLISECONDS).build());
|
||||
result.setConnectionConfig(ConnectionConfig.custom().setConnectTimeout(SmackConfiguration.getDefaultReplyTimeout(), TimeUnit.MILLISECONDS).build());
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
@ -617,6 +617,7 @@ message.restart.spark.changes = Plugin will be removed on the next startup of Sp
|
||||
message.restart.spark.to.install = You need to shut down the client to install latest version, would you like to do that now?
|
||||
message.restart.required = You will need to restart Spark to have your changes take effect, restart now?
|
||||
message.room.creation.error = The room could not be created
|
||||
message.room.destroyed.no.reason = This room has been destroyed.
|
||||
message.room.destroyed = This room has been destroyed due to the following reason: {0}
|
||||
message.room.destruction.reason = Reason for destroying the room?
|
||||
message.room.information.for = Room information for {0}
|
||||
@ -670,6 +671,7 @@ message.unrecoverable.error = Unknown connection error. Please review the logs f
|
||||
message.update.room.list = Update room list
|
||||
message.updating.cancelled = Updating has been canceled
|
||||
message.user.banned = {0} has been banned from this room. Reason: {1}
|
||||
message.user.banned.no.reason = {0} has been banned from this room.
|
||||
message.user.given.voice = {0} has been given a voice in this room
|
||||
message.user.granted.admin = {0} has been granted administrator privileges
|
||||
message.user.granted.membership = {0} has been given membership privileges
|
||||
@ -678,6 +680,7 @@ message.user.granted.owner = {0} has been granted owner privileges
|
||||
message.user.is.sending.you.a.file = {0} is sending you a file
|
||||
message.user.joined.room = {0} has joined the room
|
||||
message.user.kicked.from.room = {0} has been kicked out of the room by {1}. Reason: {2}
|
||||
message.user.kicked.from.room.no.reason = {0} has been kicked out of the room by {1}.
|
||||
message.user.left.room = {0} has left the room
|
||||
message.user.nickname.changed = {0} is now known as {1}
|
||||
message.user.now.available.to.chat = {0} is online at {1}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user