summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorniko <niko>2012-10-21 21:06:50 (GMT)
committerniko <niko>2012-10-21 21:06:50 (GMT)
commit36fa4bd13ea734583d49d38098a216dfdf943744 (patch)
treeb0477998d3b64d7f6bd4e787ab109475a7f9e408
parenteaca0119bdadb63986fc3525ee2bebd6a4c140ec (diff)
downloadsynckolab-36fa4bd13ea734583d49d38098a216dfdf943744.tar.gz
rewrite of distribution list handling
-rw-r--r--src/chrome/content/synckolab/addressbook.js364
-rw-r--r--src/chrome/content/synckolab/addressbookTools.js213
-rw-r--r--src/chrome/content/synckolab/tools.js16
-rw-r--r--test/synckolab/parser/kolab2/contactTest.js4
-rw-r--r--test/synckolab/parser/kolab2/json/list.test.json1
-rw-r--r--test/synckolab/parser/kolab2/json/list.test2.json52
-rw-r--r--test/synckolab/parser/kolab2/raw/list.test2.xml64
-rw-r--r--test/synckolab/tools/textTest.js1
8 files changed, 527 insertions, 188 deletions
diff --git a/src/chrome/content/synckolab/addressbook.js b/src/chrome/content/synckolab/addressbook.js
index 6176b5f..3ece3ab 100644
--- a/src/chrome/content/synckolab/addressbook.js
+++ b/src/chrome/content/synckolab/addressbook.js
@@ -68,7 +68,8 @@ synckolab.AddressBook = {
processedIds: [], // remember all processed ids to remove duplicates
/**
- * add the address book specific configuration to the config object
+ * add the address book specific configuration to the config object.
+ * this is called every time the config is re-/read
* @param config the config object (name is already prefilled)
* @param pref a nsIPrefBranch for reading of the configuration
*/
@@ -133,11 +134,18 @@ synckolab.AddressBook = {
cUID = synckolab.addressbookTools.getUID(newCard);
if (!cUID) {
// generate a unique id (will random be enough for the future?)
- cUID = "sk-vc-" + synckolab.tools.text.randomVcardId();
+ if (newCard.isMailList) {
+ // marker for distribution lists
+ cUID = "sk-dl-" + synckolab.tools.text.randomVcardId();
+ } else {
+ // vcards
+ cUID = "sk-vc-" + synckolab.tools.text.randomVcardId();
+ }
+
synckolab.addressbookTools.setUID(newCard, cUID);
// avoid loop
synckolab.global.triggerRunning = true;
- cConfig.addressBook.modifyCard(newCard);
+ this.tools.modifyTBEntry(cConfig, newCard);
synckolab.global.triggerRunning = false;
}
@@ -250,8 +258,17 @@ synckolab.AddressBook = {
var cUID = synckolab.addressbookTools.getUID(item);
// the item doesnt have an uuid - create one
if(!cUID) {
- synckolab.addressbookTools.setUID(item, "sk-vc-" + synckolab.tools.text.randomVcardId());
- this.gConfig.addressBook.modifyCard(item);
+ // generate a unique id (will random be enough for the future?)
+ if (item.isMailList) {
+ // marker for distribution lists
+ cUID = "sk-dl-" + synckolab.tools.text.randomVcardId();
+ } else {
+ // vcards
+ cUID = "sk-vc-" + synckolab.tools.text.randomVcardId();
+ }
+ synckolab.addressbookTools.setUID(item, cUID);
+ this.tools.modifyTBEntry(this.gConfig, item);
+
if (item.isMailList) {
synckolab.tools.logMessage("adding unsaved list: " + cUID, synckolab.global.LOG_INFO + synckolab.global.LOG_AB);
} else {
@@ -345,6 +362,86 @@ synckolab.AddressBook = {
// the current sync database filen (a file with uid:size:date:localfile)
// uid -> filename database - main functions needs to know the name
config.dbFile = synckolab.tools.file.getHashDataBaseFile(config);
+
+ // the uid database for the distribution lists (name -> hash; hash -> name); read from the config
+ config.listLookup = {
+ // db file
+ dbFile: synckolab.tools.file.getSyncDbFile(config, "listUUID.database"),
+ db: null, // the database
+ idToName: null, // hashmap: uuid -> name
+ nameToId: null, // hashmap: name -> uuid
+
+ /**
+ * read and initialize the hashmaps for lookup
+ */
+ read: function() {
+ // read the array as json: {[ {name: "string", uid: "string"} ,...]}
+ this.db = synckolab.tools.readSyncDBFile(this.dbFile);
+ // make sure we ALWAYS have an array
+ if(!this.db) {
+ this.db = [];
+ }
+ this.idToName = {};
+ this.nameToId = {};
+ for(var i = 0; i < this.db.length; i++) {
+ var curListEntry = this.db[i];
+ this.idToName[curListEntry.uuid] = curListEntry.name;
+ this.nameToId[curListEntry.name] = curListEntry.uuid;
+ }
+ },
+
+ /**
+ * write the list back to the file (or create if not existant)
+ */
+ write: function() {
+ synckolab.tools.writeSyncDBFile(this.dbFile, this.db);
+ },
+
+ /**
+ * get the UUID to a given name
+ * @return null if the uuid does not exist
+ */
+ getUUID: function(name) {
+ return this.nameToId[name];
+ },
+
+ /**
+ * get the name to a given UUID
+ * @return null if the name does not exist
+ */
+ getName: function(uuid) {
+ return this.idToName[uuid];
+ },
+
+ add: function (name, uuid) {
+ var curListEntry = {
+ name: name,
+ uuid: uuid
+ };
+ this.db.push(curListEntry);
+ this.idToName[curListEntry.uuid] = curListEntry.name;
+ this.nameToId[curListEntry.name] = curListEntry.uuid;
+
+ // write every time we have a new entry
+ this.write();
+ },
+
+ // remove an entry, persist - rereading is not really necessary
+ remove: function(uuid) {
+ for(var i = 0; i < this.db.length; i++) {
+ if(uuid === this.db[i].uuid) {
+ // remove id
+ this.db.splice(i, 1);
+ break;
+ }
+ }
+ // write to db
+ this.write();
+ }
+ };
+
+ // make sure its filled
+ config.listLookup.read();
},
init: function (config, itemList, document) {
@@ -388,17 +485,14 @@ synckolab.AddressBook = {
while (lCards.hasMoreElements() && (card = lCards.getNext()))
{
// get the right interface
- card = card.QueryInterface(Components.interfaces.nsIAbCard);
-
- // create a UUID if it does not exist!
- var cUID = this.tools.getUID(card);
- if (cUID === null || cUID === "")
- {
- cUID = "sk-vc-" + synckolab.tools.text.randomVcardId();
- this.tools.setUID(card, cUID);
- this.gConfig.addressBook.modifyCard(card);
+ if(card.isMailList) {
+ card = card.QueryInterface(Components.interfaces.nsIAbDirectory);
+ } else {
+ card = card.QueryInterface(Components.interfaces.nsIAbCard);
}
+ // create a UUID if it does not exist!
+ var cUID = this.tools.getTbirdUUID(card, this.gConfig);
this.gCardDB.put(cUID, card);
}
},
@@ -468,14 +562,7 @@ synckolab.AddressBook = {
card = card.QueryInterface(Components.interfaces.nsIAbCard);
// create a UUID if it does not exist!
- var cUID = synckolab.addressbookTools.getUID(card);
- if (cUID === null || cUID === "")
- {
- cUID = "sk-vc-" + synckolab.tools.text.randomVcardId();
- synckolab.addressbookTools.setUID(card, cUID);
- message.config.addressBook.modifyCard(card);
- }
-
+ var cUID = this.tools.getTbirdUUID(card, message.config);
message.config.cardDb.put(cUID, card);
}
}
@@ -638,10 +725,9 @@ synckolab.AddressBook = {
// parse the new item
newCard = this.tools.parseMessageContent(fileContent);
-
if (newCard && newCard.isMailList)
{
- synckolab.tools.logMessage("got mailing list " + this.tools.getUID(newCard), synckolab.global.LOG_WARNING + synckolab.global.LOG_AB);
+ synckolab.tools.logMessage("got mailing list " + this.tools.getUID(newCard) +"\n " + newCard.toSource(), synckolab.global.LOG_WARNING + synckolab.global.LOG_AB);
}
/*
if (newCard && newCard.isMailList)
@@ -693,9 +779,16 @@ synckolab.AddressBook = {
// ok lets see if we have this one already
var foundCard = this.gCardDB.get(this.gCurUID);
+
// get the dbfile from the local disk
var idxEntry = synckolab.tools.file.getSyncDbFile(this.gConfig, this.tools.getUID(newCard));
- synckolab.tools.logMessage("got entry from db: " + foundCard, synckolab.global.LOG_DEBUG + synckolab.global.LOG_AB);
+ // convert card to pojo for easier internal work
+ if(foundCard) {
+ foundCard = synckolab.addressbookTools.card2Pojo(foundCard, this.gCurUID);
+ synckolab.tools.logMessage("got entry from db: " + foundCard.toSource(), synckolab.global.LOG_DEBUG + synckolab.global.LOG_AB);
+ } else {
+ synckolab.tools.logMessage("unable to find card in DB: " + this.gCurUID, synckolab.global.LOG_DEBUG + synckolab.global.LOG_AB);
+ }
// a new card or locally deleted
if (foundCard === null)
@@ -1072,55 +1165,60 @@ synckolab.AddressBook = {
var curItem = cur;
// mailing lists are nsIABDirectory
-
if (cur.isMailList)
{
synckolab.tools.logMessage("Convert Mailing list to nsIABDirectory", synckolab.global.LOG_DEBUG + synckolab.global.LOG_AB);
curItem = Components.classes["@mozilla.org/abmanager;1"].getService(Components.interfaces.nsIAbManager).getDirectory(cur.mailListURI);
}
- // check for this entry
- if (this.tools.getUID(curItem) === null)
+ var curListItem;
+
+ // get the UUID and create on eif it does not exist yet
+ var cUID = this.tools.getTbirdUUID(curItem, this.gConfig);
+
+ var alreadyProcessed = false;
+
+ // check if we have this uid in the messages
+ for (var i = 0; i < this.folderMessageUids.length; i++)
{
-
- if (cur.isMailList)
+ if (cUID === this.folderMessageUids[i])
{
- try
- {
- // select the next card
- this.gCards.next();
- }
- catch (extMLCard)
- {
- // no next.. but we find that out early enough
- }
- // skip this one.. there simply ARE no valid mailing list without UID
+ synckolab.tools.logMessage("we got this contact already: " + cUID, synckolab.global.LOG_DEBUG + synckolab.global.LOG_AB);
return null;
}
+ }
+
+ // check the local database file
+ idxEntry = synckolab.tools.file.getSyncDbFile(this.gConfig, cUID);
+
+ if(!idxEntry) {
+ alert("unable to get sync db file for " + cUID + " please check the access rights in your profile folder!");
+ return;
+ }
+
+ // we got an idxEntry file... this means we do not have it on the imap server any more - delete it
+ if (idxEntry && idxEntry.exists() && !this.forceServerCopy)
+ {
-
- // look at new card
- // generate a unique id (will random be enough for the future?)
- synckolab.addressbookTools.setUID(curItem, "sk-vc-" + synckolab.tools.text.randomVcardId());
- if (cur.isMailList) {
- synckolab.tools.logMessage("adding unsaved list: " + this.tools.getUID(curItem), synckolab.global.LOG_INFO + synckolab.global.LOG_AB);
+ if (!curItem.isMailList)
+ {
+ this.deleteList.appendElement(curItem, false);
} else {
- synckolab.tools.logMessage("adding unsaved card: " + this.tools.getUID(curItem), synckolab.global.LOG_INFO + synckolab.global.LOG_AB);
+ // delete list
+ this.gConfig.addressBook.deleteDirectory(curItem);
}
-
- this.gConfig.addressBook.modifyCard(cur);
-
+
// create a new item in the itemList for display
this.curItemInList = this.doc.createElement("treerow");
this.curItemInListId = this.doc.createElement("treecell");
this.curItemInListStatus = this.doc.createElement("treecell");
this.curItemInListContent = this.doc.createElement("treecell");
- this.curItemInListId.setAttribute("label", this.tools.getUID(curItem));
- this.curItemInListStatus.setAttribute("label", synckolab.global.strBundle.getString("addToServer"));
+ this.curItemInListId.setAttribute("label", cUID);
+ this.curItemInListStatus.setAttribute("label", synckolab.global.strBundle.getString("localDelete"));
if (curItem.isMailList) {
this.curItemInListContent.setAttribute("label", synckolab.global.strBundle.getString("mailingList") + " <" + curItem.DisplayName + ">");
} else {
- this.curItemInListContent.setAttribute("label", cur.firstName + " " + curItem.lastName + " <" + curItem.primaryEmail + ">");
+ this.curItemInListContent.setAttribute("label", curItem.firstName + " " + curItem.lastName + " <" + curItem.primaryEmail + ">");
}
this.curItemInList.appendChild(this.curItemInListId);
@@ -1129,133 +1227,55 @@ synckolab.AddressBook = {
if (this.itemList)
{
- var curListItem = this.doc.createElement("treeitem");
+ curListItem = this.doc.createElement("treeitem");
curListItem.appendChild(this.curItemInList);
this.itemList.appendChild(curListItem);
synckolab.tools.scrollToBottom(this.itemList);
}
- // and write the message
- abcontent = synckolab.addressbookTools.card2Message(curItem, this.gConfig.email, this.gConfig.format);
- synckolab.tools.logMessage("New Card " + this.tools.getUID(curItem), synckolab.global.LOG_INFO + synckolab.global.LOG_AB);
-
- // get the dbfile from the local disk
- idxEntry = synckolab.tools.file.getSyncDbFile(this.gConfig, this.tools.getUID(curItem));
- // write the current content in the sync-db file (parse to json object first)
- synckolab.tools.writeSyncDBFile(idxEntry, this.tools.parseMessageContent(synckolab.tools.stripMailHeader(abcontent)));
+ // also remove the local db file since we deleted the contact on the server
+ idxEntry.remove(false);
+ return null;
}
- else
+
+ // ok its NOT in our internal db... this means its new - so add it to imap
+ // create a new item in the itemList for display
+ this.curItemInList = this.doc.createElement("treerow");
+ this.curItemInListId = this.doc.createElement("treecell");
+ this.curItemInListStatus = this.doc.createElement("treecell");
+ this.curItemInListContent = this.doc.createElement("treecell");
+ this.curItemInListId.setAttribute("label", cUID);
+ this.curItemInListStatus.setAttribute("label", synckolab.global.strBundle.getString("addToServer"));
+ if (curItem.isMailList) {
+ this.curItemInListContent.setAttribute("label", synckolab.global.strBundle.getString("mailingList") + " <" + curItem.DisplayName + ">");
+ } else {
+ this.curItemInListContent.setAttribute("label", curItem.firstName + " " + curItem.lastName + " <" + curItem.primaryEmail + ">");
+ }
+
+ this.curItemInList.appendChild(this.curItemInListId);
+ this.curItemInList.appendChild(this.curItemInListStatus);
+ this.curItemInList.appendChild(this.curItemInListContent);
+
+ if (this.itemList)
{
- var alreadyProcessed = false;
-
- // check if we have this uid in the messages
- for (var i = 0; i < this.folderMessageUids.length; i++)
- {
- if (this.tools.getUID(curItem) === this.folderMessageUids[i] && this.tools.getUID(curItem))
- {
- synckolab.tools.logMessage("we got this contact already: " + this.tools.getUID(curItem), synckolab.global.LOG_DEBUG + synckolab.global.LOG_AB);
- alreadyProcessed = true;
- break;
- }
- }
-
- // ok we should have this card in our db (since it has a custom4)
- // but not on the imap account. if we got this entry in our internal db
- // it has been deleted on the server, and we don't know about it yet
- if (!alreadyProcessed)
- {
- // get the dbfile from the local disk
- idxEntry = synckolab.tools.file.getSyncDbFile(this.gConfig, this.tools.getUID(curItem));
- if (this.tools.getUID(curItem) === null)
- {
- alert("UID is NULL???" + curItem.custom4);
- }
-
- if(!idxEntry) {
- alert("unable to get sync db file for " + curItem.custom4 + " please check the access rights in your profile folder!");
- return;
- }
-
- if (idxEntry && idxEntry.exists() && !this.forceServerCopy)
- {
-
- if (!curItem.isMailList)
- {
- this.deleteList.appendElement(curItem, false);
- } else {
- // delete list
- this.gConfig.addressBook.deleteDirectory(curItem);
- }
-
- // create a new item in the itemList for display
- this.curItemInList = this.doc.createElement("treerow");
- this.curItemInListId = this.doc.createElement("treecell");
- this.curItemInListStatus = this.doc.createElement("treecell");
- this.curItemInListContent = this.doc.createElement("treecell");
- this.curItemInListId.setAttribute("label", this.tools.getUID(curItem));
- this.curItemInListStatus.setAttribute("label", synckolab.global.strBundle.getString("localDelete"));
- if (curItem.isMailList) {
- this.curItemInListContent.setAttribute("label", synckolab.global.strBundle.getString("mailingList") + " <" + curItem.DisplayName + ">");
- } else {
- this.curItemInListContent.setAttribute("label", curItem.firstName + " " + curItem.lastName + " <" + curItem.primaryEmail + ">");
- }
-
- this.curItemInList.appendChild(this.curItemInListId);
- this.curItemInList.appendChild(this.curItemInListStatus);
- this.curItemInList.appendChild(this.curItemInListContent);
-
- if (this.itemList)
- {
- var curListItem = this.doc.createElement("treeitem");
- curListItem.appendChild(this.curItemInList);
- this.itemList.appendChild(curListItem);
- synckolab.tools.scrollToBottom(this.itemList);
- }
-
- // also remove the local db file since we deleted the contact on the server
- idxEntry.remove(false);
-
- }
- // ok its NOT in our internal db... add it
- else
- {
-
- // create a new item in the itemList for display
- this.curItemInList = this.doc.createElement("treerow");
- this.curItemInListId = this.doc.createElement("treecell");
- this.curItemInListStatus = this.doc.createElement("treecell");
- this.curItemInListContent = this.doc.createElement("treecell");
- this.curItemInListId.setAttribute("label", this.tools.getUID(curItem));
- this.curItemInListStatus.setAttribute("label", synckolab.global.strBundle.getString("addToServer"));
- if (curItem.isMailList) {
- this.curItemInListContent.setAttribute("label", synckolab.global.strBundle.getString("mailingList") + " <" + curItem.DisplayName + ">");
- } else {
- this.curItemInListContent.setAttribute("label", curItem.firstName + " " + curItem.lastName + " <" + curItem.primaryEmail + ">");
- }
-
- this.curItemInList.appendChild(this.curItemInListId);
- this.curItemInList.appendChild(this.curItemInListStatus);
- this.curItemInList.appendChild(this.curItemInListContent);
-
- if (this.itemList)
- {
- var curListItem = this.doc.createElement("treeitem");
- curListItem.appendChild(this.curItemInList);
- this.itemList.appendChild(curListItem);
- synckolab.tools.scrollToBottom(this.itemList);
- }
-
- // and write the message
- abcontent = synckolab.addressbookTools.card2Message(curItem, this.gConfig.email, this.gConfig.format);
- synckolab.tools.logMessage("New Card " + this.tools.getUID(curItem), synckolab.global.LOG_INFO + synckolab.global.LOG_AB);
-
- // get the dbfile from the local disk
- idxEntry = synckolab.tools.file.getSyncDbFile(this.gConfig, this.tools.getUID(curItem));
- // write the current content in the sync-db file
- synckolab.tools.writeSyncDBFile(idxEntry, this.tools.parseMessageContent(synckolab.tools.stripMailHeader(abcontent)));
- }
- }
+ curListItem = this.doc.createElement("treeitem");
+ curListItem.appendChild(this.curItemInList);
+ this.itemList.appendChild(curListItem);
+ synckolab.tools.scrollToBottom(this.itemList);
}
+
+ // convert to a pojo
+ var curCard = synckolab.addressbookTools.card2Pojo(curItem, cUID);
+
+ // and write the message
+ abcontent = synckolab.addressbookTools.card2Message(curCard, this.gConfig.email, this.gConfig.format);
+ synckolab.tools.logMessage("New Card " + cUID, synckolab.global.LOG_INFO + synckolab.global.LOG_AB);
+
+ // get the dbfile from the local disk
+ idxEntry = synckolab.tools.file.getSyncDbFile(this.gConfig, cUID);
+
+ // write the current content in the sync-db file
+ synckolab.tools.writeSyncDBFile(idxEntry, curCard);
// return the cards content
return abcontent;
diff --git a/src/chrome/content/synckolab/addressbookTools.js b/src/chrome/content/synckolab/addressbookTools.js
index 6f9a778..cf91c7d 100644
--- a/src/chrome/content/synckolab/addressbookTools.js
+++ b/src/chrome/content/synckolab/addressbookTools.js
@@ -76,9 +76,13 @@ synckolab.addressbookTools = {
if (card.isMailList && !card.getProperty) {
switch (prop) {
// really old: cannot use uid field
+ case "uuid":
case "uid":
case "UID":
+ case "UUID":
case "Uid":
+ prop = "UUID";
+ break;
case "Name":
if (card.dirName) {
prop = "dirName";
@@ -288,13 +292,14 @@ synckolab.addressbookTools = {
if (!card) {
return;
}
-
+ /*
// mailing lists dont have uuid
if (card.isMailList) {
return;
}
// listNickName is the UID
+ */
this.setCardProperty(card, "UUID", uid);
}
};
@@ -1016,7 +1021,6 @@ synckolab.addressbookTools.xml2Card = function (xml, card) {
var cnotes = cur.getFirstData();
this.setCardProperty(card, "Notes", cnotes.replace(/\\n/g, "\n"));
- synckolab.tools.logMessage("cur.firstchild.data.length=" + cur.firstChild.data.length + " - cnotes=" + cnotes.length + " - card.notes=" + this.getCardProperty(card, "Notes").length, synckolab.global.LOG_DEBUG + synckolab.global.LOG_AB);
found = true;
break;
case "DEPARTMENT":
@@ -1156,9 +1160,14 @@ synckolab.addressbookTools.xml2Card = function (xml, card) {
isMailList: false,
DisplayName: cur.getXmlResult(["dn","text"], null),
PrimaryEmail: cur.getXmlResult(["email","text"], null),
- UUID: cur.getXmlResult(["uid","uri"], null)
+ UUID: cur.getXmlResult(["uid","urn"], null)
};
+ // might be text, not urn
+ if(!value.UUID) {
+ value.UUID = cur.getXmlResult(["uid","text"], null);
+ }
+
if(value.UUID) {
card.contacts.push(value);
}
@@ -1253,9 +1262,9 @@ synckolab.addressbookTools.xml2Card = function (xml, card) {
};
/**
- * Convert a given mailing list (card) into a pojo
+ * Convert a given mailing list (card) into a pojo (using the given uid)
*/
-synckolab.addressbookTools.list2Pojo = function (card) {
+synckolab.addressbookTools.list2Pojo = function (card, uid) {
var pojo = {
synckolab : synckolab.config.version, // synckolab version
type : "maillist", // a contact
@@ -1265,13 +1274,17 @@ synckolab.addressbookTools.list2Pojo = function (card) {
// the contacts
};
- pojo.displayName = this.getUID(card);
+ pojo.UUID = uid;
+
if (this.haveCardProperty(card, "Notes")) {
pojo.Notes = this.getCardProperty(card, "Notes");
}
if (this.haveCardProperty(card, "NickName")) {
pojo.NickName = this.getCardProperty(card, "NickName");
}
+ if (this.haveCardProperty(card, "DisplayName")) {
+ pojo.DisplayName = this.getCardProperty(card, "DisplayName");
+ }
var cList = this.abListObject(card);
var lCards = cList.childCards;
@@ -1290,6 +1303,9 @@ synckolab.addressbookTools.list2Pojo = function (card) {
cardObj.UUID = this.getUID(cur);
cardObj.DisplayName = this.getCardProperty(cur, "DisplayName");
cardObj.PrimaryEmail = this.getCardProperty(cur, "PrimaryEmail");
+
+ synckolab.tools.logMessage("card of list " + pojo.DisplayName + ": " + cardObj.UUID, synckolab.global.LOG_DEBUG + synckolab.global.LOG_AB);
+
pojo.contacts.push(cardObj);
}
} else {
@@ -1721,6 +1737,78 @@ synckolab.addressbookTools.card2Kolab3 = function (card, skipHeader, fields) {
};
/**
+ * creates a pojo out of a given card
+ * @param card nsIAbCard: the adress book card
+ * @param uid the uid of the card
+ * @param fields Array: all the fields not being held in the default card
+ */
+synckolab.addressbookTools.card2Pojo = function (card, uid, fields) {
+ if(card.isMailList) {
+ return this.list2Pojo(card, uid);
+ }
+
+ var pojo = {
+ synckolab : synckolab.config.version, // synckolab version
+ type : "contact", // a contact
+ isMailList : false,
+ ts : new Date().getTime() // the current time
+ };
+
+ // go through all fields
+ /*
+ ignore this since thunderbird implementation just does not work
+ var s = cur.getXmlResult("TIMESTAMP", "");
+ */
+ // this.setCardProperty(card, "LastModifiedDate", string2DateTime(s).getTime() / 1000);
+ var copyFields = ["FirstName", "LastName", "DisplayName", "JobTitle", "NickName",
+ "PrimaryEmail", "SecondEmail", "Category", "Company",
+ "HomePhone", "WorkPhone", "CellularNumber", "FaxNumber", "PagerNumber",
+ "CellularNumber", "HomePhone", "FaxNumber", "WorkPhone",
+ "PagerNumber", "BirthYear", "BirthMonth", "BirthDay",
+ "AnniversaryYear", "AnniversaryMonth", "AnniversaryDay", "HomeAddress",
+ "HomeAddress2", "HomeCity", "HomeState", "HomeZipCode", "HomeCountry", "WorkAddress",
+ "WorkAddress2", "WorkCity", "WorkState", "WorkZipCode", "WorkCountry",
+ "PhotoName", "PhotoType", "PhotoURI", "Notes", "Department",
+ "WebPage1", "WebPage2", "WebPage3",
+ "AimScreenName", "Custom1", "Custom2", "Custom3", "Custom4", "AllowRemoteContent", "PreferMailFormat"];
+ var i;
+ for(i = 0; i < copyFields.length; i++) {
+ this.setCardProperty(pojo, copyFields[i], this.getCardProperty(card, copyFields[i]));
+ }
+
+ this.setUID(pojo, uid);
+ /*
+case "PHOTO": // kolab3
+ // handle photo VERY special... TODO
+ break;
+
+case "GROUP":
+ // how is this handled?
+ break;
+ */
+
+// fields we "know" about but just cannot work with (TODO find a way to save them and restore them!)
+ /*
+case "GENDER": // kolab3
+case "RELATED": //kolab3
+case "CREATION-DATE":
+case "LATITUDE":
+case "LONGITUDE":
+case "ASSISTANT":
+case "MANAGER-NAME":
+case "PROFESSION":
+case "SPOUSE-NAME":
+case "CHILDREN":
+case "GENDER":
+case "LANGUAGE":
+case "OFFICE-LOCATION":
+case "FREE-BUSY-URL":
+ //this.setCardProperty(card, cur.nodeName, cur.getFirstData(), true);
+ */
+ return pojo;
+};
+
+/**
* Creates xml (kolab2) out of a given card.
* The return is the xml as string.
* @param card nsIAbCard: the adress book card
@@ -2126,7 +2214,7 @@ synckolab.addressbookTools.vList2Card = function (uids, lines, card, cards) {
case "UID":
// we cannot set the custom4 for a mailing list... but since tbird defined
// the name to be unique... lets keep it that way
- //this.setCardProperty(card, "Custom4", tok[1]);
+ this.setUID(card, tok[1]);
break;
case "BEGIN":
if (!beginVCard) {
@@ -2164,6 +2252,24 @@ synckolab.addressbookTools.vList2Card = function (uids, lines, card, cards) {
break;
} // end switch
}
+
+ // make sure we got a UID
+ if(!this.getUID(card)) {
+ this.setUID(card, "sk-dl-" + synckolab.tools.text.randomVcardId());
+ }
+
+ // fix list displayname - this is the key for thunderbird
+ if(!this.getCardProperty(card, "DisplayName", null)) {
+ // check if we have a nickname
+ var newName = this.getCardProperty(card, "DisplayName", null);
+ if(newName !== null && newName.length > 0) {
+ this.setCardProperty(card, "DisplayName", newName);
+ } else {
+ // use the uid
+ this.setCardProperty(card, "DisplayName", "list " + this.getUID(card));
+ }
+ }
+
return true;
};
@@ -2174,6 +2280,8 @@ synckolab.addressbookTools.vList2Card = function (uids, lines, card, cards) {
* @param card the card object
*/
synckolab.addressbookTools.Xml2List = function (topNode, card) {
+ synckolab.tools.logMessage("parsing xml to list", synckolab.global.LOG_DEBUG + synckolab.global.LOG_AB);
+
card.type = "maillist";
card.isMailList = true;
@@ -2220,13 +2328,24 @@ synckolab.addressbookTools.Xml2List = function (topNode, card) {
this.setCardProperty(card, "Notes", cur.getFirstData());
found = true;
break;
+
case "UID":
- // the md5 of the name is the uid...
- // because for thunderbird the name is unique
+ // kolab 3: uid/uri
+ var uid = cur.getXmlResult("URI", "");
+ // kolab2: directly
+ if(uid === "") {
+ uid = cur.getFirstData();
+ } /*else {
+ // remove the urn:uuid prefix TODO check if this is required
+ if(uid.indexOf("urn:uuid:") !== -1) {
+ uid = uid.substring(9);
+ }
+ }*/
+ this.setUID(card, uid);
break;
case "MEMBER":
// sub-vcard... parse...
- if (!card.contacts) {
+ if (!card.contacts && !card.contacts.length) {
card.contacts = [];
}
var member = {
@@ -2263,7 +2382,26 @@ synckolab.addressbookTools.Xml2List = function (topNode, card) {
if (!found) {
return null;
}
- synckolab.tools.logMessage("finished parsing list: " + this.getUID(card) + "\n" + card.toSource(), synckolab.global.LOG_DEBUG + synckolab.global.LOG_AB);
+
+ // make sure we got a UID
+ if(!this.getUID(card)) {
+ this.setUID(card, "sk-dl-" + synckolab.tools.text.randomVcardId());
+ }
+
+ // fix list displayname - this is the key for thunderbird
+ if(!this.getCardProperty(card, "DisplayName", null)) {
+ // check if we have a nickname
+ var newName = this.getCardProperty(card, "DisplayName", null);
+ if(newName !== null && newName.length > 0) {
+ this.setCardProperty(card, "DisplayName", newName);
+ } else {
+ // use the uid
+ this.setCardProperty(card, "DisplayName", "list " + this.getUID(card));
+ }
+ }
+
+ synckolab.tools.logMessage("finished parsing list: " + this.getUID(card), synckolab.global.LOG_DEBUG + synckolab.global.LOG_AB);
+
return card;
};
@@ -2394,6 +2532,59 @@ synckolab.addressbookTools.addMailingList = function (addressBook, entry, cardDB
/**
+ * Get the UID from a tbird object.
+ * This will ALWAYS return a uid (the card must be non-null).
+ * If the card is a mailing list it will setup the uid in the config uid map,
+ * otherwise it will use the tbird internas to store the uid
+ * @param config the config (where the uid map is stored)
+ * @param card the card to get the uuid for
+ * @returns the uuid (existing or generated)
+ */
+synckolab.addressbookTools.getTbirdUUID = function(card, config) {
+ var cUID;
+ if (card.isMailList) {
+ var name = this.getCardProperty(card, "Name", null);
+ synckolab.tools.logMessage("get uid for maillist " + name, synckolab.global.LOG_DEBUG + synckolab.global.LOG_AB);
+
+ if(!name) {
+ throw "Fatal Error: Tbird List without a name!";
+ }
+
+ // lookup the "temporary" cached uid for this card
+ cUID = config.listLookup.getUUID(name);
+ if (!cUID || cUID === "")
+ {
+ // generate a unique id (will random be enough for the future?)
+ cUID = "sk-dl-" + synckolab.tools.text.randomVcardId();
+ // add the new uid-name relation (will also perist it)
+ config.listLookup.add(name, cUID);
+ }
+ } else {
+ // vcard
+ cUID = synckolab.addressbookTools.getUID(card);
+ synckolab.tools.logMessage("get uid for vard " + cUID, synckolab.global.LOG_DEBUG + synckolab.global.LOG_AB);
+
+ if (!cUID || cUID === "")
+ {
+ // generate a unique id (will random be enough for the future?)
+ cUID = "sk-vc-" + synckolab.tools.text.randomVcardId();
+ // set it
+ synckolab.addressbookTools.setUID(card, cUID);
+
+ if(!config.addressBook) {
+ throw "AddressBook is undefined\n" + new Error("s").stack;
+ }
+ // write back
+ config.addressBook.modifyCard(card);
+ }
+
+ }
+
+ // return
+ return cUID;
+};
+
+/**
* Transform a json object into the real deal.
* @param base the base json object
* @param cards a hashmap with address book objects (key = UID for reference in the list)
diff --git a/src/chrome/content/synckolab/tools.js b/src/chrome/content/synckolab/tools.js
index 9925cd3..237358f 100644
--- a/src/chrome/content/synckolab/tools.js
+++ b/src/chrome/content/synckolab/tools.js
@@ -162,9 +162,12 @@ copyFields: function (src, target, fields, noempty) {
/**
* compares two objects. note: empty string or null is the same as not existant
+ * @param a the object to compare
+ * @param b the object to compare with
+ * @param skipFields fields to skip when comparing (must exist - just the content does not matter) i.e.: { UUID: true }
* @return true if they contain the same content, false otherwise
*/
-equalsObject: function(a, b)
+equalsObject: function(a, b, skipFields)
{
// empty arrays
if(!a && b && b.length && b.length === 0) {
@@ -192,6 +195,7 @@ equalsObject: function(a, b)
}
for(p in a) {
+ // some fields we can skip
if (p !== "ts" && p !== "sha1" && p !== "synckolab") {
if (a[p]) {
switch(typeof(a[p])) {
@@ -204,6 +208,9 @@ equalsObject: function(a, b)
case 'function': // skip functions
break;
default:
+ if(skipFields && skipFields[p]) {
+ break;
+ }
if (a[p] !== b[p] && Number(a[p]) !== Number(b[p])) {
synckolab.tools.logMessage("not equals: : " + p + " a: " + a[p] + " b: " + b[p], synckolab.global.LOG_DEBUG);
return false;
@@ -220,6 +227,9 @@ equalsObject: function(a, b)
for(p in b) {
if(p !== "ts" && p !== "sha1" && p !== "synckolab" && p !== "type" && (!a || typeof(a[p]) === 'undefined') && b[p] !== null && b[p] !== "") {
+ if(skipFields && skipFields[p]) {
+ continue;
+ }
synckolab.tools.logMessage("not equals: " + p + " a: " + (a?a[p]:'is null') + " b: " + b[p], synckolab.global.LOG_DEBUG);
return false;
}
@@ -862,10 +872,10 @@ synckolab.tools.file = {
synckolab.tools.logMessage("Error: entry has no id (" +config.name + ": " + config.type + ")", synckolab.global.LOG_ERROR);
return null;
}
-
+ id = synckolab.tools.text.fixNameToMiniCharset(id);
+
synckolab.tools.logMessage("syncDbFile: (" +synckolab.tools.text.fixNameToMiniCharset(config.serverKey) + "/" + config.type + "_" + config.name + "/" + id + ")", synckolab.global.LOG_ERROR);
- id = id.replace(/[ :.;$\\\/]\#\@/g, "_");
var file = Components.classes["@mozilla.org/file/directory_service;1"].getService(Components.interfaces.nsIProperties).get("ProfD", Components.interfaces.nsIFile);
try {
file.append("synckolab");
diff --git a/test/synckolab/parser/kolab2/contactTest.js b/test/synckolab/parser/kolab2/contactTest.js
index d247613..6d79eb8 100644
--- a/test/synckolab/parser/kolab2/contactTest.js
+++ b/test/synckolab/parser/kolab2/contactTest.js
@@ -12,7 +12,7 @@ load("test/lib/testOverride.js");
test("skolab2 ynckolab.addressbookTools.parseMessageContent", function(){
equal(null, synckolab.addressbookTools.parseMessageContent(null), "parsing a null message");
- var testFiles = ["contactMinimalTest", "contactFullTest", "list.test"];
+ var testFiles = ["contactMinimalTest", "contactFullTest", "list.test", "list.test2"];
var content, entry, jsonEntry;
@@ -24,7 +24,7 @@ test("skolab2 ynckolab.addressbookTools.parseMessageContent", function(){
entry = synckolab.addressbookTools.parseMessageContent(content);
content = readFile("test/synckolab/parser/kolab2/json/"+src+".json");
jsonEntry = JSON.parse(content);
- equal(synckolab.tools.equalsObject(entry, jsonEntry), true, src + "\n" + JSON.stringify(entry, null, " "));
+ equal(synckolab.tools.equalsObject(entry, jsonEntry, {UUID:true}), true, src + "\n" + JSON.stringify(entry, null, " "));
// json -> kolab 2 xml
/*
diff --git a/test/synckolab/parser/kolab2/json/list.test.json b/test/synckolab/parser/kolab2/json/list.test.json
index 6288395..8e1e3b6 100644
--- a/test/synckolab/parser/kolab2/json/list.test.json
+++ b/test/synckolab/parser/kolab2/json/list.test.json
@@ -6,6 +6,7 @@
"DisplayName": "list-name",
"Notes": "list-description",
"NickName": "list-nickname",
+ "UUID": "SomeRandomUUID",
"contacts": [
{
"synckolab": "3.0.0",
diff --git a/test/synckolab/parser/kolab2/json/list.test2.json b/test/synckolab/parser/kolab2/json/list.test2.json
new file mode 100644
index 0000000..b1e48b1
--- /dev/null
+++ b/test/synckolab/parser/kolab2/json/list.test2.json
@@ -0,0 +1,52 @@
+{
+ "synckolab": "3.0.0",
+ "type": "maillist",
+ "isMailList": true,
+ "ts": 1350823376091,
+ "UUID": "dc90f284789cb642256068504d42dc7e",
+ "DisplayName": "list dc90f284789cb642256068504d42dc7e",
+ "Notes": "list-description",
+ "contacts": [
+ {
+ "synckolab": "3.0.0",
+ "listMember": true,
+ "type": "contact",
+ "isMailList": false,
+ "ts": 1350823376138,
+ "DisplayName": "user.name (Retail)",
+ "PrimaryEmail": "user.name@domain.com",
+ "UUID": "993e519e411b0c5ff6b90e2293c99bd1"
+ },
+ {
+ "synckolab": "3.0.0",
+ "listMember": true,
+ "type": "contact",
+ "isMailList": false,
+ "ts": 1350823376139,
+ "DisplayName": "user.name (Retail2)",
+ "PrimaryEmail": "a12346@domain.com",
+ "UUID": "993e519e411b0c5ff6b90e2293c99bd1"
+ },
+ {
+ "synckolab": "3.0.0",
+ "listMember": true,
+ "type": "contact",
+ "isMailList": false,
+ "ts": 1350823376140,
+ "DisplayName": "user.name (HomeServices)",
+ "PrimaryEmail": "user.name@domain.com",
+ "UUID": "e1778e4a015e7bbb068bf9375182d6ab"
+ },
+ {
+ "synckolab": "3.0.0",
+ "listMember": true,
+ "type": "contact",
+ "isMailList": false,
+ "ts": 1350823376142,
+ "DisplayName": "user.name(Retail3)",
+ "PrimaryEmail": "user.name@domain.com",
+ "UUID": "6e0366e6f12afa2e2dd8883bec36f37d"
+ }
+ ],
+ "sha1": "4717f9c787b1baa2c408ea8953a121d6181a5f04"
+} \ No newline at end of file
diff --git a/test/synckolab/parser/kolab2/raw/list.test2.xml b/test/synckolab/parser/kolab2/raw/list.test2.xml
new file mode 100644
index 0000000..dfb734d
--- /dev/null
+++ b/test/synckolab/parser/kolab2/raw/list.test2.xml
@@ -0,0 +1,64 @@
+From: someone@domain.com
+To: someone@domain.com
+Date: Thu, 18 Oct 2012 10:11:18 -0400
+X-Kolab-Type: application/x-vnd.kolab.distribution-list
+Subject: dc90f284789cb642256068504d42dc7e
+User-Agent: Horde::Kolab::Storage v0.2
+MIME-Version: 1.0
+Content-Type: multipart/mixed;
+ boundary="=_96e43p7nnc0"
+Content-Transfer-Encoding: 7bit
+
+This message is in MIME format.
+
+--=_96e43p7nnc0
+Content-Type: text/plain;
+ charset=UTF-8
+Content-Disposition: inline
+Content-Transfer-Encoding: quoted-printable
+
+This is a Kolab Groupware object. To view this object you will need an emai=
+l
+client that understands the Kolab Groupware format. For a list of such emai=
+l
+clients please visit http://www.kolab.org/kolab2-clients.html
+
+--=_96e43p7nnc0
+Content-Type: application/x-vnd.kolab.distribution-list;
+ name="kolab.xml"
+Content-Disposition: attachment;
+ filename="kolab.xml"
+Content-Transfer-Encoding: quoted-printable
+
+<?xml version=3D"1.0"?>
+<distribution-list version=3D"1.0">
+ <uid>dc90f284789cb642256068504d42dc7e</uid>
+ <body>list-description</body>
+ <categories></categories>
+ <creation-date>2012-10-18T14:11:07Z</creation-date>
+ <last-modification-date>2012-10-18T14:11:18Z</last-modification-date>
+ <sensitivity>public</sensitivity>
+ <product-id>Horde::Kolab</product-id>
+ <member>
+ <display-name>user.name (Retail)</display-name>
+ <smtp-address>user.name@domain.com</smtp-address>
+ <uid>993e519e411b0c5ff6b90e2293c99bd1</uid>
+ </member>
+ <member>
+ <display-name>user.name (Retail2)</display-name>
+ <smtp-address>a12346@domain.com</smtp-address>
+ <uid>993e519e411b0c5ff6b90e2293c99bd1</uid>
+ </member>
+ <member>
+ <display-name>user.name (HomeServices)</display-name>
+ <smtp-address>user.name@domain.com</smtp-address>
+ <uid>e1778e4a015e7bbb068bf9375182d6ab</uid>
+ </member>
+ <member>
+ <display-name>user.name(Retail3)</display-name>
+ <smtp-address>user.name@domain.com</smtp-address>
+ <uid>6e0366e6f12afa2e2dd8883bec36f37d</uid>
+ </member>
+
+</distribution-list>
+--=_96e43p7nnc0-- \ No newline at end of file
diff --git a/test/synckolab/tools/textTest.js b/test/synckolab/tools/textTest.js
index a24c32c..c98acb7 100644
--- a/test/synckolab/tools/textTest.js
+++ b/test/synckolab/tools/textTest.js
@@ -23,6 +23,7 @@ test("synckolab.tools.text.fixNameToMiniCharset", function() {
equal(synckolab.tools.text.fixNameToMiniCharset("halloWelt"), "halloWelt", "test normal chars")
equal(synckolab.tools.text.fixNameToMiniCharset("hallo Welt "), "hallo_Welt_", "test normal chars with space")
equal(synckolab.tools.text.fixNameToMiniCharset("hallo Welt "), "hallo_Welt_", "test normal chars with multi space")
+ equal(synckolab.tools.text.fixNameToMiniCharset("hallo: Welt "), "hallo_Welt_", "test normal chars with colon")
equal(synckolab.tools.text.fixNameToMiniCharset("häöüß!"), "haous_", "test german umlaut (lowercase)")
equal(synckolab.tools.text.fixNameToMiniCharset("hÄÖÜ?"), "hAOU_", "test german umlaut (uppercase)")
equal(synckolab.tools.text.fixNameToMiniCharset("hÁÀâ' '"), "hAAa_", "test french accent on a")