How to receive and distinguish between regular attachments and inline attachments in Apache Commons Email 1.4 - apache-commons-email

Currently we receive an email which gets parsed by
MimeMessageParser mimeMessageParser = parse(message);
and later pull out the attachments with
if (mimeMessageParser.hasAttachments()) {
List<DataSource> attachments = mimeMessageParser.getAttachmentList();
for (DataSource dataSource : attachments) {
saveAttachment(dataSource, subjectLineProperties, documentToUpload, firstHeaders);
}
}
The issue is that getAttachmentList is also returning inline images like in the signature line the business logo, and we do not want to pull out the inline images as attachments. We just want the actual email attachments. ATTACHMENT versus INLINE, but we also have no access to java.mail disposition via the Apache Commons Email 1.4 version, and can't find a solution. I checked their documentation https://commons.apache.org/proper/commons-email/javadocs/api-1.4/index.html
No luck. It seems that the attachments DataSource only allows me to get content and content type and name, but not if it is an inline attachment/image or a regular attachment like Mime Parts can.

I am under impression that there is a workaround without going into lower level... But I haven't checked it with all attachment types yet - only with images. Something like this:
for(DataSource ds : mimeMessageParser.getAttachmentList()) {
for(String id : mimeMessageParser.getContentIds()) {
if(ds == mimeMessageParser.findAttachmentByCid(id)) {
// It is inline attachment with Content ID
break;
}
}
// If not found - it is file attachment without content ID
}

The answer is that Apache Commons Email cannot do such a thing. You have to go lower level and code the old fashioned MimeMessage and MultiPart classes within the JDK in order to make these distinctions.
So from mimeMessageParser.getAttachmentList(); call we now have
if (mimeMessageParser.hasAttachments()) {
final Multipart mp = (Multipart) message.getContent();
if (mp != null) {
List<DataSource> attachments = extractAttachment(mp);
for (DataSource dataSource : attachments) {
saveAttachment(dataSource, subjectLineProperties, documentToUpload, firstHeaders);
}
}
}
private static List<DataSource> extractAttachment(Multipart multipart) {
List<DataSource> attachments = new ArrayList<>();
try {
for (int i = 0; i < multipart.getCount(); i++) {
BodyPart bodyPart = multipart.getBodyPart(i);
if (bodyPart.getContent() instanceof Multipart) {
// part-within-a-part, do some recursion...
extractAttachment((Multipart) bodyPart.getContent());
}
System.out.println("bodyPart.getDisposition(): " + bodyPart.getDisposition());
if (!Part.ATTACHMENT.equalsIgnoreCase(bodyPart.getDisposition())) {
continue; // dealing with attachments only
}
InputStream is = bodyPart.getInputStream();
String fileName = bodyPart.getFileName();
String contentType = bodyPart.getContentType();
ByteArrayDataSource dataSource = new ByteArrayDataSource(is, contentType);
dataSource.setName(fileName);
attachments.add(dataSource);
}
} catch (IOException | MessagingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return attachments;
}

Related

How do I append text to existing text file?

When saving the text file it is being saved for example in the Documents/ folder. I'm aware of that I need to use append to add new line of text to that existing file but I am not entirely sure how and where to add this line of code and check that file exists.
This is the current code that is handling saving the file.
...
save.setOnClickListener {
saveFile()
}
}
private fun saveFile() {
val fileIntent = Intent(Intent.ACTION_CREATE_DOCUMENT).apply {
addCategory(Intent.CATEGORY_OPENABLE)
type = "text/plain"
putExtra(Intent.EXTRA_TITLE, "measurements.txt")
// Optionally, specify a URI for the directory that should be opened in
// the system file picker before your app creates the document.
//putExtra(DocumentsContract.EXTRA_INITIAL_URI, pickerInitialUri)
}
saveLauncher.launch(fileIntent)
}
private var saveLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
if (result.resultCode == Activity.RESULT_OK) {
val uri = result.data?.data
try {
val outputStream = uri?.let { contentResolver.openOutputStream(it) }
outputStream?.write(getMeasurement?.toByteArray())
outputStream?.close()
} catch (e: Exception) {
Toast.makeText(this, "Error is ${e.localizedMessage}", Toast.LENGTH_SHORT).show()
}
}
}
You can use a Writer to append text. Also, you should not put your close call inside the try block, or it could get skipped and you won't release the file. close should go in a finally block, but it's easier to use use { } instead.
When you open an output stream from the content resolver, you can specify write and append mode by passing "wa" as the second argument. See here and here in the documentation.
openOutputStream throws an exception if the file doesn't already exist. If you want to create a file if it doesn't exist yet, you'll need to add that logic.
I like to exit early from a function rather than nest everything in an if-statement, so I rearranged it that way in my example, but you don't have to do that.
private var saveLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
val uri = result.data?.data
val content = getMeasurement
if (result.resultCode != Activity.RESULT_OK || uri == null || content == null) {
return#registerForActivityResult
}
try {
contentResolver.openOutputStream(uri, "wa")
.writer().use { it.write(content) }
} catch (e: Exception) {
Toast.makeText(this, "Error is ${e.localizedMessage}", Toast.LENGTH_SHORT).show()
}
}

How to stream text data with JAX-RS continuously

I read multiple questions that are similar to mine and found this: https://stackoverflow.com/a/34358215/12550134
But I am not able to do this. I use plain JAX-RS API and Open Liberty as my server. Unfortunately the ResourceConfig cannot be found, so I cannot disable the buffer, as described in the answer above.
This is my code:
#GET
#Produces(MediaType.TEXT_PLAIN)
public Response sayHelloStream() {
LOGGER.debug("calling sayHelloStream");
StreamingOutput out = outputStream -> {
Writer writer = new BufferedWriter(new OutputStreamWriter(outputStream));
for (int i = 0; i < 999999999; i++) {
writer.write("Hello\n");
writer.flush();
try {
LOGGER.debug("before sleep");
TimeUnit.SECONDS.sleep(3);
LOGGER.debug("after sleep");
} catch (InterruptedException e) {
LOGGER.error("error with the timer", e);
}
}
};
return Response.ok(out).build();
}
When calling it in the browser nothing happens. To my understanding due to the buffer. How am I able to stream text data like this using plain JAX-RS?
I would use the SSE extension. AFAIK it's part of the JAX-RS API, allthough you might need an extra module to enable it server-side:
https://eclipse-ee4j.github.io/jersey.github.io/documentation/latest/sse.html
...
import javax.ws.rs.sse.Sse;
import javax.ws.rs.sse.SseEventSink;
import javax.ws.rs.sse.OutboundSseEvent;
...
#Path("events")
public static class SseResource {
#GET
#Produces(MediaType.SERVER_SENT_EVENTS)
public void getServerSentEvents(#Context SseEventSink eventSink, #Context Sse sse) {
new Thread(() -> {
for (int i = 0; i < 10; i++) {
// ... code that waits 1 second
final OutboundSseEvent event = sse.newEventBuilder()
.name("message-to-client")
.data(String.class, "Hello world " + i + "!")
.build();
eventSink.send(event);
}
}).start();
}
}
It streams text data to the client in chunks in the SSE format, so it can easily be handled in the browser using e.g. the HTML5 <eventsource> element or the EventSource JavaScript API.
var source = new EventSource('.../events');
source.addEventListener('message-to-client', function(e) {
console.log(e.data);
}, false);

#MultipartForm How to get the original file name?

I am using jboss's rest-easy multipart provider for importing a file. I read here http://docs.jboss.org/resteasy/docs/1.0.0.GA/userguide/html/Content_Marshalling_Providers.html#multipartform_annotation regarding #MultipartForm because I can exactly map it with my POJO.
Below is my POJO
public class SoftwarePackageForm {
#FormParam("softwarePackage")
private File file;
private String contentDisposition;
public File getFile() {
return file;
}
public void setFile(File file) {
this.file = file;
}
public String getContentDisposition() {
return contentDisposition;
}
public void setContentDisposition(String contentDisposition) {
this.contentDisposition = contentDisposition;
}
}
Then I got the file object and printed its absolute path and it returned a file name of type file. The extension and uploaded file name are lost. My client is trying to upload a archive file(zip,tar,z)
I need this information at the server side so that I can apply the un-archive program properly.
The original file name is sent to the server in content-disposition header.
How can I get this information? Or atleast how can I say jboss to save the file with the uploaded file name and extension? Is it configurable from my application?
After looking around a bit for Resteasy examples including this one, it seems like there is no way to retrieve the original filename and extension information when using a POJO class with the #MultipartForm annotation.
The examples I have seen so far retrieve the filename from the Content-Disposition header from the "file" part of the submitted multiparts form data via HTTP POST, which essentially, looks something like:
Content-Disposition: form-data; name="file"; filename="your_file.zip"
Content-Type: application/zip
You will have to update your file upload REST service class to extract this header like this:
#POST
#Path("/upload")
#Consumes("multipart/form-data")
public Response uploadFile(MultipartFormDataInput input) {
String fileName = "";
Map<String, List<InputPart>> formParts = input.getFormDataMap();
List<InputPart> inPart = formParts.get("file"); // "file" should match the name attribute of your HTML file input
for (InputPart inputPart : inPart) {
try {
// Retrieve headers, read the Content-Disposition header to obtain the original name of the file
MultivaluedMap<String, String> headers = inputPart.getHeaders();
String[] contentDispositionHeader = headers.getFirst("Content-Disposition").split(";");
for (String name : contentDispositionHeader) {
if ((name.trim().startsWith("filename"))) {
String[] tmp = name.split("=");
fileName = tmp[1].trim().replaceAll("\"","");
}
}
// Handle the body of that part with an InputStream
InputStream istream = inputPart.getBody(InputStream.class,null);
/* ..etc.. */
}
catch (IOException e) {
e.printStackTrace();
}
}
String msgOutput = "Successfully uploaded file " + fileName;
return Response.status(200).entity(msgOutput).build();
}
Hope this helps.
You could use #PartFilename but unfortunately this is currently only used for writing forms, not reading forms: RESTEASY-1069.
Till this issue is fixed you could use MultipartFormDataInput as parameter for your resource method.
If you user MultipartFile class, than you can do something like:
MultipartFile multipartFile;
multipartFile.getOriginalFilename();
It seems that Isim is right, but there is a workaround.
Create a hidden field in your form and update its value with the selected file's name. When the form is submitted, the filename will be submitted as a #FormParam.
Here is some code you could need (jquery required).
<input id="the-file" type="file" name="file">
<input id="the-filename" type="hidden" name="filename">
<script>
$('#the-file').on('change', function(e) {
var filename = $(this).val();
var lastIndex = filename.lastIndexOf('\\');
if (lastIndex < 0) {
lastIndex = filename.lastIndexOf('/');
}
if (lastIndex >= 0) {
filename = filename.substring(lastIndex + 1);
}
$('#the-filename').val(filename);
});
</script>

asp.net web api file upload without saving

Ok, so I am writing a service to recieve file uploads from an iPhone application through phonegap. They send me a file and I am trying to grab the actual file without saving it to any type of file system. Currently this is what I have
[HttpPost]
public string processRequest()
{
string ext = "Entered";
Request.Content.ReadAsMultipartAsync<MultipartMemoryStreamProvider>(new MultipartMemoryStreamProvider()).ContinueWith((tsk) =>
{
ext = "Request";
MultipartMemoryStreamProvider prvdr = tsk.Result;
foreach (HttpContent ctnt in prvdr.Contents)
{
ext = "Foreach";
// You would get hold of the inner memory stream here
Stream stream = ctnt.ReadAsStreamAsync().Result;
if (stream == null)
{
ext = "Null Stream";
}
Image img = Image.FromStream(stream);
if (ImageFormat.Jpeg.Equals(img.RawFormat))
{
ext = "jpeg";
}
else if (ImageFormat.Png.Equals(img.RawFormat))
{
ext = "Png";
}
else if (ImageFormat.Gif.Equals(img.RawFormat))
{
ext = "Gif";
}
// do something witht his stream now
}
});
return ext;
}
I have put various responses in there so I can see where the function is getting to. Right now it always returns "Entered" which means its not even reading the content of the request, the end game is for me to grab the file object, convert it into an image and then to base 64. Any direction would be appreciated. Remember I want to do this without any file system so no solutions that involve mapping a path to a server folder.
Ok so a little update, I have edited my code according to my first response and at least it attempts to execute now but it just gets infinitely stuck inside the code. This happens during the ReadAsMultipartAsync function
[HttpPost]
public string processRequest()
{
string ext = "Entered";
Request.Content.ReadAsMultipartAsync(new MultipartMemoryStreamProvider()).ContinueWith((tsk) =>
{
ext = "Request";
MultipartMemoryStreamProvider prvdr = tsk.Result;
foreach (HttpContent ctnt in prvdr.Contents)
{
ext = "Foreach";
// You would get hold of the inner memory stream here
Stream stream = ctnt.ReadAsStreamAsync().Result;
if (stream == null)
{
ext = "Null Stream";
}
Image img = Image.FromStream(stream);
if (ImageFormat.Jpeg.Equals(img.RawFormat))
{
ext = "jpeg";
}
else if (ImageFormat.Png.Equals(img.RawFormat))
{
ext = "Png";
}
else if (ImageFormat.Gif.Equals(img.RawFormat))
{
ext = "Gif";
}
// do something witht his stream now
}
}).Wait();
return ext;
}
The block inside ContinueWith also runs asynchronously (if you look at the signature for ContinueWith, you'll see that it returns a Task as well). So, with the above code, essentially you're returning before any of that has a chance to execute.
Try doing:
Request.Content.ReadAsMultipartAsync().ContinueWith(...).Wait();
Also, not sure you need to go to the trouble of doing Request.Content.ReadAsMultipartAsync<MultipartMemoryStreamProvider>(new MultipartMemoryStreamProvider()); I believe Request.Content.ReadAsMultipartAsync() should suffice.
Hope that helps!

excel file upload using apache file upload

I am developing an testing automation tool in linux system. I dont have write permissions for tomcat directory which is located on server. I need to develop an application where we can select an excel file so that the excel content is automatically stored in already existing table.
For this pupose i have written an form to select an file which is posted to a servlet CommonsFileUploadServlet where i am storing the uploaded file and then calling ReadExcelFile class which reads the file path and create a vector for data in file which is used to sstore data in database.
My problem is that i am not able to store the uploaded file in directory. Is it necessary to have permission rights for tomcat to do this. Can i store the file on my system and pass the path to ReadExcelFile.class
Please guide me
My code is as follows:
Form in jsp
CommonsFileUploadServlet class code:
public void init(ServletConfig config) throws ServletException {
super.init(config);
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
PrintWriter out = response.getWriter();
response.setContentType("text/plain");
out.println("<h1>Servlet File Upload Example using Commons File Upload</h1>");
DiskFileItemFactory fileItemFactory = new DiskFileItemFactory ();
fileItemFactory.setSizeThreshold(1*1024*1024);
fileItemFactory.setRepository(new File("/home/example/Documents/Project/WEB-INF/tmp"));
ServletFileUpload uploadHandler = new ServletFileUpload(fileItemFactory);
try {
List items = uploadHandler.parseRequest(request);
Iterator itr = items.iterator();
while(itr.hasNext()) {
FileItem item = (FileItem) itr.next();
if(item.isFormField()) {
out.println("File Name = "+item.getFieldName()+", Value = "+item.getString());
} else {
out.println("Field Name = "+item.getFieldName()+
", File Name = "+item.getName()+
", Content type = "+item.getContentType()+
", File Size = "+item.getSize());
File file = new File("/",item.getName());
String realPath = getServletContext().getRealPath("/")+"/"+item.getName();
item.write(file);
ReadExcelFile ref= new ReadExcelFile();
String res=ref.insertReq(realPath,"1");
}
out.close();
}
}catch(FileUploadException ex) {
log("Error encountered while parsing the request",ex);
} catch(Exception ex) {
log("Error encountered while uploading file",ex);
}
}
}
ReadExcelFile code:
public static String insertReq(String fileName,String sno) {
//Read an Excel File and Store in a Vector
Vector dataHolder=readExcelFile(fileName,sno);
//store the data to database
storeCellDataToDatabase(dataHolder);
}
public static Vector readExcelFile(String fileName,String Sno)
{
/** --Define a Vector
--Holds Vectors Of Cells
*/
Vector cellVectorHolder = new Vector();
try{
/** Creating Input Stream**/
//InputStream myInput= ReadExcelFile.class.getResourceAsStream( fileName );
FileInputStream myInput = new FileInputStream(fileName);
/** Create a POIFSFileSystem object**/
POIFSFileSystem myFileSystem = new POIFSFileSystem(myInput);
/** Create a workbook using the File System**/
HSSFWorkbook myWorkBook = new HSSFWorkbook(myFileSystem);
int s=Integer.valueOf(Sno);
/** Get the first sheet from workbook**/
HSSFSheet mySheet = myWorkBook.getSheetAt(s);
/** We now need something to iterate through the cells.**/
Iterator rowIter = mySheet.rowIterator();
while(rowIter.hasNext())
{
HSSFRow myRow = (HSSFRow) rowIter.next();
Iterator cellIter = myRow.cellIterator();
Vector cellStoreVector=new Vector();
short minColIndex = myRow.getFirstCellNum();
short maxColIndex = myRow.getLastCellNum();
for(short colIndex = minColIndex; colIndex < maxColIndex; colIndex++)
{
HSSFCell myCell = myRow.getCell(colIndex);
if(myCell == null)
{
cellStoreVector.addElement(myCell);
}
else
{
cellStoreVector.addElement(myCell);
}
}
cellVectorHolder.addElement(cellStoreVector);
}
}catch (Exception e){e.printStackTrace(); }
return cellVectorHolder;
}
private static void storeCellDataToDatabase(Vector dataHolder)
{
Connection conn;
Statement stmt;
String query;
try
{
// get connection and declare statement
int z;
for (int i=1;i<dataHolder.size(); i++)
{
z=0;
Vector cellStoreVector=(Vector)dataHolder.elementAt(i);
String []stringCellValue=new String[10];
for (int j=0; j < cellStoreVector.size();j++,z++)
{
HSSFCell myCell = (HSSFCell)cellStoreVector.elementAt(j);
if(myCell==null)
stringCellValue[z]=" ";
else
stringCellValue[z] = myCell.toString();
}
try
{
//inserting into database
}
catch(Exception error)
{
String e="Error"+error;
System.out.println(e);
}
}
stmt.close();
conn.close();
System.out.println("success");
}
catch(Exception error)
{
String e="Error"+error;
System.out.println(e);
}
}
POI will happily open from an old InputStream, it needn't be a File one.
I'd suggest you look at the Commons FileUpload Streaming API and consider just passing the excel part straight to POI without touching the disk