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

source: modules/vI_smartIdentityCollection.js @ d0278d

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

bugfix: gAccountManager might not be available

  • Property mode set to 100644
File size: 17.1 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
25var EXPORTED_SYMBOLS = ["smartIdentityCollection"]
26
27Components.utils.import("resource://v_identity/vI_log.js");
28Components.utils.import("resource://v_identity/vI_identityData.js");
29Components.utils.import("resource://v_identity/vI_rdfDatasource.js");
30Components.utils.import("resource://v_identity/vI_prefs.js");
31
32let Log = setupLogging("virtualIdentity.smartIdentityCollection");
33
34function smartIdentityCollection(msgHdr, preseletedID, currentIDisVID, newsgroup, recipients) {
35    this._IDisVID = currentIDisVID;
36    this._preselectedID = preseletedID;
37    this._msgHdr = msgHdr;
38    this._newsgroup = newsgroup;
39    this._unicodeConverter.charset = "UTF-8";
40    this._recipients = recipients;
41    this._rdfDatasourceAccess = new rdfDatasourceAccess();
42    this._allIdentities = new identityCollection();
43};
44
45smartIdentityCollection.prototype = {
46    messenger : Components.classes["@mozilla.org/messenger;1"].createInstance()
47        .QueryInterface(Components.interfaces.nsIMessenger),
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        Log.debug("__autoTimestamp()");
65        if (this._IDisVID) {
66            Log.debug("Virtual Identity in use, aborting");
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        Log.debug("current email: " + current_email[0] + "@" + current_email[1]);
75       
76        var autoString = vIprefs.get("autoString");
77        var formatString = vIprefs.get("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        Log.debug("new email: " + new_email);
87
88        var newIdentity = new 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        Log.debug("checking " + vIprefs.get("idSelection_ignoreIDs") + " against " + this._preselectedID.key )
97        // check if usage if virtual Identities should be used at all for the currently selected ID
98        if (vIprefs.get("idSelection_ignoreIDs").indexOf(":" + this._preselectedID.key + ":") != -1) {
99            Log.debug("not using virtual Identites for ID " + this._preselectedID.key);
100            return true;
101        }
102        return false
103    },
104   
105    NewMail : function() {
106        Log.debug("NewMail()");
107        if (this.__ignoreID()) return;
108        this._rdfDatasourceAccess.getVIdentityFromAllRecipients(this._allIdentities, this._recipients);
109        if (this._allIdentities.number == 0 && vIprefs.get("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                Log.debug("found existing Identity, reorder to prefer this one.");
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        Log.debug("ReplyOnSent() (rules like SmartDraft)");
134        this.__SmartDraftOrReplyOnSent();
135        this._rdfDatasourceAccess.getVIdentityFromAllRecipients(this._allIdentities, this._recipients);
136    },
137
138    Draft : function() {
139        Log.debug("Draft()");
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 identityData(emails.value[index], fullNames.value[index],
150                null, 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 (!vIprefs.get("smart_draft"))
158            { Log.debug("SmartDraft deactivated"); return; }
159
160        Log.debug("__SmartDraftOrReplyOnSent()");
161
162        if (this._msgHdr) {
163            this.__parseHeadersWithArray(this._msgHdr.author, this._allIdentities)
164            Log.debug("sender '" + this._allIdentities.identityDataCollection[0].combinedName + "'");
165        }
166        else Log.debug("__SmartDraftOrReplyOnSent: No Header found, shouldn't happen");
167    },
168   
169    __filterAddresses : function() {
170        var returnIdentities = new identityCollection();
171       
172        var filterList  =
173            this._unicodeConverter.ConvertToUnicode(vIprefs.get("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              Log.debug("no filters configured");
181              recentfilterType = filterType.None;
182            }
183            else if (/^[+-]?\/(.*)\/$/.exec(filterList[i])) {
184              Log.debug("filter emails with RegExp '" + filterList[i].replace(/\\/g,"\\\\") + "'");
185              recentfilterType = filterType.RegExp;
186            }
187            else {
188              Log.debug("filter emails, compare with '" + filterList[i] + "'");
189              recentfilterType = filterType.StrCmp;
190            }
191            for (var j = 0; j < this._allIdentities.number; j++) { // check if recent email-address (pre-choosen identity) is found in
192            // copied and adapted from correctIdentity, thank you for the RegExp-idea!
193                var add_addr = false;
194                switch (recentfilterType) {
195                    case filterType.None:
196                        add_addr = true; break;
197                    case filterType.RegExp:
198                        if (skipRegExp) break;
199                        try {   /^[+-]?\/(.*)\/$/.exec(filterList[i]);
200                            if ( filterList[i][0] == "-" ) {
201                                if (this._allIdentities.identityDataCollection[j].email.match(new RegExp(RegExp.$1,"i")))
202                                    this._allIdentities.dropIdentity(j--);
203                            } else
204                                add_addr = (this._allIdentities.identityDataCollection[j].email.match(new RegExp(RegExp.$1,"i")));
205                        }
206                        catch(vErr) {
207                          this.stringBundle = Components.classes["@mozilla.org/intl/stringbundle;1"]
208                            .getService(Components.interfaces.nsIStringBundleService)
209                            .createBundle("chrome://v_identity/locale/v_identity.properties");
210                          SmartReplyNotification.info(
211                                this.stringBundle.GetStringFromName("vident.smartIdentity.ignoreRegExp") +
212                                +filterList[i].replace(/\\/g,"\\\\") + " .");
213                                skipRegExp = true; }
214                        break;
215                    case filterType.StrCmp:
216                        add_addr = ( this._allIdentities.identityDataCollection[j].email.toLowerCase().indexOf(filterList[i].toLowerCase()) != -1)
217                        break;
218                }
219                if (add_addr)   returnIdentities.addWithoutDuplicates(this._allIdentities.identityDataCollection[j])
220            }
221        }
222        this._allIdentities.takeOver(returnIdentities);
223    },
224   
225    __smartReplyCollectAddresses : function() {
226        // add emails from selected headers (stored by vI_getHeader.xul/js)
227        var reply_headers = this._unicodeConverter.ConvertToUnicode(vIprefs.get("smart_reply_headers")).split(/\n/)
228                   
229        for (var index = 0; index < reply_headers.length; index++) {
230            // ------------- prepare fields to read the stored header ----------------
231            var replyHeader_splitted = reply_headers[index].split(/:/)
232            // use first part (all before ':') as the header name
233            var replyHeaderName = replyHeader_splitted[0].toLowerCase()
234            // check second or third part for any number
235            var replyHeaderNumber = null;
236            if (replyHeader_splitted.length > 1) parseInt(replyHeader_splitted[1]);
237            if ((!replyHeaderNumber || isNaN(replyHeaderNumber)) && replyHeader_splitted.length > 2) replyHeaderNumber = parseInt(replyHeader_splitted[2]);
238            // check if Fullnames should be erased
239            var replyHeaderEmptyFullNames = ((replyHeader_splitted[1] && replyHeader_splitted[1].match(/@/)) ||
240                            (replyHeader_splitted[2] && replyHeader_splitted[2].match(/@/)));
241           
242            // create header name to find the value
243            var replyHeaderNameToRead = replyHeaderName
244            if (replyHeaderNumber && !isNaN(replyHeaderNumber)) replyHeaderNameToRead += ":" + replyHeaderNumber
245           
246            // if mailing-list ignore to-header (usually the mailing list address)
247            if (replyHeaderNameToRead == "to" && this._msgHdr.getStringProperty("vI_list-id")) {
248                Log.debug("header 'list-id' found (mailinglist), skipping header 'to'");
249                continue;
250            }
251           
252            // ------------- read the stored header -------------------------------
253            var value = this._unicodeConverter.ConvertToUnicode(this._msgHdr.getStringProperty("vI_" + replyHeaderNameToRead))
254/*          let window3pane =  Components.classes['@mozilla.org/appshell/window-mediator;1']
255                 .getService(Components.interfaces.nsIWindowMediator)
256                 .getMostRecentWindow("mail:3pane");
257           
258            Log.debug("found stored header '" +
259                replyHeaderNameToRead + "': '" + window3pane.virtualIdentityExtension.storedHeaders["vI_" + replyHeaderNameToRead] + "'");*/
260           
261            Log.debug("reading header '" +
262                replyHeaderNameToRead + "': '" + value + "'");
263           
264            // ------------- parse address-string to get a field of single email-addresses
265            var splitted = new identityCollection();
266            this.__parseHeadersWithArray(value, splitted);
267           
268            // move found addresses step by step to this._allIdentities, and change values if requested
269            for (var i = 0; i < splitted.number; i++) {
270                // if there is no email than it makes no sense to use it as a sender
271                if (!splitted.identityDataCollection[i].email.match(/^.*@.*$/)) {
272                    Log.debug("  skipping '" +
273                    splitted.identityDataCollection[i].email + "', no email")
274                    continue;
275                }
276
277                if (replyHeaderEmptyFullNames) splitted.identityDataCollection[i].fullName = ""
278
279                this._allIdentities.addWithoutDuplicates(splitted.identityDataCollection[i]);
280
281                Log.debug("  found '" +
282                    splitted.identityDataCollection[i].combinedName + "'")
283            }
284        }
285    },
286   
287    Reply : function() {
288        Log.debug("Reply()");
289
290        if (this._msgHdr && this._newsgroup && !this._msgHdr.getStringProperty("vI_content_base")) {
291        //  RFC 2821 (http://www.ietf.org/rfc/rfc2821.txt) says:
292        //  "4.4 Trace Information
293        //  When an SMTP server receives a message for delivery or further
294        //  processing, it MUST insert trace ("time stamp" or "Received")
295        //  information at the beginning of the message content, as discussed in
296        //  section 4.1.1.4."
297        //  so it should be always possible to decide if Reply or Draft based on received headers
298        //  hidden option smart_detectByReceivedHeader will act as a switch for not RFC-compliant servers
299            // RFC-compliant
300            if (vIprefs.get("smart_detectByReceivedHeader")) {
301                if (!this._msgHdr.getStringProperty("vI_received")) { // mail was not received
302                    Log.debug("reply on non-received (sent?) mail. Using SmartDraft.");
303                    this.ReplyOnSent();
304                    return;
305                }
306            }
307            // not RFC-compliant
308            else {
309                const MSG_FOLDER_FLAG_INBOX = 0x1000
310                const MSG_FOLDER_FLAG_SENTMAIL = 0x0200;
311
312                if (this._msgHdr && (this._msgHdr.folder.flags & MSG_FOLDER_FLAG_SENTMAIL)) {
313                    if (this._msgHdr.folder.flags & MSG_FOLDER_FLAG_INBOX)
314                        Log.debug("reply from Sent folder. Folder is INBOX, assuming Reply-Case.");
315                    else {
316                        Log.debug("reply from Sent folder. Using SmartDraft.");
317                        this.ReplyOnSent();
318                        return;
319                    }
320                }
321            }
322        }
323       
324        if (this.__ignoreID()) return;
325       
326        var storageIdentities = new identityCollection();
327        this._rdfDatasourceAccess.getVIdentityFromAllRecipients(storageIdentities, this._recipients);
328       
329        if (storageIdentities.number == 0 || !vIprefs.get("idSelection_storage_ignore_smart_reply"))
330            this.__SmartReply();
331        else Log.debug("SmartReply skipped, Identities in Storage found.");
332
333        // merge SmartReply-Identities and Storage-Identites
334        if (vIprefs.get("idSelection_storage_prefer_smart_reply"))
335            { this._allIdentities.mergeWithoutDuplicates(storageIdentities); }
336        else {
337            var smartIdentities = this._allIdentities;
338            this._allIdentities = storageIdentities;       
339            this._allIdentities.mergeWithoutDuplicates(smartIdentities);
340        }
341       
342        Log.debug("merged SmartReply & Storage, " + this._allIdentities.number + " address(es) left")
343    },
344   
345    // this function checks if we have a reply-case and Smart-Reply should replace the Identity
346    __SmartReply : function() {
347        if (!vIprefs.get("smart_reply"))
348            { Log.debug("SmartReply deactivated"); return; }
349        if (this._newsgroup && !vIprefs.get("smart_reply_for_newsgroups")) {
350            Log.debug("SmartReply, answering to a newsgroup, aborting");
351            return;
352        }
353
354        Log.debug("__SmartReply()");
355        Log.debug("----------------------------------------------------------")
356        if (this._msgHdr) {
357            /* first step: collect addresses */
358            this.__smartReplyCollectAddresses();
359            Log.debug("" + this._allIdentities.number + " address(es) after parsing, before filtering")
360           
361            /* second step: filter (and sort) addresses */
362            this.__filterAddresses();
363           
364            Log.debug("filtering done, " + this._allIdentities.number + " address(es) left")
365           
366            /* set default FullName */
367            var smart_reply_defaultFullName = this._unicodeConverter.ConvertToUnicode(vIprefs.get("smart_reply_defaultFullName"))
368            if (smart_reply_defaultFullName != "") {
369                for (var index = 0; index < this._allIdentities.number; index++) {
370                    if (this._allIdentities.identityDataCollection[index].fullName == "") {
371                        this._allIdentities.identityDataCollection[index].fullName = smart_reply_defaultFullName
372                        Log.debug("added default FullName '" + 
373                            smart_reply_defaultFullName + "' to '" + this._allIdentities.identityDataCollection[index].email + "'")
374                    }
375                }
376            }   
377
378            /* smart_reply_ignoreFullName: compare email with other Identities          */
379            /* if match replace FullName with existing one, keep identity in list by now        */
380            /* will not be added to the menu but probably choosen with __smartIdentitySelection     */
381            if (vIprefs.get("smart_reply_ignoreFullName")) {
382                Log.debug("compare with existing Identities (ignoring FullNames).")
383           
384                for (var index = 0; index < this._allIdentities.number; index++) {
385                    var idKey = this._allIdentities.identityDataCollection[index].isExistingIdentity(true);
386                    if (idKey) {
387                        var AccountManager = Components.classes["@mozilla.org/messenger/account-manager;1"]
388                          .getService(Components.interfaces.nsIMsgAccountManager);
389                        var newFullName = AccountManager.getIdentity(idKey).fullName;
390                        this._allIdentities.identityDataCollection[index].fullName = newFullName;
391                        Log.debug("replaced Fullname of '" + this._allIdentities.identityDataCollection[index].email + "' with '" + newFullName + "'");
392                    }
393                }
394            }
395        }
396        else Log.debug("SmartReply skipped. No Header-information found.");
397       
398        Log.debug("----------------------------------------------------------")
399    },
400   
401
402};
Note: See TracBrowser for help on using the repository browser.