landed the code for doing post attachments (the infamous paperclip)
This commit is contained in:
parent
66b7fea53b
commit
70774ead7d
26
TODO
26
TODO
|
@ -25,17 +25,27 @@ Lots!
|
||||||
statements in the case of joined queries (no need to SELECT table.column
|
statements in the case of joined queries (no need to SELECT table.column
|
||||||
AS name).
|
AS name).
|
||||||
|
|
||||||
- Getting conferencing in there - but still not there yet. We need topic and
|
- Functions still to do on conferencing "posts" page:
|
||||||
post implementations, and UI.
|
Hide/Show Topic
|
||||||
|
Next & Keep New (make it actually Keep New)
|
||||||
|
Freeze/Unfreeze Topic
|
||||||
|
Archive/Unarchive Topic
|
||||||
|
Delete Topic
|
||||||
|
Make number of "viewable" posts per page a config option
|
||||||
|
Display the message locator (i.e. <Playground.56.123>) above each message
|
||||||
|
Hide/Show Post
|
||||||
|
Scribble Post
|
||||||
|
Nuke Post
|
||||||
|
Put the HTML Guide in (for all pages w/post boxes)
|
||||||
|
|
||||||
|
- Slippage during posting is still untested.
|
||||||
|
|
||||||
|
- Functions still to do on conferencing "topics" page:
|
||||||
|
Manage Conference
|
||||||
|
Add Conference To Hotlist
|
||||||
|
|
||||||
- Implement conference hotlist for users.
|
- Implement conference hotlist for users.
|
||||||
|
|
||||||
- The HTML checker is back together and almost all integrated into the
|
|
||||||
Venice engine, but I still need to initialize the dictionary. It's going
|
|
||||||
to require configuration entries in the Venice XML config file, and the
|
|
||||||
use of LazyLexicon (to load the dictionary in the background while people
|
|
||||||
log in).
|
|
||||||
|
|
||||||
- Not everybody likes purple. Provide a way to change the default colors.
|
- Not everybody likes purple. Provide a way to change the default colors.
|
||||||
Probably via entries in render-config.xml. Of course, if we go to a
|
Probably via entries in render-config.xml. Of course, if we go to a
|
||||||
different rendering system eventually, we won't need this.
|
different rendering system eventually, we won't need this.
|
||||||
|
|
13
etc/web.xml
13
etc/web.xml
|
@ -150,6 +150,14 @@
|
||||||
<servlet-class>com.silverwrist.venice.servlets.PostMessage</servlet-class>
|
<servlet-class>com.silverwrist.venice.servlets.PostMessage</servlet-class>
|
||||||
</servlet>
|
</servlet>
|
||||||
|
|
||||||
|
<servlet>
|
||||||
|
<servlet-name>attachment</servlet-name>
|
||||||
|
<description>
|
||||||
|
Andles downloading and uploading attachments.
|
||||||
|
</description>
|
||||||
|
<servlet-class>com.silverwrist.venice.servlets.Attachment</servlet-class>
|
||||||
|
</servlet>
|
||||||
|
|
||||||
<!-- the following are test servlets, they should go away -->
|
<!-- the following are test servlets, they should go away -->
|
||||||
|
|
||||||
<servlet>
|
<servlet>
|
||||||
|
@ -213,6 +221,11 @@
|
||||||
<url-pattern>/post</url-pattern>
|
<url-pattern>/post</url-pattern>
|
||||||
</servlet-mapping>
|
</servlet-mapping>
|
||||||
|
|
||||||
|
<servlet-mapping>
|
||||||
|
<servlet-name>attachment</servlet-name>
|
||||||
|
<url-pattern>/attachment</url-pattern>
|
||||||
|
</servlet-mapping>
|
||||||
|
|
||||||
<!-- the following are test servlets, they should go away -->
|
<!-- the following are test servlets, they should go away -->
|
||||||
<servlet-mapping>
|
<servlet-mapping>
|
||||||
<servlet-name>testformdata</servlet-name>
|
<servlet-name>testformdata</servlet-name>
|
||||||
|
|
|
@ -420,6 +420,7 @@ INSERT INTO refaudit (type, descr) VALUES
|
||||||
(311, 'Hide Message'),
|
(311, 'Hide Message'),
|
||||||
(312, 'Scribble Message'),
|
(312, 'Scribble Message'),
|
||||||
(313, 'Nuke Message'),
|
(313, 'Nuke Message'),
|
||||||
|
(314, 'Upload Message Attachment'),
|
||||||
(9999999, 'DUMMY');
|
(9999999, 'DUMMY');
|
||||||
|
|
||||||
# The ISO 3166 two-letter country codes. Source is
|
# The ISO 3166 two-letter country codes. Source is
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||||
* language governing rights and limitations under the License.
|
* language governing rights and limitations under the License.
|
||||||
*
|
*
|
||||||
* The Original Code is the Venice Web Community System.
|
* The Original Code is the Venice Web Communities System.
|
||||||
*
|
*
|
||||||
* The Initial Developer of the Original Code is Eric J. Bowersox <erbo@silcom.com>,
|
* The Initial Developer of the Original Code is Eric J. Bowersox <erbo@silcom.com>,
|
||||||
* for Silverwrist Design Studios. Portions created by Eric J. Bowersox are
|
* for Silverwrist Design Studios. Portions created by Eric J. Bowersox are
|
||||||
|
@ -32,9 +32,10 @@ import javax.servlet.*;
|
||||||
|
|
||||||
public class ServletMultipartHandler
|
public class ServletMultipartHandler
|
||||||
{
|
{
|
||||||
private MimeMultipart multipart; // holds all the multipart data
|
/*--------------------------------------------------------------------------------
|
||||||
private Hashtable param_byname; // parameters by name
|
* Internal wrapper around the ServletRequest that implements DataSource
|
||||||
private Vector param_order; // parameters in order
|
*--------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
class ServletDataSource implements DataSource
|
class ServletDataSource implements DataSource
|
||||||
{
|
{
|
||||||
|
@ -75,6 +76,11 @@ public class ServletMultipartHandler
|
||||||
|
|
||||||
} // end class ServletDataSource
|
} // end class ServletDataSource
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------------
|
||||||
|
* Internal class representing a data value
|
||||||
|
*--------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
static class MultipartDataValue implements Blob
|
static class MultipartDataValue implements Blob
|
||||||
{
|
{
|
||||||
private byte[] actual_data; // the actual data we contain
|
private byte[] actual_data; // the actual data we contain
|
||||||
|
@ -83,7 +89,7 @@ public class ServletMultipartHandler
|
||||||
{
|
{
|
||||||
InputStream in = part.getInputStream();
|
InputStream in = part.getInputStream();
|
||||||
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
||||||
byte[] copybuf = new byte[1024];
|
byte[] copybuf = new byte[4096];
|
||||||
int ct = in.read(copybuf);
|
int ct = in.read(copybuf);
|
||||||
while (ct>=0)
|
while (ct>=0)
|
||||||
{ // do a simple read and write
|
{ // do a simple read and write
|
||||||
|
@ -133,6 +139,11 @@ public class ServletMultipartHandler
|
||||||
|
|
||||||
} // end class MultipartDataValue
|
} // end class MultipartDataValue
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------------
|
||||||
|
* Internal class representing a request parameter
|
||||||
|
*--------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
class MultipartParameter
|
class MultipartParameter
|
||||||
{
|
{
|
||||||
private MimeBodyPart part; // the actual body part data
|
private MimeBodyPart part; // the actual body part data
|
||||||
|
@ -178,7 +189,8 @@ public class ServletMultipartHandler
|
||||||
public String getValue()
|
public String getValue()
|
||||||
{
|
{
|
||||||
if (filename!=null)
|
if (filename!=null)
|
||||||
return filename;
|
return filename; // "value" for file parts is the filename
|
||||||
|
|
||||||
try
|
try
|
||||||
{ // Retrieve the part's actual content and convert it to a String. (Since non-file
|
{ // Retrieve the part's actual content and convert it to a String. (Since non-file
|
||||||
// fields are of type text/plain, the Object "val" should actually be a String, in
|
// fields are of type text/plain, the Object "val" should actually be a String, in
|
||||||
|
@ -228,7 +240,7 @@ public class ServletMultipartHandler
|
||||||
public MultipartDataValue getContent() throws ServletMultipartException
|
public MultipartDataValue getContent() throws ServletMultipartException
|
||||||
{
|
{
|
||||||
if (filename==null)
|
if (filename==null)
|
||||||
return null;
|
return null; // not a file parameter
|
||||||
|
|
||||||
if (cached_value==null)
|
if (cached_value==null)
|
||||||
{ // we don't have the value cached yet
|
{ // we don't have the value cached yet
|
||||||
|
@ -256,6 +268,20 @@ public class ServletMultipartHandler
|
||||||
|
|
||||||
} // end class MultipartParameter
|
} // end class MultipartParameter
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------------
|
||||||
|
* Attributes
|
||||||
|
*--------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
private MimeMultipart multipart; // holds all the multipart data
|
||||||
|
private Hashtable param_byname; // parameters by name
|
||||||
|
private Vector param_order; // parameters in order
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------------
|
||||||
|
* Constructor
|
||||||
|
*--------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
public ServletMultipartHandler(ServletRequest request) throws ServletMultipartException
|
public ServletMultipartHandler(ServletRequest request) throws ServletMultipartException
|
||||||
{
|
{
|
||||||
if (!canHandle(request))
|
if (!canHandle(request))
|
||||||
|
@ -286,6 +312,11 @@ public class ServletMultipartHandler
|
||||||
|
|
||||||
} // end constructor
|
} // end constructor
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------------
|
||||||
|
* External static operations
|
||||||
|
*--------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns <CODE>true</CODE> if the given <CODE>ServletRequest</CODE> can be handled by
|
* Returns <CODE>true</CODE> if the given <CODE>ServletRequest</CODE> can be handled by
|
||||||
* the <CODE>ServletMultipartHandler</CODE>, <CODE>false</CODE> if not.
|
* the <CODE>ServletMultipartHandler</CODE>, <CODE>false</CODE> if not.
|
||||||
|
@ -301,6 +332,11 @@ public class ServletMultipartHandler
|
||||||
|
|
||||||
} // end canHandle
|
} // end canHandle
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------------
|
||||||
|
* External operations
|
||||||
|
*--------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
public Enumeration getNames()
|
public Enumeration getNames()
|
||||||
{
|
{
|
||||||
Vector tmp_vector = new Vector();
|
Vector tmp_vector = new Vector();
|
||||||
|
|
|
@ -112,4 +112,6 @@ public interface ConferenceContext
|
||||||
public abstract TopicContext addTopic(String title, String zp_pseud, String zp_text)
|
public abstract TopicContext addTopic(String title, String zp_pseud, String zp_text)
|
||||||
throws DataException, AccessError;
|
throws DataException, AccessError;
|
||||||
|
|
||||||
|
public abstract TopicMessageContext getMessageByPostID(long postid) throws DataException, AccessError;
|
||||||
|
|
||||||
} // end interface ConferenceContext
|
} // end interface ConferenceContext
|
||||||
|
|
|
@ -66,6 +66,8 @@ public interface TopicContext
|
||||||
|
|
||||||
public abstract List getMessages(int low, int high) throws DataException, AccessError;
|
public abstract List getMessages(int low, int high) throws DataException, AccessError;
|
||||||
|
|
||||||
|
public abstract TopicMessageContext getMessage(int number) throws DataException, AccessError;
|
||||||
|
|
||||||
public abstract TopicMessageContext postNewMessage(long parent, String pseud, String text)
|
public abstract TopicMessageContext postNewMessage(long parent, String pseud, String text)
|
||||||
throws DataException, AccessError;
|
throws DataException, AccessError;
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
*/
|
*/
|
||||||
package com.silverwrist.venice.core;
|
package com.silverwrist.venice.core;
|
||||||
|
|
||||||
|
import java.io.InputStream;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
|
|
||||||
public interface TopicMessageContext
|
public interface TopicMessageContext
|
||||||
|
@ -49,6 +50,14 @@ public interface TopicMessageContext
|
||||||
|
|
||||||
public abstract boolean hasAttachment();
|
public abstract boolean hasAttachment();
|
||||||
|
|
||||||
|
public abstract String getAttachmentType();
|
||||||
|
|
||||||
|
public abstract String getAttachmentFilename();
|
||||||
|
|
||||||
|
public abstract int getAttachmentLength();
|
||||||
|
|
||||||
|
public abstract InputStream getAttachmentData() throws AccessError, DataException;
|
||||||
|
|
||||||
public abstract boolean canHide();
|
public abstract boolean canHide();
|
||||||
|
|
||||||
public abstract boolean canScribble();
|
public abstract boolean canScribble();
|
||||||
|
@ -61,4 +70,7 @@ public interface TopicMessageContext
|
||||||
|
|
||||||
public abstract void nuke() throws DataException, AccessError;
|
public abstract void nuke() throws DataException, AccessError;
|
||||||
|
|
||||||
|
public abstract void attachData(String m_type, String file, int length, InputStream data)
|
||||||
|
throws AccessError, DataException;
|
||||||
|
|
||||||
} // end interface TopicMessageContext
|
} // end interface TopicMessageContext
|
||||||
|
|
|
@ -884,6 +884,20 @@ class ConferenceUserContextImpl implements ConferenceContext, ConferenceBackend
|
||||||
|
|
||||||
} // end addTopic
|
} // end addTopic
|
||||||
|
|
||||||
|
public TopicMessageContext getMessageByPostID(long postid) throws DataException, AccessError
|
||||||
|
{
|
||||||
|
if (!(getConferenceData().canReadConference(level)))
|
||||||
|
{ // the luser can't even read the conference...
|
||||||
|
logger.error("user not permitted to change membership");
|
||||||
|
throw new AccessError("You are not permitted to read this conference.");
|
||||||
|
|
||||||
|
} // end if
|
||||||
|
|
||||||
|
// call down to the static function level
|
||||||
|
return TopicMessageUserContextImpl.getMessage(engine,this,datapool,postid);
|
||||||
|
|
||||||
|
} // end getMessageByPostID
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------------
|
/*--------------------------------------------------------------------------------
|
||||||
* Implementations from interface UserBackend
|
* Implementations from interface UserBackend
|
||||||
*--------------------------------------------------------------------------------
|
*--------------------------------------------------------------------------------
|
||||||
|
|
|
@ -17,9 +17,11 @@
|
||||||
*/
|
*/
|
||||||
package com.silverwrist.venice.core.impl;
|
package com.silverwrist.venice.core.impl;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
import java.sql.*;
|
import java.sql.*;
|
||||||
import java.util.*;
|
import java.util.*;
|
||||||
import org.apache.log4j.*;
|
import org.apache.log4j.*;
|
||||||
|
import com.silverwrist.util.StringUtil;
|
||||||
import com.silverwrist.venice.db.*;
|
import com.silverwrist.venice.db.*;
|
||||||
import com.silverwrist.venice.security.AuditRecord;
|
import com.silverwrist.venice.security.AuditRecord;
|
||||||
import com.silverwrist.venice.core.*;
|
import com.silverwrist.venice.core.*;
|
||||||
|
@ -33,6 +35,8 @@ class TopicMessageUserContextImpl implements TopicMessageContext
|
||||||
|
|
||||||
private static Category logger = Category.getInstance(TopicMessageUserContextImpl.class.getName());
|
private static Category logger = Category.getInstance(TopicMessageUserContextImpl.class.getName());
|
||||||
|
|
||||||
|
private static final int MAX_ATTACH = 1048576; // TODO: should be a configurable parameter
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------------
|
/*--------------------------------------------------------------------------------
|
||||||
* Attributes
|
* Attributes
|
||||||
*--------------------------------------------------------------------------------
|
*--------------------------------------------------------------------------------
|
||||||
|
@ -329,6 +333,113 @@ class TopicMessageUserContextImpl implements TopicMessageContext
|
||||||
|
|
||||||
} // end hasAttachment
|
} // 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()
|
public boolean canHide()
|
||||||
{
|
{
|
||||||
return ((creator_uid==conf.realUID()) || conf.userCanHide());
|
return ((creator_uid==conf.realUID()) || conf.userCanHide());
|
||||||
|
@ -641,6 +752,125 @@ class TopicMessageUserContextImpl implements TopicMessageContext
|
||||||
|
|
||||||
} // end nuke
|
} // 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
|
* External static operations
|
||||||
*--------------------------------------------------------------------------------
|
*--------------------------------------------------------------------------------
|
||||||
|
@ -703,4 +933,105 @@ class TopicMessageUserContextImpl implements TopicMessageContext
|
||||||
|
|
||||||
} // end loadMessageRange
|
} // 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
|
} // end class TopicMessageUserContextImpl
|
||||||
|
|
|
@ -569,6 +569,20 @@ class TopicUserContextImpl implements TopicContext
|
||||||
|
|
||||||
} // end getMessages
|
} // end getMessages
|
||||||
|
|
||||||
|
public TopicMessageContext getMessage(int number) throws DataException, AccessError
|
||||||
|
{
|
||||||
|
if (!(conf.userCanRead()))
|
||||||
|
{ // they can't read messages in this topic!
|
||||||
|
logger.error("trying to read postings w/o permission!");
|
||||||
|
throw new AccessError("You do not have permission to read messages in this conference.");
|
||||||
|
|
||||||
|
} // end if
|
||||||
|
|
||||||
|
// pass down to one of our static functiions to return this
|
||||||
|
return TopicMessageUserContextImpl.loadMessage(engine,conf,datapool,topicid,number);
|
||||||
|
|
||||||
|
} // end getMessage
|
||||||
|
|
||||||
public TopicMessageContext postNewMessage(long parent, String pseud, String text)
|
public TopicMessageContext postNewMessage(long parent, String pseud, String text)
|
||||||
throws DataException, AccessError
|
throws DataException, AccessError
|
||||||
{
|
{
|
||||||
|
|
|
@ -58,5 +58,6 @@ public interface Audit
|
||||||
public static final int HIDE_MESSAGE = 311;
|
public static final int HIDE_MESSAGE = 311;
|
||||||
public static final int SCRIBBLE_MESSAGE = 312;
|
public static final int SCRIBBLE_MESSAGE = 312;
|
||||||
public static final int NUKE_MESSAGE = 313;
|
public static final int NUKE_MESSAGE = 313;
|
||||||
|
public static final int UPLOAD_ATTACHMENT = 314;
|
||||||
|
|
||||||
} // end interface Audit
|
} // end interface Audit
|
||||||
|
|
427
src/com/silverwrist/venice/servlets/Attachment.java
Normal file
427
src/com/silverwrist/venice/servlets/Attachment.java
Normal file
|
@ -0,0 +1,427 @@
|
||||||
|
/*
|
||||||
|
* The contents of this file are subject to the Mozilla Public License Version 1.1
|
||||||
|
* (the "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at <http://www.mozilla.org/MPL/>.
|
||||||
|
*
|
||||||
|
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||||
|
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||||
|
* language governing rights and limitations under the License.
|
||||||
|
*
|
||||||
|
* The Original Code is the Venice Web Communities System.
|
||||||
|
*
|
||||||
|
* The Initial Developer of the Original Code is Eric J. Bowersox <erbo@silcom.com>,
|
||||||
|
* for Silverwrist Design Studios. Portions created by Eric J. Bowersox are
|
||||||
|
* Copyright (C) 2001 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
*/
|
||||||
|
package com.silverwrist.venice.servlets;
|
||||||
|
|
||||||
|
import java.io.*;
|
||||||
|
import java.util.*;
|
||||||
|
import javax.servlet.*;
|
||||||
|
import javax.servlet.http.*;
|
||||||
|
import org.apache.log4j.*;
|
||||||
|
import com.silverwrist.util.StringUtil;
|
||||||
|
import com.silverwrist.util.ServletMultipartHandler;
|
||||||
|
import com.silverwrist.util.ServletMultipartException;
|
||||||
|
import com.silverwrist.venice.ValidationException;
|
||||||
|
import com.silverwrist.venice.core.*;
|
||||||
|
import com.silverwrist.venice.servlets.format.*;
|
||||||
|
|
||||||
|
public class Attachment extends VeniceServlet
|
||||||
|
{
|
||||||
|
/*--------------------------------------------------------------------------------
|
||||||
|
* Static data members
|
||||||
|
*--------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
private static Category logger = Category.getInstance(Attachment.class.getName());
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------------
|
||||||
|
* Internal functions
|
||||||
|
*--------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
private static SIGContext getSIGParameter(String str, UserContext user)
|
||||||
|
throws ValidationException, DataException
|
||||||
|
{
|
||||||
|
if (str==null)
|
||||||
|
{ // no SIG parameter - bail out now!
|
||||||
|
logger.error("SIG parameter not specified!");
|
||||||
|
throw new ValidationException("No SIG specified.");
|
||||||
|
|
||||||
|
} // end if
|
||||||
|
|
||||||
|
try
|
||||||
|
{ // turn the string into a SIGID, and thence to a SIGContext
|
||||||
|
int sigid = Integer.parseInt(str);
|
||||||
|
return user.getSIGContext(sigid);
|
||||||
|
|
||||||
|
} // end try
|
||||||
|
catch (NumberFormatException nfe)
|
||||||
|
{ // error in Integer.parseInt
|
||||||
|
logger.error("Cannot convert SIG parameter '" + str + "'!");
|
||||||
|
throw new ValidationException("Invalid SIG parameter.");
|
||||||
|
|
||||||
|
} // end catch
|
||||||
|
|
||||||
|
} // end getSIGParameter
|
||||||
|
|
||||||
|
private static SIGContext getSIGParameter(ServletRequest request, UserContext user)
|
||||||
|
throws ValidationException, DataException
|
||||||
|
{
|
||||||
|
return getSIGParameter(request.getParameter("sig"),user);
|
||||||
|
|
||||||
|
} // end getSIGParameter
|
||||||
|
|
||||||
|
private static SIGContext getSIGParameter(ServletMultipartHandler mphandler, UserContext user)
|
||||||
|
throws ValidationException, DataException
|
||||||
|
{
|
||||||
|
if (mphandler.isFileParam("sig"))
|
||||||
|
throw new ValidationException("Internal Error: SIG should be a normal param");
|
||||||
|
return getSIGParameter(mphandler.getValue("sig"),user);
|
||||||
|
|
||||||
|
} // end getSIGParameter
|
||||||
|
|
||||||
|
private static ConferenceContext getConferenceParameter(String str, SIGContext sig)
|
||||||
|
throws ValidationException, DataException, AccessError
|
||||||
|
{
|
||||||
|
if (str==null)
|
||||||
|
{ // no conference parameter - bail out now!
|
||||||
|
logger.error("Conference parameter not specified!");
|
||||||
|
throw new ValidationException("No conference specified.");
|
||||||
|
|
||||||
|
} // end if
|
||||||
|
|
||||||
|
try
|
||||||
|
{ // turn the string into a ConfID, and thence to a ConferenceContext
|
||||||
|
int confid = Integer.parseInt(str);
|
||||||
|
return sig.getConferenceContext(confid);
|
||||||
|
|
||||||
|
} // end try
|
||||||
|
catch (NumberFormatException nfe)
|
||||||
|
{ // error in Integer.parseInt
|
||||||
|
logger.error("Cannot convert conference parameter '" + str + "'!");
|
||||||
|
throw new ValidationException("Invalid conference parameter.");
|
||||||
|
|
||||||
|
} // end catch
|
||||||
|
|
||||||
|
} // end getConferenceParameter
|
||||||
|
|
||||||
|
private static ConferenceContext getConferenceParameter(ServletRequest request, SIGContext sig)
|
||||||
|
throws ValidationException, DataException, AccessError
|
||||||
|
{
|
||||||
|
return getConferenceParameter(request.getParameter("conf"),sig);
|
||||||
|
|
||||||
|
} // end getConferenceParameter
|
||||||
|
|
||||||
|
private static ConferenceContext getConferenceParameter(ServletMultipartHandler mphandler, SIGContext sig)
|
||||||
|
throws ValidationException, DataException, AccessError
|
||||||
|
{
|
||||||
|
if (mphandler.isFileParam("conf"))
|
||||||
|
throw new ValidationException("Internal Error: conference should be a normal param");
|
||||||
|
return getConferenceParameter(mphandler.getValue("conf"),sig);
|
||||||
|
|
||||||
|
} // end getConferenceParameter
|
||||||
|
|
||||||
|
private static TopicMessageContext getMessageParameter(String str, ConferenceContext conf)
|
||||||
|
throws ValidationException, DataException, AccessError
|
||||||
|
{
|
||||||
|
if (str==null)
|
||||||
|
{ // no conference parameter - bail out now!
|
||||||
|
logger.error("Message parameter not specified!");
|
||||||
|
throw new ValidationException("No message specified.");
|
||||||
|
|
||||||
|
} // end if
|
||||||
|
|
||||||
|
try
|
||||||
|
{ // turn the string into a postid, and thence to a TopicMessageContext
|
||||||
|
long postid = Long.parseLong(str);
|
||||||
|
return conf.getMessageByPostID(postid);
|
||||||
|
|
||||||
|
} // end try
|
||||||
|
catch (NumberFormatException nfe)
|
||||||
|
{ // error in Integer.parseInt
|
||||||
|
logger.error("Cannot convert message parameter '" + str + "'!");
|
||||||
|
throw new ValidationException("Invalid message parameter.");
|
||||||
|
|
||||||
|
} // end catch
|
||||||
|
|
||||||
|
} // end getMessageParameter
|
||||||
|
|
||||||
|
private static TopicMessageContext getMessageParameter(ServletRequest request, ConferenceContext conf)
|
||||||
|
throws ValidationException, DataException, AccessError
|
||||||
|
{
|
||||||
|
return getMessageParameter(request.getParameter("msg"),conf);
|
||||||
|
|
||||||
|
} // end getMessageParameter
|
||||||
|
|
||||||
|
private static TopicMessageContext getMessageParameter(ServletMultipartHandler mphandler,
|
||||||
|
ConferenceContext conf)
|
||||||
|
throws ValidationException, DataException, AccessError
|
||||||
|
{
|
||||||
|
if (mphandler.isFileParam("msg"))
|
||||||
|
throw new ValidationException("Internal Error: message should be a normal param");
|
||||||
|
return getMessageParameter(mphandler.getValue("msg"),conf);
|
||||||
|
|
||||||
|
} // end getMessageParameter
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------------
|
||||||
|
* Overrides from class HttpServlet
|
||||||
|
*--------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
public String getServletInfo()
|
||||||
|
{
|
||||||
|
String rc = "Attachment servlet - Handles uploading and downloading attachments\n"
|
||||||
|
+ "Part of the Venice Web Communities System\n";
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
} // end getServletInfo
|
||||||
|
|
||||||
|
public void doGet(HttpServletRequest request, HttpServletResponse response)
|
||||||
|
throws ServletException, IOException
|
||||||
|
{
|
||||||
|
UserContext user = getUserContext(request);
|
||||||
|
RenderData rdat = createRenderData(request,response);
|
||||||
|
String page_title = null;
|
||||||
|
Object content = null;
|
||||||
|
SIGContext sig = null; // SIG context
|
||||||
|
ConferenceContext conf = null; // conference context
|
||||||
|
TopicMessageContext msg = null; // message context
|
||||||
|
|
||||||
|
try
|
||||||
|
{ // this outer try is to catch ValidationException
|
||||||
|
try
|
||||||
|
{ // all commands require a SIG parameter
|
||||||
|
sig = getSIGParameter(request,user);
|
||||||
|
changeMenuSIG(request,sig);
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
logger.debug("found SIG #" + String.valueOf(sig.getSIGID()));
|
||||||
|
|
||||||
|
} // end try
|
||||||
|
catch (DataException de)
|
||||||
|
{ // error looking up the SIG
|
||||||
|
page_title = "Database Error";
|
||||||
|
content = new ErrorBox(page_title,"Database error finding SIG: " + de.getMessage(),"top");
|
||||||
|
|
||||||
|
} // end catch
|
||||||
|
|
||||||
|
if (content==null)
|
||||||
|
{ // we got the SIG parameter OK
|
||||||
|
try
|
||||||
|
{ // all commands require a conference parameter
|
||||||
|
conf = getConferenceParameter(request,sig);
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
logger.debug("found conf #" + String.valueOf(conf.getConfID()));
|
||||||
|
|
||||||
|
} // end try
|
||||||
|
catch (DataException de)
|
||||||
|
{ // error looking up the conference
|
||||||
|
page_title = "Database Error";
|
||||||
|
content = new ErrorBox(page_title,"Database error finding conference: " + de.getMessage(),"top");
|
||||||
|
|
||||||
|
} // end catch
|
||||||
|
|
||||||
|
} // end if
|
||||||
|
|
||||||
|
if (content==null)
|
||||||
|
{ // we got the conference parameter OK
|
||||||
|
try
|
||||||
|
{ // now we need a message parameter
|
||||||
|
msg = getMessageParameter(request,conf);
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
logger.debug("found post #" + String.valueOf(msg.getPostID()));
|
||||||
|
|
||||||
|
} // end try
|
||||||
|
catch (DataException de)
|
||||||
|
{ // error looking up the conference
|
||||||
|
page_title = "Database Error";
|
||||||
|
content = new ErrorBox(page_title,"Database error finding message: " + de.getMessage(),"top");
|
||||||
|
|
||||||
|
} // end catch
|
||||||
|
|
||||||
|
} // end if
|
||||||
|
|
||||||
|
} // end try
|
||||||
|
catch (ValidationException ve)
|
||||||
|
{ // these all get handled in pretty much the same way
|
||||||
|
page_title = "Error";
|
||||||
|
content = new ErrorBox(null,ve.getMessage(),"top");
|
||||||
|
|
||||||
|
} // end catch
|
||||||
|
catch (AccessError ae)
|
||||||
|
{ // these all get handled in pretty much the same way
|
||||||
|
page_title = "Access Error";
|
||||||
|
content = new ErrorBox(page_title,ae.getMessage(),"top");
|
||||||
|
|
||||||
|
} // end catch
|
||||||
|
|
||||||
|
if (content==null)
|
||||||
|
{ // extract the attachment data from the message and send it out
|
||||||
|
try
|
||||||
|
{ // extract the attachment data and send it out!
|
||||||
|
rdat.sendBinaryData(msg.getAttachmentType(),msg.getAttachmentFilename(),
|
||||||
|
msg.getAttachmentLength(),msg.getAttachmentData());
|
||||||
|
return; // now we're all done!
|
||||||
|
|
||||||
|
} // end try
|
||||||
|
catch (AccessError ae)
|
||||||
|
{ // these all get handled in pretty much the same way
|
||||||
|
page_title = "Access Error";
|
||||||
|
content = new ErrorBox(page_title,ae.getMessage(),"top");
|
||||||
|
|
||||||
|
} // end catch
|
||||||
|
catch (DataException de)
|
||||||
|
{ // error looking up the conference
|
||||||
|
page_title = "Database Error";
|
||||||
|
content = new ErrorBox(page_title,"Database error retrieving attachment: " + de.getMessage(),"top");
|
||||||
|
|
||||||
|
} // end catch
|
||||||
|
|
||||||
|
} // end if
|
||||||
|
|
||||||
|
// we only get here if there were an error
|
||||||
|
BaseJSPData basedat = new BaseJSPData(page_title,"top",content);
|
||||||
|
basedat.transfer(getServletContext(),rdat);
|
||||||
|
|
||||||
|
} // end doGet
|
||||||
|
|
||||||
|
public void doPost(HttpServletRequest request, HttpServletResponse response)
|
||||||
|
throws ServletException, IOException
|
||||||
|
{
|
||||||
|
UserContext user = getUserContext(request);
|
||||||
|
RenderData rdat = createRenderData(request,response);
|
||||||
|
ServletMultipartHandler mphandler = null;
|
||||||
|
String target = "top";
|
||||||
|
String page_title = null;
|
||||||
|
Object content = null;
|
||||||
|
SIGContext sig = null; // SIG context
|
||||||
|
ConferenceContext conf = null; // conference context
|
||||||
|
TopicMessageContext msg = null; // message context
|
||||||
|
|
||||||
|
try
|
||||||
|
{ // this outer try is to catch ValidationException
|
||||||
|
mphandler = new ServletMultipartHandler(request);
|
||||||
|
|
||||||
|
if (mphandler.isFileParam("target"))
|
||||||
|
throw new ValidationException("Internal Error: 'target' should be a normal param");
|
||||||
|
target = mphandler.getValue("target");
|
||||||
|
|
||||||
|
try
|
||||||
|
{ // all commands require a SIG parameter
|
||||||
|
sig = getSIGParameter(mphandler,user);
|
||||||
|
changeMenuSIG(request,sig);
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
logger.debug("found SIG #" + String.valueOf(sig.getSIGID()));
|
||||||
|
|
||||||
|
} // end try
|
||||||
|
catch (DataException de)
|
||||||
|
{ // error looking up the SIG
|
||||||
|
page_title = "Database Error";
|
||||||
|
content = new ErrorBox(page_title,"Database error finding SIG: " + de.getMessage(),target);
|
||||||
|
|
||||||
|
} // end catch
|
||||||
|
|
||||||
|
if (content==null)
|
||||||
|
{ // we got the SIG parameter OK
|
||||||
|
try
|
||||||
|
{ // all commands require a conference parameter
|
||||||
|
conf = getConferenceParameter(mphandler,sig);
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
logger.debug("found conf #" + String.valueOf(conf.getConfID()));
|
||||||
|
|
||||||
|
} // end try
|
||||||
|
catch (DataException de)
|
||||||
|
{ // error looking up the conference
|
||||||
|
page_title = "Database Error";
|
||||||
|
content = new ErrorBox(page_title,"Database error finding conference: " + de.getMessage(),target);
|
||||||
|
|
||||||
|
} // end catch
|
||||||
|
|
||||||
|
} // end if
|
||||||
|
|
||||||
|
if (content==null)
|
||||||
|
{ // we got the conference parameter OK
|
||||||
|
try
|
||||||
|
{ // now we need a message parameter
|
||||||
|
msg = getMessageParameter(mphandler,conf);
|
||||||
|
if (logger.isDebugEnabled())
|
||||||
|
logger.debug("found post #" + String.valueOf(msg.getPostID()));
|
||||||
|
|
||||||
|
} // end try
|
||||||
|
catch (DataException de)
|
||||||
|
{ // error looking up the conference
|
||||||
|
page_title = "Database Error";
|
||||||
|
content = new ErrorBox(page_title,"Database error finding message: " + de.getMessage(),target);
|
||||||
|
|
||||||
|
} // end catch
|
||||||
|
|
||||||
|
} // end if
|
||||||
|
|
||||||
|
// also check on file and target parameter status
|
||||||
|
if (!(mphandler.isFileParam("thefile")))
|
||||||
|
throw new ValidationException("Internal error: 'thefile' should be a file param");
|
||||||
|
|
||||||
|
|
||||||
|
} // end try
|
||||||
|
catch (ValidationException ve)
|
||||||
|
{ // these all get handled in pretty much the same way
|
||||||
|
page_title = "Error";
|
||||||
|
content = new ErrorBox(null,ve.getMessage(),target);
|
||||||
|
|
||||||
|
} // end catch
|
||||||
|
catch (AccessError ae)
|
||||||
|
{ // these all get handled in pretty much the same way
|
||||||
|
page_title = "Access Error";
|
||||||
|
content = new ErrorBox(page_title,ae.getMessage(),target);
|
||||||
|
|
||||||
|
} // end catch
|
||||||
|
catch (ServletMultipartException smpe)
|
||||||
|
{ // this is kind of a special case
|
||||||
|
page_title = "Error";
|
||||||
|
content = new ErrorBox(page_title,"Internal Error: " + smpe.getMessage(),target);
|
||||||
|
|
||||||
|
} // end catch
|
||||||
|
|
||||||
|
if (content==null)
|
||||||
|
{ // we're ready to get the data and attach it
|
||||||
|
try
|
||||||
|
{ // attach the data to the message!
|
||||||
|
msg.attachData(mphandler.getContentType("thefile"),mphandler.getValue("thefile"),
|
||||||
|
mphandler.getContentSize("thefile"),mphandler.getFileContentStream("thefile"));
|
||||||
|
|
||||||
|
// go back to where we should have gone before we uploaded the message
|
||||||
|
rdat.redirectTo(target);
|
||||||
|
return;
|
||||||
|
|
||||||
|
} // end try
|
||||||
|
catch (ServletMultipartException smpe)
|
||||||
|
{ // this is kind of a special case
|
||||||
|
page_title = "Error";
|
||||||
|
content = new ErrorBox(page_title,"Internal Error: " + smpe.getMessage(),target);
|
||||||
|
|
||||||
|
} // end catch
|
||||||
|
catch (AccessError ae)
|
||||||
|
{ // these all get handled in pretty much the same way
|
||||||
|
page_title = "Access Error";
|
||||||
|
content = new ErrorBox(page_title,ae.getMessage(),target);
|
||||||
|
|
||||||
|
} // end catch
|
||||||
|
catch (DataException de)
|
||||||
|
{ // error looking up the conference
|
||||||
|
page_title = "Database Error";
|
||||||
|
content = new ErrorBox(page_title,"Database error storing attachment: " + de.getMessage(),target);
|
||||||
|
|
||||||
|
} // end catch
|
||||||
|
|
||||||
|
} // end if (we got all the parameters OK)
|
||||||
|
|
||||||
|
// we only get here if there were an error
|
||||||
|
BaseJSPData basedat = new BaseJSPData(page_title,target,content);
|
||||||
|
basedat.transfer(getServletContext(),rdat);
|
||||||
|
|
||||||
|
} // end doPost
|
||||||
|
|
||||||
|
} // end class Attachment
|
|
@ -453,9 +453,10 @@ public class ConfOperations extends VeniceServlet
|
||||||
final String yes = "Y";
|
final String yes = "Y";
|
||||||
if (yes.equals(request.getParameter("attach")))
|
if (yes.equals(request.getParameter("attach")))
|
||||||
{ // we need to upload an attachment for this post
|
{ // we need to upload an attachment for this post
|
||||||
// TODO: jump somewhere to upload an attachment
|
TopicMessageContext msg = topic.getMessage(0); // load the "zero post"
|
||||||
rdat.redirectTo(on_error);
|
|
||||||
return;
|
content = new AttachmentForm(sig,conf,msg,on_error);
|
||||||
|
page_title = "Upload Attachment";
|
||||||
|
|
||||||
} // end if
|
} // end if
|
||||||
else
|
else
|
||||||
|
|
|
@ -276,12 +276,12 @@ public class PostMessage extends VeniceServlet
|
||||||
{ // no slippage - post the message!!!
|
{ // no slippage - post the message!!!
|
||||||
TopicMessageContext msg = topic.postNewMessage(0,request.getParameter("pseud"),raw_postdata);
|
TopicMessageContext msg = topic.postNewMessage(0,request.getParameter("pseud"),raw_postdata);
|
||||||
if (yes.equals(request.getParameter("attach")))
|
if (yes.equals(request.getParameter("attach")))
|
||||||
{ // we have an attachment to upload...
|
{ // we have an attachment to upload...display the "Upload Attachment" form
|
||||||
// TODO: do something to upload the attachment
|
String target = "confdisp?sig=" + String.valueOf(sig.getSIGID()) + "&conf="
|
||||||
rdat.redirectTo("confdisp?sig=" + String.valueOf(sig.getSIGID()) + "&conf="
|
+ String.valueOf(conf.getConfID()) + "&top="
|
||||||
+ String.valueOf(conf.getConfID()) + "&top="
|
+ String.valueOf(topic.getTopicNumber()) + "&rnm=1";
|
||||||
+ String.valueOf(topic.getTopicNumber()) + "&rnm=1");
|
content = new AttachmentForm(sig,conf,msg,target);
|
||||||
return;
|
page_title = "Upload Attachment";
|
||||||
|
|
||||||
} // end if
|
} // end if
|
||||||
else
|
else
|
||||||
|
|
118
src/com/silverwrist/venice/servlets/format/AttachmentForm.java
Normal file
118
src/com/silverwrist/venice/servlets/format/AttachmentForm.java
Normal file
|
@ -0,0 +1,118 @@
|
||||||
|
/*
|
||||||
|
* The contents of this file are subject to the Mozilla Public License Version 1.1
|
||||||
|
* (the "License"); you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at <http://www.mozilla.org/MPL/>.
|
||||||
|
*
|
||||||
|
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||||
|
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||||
|
* language governing rights and limitations under the License.
|
||||||
|
*
|
||||||
|
* The Original Code is the Venice Web Communities System.
|
||||||
|
*
|
||||||
|
* The Initial Developer of the Original Code is Eric J. Bowersox <erbo@silcom.com>,
|
||||||
|
* for Silverwrist Design Studios. Portions created by Eric J. Bowersox are
|
||||||
|
* Copyright (C) 2001 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
|
||||||
|
*
|
||||||
|
* Contributor(s):
|
||||||
|
*/
|
||||||
|
package com.silverwrist.venice.servlets.format;
|
||||||
|
|
||||||
|
import java.util.*;
|
||||||
|
import javax.servlet.*;
|
||||||
|
import javax.servlet.http.*;
|
||||||
|
import com.silverwrist.util.StringUtil;
|
||||||
|
import com.silverwrist.venice.htmlcheck.*;
|
||||||
|
import com.silverwrist.venice.core.*;
|
||||||
|
|
||||||
|
public class AttachmentForm implements JSPRender
|
||||||
|
{
|
||||||
|
/*--------------------------------------------------------------------------------
|
||||||
|
* Static data members
|
||||||
|
*--------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
// Attribute name for request attribute
|
||||||
|
protected static final String ATTR_NAME = "com.silverwrist.venice.content.AttachmentForm";
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------------
|
||||||
|
* Attributes
|
||||||
|
*--------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
private int sigid;
|
||||||
|
private int confid;
|
||||||
|
private long postid;
|
||||||
|
private String target;
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------------
|
||||||
|
* Constructor
|
||||||
|
*--------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
public AttachmentForm(SIGContext sig, ConferenceContext conf, TopicMessageContext msg, String target)
|
||||||
|
{
|
||||||
|
this.sigid = sig.getSIGID();
|
||||||
|
this.confid = conf.getConfID();
|
||||||
|
this.postid = msg.getPostID();
|
||||||
|
this.target = target;
|
||||||
|
|
||||||
|
} // end constructor
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------------
|
||||||
|
* External static functions
|
||||||
|
*--------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
public static AttachmentForm retrieve(ServletRequest request)
|
||||||
|
{
|
||||||
|
return (AttachmentForm)(request.getAttribute(ATTR_NAME));
|
||||||
|
|
||||||
|
} // end retrieve
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------------
|
||||||
|
* Implementations from interface JSPRender
|
||||||
|
*--------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
public void store(ServletRequest request)
|
||||||
|
{
|
||||||
|
request.setAttribute(ATTR_NAME,this);
|
||||||
|
|
||||||
|
} // end store
|
||||||
|
|
||||||
|
public String getTargetJSPName()
|
||||||
|
{
|
||||||
|
return "attach_form.jsp";
|
||||||
|
|
||||||
|
} // end getTargetJSPName
|
||||||
|
|
||||||
|
/*--------------------------------------------------------------------------------
|
||||||
|
* External operations
|
||||||
|
*--------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
public int getSIGID()
|
||||||
|
{
|
||||||
|
return sigid;
|
||||||
|
|
||||||
|
} // end getSIGID
|
||||||
|
|
||||||
|
public int getConfID()
|
||||||
|
{
|
||||||
|
return confid;
|
||||||
|
|
||||||
|
} // end getConfID
|
||||||
|
|
||||||
|
public long getPostID()
|
||||||
|
{
|
||||||
|
return postid;
|
||||||
|
|
||||||
|
} // end getPostID
|
||||||
|
|
||||||
|
public String getTarget()
|
||||||
|
{
|
||||||
|
return target;
|
||||||
|
|
||||||
|
} // end getTarget
|
||||||
|
|
||||||
|
} // end class AttachmentForm
|
|
@ -299,4 +299,25 @@ public class RenderData
|
||||||
|
|
||||||
} // end nullResponse
|
} // end nullResponse
|
||||||
|
|
||||||
|
public void sendBinaryData(String type, String filename, int length, InputStream data) throws IOException
|
||||||
|
{
|
||||||
|
response.setContentType(type);
|
||||||
|
response.setContentLength(length);
|
||||||
|
if (filename!=null) // make sure we pass the filename along, too
|
||||||
|
response.setHeader("Content-Disposition","attachment; filename=\"" + filename + "\";");
|
||||||
|
|
||||||
|
// Copy the contents of the "data" stream to the output.
|
||||||
|
ServletOutputStream stm = response.getOutputStream();
|
||||||
|
byte[] buffer = new byte[4096];
|
||||||
|
int rd = data.read(buffer);
|
||||||
|
while (rd>=0)
|
||||||
|
{ // simple read-write loop to shove data out the door
|
||||||
|
if (rd>0)
|
||||||
|
stm.write(buffer,0,rd);
|
||||||
|
rd = data.read(buffer);
|
||||||
|
|
||||||
|
} // end while
|
||||||
|
|
||||||
|
} // end sendBinaryData
|
||||||
|
|
||||||
} // end class RenderData
|
} // end class RenderData
|
||||||
|
|
41
web/format/attach_form.jsp
Normal file
41
web/format/attach_form.jsp
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
<%--
|
||||||
|
The contents of this file are subject to the Mozilla Public License Version 1.1
|
||||||
|
(the "License"); you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at <http://www.mozilla.org/MPL/>.
|
||||||
|
|
||||||
|
Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
||||||
|
WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
||||||
|
language governing rights and limitations under the License.
|
||||||
|
|
||||||
|
The Original Code is the Venice Web Communities System.
|
||||||
|
|
||||||
|
The Initial Developer of the Original Code is Eric J. Bowersox <erbo@silcom.com>,
|
||||||
|
for Silverwrist Design Studios. Portions created by Eric J. Bowersox are
|
||||||
|
Copyright (C) 2001 Eric J. Bowersox/Silverwrist Design Studios. All Rights Reserved.
|
||||||
|
|
||||||
|
Contributor(s):
|
||||||
|
--%>
|
||||||
|
<%@ page import = "java.util.*" %>
|
||||||
|
<%@ page import = "com.silverwrist.util.StringUtil" %>
|
||||||
|
<%@ page import = "com.silverwrist.venice.core.*" %>
|
||||||
|
<%@ page import = "com.silverwrist.venice.servlets.Variables" %>
|
||||||
|
<%@ page import = "com.silverwrist.venice.servlets.format.*" %>
|
||||||
|
<%
|
||||||
|
AttachmentForm data = AttachmentForm.retrieve(request);
|
||||||
|
Variables.failIfNull(data);
|
||||||
|
RenderData rdat = RenderConfig.createRenderData(application,request,response);
|
||||||
|
%>
|
||||||
|
<% rdat.writeContentHeader(out,"Upload Your Attachment",null); %>
|
||||||
|
<%= rdat.getStdFontTag(null,2) %>
|
||||||
|
Your attachment may be no more than <B>1 megabyte</B> in size.<P>
|
||||||
|
<FORM METHOD="POST" ENCTYPE="multipart/form-data" ACTION="<%= rdat.getEncodedServletPath("attachment") %>">
|
||||||
|
<INPUT TYPE=HIDDEN NAME="sig" VALUE="<%= data.getSIGID() %>">
|
||||||
|
<INPUT TYPE=HIDDEN NAME="conf" VALUE="<%= data.getConfID() %>">
|
||||||
|
<INPUT TYPE=HIDDEN NAME="msg" VALUE="<%= data.getPostID() %>">
|
||||||
|
<INPUT TYPE=HIDDEN NAME="target" VALUE="<%= data.getTarget() %>">
|
||||||
|
File to attach: <INPUT TYPE="FILE" NAME="thefile"><BR>
|
||||||
|
<INPUT TYPE=IMAGE SRC="<%= rdat.getFullImagePath("bn_upload.gif") %>" NAME="upload" ALT="Upload"
|
||||||
|
WIDTH=80 HEIGHT=24 BORDER=0>
|
||||||
|
</FORM><P>
|
||||||
|
</FONT>
|
||||||
|
<% rdat.writeFooter(out); %>
|
|
@ -171,7 +171,13 @@
|
||||||
<A HREF="<%= rdat.getEncodedServletPath("user/" + poster) %>" TARGET="_blank"><%= poster %></A>,
|
<A HREF="<%= rdat.getEncodedServletPath("user/" + poster) %>" TARGET="_blank"><%= poster %></A>,
|
||||||
<%= rdat.formatDateForDisplay(msg.getPostDate()) %>
|
<%= rdat.formatDateForDisplay(msg.getPostDate()) %>
|
||||||
</EM>)
|
</EM>)
|
||||||
<%-- TODO: paperclip goes here if we have an attachment --%>
|
<% if (msg.hasAttachment()) { %>
|
||||||
|
<A HREF="<%= rdat.getEncodedServletPath("attachment?" + data.getConfLocator() + "&msg="
|
||||||
|
+ String.valueOf(msg.getPostID())) %>"><IMG
|
||||||
|
SRC="<%= rdat.getFullImagePath("attachment.gif") %>"
|
||||||
|
ALT="(Attachment <%= msg.getAttachmentFilename() %> - <%= msg.getAttachmentLength() %> bytes)"
|
||||||
|
WIDTH=16 HEIGHT=16 BORDER=0></A>
|
||||||
|
<% } // end if %>
|
||||||
</FONT><P>
|
</FONT><P>
|
||||||
<% if (msg.isScribbled()) { %>
|
<% if (msg.isScribbled()) { %>
|
||||||
<TT><EM><B>
|
<TT><EM><B>
|
||||||
|
|
BIN
web/images/attachment.gif
Normal file
BIN
web/images/attachment.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 102 B |
BIN
web/images/bn_upload.gif
Normal file
BIN
web/images/bn_upload.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 942 B |
Loading…
Reference in New Issue
Block a user