|
|
|
@@ -17,9 +17,11 @@
|
|
|
|
|
*/
|
|
|
|
|
package com.silverwrist.venice.core.impl;
|
|
|
|
|
|
|
|
|
|
import java.io.*;
|
|
|
|
|
import java.sql.*;
|
|
|
|
|
import java.util.*;
|
|
|
|
|
import org.apache.log4j.*;
|
|
|
|
|
import com.silverwrist.util.StringUtil;
|
|
|
|
|
import com.silverwrist.venice.db.*;
|
|
|
|
|
import com.silverwrist.venice.security.AuditRecord;
|
|
|
|
|
import com.silverwrist.venice.core.*;
|
|
|
|
@@ -33,6 +35,8 @@ class TopicMessageUserContextImpl implements TopicMessageContext
|
|
|
|
|
|
|
|
|
|
private static Category logger = Category.getInstance(TopicMessageUserContextImpl.class.getName());
|
|
|
|
|
|
|
|
|
|
private static final int MAX_ATTACH = 1048576; // TODO: should be a configurable parameter
|
|
|
|
|
|
|
|
|
|
/*--------------------------------------------------------------------------------
|
|
|
|
|
* Attributes
|
|
|
|
|
*--------------------------------------------------------------------------------
|
|
|
|
@@ -329,6 +333,113 @@ class TopicMessageUserContextImpl implements TopicMessageContext
|
|
|
|
|
|
|
|
|
|
} // end hasAttachment
|
|
|
|
|
|
|
|
|
|
public String getAttachmentType()
|
|
|
|
|
{
|
|
|
|
|
return mimetype;
|
|
|
|
|
|
|
|
|
|
} // end getAttachmentType
|
|
|
|
|
|
|
|
|
|
public String getAttachmentFilename()
|
|
|
|
|
{
|
|
|
|
|
return ((mimetype!=null) ? filename : null);
|
|
|
|
|
|
|
|
|
|
} // end getAttachmentFilename
|
|
|
|
|
|
|
|
|
|
public int getAttachmentLength()
|
|
|
|
|
{
|
|
|
|
|
return ((mimetype!=null) ? datalen : 0);
|
|
|
|
|
|
|
|
|
|
} // end getAttachmentLength
|
|
|
|
|
|
|
|
|
|
public InputStream getAttachmentData() throws AccessError, DataException
|
|
|
|
|
{
|
|
|
|
|
if (nuked || (scribble_date!=null))
|
|
|
|
|
{ // this would be an exercise in futility!
|
|
|
|
|
logger.error("cannot attach to a nuked or scribbled message");
|
|
|
|
|
throw new AccessError("You cannot attach data to a message that no longer exists.");
|
|
|
|
|
|
|
|
|
|
} // end if
|
|
|
|
|
|
|
|
|
|
Connection conn = null;
|
|
|
|
|
InputStream rc = null;
|
|
|
|
|
try
|
|
|
|
|
{ // open up a database connection
|
|
|
|
|
conn = datapool.getConnection();
|
|
|
|
|
|
|
|
|
|
// make sure we have current data
|
|
|
|
|
refresh(conn);
|
|
|
|
|
if (nuked || (scribble_date!=null))
|
|
|
|
|
{ // this would be an exercise in futility!
|
|
|
|
|
logger.error("cannot attach to a nuked or scribbled message");
|
|
|
|
|
throw new AccessError("You cannot attach data to a message that no longer exists.");
|
|
|
|
|
|
|
|
|
|
} // end if
|
|
|
|
|
|
|
|
|
|
if (mimetype==null)
|
|
|
|
|
{ // there is no attachment data!
|
|
|
|
|
logger.error("no attachment data to get");
|
|
|
|
|
throw new AccessError("There is no attachment data for this message.");
|
|
|
|
|
|
|
|
|
|
} // end if
|
|
|
|
|
|
|
|
|
|
// Create the statement and the SQL we need to retrieve the attachment.
|
|
|
|
|
Statement stmt = conn.createStatement();
|
|
|
|
|
StringBuffer sql = new StringBuffer("SELECT data FROM postattach WHERE postid = ");
|
|
|
|
|
sql.append(postid).append(';');
|
|
|
|
|
|
|
|
|
|
// Execute the query!
|
|
|
|
|
ResultSet rs = stmt.executeQuery(sql.toString());
|
|
|
|
|
if (!(rs.next()))
|
|
|
|
|
{ // there is no attachment data!
|
|
|
|
|
logger.error("no attachment data to get");
|
|
|
|
|
throw new AccessError("There is no attachment data for this message.");
|
|
|
|
|
|
|
|
|
|
} // end if
|
|
|
|
|
|
|
|
|
|
// Since the InputStream we get from JDBC will probably go away when the connection is dropped, we
|
|
|
|
|
// need to make a temporary copy of it, to a ByteArrayOutputStream. (Attachments can only be
|
|
|
|
|
// 1 Mb in size, so this shouldn't be a big problem.)
|
|
|
|
|
InputStream sqldata = rs.getBinaryStream(1);
|
|
|
|
|
ByteArrayOutputStream copy = new ByteArrayOutputStream(datalen);
|
|
|
|
|
byte[] buffer = new byte[4096];
|
|
|
|
|
int rd = sqldata.read(buffer);
|
|
|
|
|
while (rd>=0)
|
|
|
|
|
{ // write, then read again
|
|
|
|
|
if (rd>0)
|
|
|
|
|
copy.write(buffer,0,rd);
|
|
|
|
|
rd = sqldata.read(buffer);
|
|
|
|
|
|
|
|
|
|
} // end while
|
|
|
|
|
|
|
|
|
|
// Close both our streams, making sure we create the stream we need for the return value.
|
|
|
|
|
sqldata.close();
|
|
|
|
|
rc = new ByteArrayInputStream(copy.toByteArray());
|
|
|
|
|
copy.close();
|
|
|
|
|
|
|
|
|
|
} // end try
|
|
|
|
|
catch (SQLException e)
|
|
|
|
|
{ // turn this into a DataException
|
|
|
|
|
logger.error("DB error retrieving attachment: " + e.getMessage(),e);
|
|
|
|
|
throw new DataException("unable to retrieve attachment data: " + e.getMessage(),e);
|
|
|
|
|
|
|
|
|
|
} // end catch
|
|
|
|
|
catch (IOException e)
|
|
|
|
|
{ // turn this into a DataException too
|
|
|
|
|
logger.error("I/O error copying attachment data: " + e.getMessage(),e);
|
|
|
|
|
throw new DataException("unable to retrieve attachment data: " + e.getMessage(),e);
|
|
|
|
|
|
|
|
|
|
} // end catch
|
|
|
|
|
finally
|
|
|
|
|
{ // make sure we release the connection before we go
|
|
|
|
|
if (conn!=null)
|
|
|
|
|
datapool.releaseConnection(conn);
|
|
|
|
|
|
|
|
|
|
} // end finally
|
|
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
|
|
} // end getAttachmentData
|
|
|
|
|
|
|
|
|
|
public boolean canHide()
|
|
|
|
|
{
|
|
|
|
|
return ((creator_uid==conf.realUID()) || conf.userCanHide());
|
|
|
|
@@ -641,6 +752,125 @@ class TopicMessageUserContextImpl implements TopicMessageContext
|
|
|
|
|
|
|
|
|
|
} // end nuke
|
|
|
|
|
|
|
|
|
|
public void attachData(String m_type, String file, int length, InputStream data)
|
|
|
|
|
throws AccessError, DataException
|
|
|
|
|
{
|
|
|
|
|
if (mimetype!=null)
|
|
|
|
|
{ // the message already has an attachment
|
|
|
|
|
logger.error("tried to attach data to a message that already has it!");
|
|
|
|
|
throw new AccessError("This message already has an attachment.");
|
|
|
|
|
|
|
|
|
|
} // end if
|
|
|
|
|
|
|
|
|
|
if (creator_uid!=conf.realUID())
|
|
|
|
|
{ // you can't attach to this message!
|
|
|
|
|
logger.error("tried to attach data to a message that's not yours!");
|
|
|
|
|
throw new AccessError("You are not permitted to add an attachment to this message.");
|
|
|
|
|
|
|
|
|
|
} // end if
|
|
|
|
|
|
|
|
|
|
if (nuked || (scribble_date!=null))
|
|
|
|
|
{ // this would be an exercise in futility!
|
|
|
|
|
logger.error("cannot attach to a nuked or scribbled message");
|
|
|
|
|
throw new AccessError("You cannot attach data to a message that no longer exists.");
|
|
|
|
|
|
|
|
|
|
} // end if
|
|
|
|
|
|
|
|
|
|
if (StringUtil.isStringEmpty(m_type))
|
|
|
|
|
{ // no MIME type specified
|
|
|
|
|
logger.error("no MIME type specified for attachment");
|
|
|
|
|
throw new AccessError("MIME type of attachment data not specified.");
|
|
|
|
|
|
|
|
|
|
} // end if
|
|
|
|
|
|
|
|
|
|
if (StringUtil.isStringEmpty(file))
|
|
|
|
|
{ // no MIME type specified
|
|
|
|
|
logger.error("no filename specified for attachment");
|
|
|
|
|
throw new AccessError("Filename of attachment data not specified.");
|
|
|
|
|
|
|
|
|
|
} // end if
|
|
|
|
|
|
|
|
|
|
if (length<=0)
|
|
|
|
|
{ // a length of 0 or less is just WRONG
|
|
|
|
|
logger.error("non-positive length specified for attachment");
|
|
|
|
|
throw new AccessError("Invalid attachment length.");
|
|
|
|
|
|
|
|
|
|
} // end if
|
|
|
|
|
else if (length>MAX_ATTACH)
|
|
|
|
|
{ // the attachment is too damn long!
|
|
|
|
|
logger.error("attachment is too long (" + String.valueOf(length) + " bytes)");
|
|
|
|
|
throw new AccessError("The attachment is too long to store. Maximum available length is "
|
|
|
|
|
+ String.valueOf(MAX_ATTACH) + " bytes.");
|
|
|
|
|
|
|
|
|
|
} // end else if
|
|
|
|
|
|
|
|
|
|
Connection conn = null;
|
|
|
|
|
AuditRecord ar = null;
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{ // open up a database connection
|
|
|
|
|
conn = datapool.getConnection();
|
|
|
|
|
|
|
|
|
|
// make sure we have the right status to upload
|
|
|
|
|
refresh(conn);
|
|
|
|
|
if (nuked || (scribble_date!=null))
|
|
|
|
|
{ // this would be an exercise in futility!
|
|
|
|
|
logger.error("cannot attach to a nuked or scribbled message");
|
|
|
|
|
throw new AccessError("You cannot attach data to a message that no longer exists.");
|
|
|
|
|
|
|
|
|
|
} // end if
|
|
|
|
|
|
|
|
|
|
// Build the SQL statement that inserts the attachment. Note the use of the "?" to specify the
|
|
|
|
|
// BLOB parameter (the attachment data itself); this comes later.
|
|
|
|
|
StringBuffer sql =
|
|
|
|
|
new StringBuffer("INSERT INTO postattach (postid, datalen, filename, mimetype, data) VALUES (");
|
|
|
|
|
sql.append(postid).append(", ").append(length).append(", '").append(SQLUtil.encodeString(file));
|
|
|
|
|
sql.append("', '").append(SQLUtil.encodeString(m_type)).append("', ?);");
|
|
|
|
|
|
|
|
|
|
// Prepare the statement, set the BLOB parameter, and execute it.
|
|
|
|
|
PreparedStatement stmt = conn.prepareStatement(sql.toString());
|
|
|
|
|
stmt.setBinaryStream(1,data,length);
|
|
|
|
|
stmt.executeUpdate();
|
|
|
|
|
|
|
|
|
|
// Save off the local attachment values.
|
|
|
|
|
datalen = length;
|
|
|
|
|
filename = file;
|
|
|
|
|
mimetype = m_type;
|
|
|
|
|
|
|
|
|
|
// Generate an audit record indicating what we did.
|
|
|
|
|
ar = new AuditRecord(AuditRecord.UPLOAD_ATTACHMENT,conf.realUID(),conf.userRemoteAddress(),
|
|
|
|
|
conf.realSIGID(),"conf=" + String.valueOf(conf.realConfID()) + ",post="
|
|
|
|
|
+ String.valueOf(postid),"len=" + String.valueOf(length) + ",type=" + m_type
|
|
|
|
|
+ ",name=" + file);
|
|
|
|
|
|
|
|
|
|
} // end try
|
|
|
|
|
catch (SQLException e)
|
|
|
|
|
{ // turn this into a DataException
|
|
|
|
|
logger.error("DB error saving attachment: " + e.getMessage(),e);
|
|
|
|
|
throw new DataException("unable to save attachment data: " + e.getMessage(),e);
|
|
|
|
|
|
|
|
|
|
} // end catch
|
|
|
|
|
finally
|
|
|
|
|
{ // make sure we release the connection before we go
|
|
|
|
|
try
|
|
|
|
|
{ // save off the audit record before we go, though
|
|
|
|
|
if ((ar!=null) && (conn!=null))
|
|
|
|
|
ar.store(conn);
|
|
|
|
|
|
|
|
|
|
} // end try
|
|
|
|
|
catch (SQLException e)
|
|
|
|
|
{ // we couldn't store the audit record!
|
|
|
|
|
logger.error("DB error saving audit record: " + e.getMessage(),e);
|
|
|
|
|
|
|
|
|
|
} // end catch
|
|
|
|
|
|
|
|
|
|
if (conn!=null)
|
|
|
|
|
datapool.releaseConnection(conn);
|
|
|
|
|
|
|
|
|
|
} // end finally
|
|
|
|
|
|
|
|
|
|
} // end attachData
|
|
|
|
|
|
|
|
|
|
/*--------------------------------------------------------------------------------
|
|
|
|
|
* External static operations
|
|
|
|
|
*--------------------------------------------------------------------------------
|
|
|
|
@@ -703,4 +933,105 @@ class TopicMessageUserContextImpl implements TopicMessageContext
|
|
|
|
|
|
|
|
|
|
} // end loadMessageRange
|
|
|
|
|
|
|
|
|
|
static TopicMessageContext loadMessage(EngineBackend engine, ConferenceBackend conf, DataPool datapool,
|
|
|
|
|
int topicid, int message_num) throws DataException
|
|
|
|
|
{
|
|
|
|
|
if (logger.isDebugEnabled())
|
|
|
|
|
logger.debug("loadMessage for conf # " + String.valueOf(conf.realConfID()) + ", topic #"
|
|
|
|
|
+ String.valueOf(topicid) + ", message " + String.valueOf(message_num));
|
|
|
|
|
|
|
|
|
|
Connection conn = null; // pooled database connection
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{ // get a database connection
|
|
|
|
|
conn = datapool.getConnection();
|
|
|
|
|
Statement stmt = conn.createStatement();
|
|
|
|
|
|
|
|
|
|
// run a query to get all the posts in a particular topic
|
|
|
|
|
StringBuffer sql =
|
|
|
|
|
new StringBuffer("SELECT p.postid, p.parent, p.num, p.linecount, p.creator_uid, p.posted, "
|
|
|
|
|
+ "p.hidden, p.scribble_uid, p.scribble_date, p.pseud, a.datalen, a.filename, "
|
|
|
|
|
+ "a.mimetype FROM posts p LEFT JOIN postattach a ON p.postid = a.postid "
|
|
|
|
|
+ "WHERE p.topicid = ");
|
|
|
|
|
sql.append(topicid).append(" AND p.num = ").append(message_num).append(';');
|
|
|
|
|
if (logger.isDebugEnabled())
|
|
|
|
|
logger.debug("SQL: " + sql.toString());
|
|
|
|
|
ResultSet rs = stmt.executeQuery(sql.toString());
|
|
|
|
|
|
|
|
|
|
if (rs.next()) // create an object reference and return it
|
|
|
|
|
return new TopicMessageUserContextImpl(engine,conf,datapool,rs.getLong(1),rs.getLong(2),rs.getInt(3),
|
|
|
|
|
rs.getInt(4),rs.getInt(5),SQLUtil.getFullDateTime(rs,6),
|
|
|
|
|
rs.getBoolean(7),rs.getInt(8),SQLUtil.getFullDateTime(rs,9),
|
|
|
|
|
rs.getString(10),rs.getInt(11),rs.getString(12),
|
|
|
|
|
rs.getString(13));
|
|
|
|
|
|
|
|
|
|
// indicates an error...
|
|
|
|
|
throw new DataException("Message not found.");
|
|
|
|
|
|
|
|
|
|
} // end try
|
|
|
|
|
catch (SQLException e)
|
|
|
|
|
{ // turn SQLException into data exception
|
|
|
|
|
logger.error("DB error reading message entry: " + e.getMessage(),e);
|
|
|
|
|
throw new DataException("unable to retrieve message: " + e.getMessage(),e);
|
|
|
|
|
|
|
|
|
|
} // end catch
|
|
|
|
|
finally
|
|
|
|
|
{ // make sure we release the connection before we go
|
|
|
|
|
if (conn!=null)
|
|
|
|
|
datapool.releaseConnection(conn);
|
|
|
|
|
|
|
|
|
|
} // end finally
|
|
|
|
|
|
|
|
|
|
} // end loadMessage
|
|
|
|
|
|
|
|
|
|
static TopicMessageContext getMessage(EngineBackend engine, ConferenceBackend conf, DataPool datapool,
|
|
|
|
|
long postid) throws DataException
|
|
|
|
|
{
|
|
|
|
|
if (logger.isDebugEnabled())
|
|
|
|
|
logger.debug("getMessage for conf # " + String.valueOf(conf.realConfID()) + ", post #"
|
|
|
|
|
+ String.valueOf(postid));
|
|
|
|
|
|
|
|
|
|
Connection conn = null; // pooled database connection
|
|
|
|
|
|
|
|
|
|
try
|
|
|
|
|
{ // get a database connection
|
|
|
|
|
conn = datapool.getConnection();
|
|
|
|
|
Statement stmt = conn.createStatement();
|
|
|
|
|
|
|
|
|
|
StringBuffer sql =
|
|
|
|
|
new StringBuffer("SELECT p.postid, p.parent, p.num, p.linecount, p.creator_uid, p.posted, "
|
|
|
|
|
+ "p.hidden, p.scribble_uid, p.scribble_date, p.pseud, a.datalen, a.filename, "
|
|
|
|
|
+ "a.mimetype FROM topics t, posts p LEFT JOIN postattach a ON p.postid = a.postid "
|
|
|
|
|
+ "WHERE t.topicid = p.topicid AND t.confid = ");
|
|
|
|
|
sql.append(conf.realConfID()).append(" AND p.postid = ").append(postid).append(';');
|
|
|
|
|
if (logger.isDebugEnabled())
|
|
|
|
|
logger.debug("SQL: " + sql.toString());
|
|
|
|
|
ResultSet rs = stmt.executeQuery(sql.toString());
|
|
|
|
|
|
|
|
|
|
if (rs.next()) // create an object reference and return it
|
|
|
|
|
return new TopicMessageUserContextImpl(engine,conf,datapool,rs.getLong(1),rs.getLong(2),rs.getInt(3),
|
|
|
|
|
rs.getInt(4),rs.getInt(5),SQLUtil.getFullDateTime(rs,6),
|
|
|
|
|
rs.getBoolean(7),rs.getInt(8),SQLUtil.getFullDateTime(rs,9),
|
|
|
|
|
rs.getString(10),rs.getInt(11),rs.getString(12),
|
|
|
|
|
rs.getString(13));
|
|
|
|
|
|
|
|
|
|
// indicates an error...
|
|
|
|
|
throw new DataException("Message not found.");
|
|
|
|
|
|
|
|
|
|
} // end try
|
|
|
|
|
catch (SQLException e)
|
|
|
|
|
{ // turn SQLException into data exception
|
|
|
|
|
logger.error("DB error reading message entries: " + e.getMessage(),e);
|
|
|
|
|
throw new DataException("unable to retrieve messages: " + e.getMessage(),e);
|
|
|
|
|
|
|
|
|
|
} // end catch
|
|
|
|
|
finally
|
|
|
|
|
{ // make sure we release the connection before we go
|
|
|
|
|
if (conn!=null)
|
|
|
|
|
datapool.releaseConnection(conn);
|
|
|
|
|
|
|
|
|
|
} // end finally
|
|
|
|
|
|
|
|
|
|
} // end getMessage
|
|
|
|
|
|
|
|
|
|
} // end class TopicMessageUserContextImpl
|
|
|
|
|