if (!org.bustany.TrackerBird.TrackerStore || !org.bustany.TrackerBird.TrackerStore.__initialized)
org.bustany.TrackerBird.TrackerStore = {
	// Init barrier
	__initialized: true,

	_addressParser: org.bustany.TrackerBird.EmailAddressParser,
	_tracker: org.bustany.TrackerBird.TrackerSparql,

	storeMessage: function(folder, header) {
		var uri = folder.getUriForMsg(header);
		var fromEmailAddress;
		var toEmailAddresses = [];

		fromEmailAddress = this._addressParser.parse(header.mime2DecodedAuthor);

		// FIXME: this is not bullet-proof, but will do for now
		var unparsedRecipients = header.mime2DecodedRecipients.split(">,");
		for (var i in unparsedRecipients) {
			var parsedAddress = this._addressParser.parse(unparsedRecipients[i] + ">");

			if (parsedAddress) {
				toEmailAddresses.push(parsedAddress);
			}
		}

		var query = this.baseQuery(uri, header)
		          + this.contactQuery("nmo:from", fromEmailAddress)
		          + this.contactsQuery("nmo:to", toEmailAddresses);

		if ((header.flags & Components.interfaces.nsMsgMessageFlags.Offline)
		 || (header.folder instanceof Components.interfaces.nsIMsgLocalMailFolder)) {
			 // We can access mail body
		}

		dump(query+"\n");
	},

	baseQuery: function(uri, hdr) {
		var query = "<" + uri + "> a nmo:Email, nmo:MailboxDataObject";
		          + "; nie:url \"" + uri + "\" ";

		if (hdr.mime2DecodedSubject != "") {
			query += "; nmo:messageSubject \""
			       + this.escapeString(hdr.mime2DecodedSubject)
				   + "\" ";
		}

		query += "; nmo:sentDate \""
		       + new Date(hdr.dateInSeconds).toISOString()
			   + "\" ";

		return query;
	},

	contactQuery: function(predicate, address) {
		if (address == null) {
			return "";
		}

		var nameSparql = "";

		if (address.name != "") {
			nameSparql = "; nco:fullname: \""
			           + this.escapeString(address.name)
			           + "\" ";
		}

		var emailSparql = "; nco:hasEmailAddress <mailto:"
		                + address.address
		                + "> ";

		return "; " + predicate + " [ a nco:Contact " + nameSparql + emailSparql + "] ";
	},

	contactsQuery: function(predicate, addresses) {
		var query = "";

		for (var i in addresses) {
			query += this.contactQuery(predicate, addresses[i]);
		}

		return query;
	},

	escapeString: function(str) {
		return this._tracker.escape_string(str).readString();
	}
}

@@ -172,16 +172,75 @@
  true,%0A%0A
+%09_graph: %22urn:uuid:0aa84c52-396d-4c37-bc6c-8342699f810c%22,%0A%0A
 %09_addres
@@ -343,16 +343,44 @@
 parql,%0A%0A
+%09_knownEmailAddresses: %7B%7D,%0A%0A
 %09storeMe
@@ -508,16 +508,35 @@
  = %5B%5D;%0A%0A
+%09%09var query = %22%22;%0A%0A
 %09%09fromEm
@@ -601,16 +601,70 @@
 Author);
+%0A%09%09query += this.insertEmailAddress(fromEmailAddress);
 %0A%0A%09%09// F
@@ -969,16 +969,69 @@
 dress);%0A
+%09%09%09%09query += this.insertEmailAddress(parsedAddress);%0A
 %09%09%09%7D%0A%09%09%7D
@@ -1032,29 +1032,79 @@
 %09%7D%0A%09%09%7D%0A%0A
+%0A
 %09%09
-var 
 query 
++
 =
+ %22INSERT %7B GRAPH %3C%22 + this._graph + %22%3E %7B%22%0A%09%09       +
  this.ba
@@ -1125,35 +1125,32 @@
 eader)%0A%09%09       
-   
 + this.contactQu
@@ -1188,27 +1188,24 @@
 s)%0A%09%09       
-   
 + this.conta
@@ -1240,16 +1240,29 @@
 dresses)
+%0A%09%09%09   + %22%7D%7D%22
 ;%0A%0A%09%09if 
@@ -2611,13 +2611,384 @@
 ring();%0A
+%09%7D,%0A%0A%09insertEmailAddress: function(address) %7B%0A%09%09if (this._knownEmailAddresses%5Baddress.address%5D) %7B%0A%09%09%09return %22%22;%0A%09%09%7D%0A%0A%09%09var query = %22INSERT %7B GRAPH %3C%22 + this._graph + %22%3E %7B%22%0A%09%09          + %22%3C%22 + address.address + %22%3E a nco:EmailAddress%22%0A%09%09          + %22; nco:emailAddress %5C%22%22 + address.address + %22%5C%22%7D%7D%5Cn%22;%0A%0A%09%09this._knownEmailAddresses%5Baddress.address%5D = true;%0A%09%09return query;%0A
 %09%7D%0A%7D%0A

Insert nco:EmailAddress resources