summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorniko <niko>2012-10-24 23:31:38 (GMT)
committerniko <niko>2012-10-24 23:31:38 (GMT)
commit15b7152f1e238951bb958dca427af4470261d9ee (patch)
tree8780730dfada9d79bee7c0fea1938de1bb9e0f3b
parentc78e1481c53942e6f3b33f97150946565b2ad060 (diff)
downloadsynckolab-15b7152f1e238951bb958dca427af4470261d9ee.tar.gz
refactor attachment handling
-rw-r--r--src/chrome/content/synckolab/addressbook.js2
-rw-r--r--src/chrome/content/synckolab/addressbookTools.js53
-rw-r--r--src/chrome/content/synckolab/calendarTools.js5
-rw-r--r--src/chrome/content/synckolab/synckolab.js2
-rw-r--r--src/chrome/content/synckolab/tools.js156
-rw-r--r--test/synckolab/parser/kolab3/json/contact.complex.mime.json2
-rw-r--r--test/synckolab/tools/toolsTest.js6
7 files changed, 171 insertions, 55 deletions
diff --git a/src/chrome/content/synckolab/addressbook.js b/src/chrome/content/synckolab/addressbook.js
index 3ece3ab..7ea3803 100644
--- a/src/chrome/content/synckolab/addressbook.js
+++ b/src/chrome/content/synckolab/addressbook.js
@@ -691,7 +691,7 @@ synckolab.AddressBook = {
// mailing lists should be kept for "after" the normal messages have been parsed
if (checkForLater)
{
- if (this.tools.isMailList(fileContent))
+ if (this.tools.isMailList(fileContent.content))
{
return "LATER";
}
diff --git a/src/chrome/content/synckolab/addressbookTools.js b/src/chrome/content/synckolab/addressbookTools.js
index 8291e6f..ea6b64d 100644
--- a/src/chrome/content/synckolab/addressbookTools.js
+++ b/src/chrome/content/synckolab/addressbookTools.js
@@ -564,8 +564,9 @@ synckolab.addressbookTools.findCard = function (cards, vId, directory) {
*
* @param xml a dom node of a card or a string with the xml
* @param card the card object to update
+ * @param attachment optional attachment image (photo)
*/
-synckolab.addressbookTools.xml2Card = function (xml, card) {
+synckolab.addressbookTools.xml2Card = function (xml, card, attachment) {
var cur;
// if xml has a nodeType attribute - its already a node
@@ -990,14 +991,47 @@ synckolab.addressbookTools.xml2Card = function (xml, card) {
}
found = true;
break;
+
+ case "PHOTO": // kolab3
+ tok = cur.getChildNode("uri");
+ if(tok) {
+ value = tok.getFirstData();
+ types = value.substring(0, 30); // get the first few bytes
+ if(types.indexOf("data:") !== -1) { // got an inline data uri
+ // get the correct type:
+ // data:image/png;base64,BASE64DATA
+ types = types.substring(5); // cut away data:
+ tok = types.indexOf(";"); // search for the mime
+ where = synckolab.tools.file.analyzeMimeType(type.substring(0, tok).toLowerCase());
+ // set the type
+ this.setCardProperty(card, "PhotoType", "inline");
+ this.setCardProperty(card, "PhotoName", "photo." + where); // generate filename
+
+ where = type.substring(tok);
+ if(where.indexOf("base64") !== -1) {
+ tok = value.indexOf(",");
+ // get rid of newlines and =
+ this.setCardProperty(card, "PhotoData", value.substring(tok+1).replace("=3D", "").replace(/[\r\n \t=]+/g, ""));
+ } else {
+ synckolab.tools.logMessage("Unknown photo encoding: " + value.substring(0, 30), synckolab.global.LOG_INFO + synckolab.global.LOG_AB);
+ }
+ }
+ }
+
+ break;
+
+ // kolab 2: name of the picutre
case "PICTURE":
if (cur.firstChild === null) {
break;
}
- // we should have a picture named /tmp/synckolab.img - this will be moved if we keep this contact
this.setCardProperty(card, "PhotoName", cur.getFirstData());
+ // the attachment already happened in parseMessageContent
+
break;
+
+ // kolab 2: the uri of the picture
case "PICTURE-URI":
if (cur.firstChild === null) {
break;
@@ -2467,6 +2501,18 @@ synckolab.addressbookTools.parseMessageContent = function (message) {
ts : new Date().getTime()
// the current time
};
+
+ // its possible we have an image - attach it (still base64 encoded)
+ if(message.image) {
+ this.setCardProperty(card, "PhotoName", message.imageName); // generate filename
+ this.setCardProperty(card, "PhotoType", "inline");
+ this.setCardProperty(card, "PhotoData", message.image.replace("=3D", "").replace(/[\r\n \t=]+/g, ""));
+ }
+
+ // form now one: message is just a string (the content)
+ if(message.content) {
+ message = message.content;
+ }
// check for xml style
if (message.indexOf("<?xml") !== -1 || message.indexOf("<?XML") !== -1) {
@@ -2925,7 +2971,7 @@ synckolab.addressbookTools.message2Card = function (lines, card, startI, endI) {
found = true;
break;
case "PICTURE":
- // skip
+ // TODO picture
break;
case "PICTURE-URI":
var uri = tok[1];
@@ -3376,6 +3422,7 @@ synckolab.addressbookTools.card2Message = function (card, email, format, fields)
if (card.isMailList) {
return synckolab.tools.generateMail(this.getUID(card), email, "", "application/x-vnd.kolab.contact.distlist", true, synckolab.tools.text.utf8.encode(this.list2Xml(card, fields)), this.list2Human(card));
} else {
+ // generat email with optional image attachment
return synckolab.tools.generateMail(this.getUID(card), email, "", "application/x-vnd.kolab.contact", true, synckolab.tools.text.utf8.encode(this.card2Xml(card, fields)), this.card2Human(card), this.getCardProperty(card, "PhotoName"));
}
} else if(format === "xml-k3") {
diff --git a/src/chrome/content/synckolab/calendarTools.js b/src/chrome/content/synckolab/calendarTools.js
index 1cc602a..409b3c2 100644
--- a/src/chrome/content/synckolab/calendarTools.js
+++ b/src/chrome/content/synckolab/calendarTools.js
@@ -369,6 +369,11 @@ synckolab.calendarTools.message2json = function (fileContent, syncTasks) {
if(fileContent.synckolab) {
return fileContent;
}
+
+ // ignore any img attachment - just work with the content
+ if(fileContent.content) {
+ fileContent = fileContent.content;
+ }
// fileContent should be a string - with indexOf
if(!fileContent.indexOf) {
diff --git a/src/chrome/content/synckolab/synckolab.js b/src/chrome/content/synckolab/synckolab.js
index 6f81e7d..19b3ac4 100644
--- a/src/chrome/content/synckolab/synckolab.js
+++ b/src/chrome/content/synckolab/synckolab.js
@@ -992,7 +992,7 @@ synckolab.main.parseMessageRunner = function()
// fix the message for line truncs (last char in line is =)
// content might be a preparsed json
if(!synckolab.main.currentMessage.fileContent.synckolab) {
- synckolab.main.currentMessage.fileContent = synckolab.main.currentMessage.fileContent.replace(/\=\n(\S)/g, "$1");
+ synckolab.main.currentMessage.fileContent = synckolab.main.currentMessage.fileContent.content.replace(/\=\n(\S)/g, "$1");
}
skcontent = synckolab.main.gSync.parseMessage(synckolab.main.currentMessage.fileContent, synckolab.main.updateMessagesContent, (synckolab.main.gLaterMessages.pointer === 0));
}
diff --git a/src/chrome/content/synckolab/tools.js b/src/chrome/content/synckolab/tools.js
index 23aa22f..be1a9b9 100644
--- a/src/chrome/content/synckolab/tools.js
+++ b/src/chrome/content/synckolab/tools.js
@@ -241,6 +241,8 @@ equalsObject: function(a, b, skipFields)
/**
* Removes a possible mail header and extracts only the "real" content.
* This also trims the message and removes some common problems (like -- at the end)
+ * @param skcontent the mail content
+ * @returns Object with content and image ({ content: STRING, image: STRING });
*/
stripMailHeader: function (skcontent) {
if (skcontent === null) {
@@ -289,7 +291,9 @@ stripMailHeader: function (skcontent) {
skcontent = skcontent.substring(startPos, skcontent.length);
}
- return synckolab.tools.text.trim(skcontent);
+ return {
+ content: synckolab.tools.text.trim(skcontent)
+ };
}
this.logMessage("Stripping header from multipart message", synckolab.global.LOG_DEBUG);
@@ -343,9 +347,12 @@ stripMailHeader: function (skcontent) {
// check if we have an image attachment
var imgC = skcontent;
var imgIdx = imgC.search(/Content-Type:[ \t\r\n]+image/i);
+ var imgName = "photo.png";
+
+ // TODO figure out the picture name
// only works in xul environment
- if (imgIdx !== -1 && typeof Components !== "undefined")
+ if (imgIdx !== -1)
{
// get rid of the last part until the boundary
imgC = imgC.substring(imgIdx);
@@ -358,24 +365,9 @@ stripMailHeader: function (skcontent) {
idx = imgC.indexOf('\n\n');
imgC = imgC.substring(idx);
imgC = imgC.replace(/[\r\n \t\-]+/g, "");
- // now we got one line of data - write it in a tmpfile (unencoded - obviously)
- file.create(file.NORMAL_FILE_TYPE, parseInt("0666", 8));
- var stream = Components.classes['@mozilla.org/network/file-output-stream;1'].createInstance(Components.interfaces.nsIFileOutputStream);
- stream.init(file, 2, 0x200, false); // open as "write only"
- var fileIO = Components.classes["@mozilla.org/binaryoutputstream;1"].createInstance(Components.interfaces.nsIBinaryOutputStream);
- fileIO.setOutputStream(stream);
-
- try {
- var fcontent = atob(imgC);
- fileIO.writeBytes(fcontent, fcontent.length);
- }
- catch (ex) {
- // still continue
- this.logMessage("Error while handling image: " + ex + "\nStream:\n" + imgC, synckolab.global.LOG_INFO);
- }
-
- fileIO.close();
- stream.close();
+ } else {
+ // no image attached
+ imgC = null;
}
// check kolab XML first
@@ -523,19 +515,23 @@ stripMailHeader: function (skcontent) {
skcontent = synckolab.tools.text.quoted.decode(skcontent);
}
- return synckolab.tools.text.trim(skcontent);
+ return {
+ content: synckolab.tools.text.trim(skcontent),
+ imageName: imgName,
+ image: imgC
+ };
},
/**
* Create a message to be stored on the Kolab server
*
- * cid: the id of the card/event
- * adsubject: optional additional subject (iCal or vCard)
- * mime: the mime type (application/x-vnd.kolab.contact, application/x-vnd.kolab.event, application/x-vnd.kolab.task, application/x-vnd.kolab.journal, text/x-vcard, text/calendar)
- * part: true if this is a multipart message
- * content: the content for the message
- * hr: human Readable Part (optional)
- * profileimage: optional image attachment (the name of the image - it always resides in profile/Photos/XXX.jpg!)
+ * @param cid the id of the card/event
+ * @param adsubject optional additional subject (iCal or vCard)
+ * @param mime the mime type (application/x-vnd.kolab.contact, application/x-vnd.kolab.event, application/x-vnd.kolab.task, application/x-vnd.kolab.journal, text/x-vcard, text/calendar)
+ * @param part true if this is a multipart message
+ * @param content the content for the message
+ * @param hr human Readable Part (optional)
+ * @param profileimage optional image attachment (the name of the image - it always resides in profile/Photos/XXX.jpg!)
*/
generateMail: function (cid, mail, adsubject, mime, part, skcontent, hr, image){
// sometime we just do not want a new message :)
@@ -616,7 +612,7 @@ generateMail: function (cid, mail, adsubject, mime, part, skcontent, hr, image){
} else {
msg += acontent.slice(n);
}
- msg += "\n";
+ msg += "=\n";
n+=80;
}
}
@@ -640,24 +636,9 @@ generateMail: function (cid, mail, adsubject, mime, part, skcontent, hr, image){
file.append(imageName);
// file actually exists - we can try to read it and attach it
- if (file.exists() && file.isReadable())
- {
- // setup the input stream on the file
- var istream = Components.classes["@mozilla.org/network/file-input-stream;1"].createInstance(Components.interfaces.nsIFileInputStream);
- istream.init(file, 0x01, 4, null);
- var fileIO = Components.classes["@mozilla.org/binaryinputstream;1"].createInstance(Components.interfaces.nsIBinaryInputStream);
- fileIO.setInputStream(istream);
- // get the image
- var fileContent = "";
- var csize = 0;
- while ((csize = fileIO.available()) !== 0)
- {
- var data = fileIO.readBytes(csize);
- fileContent += btoa(data);
- }
- fileIO.close();
- istream.close();
-
+ var fileContent = this.readFileIntoBase64(file);
+
+ if (fileContent !== null) {
this.logMessage("got " + fileContent.length + " bytes", synckolab.global.LOG_WARNING);
// now we got the image into fileContent - lets attach
@@ -687,6 +668,46 @@ generateMail: function (cid, mail, adsubject, mime, part, skcontent, hr, image){
},
/**
+ * reads given file into a base64 string.
+ *
+ */
+readFileIntoBase64: function (file) {
+ var fileContent = "";
+ if (file.exists() && file.isReadable())
+ {
+ // setup the input stream on the file
+ var istream = Components.classes["@mozilla.org/network/file-input-stream;1"].createInstance(Components.interfaces.nsIFileInputStream);
+ istream.init(file, 0x01, 4, null);
+ var fileIO = Components.classes["@mozilla.org/binaryinputstream;1"].createInstance(Components.interfaces.nsIBinaryInputStream);
+ fileIO.setInputStream(istream);
+ // get the image
+ var csize = 0;
+ while ((csize = fileIO.available()) !== 0)
+ {
+ var data = fileIO.readBytes(csize);
+
+ // keep lines at 80 chars
+ var acontent = btoa(data);
+ var n = 0;
+ for (n= 0; n < acontent.length; )
+ {
+ if (n + 80 < acontent.length) {
+ fileContent += acontent.slice(n, n+80);
+ } else {
+ fileContent += acontent.slice(n);
+ }
+ fileContent += "=\n";
+ n+=80;
+ }
+ }
+ fileIO.close();
+ istream.close();
+ return fileContent;
+ }
+ return null;
+},
+
+/**
* Launch a url
*/
launchUrl: function (url)
@@ -857,6 +878,47 @@ getMsgFolder: function (accountKey, path)
synckolab.tools.file = {
+
+ analyzeMimeType: function(mime) {
+ if(!mime) {
+ return "data";
+ }
+
+ switch(mime.toLowerCase()) {
+ case "png":
+ case "image/png":
+ return "png";
+ case "jpeg":
+ case "jpg":
+ case "image/jpg":
+ return "png";
+ case "gif":
+ case "image/gif":
+ return "gif";
+ case "bmp":
+ case "image/bmp":
+ case "image/bitmap":
+ return "bmp";
+ case "tiff":
+ case "tif":
+ case "image/tif":
+ case "image/tiff":
+ return "tif";
+ }
+ return "data";
+ },
+
+ getMimeType: function(ext) {
+ switch(ext.toLowerCase()) {
+ case "png": return "image/png";
+ case "gif": return "image/gif";
+ case "bmp": return "image/bmp";
+ case "tif": case "tiff": return "image/tif";
+ case "jpeg": case "jpg": return "image/jpg";
+ }
+ return "data/unknown";
+ },
+
/**
* Copies a local file into any mail folder.
* In order to be displayed correct, make sure to create a complete message file!!!
diff --git a/test/synckolab/parser/kolab3/json/contact.complex.mime.json b/test/synckolab/parser/kolab3/json/contact.complex.mime.json
index 503f28f..9745af3 100644
--- a/test/synckolab/parser/kolab3/json/contact.complex.mime.json
+++ b/test/synckolab/parser/kolab3/json/contact.complex.mime.json
@@ -9,6 +9,8 @@
"LastName": "Firstname",
"Notes": "Notes",
"JobTitle": "Title",
+ "PhotoType": "inline:image/png",
+ "PhotoData": "iVBORw0KGgoAAAANSUhEUgAAAGQAAABkCAYAAABw4pVUAAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAAOTQAADpwB3vacVwAABAVJREFUeJztncFrFGcYxt/szLrJmk2yWTeojQktQluiqNFeKglSQmsOHhRyUApKPbeHQC8taKl4E0Hw4sGToAcvgojVQCg0B+2ph0DprTlYs7SQsNlkdzKzmf4DzxvYsCRP9Pkdn5n53iG/fPDy7TczZkIIIYQQov107PQNtI0vrR/mOfveveap/eAcSXeqRsYdSOwIEkKGhJAhIWRICBkSQsbua3u/slEUj346OoPyUrGEW1Uzm5mfycMDNRtB8ciHIy9RXswXi16NuYU5XOOx1VGsGUKGhJAhIWRICBkSQka40zfgcs6uoHjis4l7KB8fG8+ifPa3Wb9GZJdRPHZq7A7KTx45CWu8/uO1X6NFNEPIkBAyJIQMCSFDQsjYni4rxWtmnVOdsGMyM5s8PfkNyocPDwcor1QrcJwoiNzbOvvF2bsoL5fKsMZidRGOU7OaW6NVNEPIkBAyJIQMCSFDQshob5flbCTr/br3BcrPjJ854Q2V78/DTudt9S08P7YY5uXhslfC4jjGNdZwjaSewHwtXHNrtIpmCBkSQoaEkCEhZEgIGRJCxtba3vN4s1q5NADb2+MfHYMbyRqZBmw7zcxqq3jBLg5xe5tkcEu6buteCUsSfE0cOzUifH4jbLg1WkUzhAwJIUNCyJAQMiSEDL/LumQXvENDhaFHKB/sG4QbyZaiJfgTblLDXYuZWZzHnc56irum9SzOkw6/RtOaOE9xnjTxWJmwff/XmiFkSAgZEkKGhJAhIWT4XVYQuOtMS7Vl+J6ON3+/gedv7NvAA5X8G0uL+HUj5j1eCfu7TfLNjjmlzdlz19XEz3VuBc0QMiSEDAkhQ0LIkBAy/C7rQfOxd2jl6toCygufFJ6jPGlEPSiv5+p+/b1OXnByr/varAHyuinv6QLn/CByG9KW0QwhQ0LIkBAyJIQMCSFDQsjY2ka5+8nvKF6ZXv4Y5YWBnl9R3pfthOebmS1nl/C9dToXOO1wrj/nlbAocVYLvXZ4FcdBs32P2WiGkCEhZEgIGRJChoSQ0d6ncG/bfyheSatHUd71c/dDb6gDuQ+mUL6Y/gNX8tIUt0Z9/7qv7bVKXME74jIbeLXQ+SU6zKjLemeREDIkhAwJIUNCyNieN8p14NWhutUuepdEPzVeofxQbugWyivVRa/78r8A8Zf9CPOBzA0U70lC+PcK0qBtX5nQDCFDQsiQEDIkhAwJIWP3fYPqevg5ig8ePPALynu7e72tdfbnk3m8je54eArF+8v7n6G8mOnza7xwaugbVLsDCSFDQsiQEDIkhAwJIWP3tb0eNw2+MTnoyl7zLmlOx985h/DvwV6Nnk1qfNtaDc0QMiSEDAkhQ0LIkBAhhBBCCPEe8D+b5dDLeP4TXAAAAABJRU5ErkJggg"
"WebPage1": "www.homepage.org",
"WebPage2": "www.blog.test",
"HomeAddress": "Home Street",
diff --git a/test/synckolab/tools/toolsTest.js b/test/synckolab/tools/toolsTest.js
index 24eff6e..b58f210 100644
--- a/test/synckolab/tools/toolsTest.js
+++ b/test/synckolab/tools/toolsTest.js
@@ -31,9 +31,9 @@ test("synckolab.Node", function(){
* Test uuencoded message
*/
test("synckolab.tools.uudecode", function(){
- var content = readFile("test/synckolab/tools/data/uutest1.eml");
- content = synckolab.tools.stripMailHeader(content);
- equal(content.replace(/[\r\n]+/g, " "), ("BEGIN:VCARD " +
+ var message = readFile("test/synckolab/tools/data/uutest1.eml");
+ message = synckolab.tools.stripMailHeader(message);
+ equal(message.content.replace(/[\r\n]+/g, " "), ("BEGIN:VCARD " +
"VERSION:3.0 " +
"PRODID:-//kerio.com/Contacts//NONSGML v1.0//EN " +
"ADR;TYPE=HOME:;;Street 1\\nStreet 2;City;;zipcode;France " +