mirror of https://github.com/sipwise/jitsi.git
Adds check for image size and content type for the image replacement of links. Adds "show preview" link next to the image link if the preview of the images is disabled. Patch provided by Marin Dzhigarov on dev mailing list (subject: "PATCH: Replacement of Image/Video links").
parent
f02a12d22d
commit
a16097f5cd
@ -0,0 +1,301 @@
|
||||
package net.java.sip.communicator.impl.gui.main.chat;
|
||||
|
||||
import java.awt.*;
|
||||
import java.awt.event.*;
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.*;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.text.*;
|
||||
|
||||
import net.java.sip.communicator.impl.gui.*;
|
||||
import net.java.sip.communicator.plugin.desktoputil.*;
|
||||
import net.java.sip.communicator.plugin.desktoputil.SwingWorker;
|
||||
import net.java.sip.communicator.service.gui.*;
|
||||
import net.java.sip.communicator.service.replacement.*;
|
||||
import net.java.sip.communicator.service.replacement.directimage.*;
|
||||
import net.java.sip.communicator.util.*;
|
||||
|
||||
import org.jitsi.service.configuration.*;
|
||||
|
||||
public class ShowPreviewDialog
|
||||
extends SIPCommDialog
|
||||
implements ActionListener,
|
||||
ChatLinkClickedListener
|
||||
{
|
||||
/**
|
||||
* Serial version UID.
|
||||
*/
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* The <tt>Logger</tt> used by the <tt>ShowPreviewDialog</tt> class and
|
||||
* its instances for logging output.
|
||||
*/
|
||||
private static final Logger logger
|
||||
= Logger.getLogger(ShowPreviewDialog.class);
|
||||
|
||||
ConfigurationService cfg
|
||||
= GuiActivator.getConfigurationService();
|
||||
|
||||
/**
|
||||
* The Ok button.
|
||||
*/
|
||||
private final JButton okButton;
|
||||
|
||||
/**
|
||||
* The cancel button.
|
||||
*/
|
||||
private final JButton cancelButton;
|
||||
|
||||
/**
|
||||
* Checkbox that indicates whether or not to show this dialog next time.
|
||||
*/
|
||||
private final JCheckBox enableReplacementProposal;
|
||||
|
||||
/**
|
||||
* Checkbox that indicates whether or not to show previews automatically
|
||||
*/
|
||||
private final JCheckBox enableReplacement;
|
||||
|
||||
/**
|
||||
* The <tt>ChatConversationPanel</tt> that this dialog is associated with.
|
||||
*/
|
||||
private final ChatConversationPanel chatPanel;
|
||||
|
||||
/**
|
||||
* Mapping between messageID and the string representation of the chat
|
||||
* message.
|
||||
*/
|
||||
private Map<String, String> msgIDToChatString
|
||||
= new ConcurrentHashMap<String, String>();
|
||||
|
||||
/**
|
||||
* Mapping between the pair (messageID, link position) and the actual link
|
||||
* in the string representation of the chat message.
|
||||
*/
|
||||
private Map<String, String> msgIDandPositionToLink
|
||||
= new ConcurrentHashMap<String, String>();
|
||||
|
||||
/**
|
||||
* Mapping between link and replacement for this link that is acquired
|
||||
* from it's corresponding <tt>ReplacementService</tt>.
|
||||
*/
|
||||
private Map<String, String> linkToReplacement
|
||||
= new ConcurrentHashMap<String, String>();
|
||||
|
||||
/**
|
||||
* The id of the message that is currently associated with this dialog.
|
||||
*/
|
||||
private String currentMessageID = "";
|
||||
|
||||
/**
|
||||
* The position of the link in the current message.
|
||||
*/
|
||||
private String currentLinkPosition = "";
|
||||
|
||||
/**
|
||||
* Creates an instance of <tt>ShowPreviewDialog</tt>
|
||||
* @param chatPanel The <tt>ChatConversationPanel</tt> that is associated
|
||||
* with this dialog.
|
||||
*/
|
||||
ShowPreviewDialog(final ChatConversationPanel chatPanel)
|
||||
{
|
||||
this.chatPanel = chatPanel;
|
||||
|
||||
okButton = new JButton(
|
||||
GuiActivator.getResources().getI18NString("service.gui.OK"));
|
||||
cancelButton = new JButton(
|
||||
GuiActivator.getResources().getI18NString("service.gui.CANCEL"));
|
||||
|
||||
JPanel mainPanel = new TransparentPanel(new BorderLayout());
|
||||
this.getContentPane().add(mainPanel);
|
||||
|
||||
JTextPane descriptionMsg = new JTextPane();
|
||||
descriptionMsg.setEditable(false);
|
||||
descriptionMsg.setOpaque(false);
|
||||
descriptionMsg.setText(
|
||||
GuiActivator.getResources().getI18NString(
|
||||
"service.gui.SHOW_PREVIEW_WARNING_DESCRIPTION"));
|
||||
|
||||
enableReplacement
|
||||
= new JCheckBox(
|
||||
GuiActivator.getResources().getI18NString(
|
||||
"plugin.chatconfig.replacement.ENABLE_REPLACEMENT_STATUS"));
|
||||
enableReplacement.setOpaque(false);
|
||||
enableReplacement.setSelected(
|
||||
cfg.getBoolean(ReplacementProperty.REPLACEMENT_ENABLE, true));
|
||||
enableReplacementProposal
|
||||
= new JCheckBox(
|
||||
GuiActivator.getResources().getI18NString(
|
||||
"plugin.chatconfig.replacement.ENABLE_REPLACEMENT_PROPOSAL"));
|
||||
enableReplacementProposal.setOpaque(false);
|
||||
|
||||
JPanel checkBoxPanel = new TransparentPanel(new GridLayout(0, 1));
|
||||
checkBoxPanel.add(enableReplacement);
|
||||
checkBoxPanel.add(enableReplacementProposal);
|
||||
|
||||
JPanel buttonsPanel
|
||||
= new TransparentPanel(new FlowLayout(FlowLayout.CENTER));
|
||||
buttonsPanel.add(okButton);
|
||||
buttonsPanel.add(cancelButton);
|
||||
|
||||
JPanel panel = new TransparentPanel(new GridLayout(0, 1));
|
||||
panel.add(descriptionMsg);
|
||||
panel.add(checkBoxPanel);
|
||||
mainPanel.add(panel, BorderLayout.NORTH);
|
||||
mainPanel.add(buttonsPanel, BorderLayout.CENTER);
|
||||
|
||||
okButton.addActionListener(this);
|
||||
cancelButton.addActionListener(this);
|
||||
|
||||
this.setPreferredSize(new Dimension(350, 200));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent arg0)
|
||||
{
|
||||
if (arg0.getSource().equals(okButton))
|
||||
{
|
||||
cfg.setProperty(ReplacementProperty.REPLACEMENT_ENABLE,
|
||||
enableReplacement.isSelected());
|
||||
cfg.setProperty(ReplacementProperty.REPLACEMENT_PROPOSAL
|
||||
, enableReplacementProposal.isSelected());
|
||||
SwingWorker worker = new SwingWorker()
|
||||
{
|
||||
/**
|
||||
* Called on the event dispatching thread
|
||||
* (not on the worker thread) after the
|
||||
* <code>construct</code> method has returned.
|
||||
*/
|
||||
@Override
|
||||
public void finished()
|
||||
{
|
||||
String newChatString = (String)get();
|
||||
|
||||
if (newChatString != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
Element elem =
|
||||
chatPanel.document.getElement(currentMessageID);
|
||||
chatPanel.document.setOuterHTML(
|
||||
elem, newChatString);
|
||||
msgIDToChatString.put(
|
||||
currentMessageID, newChatString);
|
||||
}
|
||||
catch (BadLocationException ex)
|
||||
{
|
||||
logger.error("Could not replace chat message", ex);
|
||||
}
|
||||
catch (IOException ex)
|
||||
{
|
||||
logger.error("Could not replace chat message", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Object construct() throws Exception
|
||||
{
|
||||
String newChatString
|
||||
= msgIDToChatString.get(currentMessageID);
|
||||
try
|
||||
{
|
||||
String originalLink = msgIDandPositionToLink.get
|
||||
(currentMessageID + "#" + currentLinkPosition);
|
||||
String replacementLink
|
||||
= linkToReplacement.get(originalLink);
|
||||
String replacement;
|
||||
DirectImageReplacementService source
|
||||
= GuiActivator.getDirectImageReplacementSource();
|
||||
if (originalLink.equals(replacementLink) &&
|
||||
(!source.isDirectImage(originalLink) ||
|
||||
source.getImageSize(originalLink) == -1))
|
||||
{
|
||||
replacement = originalLink;
|
||||
}
|
||||
else
|
||||
{
|
||||
replacement =
|
||||
"<IMG HEIGHT=\"90\" WIDTH=\"120\" SRC=\""
|
||||
+ replacementLink + "\" BORDER=\"0\" ALT=\""
|
||||
+ originalLink + "\"></IMG>";
|
||||
}
|
||||
|
||||
String old = originalLink + "</A> <A href=\"jitsi://"
|
||||
+ ShowPreviewDialog.this.getClass().getName()
|
||||
+ "/SHOWPREVIEW?" + currentMessageID + "#"
|
||||
+ currentLinkPosition + "\">"
|
||||
+ GuiActivator.getResources().
|
||||
getI18NString("service.gui.SHOW_PREVIEW");
|
||||
|
||||
newChatString = newChatString.replace(old, replacement);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.error("Could not replace chat message", ex);
|
||||
}
|
||||
return newChatString;
|
||||
}
|
||||
};
|
||||
worker.start();
|
||||
this.setVisible(false);
|
||||
}
|
||||
else if (arg0.getSource().equals(cancelButton))
|
||||
{
|
||||
this.setVisible(false);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void chatLinkClicked(URI url)
|
||||
{
|
||||
String action = url.getPath();
|
||||
if (action.equals("/SHOWPREVIEW"))
|
||||
{
|
||||
enableReplacement.setSelected(
|
||||
cfg.getBoolean(ReplacementProperty.REPLACEMENT_ENABLE, true));
|
||||
enableReplacementProposal.setSelected(
|
||||
cfg.getBoolean(ReplacementProperty.REPLACEMENT_PROPOSAL, true));
|
||||
|
||||
currentMessageID = url.getQuery();
|
||||
currentLinkPosition = url.getFragment();
|
||||
|
||||
this.setVisible(true);
|
||||
this.setLocationRelativeTo(chatPanel);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns mapping between messageID and the string representation of
|
||||
* the chat message.
|
||||
* @return mapping between messageID and chat string.
|
||||
*/
|
||||
Map<String, String> getMsgIDToChatString()
|
||||
{
|
||||
return msgIDToChatString;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns mapping between the pair (messageID, link position) and the
|
||||
* actual link in the string representation of the chat message.
|
||||
* @return mapping between (messageID, linkPosition) and link.
|
||||
*/
|
||||
Map<String, String> getMsgIDandPositionToLink()
|
||||
{
|
||||
return msgIDandPositionToLink;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns mapping between link and replacement for this link that was
|
||||
* acquired from it's corresponding <tt>ReplacementService</tt>.
|
||||
* @return mapping between link and it's corresponding replacement.
|
||||
*/
|
||||
Map<String, String> getLinkToReplacement()
|
||||
{
|
||||
return linkToReplacement;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license.
|
||||
* See terms of license at gnu.org.
|
||||
*/
|
||||
package net.java.sip.communicator.service.replacement.directimage;
|
||||
|
||||
import net.java.sip.communicator.service.replacement.*;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author Marin Dzhigarov
|
||||
*
|
||||
*/
|
||||
public interface DirectImageReplacementService
|
||||
extends ReplacementService
|
||||
{
|
||||
/**
|
||||
* Returns the size of the image in bytes.
|
||||
* @param sourceString the image link.
|
||||
* @return the file size in bytes of the image link provided; -1 if the size
|
||||
* isn't available or exceeds the max allowed image size.
|
||||
*/
|
||||
public long getImageSize(String sourceString);
|
||||
|
||||
/**
|
||||
* Checks if the resource pointed by sourceString is an image.
|
||||
* @param sourceString the image link.
|
||||
* @return true if the content type of the resource
|
||||
* pointed by sourceString is an image.
|
||||
*/
|
||||
public boolean isDirectImage(String sourceString);
|
||||
}
|
||||
@ -0,0 +1,247 @@
|
||||
/*
|
||||
* Jitsi, the OpenSource Java VoIP and Instant Messaging client.
|
||||
*
|
||||
* Distributable under LGPL license. See terms of license at gnu.org.
|
||||
*/
|
||||
package net.java.sip.communicator.util;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.*;
|
||||
|
||||
/**
|
||||
* Utility class that allows to check the size of ftp file.
|
||||
*
|
||||
* @author Hristo Terezov
|
||||
*/
|
||||
public class FTPUtils
|
||||
{
|
||||
/**
|
||||
* The connection
|
||||
* to the FTP server.
|
||||
*/
|
||||
private Socket socket = null;
|
||||
|
||||
/**
|
||||
* The reader from the connection.
|
||||
*/
|
||||
private BufferedReader reader = null;
|
||||
|
||||
/**
|
||||
* The writer which is used to send commands to the server.
|
||||
*/
|
||||
private BufferedWriter writer = null;
|
||||
|
||||
/**
|
||||
* Default port constant. It is used when the port is not available in URL.
|
||||
*/
|
||||
private final int DEFAULT_PORT = 21;
|
||||
|
||||
/**
|
||||
* Constant for the invalid file size.
|
||||
*/
|
||||
private final int INVALID_FILE_SIZE = -1;
|
||||
|
||||
/**
|
||||
* The user name for the FTP connection.
|
||||
*/
|
||||
private String user = null;
|
||||
|
||||
/**
|
||||
* The password for the FTP connection.
|
||||
*/
|
||||
private String pass = null;
|
||||
|
||||
/**
|
||||
* The path to the file.
|
||||
*/
|
||||
private String path = null;
|
||||
|
||||
/**
|
||||
* The host name of the FTP server.
|
||||
*/
|
||||
private String host = null;
|
||||
|
||||
/**
|
||||
* The port for the FTP connection.
|
||||
*/
|
||||
private int port = DEFAULT_PORT;
|
||||
|
||||
/**
|
||||
* Parses the URL, connects to the FTP server and then executes the login.
|
||||
*
|
||||
* @param urlString the URL of the file.
|
||||
* @throws Exception if something with parsing the URL or connection or
|
||||
* login fails.
|
||||
*/
|
||||
public FTPUtils(String urlString) throws Exception
|
||||
{
|
||||
parseUrl(urlString);
|
||||
socket = new Socket( host, port);
|
||||
reader = new BufferedReader(
|
||||
new InputStreamReader(socket.getInputStream()));
|
||||
writer = new BufferedWriter(
|
||||
new OutputStreamWriter(socket.getOutputStream()));
|
||||
checkConnectionGreetings();
|
||||
login();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the connection greetings messages from the FTP server
|
||||
* checks the response code.
|
||||
*
|
||||
* @throws Exception if the response code is not for success.
|
||||
*/
|
||||
private void checkConnectionGreetings() throws Exception
|
||||
{
|
||||
String code = getResponseCode();
|
||||
if(!code.equals("220"))
|
||||
{
|
||||
throw new Exception("Connection Error.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the response messages from the FTP server and
|
||||
* returns the response code.
|
||||
*
|
||||
* @return the response code.
|
||||
* @throws Exception if <tt>readLine</tt> fails.
|
||||
*/
|
||||
private String getResponseCode() throws Exception
|
||||
{
|
||||
String line;
|
||||
while((line = readLine()).charAt(3) != ' ');
|
||||
|
||||
return line.substring(0, 3);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes the login sequence of FTP commands based on RFC 959.
|
||||
*
|
||||
* @throws Exception if the login fails.
|
||||
*/
|
||||
private void login() throws Exception
|
||||
{
|
||||
sendLine("USER " + user);
|
||||
String code = getResponseCode();
|
||||
if(code.equals("331") || code.equals("332"))
|
||||
{
|
||||
sendLine("PASS " + pass);
|
||||
code = getResponseCode();
|
||||
if(!code.equals("230"))
|
||||
{
|
||||
throw new Exception("Login error.");
|
||||
}
|
||||
}
|
||||
else if(!code.equals("230"))
|
||||
{
|
||||
throw new Exception("Login error.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends FTP command for the size of the file and reads and parses
|
||||
* the response from the the FTP server.
|
||||
*
|
||||
* @return the size of the file in bytes.
|
||||
* @throws Exception if <tt>readLine</tt> fails.
|
||||
*/
|
||||
public long getSize() throws Exception
|
||||
{
|
||||
sendLine("SIZE " + path);
|
||||
|
||||
String line = readLine();
|
||||
if(!line.startsWith("213 "))
|
||||
{
|
||||
throw new Exception("Size Error.");
|
||||
}
|
||||
|
||||
String fileSizeStr = line.substring(4);
|
||||
long fileSize = INVALID_FILE_SIZE;
|
||||
|
||||
try
|
||||
{
|
||||
fileSize = Long.parseLong(fileSizeStr);
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
return INVALID_FILE_SIZE;
|
||||
}
|
||||
|
||||
return fileSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses the URL to host, port, user, password and path to the file parts.
|
||||
*
|
||||
* @param urlString the URL of the file.
|
||||
* @throws Exception if the parsing of the URL fails.
|
||||
*/
|
||||
private void parseUrl(String urlString) throws Exception
|
||||
{
|
||||
URL url = new URL(urlString);
|
||||
|
||||
host = url.getHost();
|
||||
port = url.getPort();
|
||||
if (port == -1)
|
||||
{
|
||||
port = DEFAULT_PORT;
|
||||
}
|
||||
|
||||
String tmpUserInfo = url.getUserInfo();
|
||||
if(tmpUserInfo != null)
|
||||
{
|
||||
int separatorIdx = tmpUserInfo.lastIndexOf(':');
|
||||
if (separatorIdx != -1)
|
||||
{
|
||||
pass = tmpUserInfo.substring(separatorIdx+1);
|
||||
user = tmpUserInfo.substring(0, separatorIdx);
|
||||
}
|
||||
}
|
||||
|
||||
if(user == null)
|
||||
{
|
||||
user ="anonymus";
|
||||
}
|
||||
|
||||
if(pass == null)
|
||||
{
|
||||
pass ="anonymus";
|
||||
}
|
||||
|
||||
path = url.getPath();
|
||||
if(path == "")
|
||||
{
|
||||
throw new Exception("Not available path.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnects from the FTP server.
|
||||
*/
|
||||
public void disconnect() throws IOException {
|
||||
sendLine("QUIT");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a raw command to the FTP server.
|
||||
*
|
||||
* @param line the message that will be send to the FTP server.
|
||||
* @throws IOException if sending fails.
|
||||
*/
|
||||
private void sendLine(String line) throws IOException {
|
||||
writer.write(line + "\r\n");
|
||||
writer.flush();
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads a line from the response of the FTP server.
|
||||
*
|
||||
* @return line from the response of the FTP server.
|
||||
* @throws IOException if reading fails.
|
||||
*/
|
||||
private String readLine() throws IOException {
|
||||
String line = reader.readLine();
|
||||
return line;
|
||||
}
|
||||
}
|
||||
Loading…
Reference in new issue