How can I get the contents of an attachment in a Mozilla Thunderbird extension? - thunderbird

I'm building an extension to Mozilla Thunderbird that does some translation of messages. I'd like to add a translate attachment feature, although I'm having a bit of trouble getting to the contents of each attachment. At the moment, I'm hooking into the attachmentListContext popup, and I have some code that gathers the relevant attachment URI and URLs. How can access the binary data of each relevant attachment?
Current code to get selected attachments:
handleAttachmentTranslate : function() {
// see code in msgHeaderViewOverlay.js in Thunderbird source
var attachmentList = document.getElementById('attachmentList');
var selectedAttachments = new Array();
for (var i in attachmentList.selectedItems) {
var attachment = attachmentList.selectedItems[i].attachment;
// we can now access attachment.url or attachment.uri, etc
selectedAttachments.push(attachment.url);
// or (ideally)
// alert(this.translate(getData(attachment.url)))
// but what is getData()?
}
},

FiltaQuilla addon does have the ability to save attachments etc. It may contain some code that's relevant.
Update Apr 25 2011: The page posted by speedball2001 has been modified between Mar 25 and Mar 31. Now it has a complete example. Check that out. It also points to a real extension that does exactly the attachment manipulation. This looks to be a promising answer.
The thought now is to hook up this new demo code to FiltaQuilla if necessary.

Have you checked MDN? They have howtos for this kind of stuff:
http://mdn.beonex.com/en/Extensions/Thunderbird/HowTos/Common_Thunderbird_Use_Cases/View_Message.html

Related

Intercept and edit multipart form-data POST request body in Browser

I've got a site that accepts file uploads which are sent as multipart/form-data within a POST request. To verify that the upload, which shows the filename afterwards, is secured against XSS I want to upload a file which contains HTML Tags in the filename.
This is actually harder than I expected. I can't create a file containing < on my filesystem (Windows). Also, I don't know a way to change the filename of the file input element inside the DOM before the upload (which is what I would do with normal/hidden inputs). So I thought about editing the POST body before it's uploaded, but I don't know how. Popular extensions (I recall Tamper Data, Tamper Dev) only let me change headers. I guess this is due to the plugin system of Chrome, which is the Browser I use.
So, what's the simplest way of manipulating the POST requests body? I could craft the entire request using cUrl, but I also need state, lots of additional parameters and session data etc. which gets quite complex... A simple way within the Browser would ne nice.
So, while this is not a perfect solution, it is at least a way to recreate and manipulate the form submit using FormData and fetch. It is not as generic as I'd like it to be, but it works in that case. Just use this code in the devtools to submit the form with the altered filename:
let formElement = document.querySelector('#idForm'); // get the form element
let oldForm = new FormData(formElement);
let newForm = new FormData;
// copy the FormData entry by entry
for (var pair of oldForm.entries()) {
console.log(pair[0]+': '+pair[1]);
if(typeof(pair[1]) == 'object' && pair[1].name) {
// alter the filename if it's a file
newForm.append(pair[0],pair[1],'yourNewFilename.txt');
} else {
newForm.append(pair[0],pair[1]);
}
}
// Log the new FormData
for (var pair of newForm.entries()) {
console.log(pair[0]+': ');
console.log(pair[1]);
}
// Submit it
fetch(formElement.action, {
method: formElement.method,
body: newForm
});
I'd still appreciate other approaches.

C++ Builder - Indy - Receiving certified emails

i'm using C++ builder 6 and Indy 9/10.
I'm coding to receive certified emails with attachments (basically pdf and xml files).
When i receive the email, it have a TidMessageParts with one multipart/mixed part and others parts for a small text, an xml attachment with info about the certification of the email and parts for digital signature and more.
My problem is: how to open the first part (multipart/mixed) to extract text and attachment in it.
See the answer i'll post.
Thank you.
Fabrizio
TIdMessagePart is a TCollectionItem descendant. The TCollectionItem::Collection property points to the owning (parent) TCollection, not to some inner collection, like you are expecting 1. That is why mp1 and mp are pointing at the same address in memory.
You don't "open a message part" in Indy. You simply iterate the TIdMessage::MessageParts collection from one end to the other until you find the particular part you are interested in, such as by looking at their class type, ContentType properties, etc. For example:
TIdMessageParts *mp = MailMessage->MessageParts;
for (int i = mp->Count-1; i > 0; --i)
{
TIdMessagePart *part = mp->Items[i];
if ((TIdAttachment *att = dynamic_cast<TIdAttachment*>(part)) != NULL)
{
...
}
else if ((TIdText *txt = dynamic_cast<TIdText*>(part)) != NULL)
{
if (txt->ContentType = "text/xml")
{
...
}
else if (txt->ContentType = "text/plain")
{
...
}
}
}
1: support for inner nested collections has not been implemented yet, not even in Indy 10. It won't be implemented until Indy 12 at the earliest.
The answer to the problem i posted:
#Remy told me a right observation i was unable to understand well: "The content is parsed and separated into additional collection items as needed."
The email i'm reading is a 'certified email' so the real email is the attachment with .eml extension that indy where reading and i ignored (my email client shows the attachments in the contained email joined with the attachments of the base email).
So, when i have right understood the Remy words and realized where to search the attachments:
i have estracted the .eml file to a folder
added a new TIdMessage component on the form (called PartMessage);
used LoadFromFile method to read the stored file
and now in PartMessage all attachments are visible and i was able to save them as files.
Thanks again to Remy as his words that where preciouses to reach the solution.
P.S. The solution works fine for Indy 9 and 10 with necessary adjustments due to different versions.
P.P.S. i don't know why during my tests i found the text that the email was s/mime encoded as it is not.

Return Email Message from Web Api

I'm not sure if this is possible, but I need to return an email message from a web api controller. Essentially, it would then allow the user the open the file (an eml or msg), make some changes and then send it to the relevant person.
Code wise I have a service that returns a MailMessage.
I have a controller that returns a pdf, using the file's byte array as it's content, but a mail message doesn't seem the easiest thing to convert.
Is this possible? I would rather not write the message to disk first if I can help it, but I could if this is the only solution.
I have just faced the same problem, and I resolved it like this:
var stream = new MemoryStream(); // this has to contain your file content
var response = new HttpResponseMessage(HttpStatusCode.OK)
{
Content = new ByteArrayContent(stream.GetBuffer())
};
response.Content.Headers.ContentType = new MediaTypeHeaderValue("message/rfc822");
response.Content.Headers.ContentDisposition = new ContentDispositionHeaderValue("attachment")
{
FileName = "test.eml"
};
If you want to know how to generate emails and do not send the but save them to disk instead, you can check the solution proposed here: How to save MailMessage object to disk as *.eml or *.msg file

phpmailer attach pdf from dynamic url

I'm sending an email using phpmailer. I have web service to generate pdf. This pdf is not uploading or downloading to anywhere.
PDF url is like
http://mywebsite/webservices/report/sales_invoice.php?company=development&sale_id=2
I need to attach this dynamic pdf url to my email.
My email sending service url is like
http://mywebsite/webservices/mailservices/sales_email.php
Below is the code which i am using to attach the pdf.
$pdf_url = "../report/sales_invoice.php?company=development&sale_id=2";
$mail->AddAttachment($pdf_url);
Sending message is working but pdf doesn't attached. It gives below message.
Could not access file: ../report/sales_invoice.php?company=development&sale_id=2
I need some help
To have the answer right here:
As phpmailer would not auto-fetch the remote content, you need to do it yourself.
So you go:
// we can use file_get_contents to fetch binary data from a remote location
$url = 'http://mywebsite/webservices/report/sales_invoice.php?company=development&sale_id=2';
$binary_content = file_get_contents($url);
// You should perform a check to see if the content
// was actually fetched. Use the === (strict) operator to
// check $binary_content for false.
if ($binary_content === false) {
throw new Exception("Could not fetch remote content from: '$url'");
}
// $mail must have been created
$mail->AddStringAttachment($binary_content, "sales_invoice.pdf", $encoding = 'base64', $type = 'application/pdf');
// continue building your mail object...
Some other things to watch out for:
Depending on the server response time, your script might run into timing issues. Also, the fetched data might be pretty large and could cause php to exceed its memory allocation.

Soundmanager2 won't load sound from google translate

I want to speak some text; I can get the audio-file(mp3) from google translate tts if I enter a properly formatted url in the browser.
But if I try to createSound it, I only see a 404-error in firebug.
I use this, but it fails:
soundManager.createSound(
{id:'testsound',
autoLoad:true,
url:'http://translate.google.com/translate_tts?ie=UTF-8&tl=da&q=testing'}
);
I have pre-fetched the fixed voiceprompts with wget, so they are as local mp3-files on the same webserver as the page. But I would like to say a dynamic prompt.
I see this was asked long time ago, but I have come to a similar issue, and I was able to make it work for Chrome and Firefox, but with the Audio Tag.
Here is the demo page I have made
http://jsfiddle.net/royriojas/SE6ET/
here is the code that made the trick for me...
var sayIt;
function createSayIt() {
// Tiny trick to make the request to google actually work!, they deny the request if it comes from a page but somehow it works when the function is inside this iframe!
//create an iframe without setting the src attribute
var iframe = document.createElement('iframe');
// don't know if the attribute is required, but it was on the codepen page where this code worked, so I just put this here. Might be not needed.
iframe.setAttribute('sandbox', 'allow-scripts allow-same-origin allow-pointer-lock');
// hide the iframe... cause you know, it is ugly letting iframes be visible around...
iframe.setAttribute('class', 'hidden-iframe')
// append it to the body
document.body.appendChild(iframe);
// obtain a reference to the contentWindow
var v = iframe.contentWindow;
// parse the sayIt function in this contentWindow scope
// Yeah, I know eval is evil, but its evilness fixed this issue...
v.eval("function sayIt(query, language, cb) { var audio = new Audio(); audio.src = 'http://translate.google.com/translate_tts?ie=utf-8&tl=' + language + '&q=' + encodeURIComponent(query); cb && audio.addEventListener('ended', cb); audio.play();}");
// export it under sayIt variable
sayIt = v.sayIt;
}
I guess that I was able to byPass that restriction. They could potentially fix this hack in the future I don't know. I actually hope they don't...
You can also try to use the Text2Speech HTML5 api, but it is still very young...
IE 11 is not working with this hack, some time in the future I might try to fix it
Even though you see this as a 404 error, you're actually running into a cross-domain restriction.
Some of the response headers from that 404 will also give you a clue of what's going on:
X-Content-Type-Options:nosniff
X-XSS-Protection:1; mode=block
So, you won't be able to do this client-side, as Google does not (and probably will never) allow you to do so.
In order to do this dynamic loading of audio, you need to work around this x-domain restriction by setting up a proxy on your own server, which would download whatever file requested by the end-user from Google's servers (via wget or whatever) and spitting whatever data comes from google.
Code I used to reproduce the issue:
soundManager.setup({
url: 'swf',
onready: function() {
soundManager.createSound({
id:'testsound',
autoLoad:true,
url:'http://translate.google.com/translate_tts?ie=UTF-8&tl=da&q=testing'
});
}
});
Your code should look like this:
soundManager.createSound({
id:'testsound',
autoLoad:true,
url:'/audioproxy.php?ie=UTF-8&tl=da&q=testing' // Same domain!
});
Regards and good luck!