This is just some static backup of the original site, don't expect every link to work!

source: content/modules/vI_smartIdentityCollection.js @ 184c6c

ng_0.9
Last change on this file since 184c6c was 184c6c, checked in by rene <rene@…>, 11 years ago

rearranged tree structure / added build-script

  • Property mode set to 100644
File size: 19.0 KB
Line 
1/* ***** BEGIN LICENSE BLOCK *****
2    This program is free software; you can redistribute it and/or modify
3    it under the terms of the GNU General Public License as published by
4    the Free Software Foundation; either version 2 of the License, or
5    (at your option) any later version.
6
7    This program is distributed in the hope that it will be useful,
8    but WITHOUT ANY WARRANTY; without even the implied warranty of
9    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10    GNU General Public License for more details.
11
12    You should have received a copy of the GNU General Public License
13    along with this program; if not, write to the Free Software
14    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
15
16    The Original Code is the Virtual Identity Extension.
17
18    The Initial Developer of the Original Code is Rene Ejury.
19    Portions created by the Initial Developer are Copyright (C) 2007
20    the Initial Developer. All Rights Reserved.
21
22    Contributor(s):
23 * ***** END LICENSE BLOCK ***** */
24
25/* this is now used as a module - there is no required reference to any other interface-elements in this code */
26
27virtualIdentityExtension.ns(function() { with (virtualIdentityExtension.LIB) {
28   
29function smartIdentityCollection(msgHdr, preseletedID, currentIDisVID, newsgroup, recipients) {
30    dump("## smartIdentityCollection: constructor\n");
31    this._IDisVID = currentIDisVID;
32    this._preselectedID = preseletedID;
33    this._msgHdr = msgHdr;
34    this._newsgroup = newsgroup;
35    this._unicodeConverter.charset = "UTF-8";
36    this._recipients = recipients;
37    this._rdfDatasourceAccess = new vI.rdfDatasourceAccess();
38    this._allIdentities = new vI.identityCollection();
39    dump("## smartIdentityCollection: constructor done \n");
40};
41
42smartIdentityCollection.prototype = {
43    messenger : Components.classes["@mozilla.org/messenger;1"].createInstance()
44        .QueryInterface(Components.interfaces.nsIMessenger),
45    _pref : Components.classes["@mozilla.org/preferences-service;1"]
46            .getService(Components.interfaces.nsIPrefService)
47            .getBranch("extensions.virtualIdentity."),
48    _unicodeConverter : Components.classes["@mozilla.org/intl/scriptableunicodeconverter"]
49            .createInstance(Components.interfaces.nsIScriptableUnicodeConverter),
50    _headerParser : Components.classes["@mozilla.org/messenger/headerparser;1"]
51            .getService(Components.interfaces.nsIMsgHeaderParser),
52
53    _msgComposeTypeReference : Components.interfaces.nsIMsgCompType,
54   
55    _IDisVID : false,
56    _preselectedID : null,
57    _allIdentities : null,
58    _selectedValue : null,
59    _newsgroup : null,
60    _rdfDatasourceAccess : null,
61
62    // this function adds a timestamp to the current sender
63    __autoTimestamp : function() {
64        if (vI.notificationBar) vI.notificationBar.dump("## smartIdentity: __autoTimestamp()\n");
65        if (this._IDisVID) {
66            if (vI.notificationBar) vI.notificationBar.dump("## smartIdentity: Virtual Identity in use, aborting\n");
67            return;
68        }
69
70        var current_email = this._preselectedID.email.split("@");
71        var localpart = current_email[0];
72        var domain = current_email[1];
73       
74        if (vI.notificationBar) vI.notificationBar.dump("## smartIdentity: current email: " + current_email[0] + "@" + current_email[1] + "\n");
75       
76        var autoString = this._pref.getCharPref("autoString");
77        var formatString = this._pref.getCharPref("autoTimeFormat");
78       
79        var dateObj = new Date(); var dateString = "";
80        if (formatString == "") dateString = parseInt(dateObj.getTime()/1000);
81        else try {  //  you never know what the formatString will be...
82            dateString = dateObj.toLocaleFormat(formatString).replace(/\s+|[\x00-\x2a]|\x2c|\x2f|[\x3a-\x40]|[\x5b-\x5d]|\x60|\x7c|[\x7f-\xff]/g,"_");
83        } catch(e) { };
84       
85        var new_email = autoString.replace(/%l/g, localpart).replace(/%d/g, domain).replace(/%t/g,dateString);
86        if (vI.notificationBar) vI.notificationBar.dump("## smartIdentity: new email: " + new_email + "\n");
87
88        var newIdentity = new vI.identityData(new_email,
89            this._preselectedID.fullName, this._preselectedID.key, this._preselectedID.smtpServerKey, null, null)
90
91        this._allIdentities.addWithoutDuplicates(newIdentity);
92        this._selectedValue = 0;
93    },
94   
95    __ignoreID : function() {
96        if (vI.notificationBar) vI.notificationBar.dump("## smartIdentity: checking " + this._pref.getCharPref("idSelection_ignoreIDs") + " against " + this._preselectedID.key + "\n")
97        // check if usage if virtual Identities should be used at all for the currently selected ID
98        if (this._pref.getCharPref("idSelection_ignoreIDs").indexOf(":" + this._preselectedID.key + ":") != -1) {
99            if (vI.notificationBar) vI.notificationBar.dump("## smartIdentity: not using virtual Identites for ID " + this._preselectedID.key + "\n");
100            return true;
101        }
102        return false
103    },
104   
105    NewMail : function() {
106        if (vI.notificationBar) vI.notificationBar.dump("## smartIdentity: NewMail()\n");
107        if (this.__ignoreID()) return;
108        this._rdfDatasourceAccess.getVIdentityFromAllRecipients(this._allIdentities, this._recipients);
109        if (this._allIdentities.number == 0 && this._pref.getBoolPref("autoTimestamp")) this.__autoTimestamp();
110    },
111   
112    _foundExistingIdentity : function() {
113        /* compare with existing Identities                                     */
114        for (var index = 0; index < this._allIdentities.number; index++) {
115            var existingID = this._allIdentities.identityDataCollection[index].isExistingIdentity(false);
116            if (existingID) {
117                this._allIdentities.identityDataCollection[index].id.key = existingID;  // set found identity
118                // reorder list of Identities to prefer it on autoselect
119                // has to be done before Identities are added to the Menu
120                if (vI.notificationBar) vI.notificationBar.dump("## smartIdentity: found existing Identity, reorder to prefer this one.\n");
121                var firstIdentity = this._allIdentities.identityDataCollection[index];
122                for (var i = index; index > 0; index--) {
123                    this._allIdentities.identityDataCollection[index] = this._allIdentities.identityDataCollection[index-1];
124                }
125                this._allIdentities.identityDataCollection[0] = firstIdentity;
126                return { key: index };
127            }
128        }
129        return null;
130    },
131   
132    ReplyOnSent : function() {
133        if (vI.notificationBar) vI.notificationBar.dump("## smartIdentity: ReplyOnSent() (rules like SmartDraft)\n");
134        this.__SmartDraftOrReplyOnSent();
135        this._rdfDatasourceAccess.getVIdentityFromAllRecipients(this._allIdentities, this._recipients);
136    },
137
138    Draft : function() {
139        if (vI.notificationBar) vI.notificationBar.dump("## smartIdentity: Draft()\n");
140       
141        this.__SmartDraftOrReplyOnSent();
142        this._rdfDatasourceAccess.getVIdentityFromAllRecipients(this._allIdentities, this._recipients);
143    },
144   
145    __parseHeadersWithArray: function(header, identityCollection) {
146        var emails = {}; var fullNames = {}; var combinedNames = {};
147        var number = this._headerParser.parseHeadersWithArray(header, emails, fullNames, combinedNames);
148        for (var index = 0; index < number; index++) {
149            var newIdentity = new vI.identityData(emails.value[index], fullNames.value[index],
150                null, vI.NO_SMTP_TAG, null, null);
151            identityCollection.addWithoutDuplicates(newIdentity);
152        }
153    },
154
155    // this function checks if we have a draft-case and Smart-Draft should replace the Identity
156    __SmartDraftOrReplyOnSent : function() {
157        if (!this._pref.getBoolPref("smart_draft"))
158            { if (vI.notificationBar) vI.notificationBar.dump("## smartIdentity: SmartDraft deactivated\n"); return; }
159
160        if (vI.notificationBar) vI.notificationBar.dump("## smartIdentity: __SmartDraftOrReplyOnSent()\n");
161
162        if (this._msgHdr) {
163            this.__parseHeadersWithArray(this._msgHdr.author, this._allIdentities)
164            if (vI.notificationBar) vI.notificationBar.dump("## smartIdentity: sender '" + this._allIdentities.identityDataCollection[0].combinedName + "'\n");
165        }
166        else if (vI.notificationBar) vI.notificationBar.dump("## smartIdentity: __SmartDraftOrReplyOnSent: No Header found, shouldn't happen\n");
167    },
168   
169    __filterAddresses : function() {
170        var returnIdentities = new vI.identityCollection();
171       
172        var filterList  =
173            this._unicodeConverter.ConvertToUnicode(this._pref.getCharPref("smart_reply_filter")).split(/\n/)
174        if (filterList.length == 0) filterList[0] == ""
175       
176        for (var i = 0; i < filterList.length; i++) {
177            const filterType = { None : 0, RegExp : 1, StrCmp : 2 }
178            var recentfilterType; var skipRegExp = false;
179            if (filterList.length <= 1 && filterList[0] == "")
180                { if (vI.notificationBar) vI.notificationBar.dump("## smartIdentity: no filters configured\n"); recentfilterType = filterType.None; }
181            else if (/^[+-]?\/(.*)\/$/.exec(filterList[i]))
182                { if (vI.notificationBar) vI.notificationBar.dump("## smartIdentity: filter emails with RegExp '"
183                    + filterList[i].replace(/\\/g,"\\\\") + "'\n"); recentfilterType = filterType.RegExp; }
184            else    { if (vI.notificationBar) vI.notificationBar.dump("## smartIdentity: filter emails, compare with '"
185                    + filterList[i] + "'\n"); recentfilterType = filterType.StrCmp; }
186            for (var j = 0; j < this._allIdentities.number; j++) { // check if recent email-address (pre-choosen identity) is found in
187            // copied and adapted from correctIdentity, thank you for the RegExp-idea!
188                var add_addr = false;
189                switch (recentfilterType) {
190                    case filterType.None:
191                        add_addr = true; break;
192                    case filterType.RegExp:
193                        if (skipRegExp) break;
194                        try {   /^[+-]?\/(.*)\/$/.exec(filterList[i]);
195                            if ( filterList[i][0] == "-" ) {
196                                if (this._allIdentities.identityDataCollection[j].email.match(new RegExp(RegExp.$1,"i")))
197                                    this._allIdentities.dropIdentity(j--);
198                            } else
199                                add_addr = (this._allIdentities.identityDataCollection[j].email.match(new RegExp(RegExp.$1,"i")));
200                        }
201                        catch(vErr) {
202                            if (vI.notificationBar) vI.notificationBar.addNote(
203                                vI.main.elements.strings.getString("vident.smartIdentity.ignoreRegExp") +
204                                +filterList[i].replace(/\\/g,"\\\\") + " .",
205                                "smart_reply_notification");
206                                skipRegExp = true; }
207                        break;
208                    case filterType.StrCmp:
209                        add_addr = ( this._allIdentities.identityDataCollection[j].email.toLowerCase().indexOf(filterList[i].toLowerCase()) != -1)
210                        break;
211                }
212                if (add_addr)   returnIdentities.addWithoutDuplicates(this._allIdentities.identityDataCollection[j])
213            }
214        }
215        this._allIdentities.takeOver(returnIdentities);
216    },
217   
218    __smartReplyCollectAddresses : function() {
219        // add emails from selected headers (stored by vI_getHeader.xul/js)
220        var reply_headers = this._unicodeConverter.ConvertToUnicode(this._pref.getCharPref("smart_reply_headers")).split(/\n/)
221                   
222        for (var index = 0; index < reply_headers.length; index++) {
223            // ------------- prepare fields to read the stored header ----------------
224            var replyHeader_splitted = reply_headers[index].split(/:/)
225            // use first part (all before ':') as the header name
226            var replyHeaderName = replyHeader_splitted[0].toLowerCase()
227            // check second or third part for any number
228            var replyHeaderNumber = parseInt(replyHeader_splitted[1])
229            if (isNaN(replyHeaderNumber)) replyHeaderNumber = parseInt(replyHeader_splitted[2])
230            // check if Fullnames should be erased
231            var replyHeaderEmptyFullNames = ((replyHeader_splitted[1] && replyHeader_splitted[1].match(/@/)) ||
232                            (replyHeader_splitted[2] && replyHeader_splitted[2].match(/@/)))
233           
234            // create header name to find the value
235            var replyHeaderNameToRead = replyHeaderName
236            if (!isNaN(replyHeaderNumber)) replyHeaderNameToRead += ":" + replyHeaderNumber
237           
238            // if mailing-list ignore to-header (usually the mailing list address)
239            if (replyHeaderNameToRead == "to" && this._msgHdr.getStringProperty("vI_list-id")) {
240                if (vI.notificationBar) vI.notificationBar.dump("## smartIdentity: header 'list-id' found (mailinglist), skipping header 'to'\n");
241                continue;
242            }
243           
244            // ------------- read the stored header -------------------------------
245            var value = this._unicodeConverter.ConvertToUnicode(this._msgHdr.getStringProperty("vI_" + replyHeaderNameToRead))
246/*          let window3pane =  Components.classes['@mozilla.org/appshell/window-mediator;1']
247                 .getService(Components.interfaces.nsIWindowMediator)
248                 .getMostRecentWindow("mail:3pane");
249           
250            if (vI.notificationBar) vI.notificationBar.dump("## smartIdentity: found stored header '" +
251                replyHeaderNameToRead + "': '" + window3pane.virtualIdentityExtension.storedHeaders["vI_" + replyHeaderNameToRead] + "'\n");*/
252           
253            if (vI.notificationBar) vI.notificationBar.dump("## smartIdentity: reading header '" +
254                replyHeaderNameToRead + "': '" + value + "'\n");
255           
256            // ------------- parse address-string to get a field of single email-addresses
257            var splitted = new vI.identityCollection();
258            this.__parseHeadersWithArray(value, splitted);
259           
260            // move found addresses step by step to this._allIdentities, and change values if requested
261            for (var i = 0; i < splitted.number; i++) {
262                // if there is no email than it makes no sense to use it as a sender
263                if (!splitted.identityDataCollection[i].email.match(/^.*@.*$/)) {
264                    if (vI.notificationBar) vI.notificationBar.dump("## smartIdentity:   skipping '" +
265                    splitted.identityDataCollection[i].email + "', no email\n")
266                    continue;
267                }
268
269                if (replyHeaderEmptyFullNames) splitted.identityDataCollection[i].fullName = ""
270
271                this._allIdentities.addWithoutDuplicates(splitted.identityDataCollection[i]);
272
273                if (vI.notificationBar) vI.notificationBar.dump("## smartIdentity:   found '" +
274                    splitted.identityDataCollection[i].combinedName + "'\n")
275            }
276        }
277    },
278   
279    Reply : function() {
280        if (vI.notificationBar) vI.notificationBar.dump("## smartIdentity: Reply()\n");
281
282        if (this._msgHdr && this._newsgroup && !this._msgHdr.getStringProperty("vI_content_base")) {
283        //  RFC 2821 (http://www.ietf.org/rfc/rfc2821.txt) says:
284        //  "4.4 Trace Information
285        //  When an SMTP server receives a message for delivery or further
286        //  processing, it MUST insert trace ("time stamp" or "Received")
287        //  information at the beginning of the message content, as discussed in
288        //  section 4.1.1.4."
289        //  so it should be always possible to decide if Reply or Draft based on received headers
290        //  hidden option smart_detectByReceivedHeader will act as a switch for not RFC-compliant servers
291            // RFC-compliant
292            if (this._pref.getBoolPref("smart_detectByReceivedHeader")) {
293                if (!this._msgHdr.getStringProperty("vI_received")) { // mail was not received
294                    if (vI.notificationBar) vI.notificationBar.dump("## smartIdentity: reply on non-received (sent?) mail. Using SmartDraft. \n");
295                    this.ReplyOnSent();
296                    return;
297                }
298            }
299            // not RFC-compliant
300            else {
301                const MSG_FOLDER_FLAG_INBOX = 0x1000
302                const MSG_FOLDER_FLAG_SENTMAIL = 0x0200;
303
304                if (this._msgHdr && (this._msgHdr.folder.flags & MSG_FOLDER_FLAG_SENTMAIL)) {
305                    if (vI.notificationBar) vI.notificationBar.dump("## smartIdentity: reply from Sent folder.");
306                    if (this._msgHdr.folder.flags & MSG_FOLDER_FLAG_INBOX)
307                        if (vI.notificationBar) vI.notificationBar.dump(" Folder is INBOX, assuming Reply-Case. \n");
308                    else {
309                        if (vI.notificationBar) vI.notificationBar.dump(" Using SmartDraft. \n");
310                        this.ReplyOnSent();
311                        return;
312                    }
313                }
314            }
315        }
316       
317        if (this.__ignoreID()) return;
318       
319        var storageIdentities = new vI.identityCollection();
320        this._rdfDatasourceAccess.getVIdentityFromAllRecipients(storageIdentities, this._recipients);
321       
322        if (storageIdentities.number == 0 || !this._pref.getBoolPref("idSelection_storage_ignore_smart_reply"))
323            this.__SmartReply();
324        else if (vI.notificationBar) vI.notificationBar.dump("## smartIdentity: SmartReply skipped, Identities in Storage found.\n");
325
326        // merge SmartReply-Identities and Storage-Identites
327        if (this._pref.getBoolPref("idSelection_storage_prefer_smart_reply"))
328            { this._allIdentities.mergeWithoutDuplicates(storageIdentities); }
329        else {
330            var smartIdentities = this._allIdentities;
331            this._allIdentities = storageIdentities;       
332            this._allIdentities.mergeWithoutDuplicates(smartIdentities);
333        }
334       
335        if (vI.notificationBar) vI.notificationBar.dump("## smartIdentity: merged SmartReply & Storage, " + this._allIdentities.number + " address(es) left\n")
336    },
337   
338    // this function checks if we have a reply-case and Smart-Reply should replace the Identity
339    __SmartReply : function() {
340        if (!this._pref.getBoolPref("smart_reply"))
341            { if (vI.notificationBar) vI.notificationBar.dump("## smartIdentity: SmartReply deactivated\n"); return; }
342        if (this._newsgroup && !this._pref.getBoolPref("smart_reply_for_newsgroups")) {
343            if (vI.notificationBar) vI.notificationBar.dump("## smartIdentity: SmartReply, answering to a newsgroup, aborting\n");
344            return;
345        }
346
347        if (vI.notificationBar) vI.notificationBar.dump("## smartIdentity: __SmartReply()\n");
348        if (vI.notificationBar) vI.notificationBar.dump("## smartIdentity: ----------------------------------------------------------\n")
349        if (this._msgHdr) {
350            /* first step: collect addresses */
351            this.__smartReplyCollectAddresses();
352            if (vI.notificationBar) vI.notificationBar.dump("## smartIdentity: " + this._allIdentities.number + " address(es) after parsing, before filtering\n")
353           
354            /* second step: filter (and sort) addresses */
355            this.__filterAddresses();
356           
357            if (vI.notificationBar) vI.notificationBar.dump("## smartIdentity: filtering done, " + this._allIdentities.number + " address(es) left\n")
358           
359            /* set default FullName */
360            var smart_reply_defaultFullName = this._unicodeConverter.ConvertToUnicode(this._pref.getCharPref("smart_reply_defaultFullName"))
361            if (smart_reply_defaultFullName != "") {
362                for (var index = 0; index < this._allIdentities.number; index++) {
363                    if (this._allIdentities.identityDataCollection[index].fullName == "") {
364                        this._allIdentities.identityDataCollection[index].fullName = smart_reply_defaultFullName
365                        if (vI.notificationBar) vI.notificationBar.dump("## smartIdentity: added default FullName '" + 
366                            smart_reply_defaultFullName + "' to '" + this._allIdentities.identityDataCollection[index].email + "'\n")
367                    }
368                }
369            }   
370
371            /* smart_reply_ignoreFullName: compare email with other Identities          */
372            /* if match replace FullName with existing one, keep identity in list by now        */
373            /* will not be added to the menu but probably choosen with __smartIdentitySelection     */
374            if (this._pref.getBoolPref("smart_reply_ignoreFullName")) {
375                if (vI.notificationBar) vI.notificationBar.dump("## smartIdentity: compare with existing Identities (ignoring FullNames).\n")
376           
377                for (var index = 0; index < this._allIdentities.number; index++) {
378                    var idKey = this._allIdentities.identityDataCollection[index].isExistingIdentity(true);
379                    if (idKey) {
380                        var newFullName = gAccountManager.getIdentity(idKey).fullName;
381                        this._allIdentities.identityDataCollection[index].fullName = newFullName;
382                        if (vI.notificationBar) vI.notificationBar.dump("## smartIdentity: replaced Fullname of '" + this._allIdentities.identityDataCollection[index].email + "' with '" + newFullName + "' \n");
383                    }
384                }
385            }
386        }
387        else if (vI.notificationBar) vI.notificationBar.dump("## smartIdentity: SmartReply skipped. No Header-information found.\n");
388       
389        if (vI.notificationBar) vI.notificationBar.dump("## smartIdentity: ----------------------------------------------------------\n")
390    },
391   
392
393};
394vI.smartIdentityCollection = smartIdentityCollection;
395}});
Note: See TracBrowser for help on using the repository browser.