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

source: modules/vI_smartIdentityCollection.js @ 509348

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

code formatting (no code changes)

  • Property mode set to 100644
File size: 18.4 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();
80    var dateString = "";
81    if (formatString == "") dateString = parseInt(dateObj.getTime() / 1000);
82    else try { //   you never know what the formatString will be...
83      dateString = dateObj.toLocaleFormat(formatString).replace(/\s+|[\x00-\x2a]|\x2c|\x2f|[\x3a-\x40]|[\x5b-\x5d]|\x60|\x7c|[\x7f-\xff]/g, "_");
84    } catch (e) {};
85
86    var new_email = autoString.replace(/%l/g, localpart).replace(/%d/g, domain).replace(/%t/g, dateString);
87    Log.debug("new email: " + new_email);
88
89    var newIdentity = new identityData(new_email,
90      this._preselectedID.fullName, this._preselectedID.key, this._preselectedID.smtpServerKey, null, null)
91
92    this._allIdentities.addWithoutDuplicates(newIdentity);
93    this._selectedValue = 0;
94  },
95
96  __ignoreID: function () {
97    Log.debug("checking " + vIprefs.get("idSelection_ignoreIDs") + " against " + this._preselectedID.key)
98      // check if usage if virtual Identities should be used at all for the currently selected ID
99    if (vIprefs.get("idSelection_ignoreIDs").indexOf(":" + this._preselectedID.key + ":") != -1) {
100      Log.debug("not using virtual Identites for ID " + this._preselectedID.key);
101      return true;
102    }
103    return false
104  },
105
106  NewMail: function () {
107    Log.debug("NewMail()");
108    if (this.__ignoreID()) return;
109    this._rdfDatasourceAccess.getVIdentityFromAllRecipients(this._allIdentities, this._recipients);
110    if (this._allIdentities.number == 0 && vIprefs.get("autoTimestamp")) this.__autoTimestamp();
111  },
112
113  _foundExistingIdentity: function () {
114    /* compare with existing Identities                                     */
115    for (var index = 0; index < this._allIdentities.number; index++) {
116      var existingID = this._allIdentities.identityDataCollection[index].isExistingIdentity(false);
117      if (existingID) {
118        this._allIdentities.identityDataCollection[index].id.key = existingID; // set found identity
119        // reorder list of Identities to prefer it on autoselect
120        // has to be done before Identities are added to the Menu
121        Log.debug("found existing Identity, reorder to prefer this one.");
122        var firstIdentity = this._allIdentities.identityDataCollection[index];
123        for (var i = index; index > 0; index--) {
124          this._allIdentities.identityDataCollection[index] = this._allIdentities.identityDataCollection[index - 1];
125        }
126        this._allIdentities.identityDataCollection[0] = firstIdentity;
127        return {
128          key: index
129        };
130      }
131    }
132    return null;
133  },
134
135  ReplyOnSent: function () {
136    Log.debug("ReplyOnSent() (rules like SmartDraft)");
137    this.__SmartDraftOrReplyOnSent();
138    this._rdfDatasourceAccess.getVIdentityFromAllRecipients(this._allIdentities, this._recipients);
139  },
140
141  Draft: function () {
142    Log.debug("Draft()");
143
144    this.__SmartDraftOrReplyOnSent();
145    this._rdfDatasourceAccess.getVIdentityFromAllRecipients(this._allIdentities, this._recipients);
146  },
147
148  __parseHeadersWithArray: function (header, identityCollection) {
149    var emails = {};
150    var fullNames = {};
151    var combinedNames = {};
152    var number = this._headerParser.parseHeadersWithArray(header, emails, fullNames, combinedNames);
153    for (var index = 0; index < number; index++) {
154      var newIdentity = new identityData(emails.value[index], fullNames.value[index],
155        null, NO_SMTP_TAG, null, null);
156      identityCollection.addWithoutDuplicates(newIdentity);
157    }
158  },
159
160  // this function checks if we have a draft-case and Smart-Draft should replace the Identity
161  __SmartDraftOrReplyOnSent: function () {
162    if (!vIprefs.get("smart_draft")) {
163      Log.debug("SmartDraft deactivated");
164      return;
165    }
166
167    Log.debug("__SmartDraftOrReplyOnSent()");
168
169    if (this._msgHdr) {
170      this.__parseHeadersWithArray(this._msgHdr.author, this._allIdentities)
171      Log.debug("sender '" + this._allIdentities.identityDataCollection[0].combinedName + "'");
172    } else Log.debug("__SmartDraftOrReplyOnSent: No Header found, shouldn't happen");
173  },
174
175  __filterAddresses: function () {
176    var returnIdentities = new identityCollection();
177
178    var filterList =
179      this._unicodeConverter.ConvertToUnicode(vIprefs.get("smart_reply_filter")).split(/\n/)
180    if (filterList.length == 0) filterList[0] == ""
181
182    for (var i = 0; i < filterList.length; i++) {
183      const filterType = {
184        None: 0,
185        RegExp: 1,
186        StrCmp: 2
187      }
188      var recentfilterType;
189      var skipRegExp = false;
190      if (filterList.length <= 1 && filterList[0] == "") {
191        Log.debug("no filters configured");
192        recentfilterType = filterType.None;
193      } else if (/^[+-]?\/(.*)\/$/.exec(filterList[i])) {
194        Log.debug("filter emails with RegExp '" + filterList[i].replace(/\\/g, "\\\\") + "'");
195        recentfilterType = filterType.RegExp;
196      } else {
197        Log.debug("filter emails, compare with '" + filterList[i] + "'");
198        recentfilterType = filterType.StrCmp;
199      }
200      for (var j = 0; j < this._allIdentities.number; j++) { // check if recent email-address (pre-choosen identity) is found in
201        // copied and adapted from correctIdentity, thank you for the RegExp-idea!
202        var add_addr = false;
203        switch (recentfilterType) {
204        case filterType.None:
205          add_addr = true;
206          break;
207        case filterType.RegExp:
208          if (skipRegExp) break;
209          try {
210            /^[+-]?\/(.*)\/$/.exec(filterList[i]);
211            if (filterList[i][0] == "-") {
212              if (this._allIdentities.identityDataCollection[j].email.match(new RegExp(RegExp.$1, "i")))
213                this._allIdentities.dropIdentity(j--);
214            } else
215              add_addr = (this._allIdentities.identityDataCollection[j].email.match(new RegExp(RegExp.$1, "i")));
216          } catch (vErr) {
217            this.stringBundle = Components.classes["@mozilla.org/intl/stringbundle;1"]
218              .getService(Components.interfaces.nsIStringBundleService)
219              .createBundle("chrome://v_identity/locale/v_identity.properties");
220            SmartReplyNotification.info(
221              this.stringBundle.GetStringFromName("vident.smartIdentity.ignoreRegExp") +
222              +filterList[i].replace(/\\/g, "\\\\") + " .");
223            skipRegExp = true;
224          }
225          break;
226        case filterType.StrCmp:
227          add_addr = (this._allIdentities.identityDataCollection[j].email.toLowerCase().indexOf(filterList[i].toLowerCase()) != -1)
228          break;
229        }
230        if (add_addr) returnIdentities.addWithoutDuplicates(this._allIdentities.identityDataCollection[j])
231      }
232    }
233    this._allIdentities.takeOver(returnIdentities);
234  },
235
236  __smartReplyCollectAddresses: function () {
237    // add emails from selected headers (stored by vI_getHeader.xul/js)
238    var reply_headers = this._unicodeConverter.ConvertToUnicode(vIprefs.get("smart_reply_headers")).split(/\n/)
239
240    for (var index = 0; index < reply_headers.length; index++) {
241      // ------------- prepare fields to read the stored header ----------------
242      var replyHeader_splitted = reply_headers[index].split(/:/)
243        // use first part (all before ':') as the header name
244      var replyHeaderName = replyHeader_splitted[0].toLowerCase()
245        // check second or third part for any number
246      var replyHeaderNumber = null;
247      if (replyHeader_splitted.length > 1) parseInt(replyHeader_splitted[1]);
248      if ((!replyHeaderNumber || isNaN(replyHeaderNumber)) && replyHeader_splitted.length > 2) replyHeaderNumber = parseInt(replyHeader_splitted[2]);
249      // check if Fullnames should be erased
250      var replyHeaderEmptyFullNames = ((replyHeader_splitted[1] && replyHeader_splitted[1].match(/@/)) ||
251        (replyHeader_splitted[2] && replyHeader_splitted[2].match(/@/)));
252
253      // create header name to find the value
254      var replyHeaderNameToRead = replyHeaderName
255      if (replyHeaderNumber && !isNaN(replyHeaderNumber)) replyHeaderNameToRead += ":" + replyHeaderNumber
256
257      // if mailing-list ignore to-header (usually the mailing list address)
258      if (replyHeaderNameToRead == "to" && this._msgHdr.getStringProperty("vI_list-id")) {
259        Log.debug("header 'list-id' found (mailinglist), skipping header 'to'");
260        continue;
261      }
262
263      // ------------- read the stored header -------------------------------
264      var value = this._unicodeConverter.ConvertToUnicode(this._msgHdr.getStringProperty("vI_" + replyHeaderNameToRead))
265        /*          let window3pane =  Components.classes['@mozilla.org/appshell/window-mediator;1']
266                         .getService(Components.interfaces.nsIWindowMediator)
267                         .getMostRecentWindow("mail:3pane");
268                   
269                    Log.debug("found stored header '" +
270                        replyHeaderNameToRead + "': '" + window3pane.virtualIdentityExtension.storedHeaders["vI_" + replyHeaderNameToRead] + "'");*/
271
272      Log.debug("reading header '" +
273        replyHeaderNameToRead + "': '" + value + "'");
274
275      // ------------- parse address-string to get a field of single email-addresses
276      var splitted = new identityCollection();
277      this.__parseHeadersWithArray(value, splitted);
278
279      // move found addresses step by step to this._allIdentities, and change values if requested
280      for (var i = 0; i < splitted.number; i++) {
281        // if there is no email than it makes no sense to use it as a sender
282        if (!splitted.identityDataCollection[i].email.match(/^.*@.*$/)) {
283          Log.debug("  skipping '" +
284            splitted.identityDataCollection[i].email + "', no email")
285          continue;
286        }
287
288        if (replyHeaderEmptyFullNames) splitted.identityDataCollection[i].fullName = ""
289
290        this._allIdentities.addWithoutDuplicates(splitted.identityDataCollection[i]);
291
292        Log.debug("  found '" +
293          splitted.identityDataCollection[i].combinedName + "'")
294      }
295    }
296  },
297
298  Reply: function () {
299    Log.debug("Reply()");
300
301    if (this._msgHdr && !this._newsgroup && !this._msgHdr.getStringProperty("vI_content_base")) {
302      //    RFC 2821 (http://www.ietf.org/rfc/rfc2821.txt) says:
303      //    "4.4 Trace Information
304      //    When an SMTP server receives a message for delivery or further
305      //    processing, it MUST insert trace ("time stamp" or "Received")
306      //    information at the beginning of the message content, as discussed in
307      //    section 4.1.1.4."
308      //    so it should be always possible to decide if Reply or Draft based on received headers
309      //    hidden option smart_detectByReceivedHeader will act as a switch for not RFC-compliant servers
310      // RFC-compliant
311      if (vIprefs.get("smart_detectByReceivedHeader")) {
312        if (!this._msgHdr.getStringProperty("vI_received")) { // mail was not received
313          Log.debug("reply on non-received (sent?) mail. Using SmartDraft.");
314          this.ReplyOnSent();
315          return;
316        }
317      }
318      // not RFC-compliant
319      else {
320        const MSG_FOLDER_FLAG_INBOX = 0x1000
321        const MSG_FOLDER_FLAG_SENTMAIL = 0x0200;
322
323        if (this._msgHdr && (this._msgHdr.folder.flags & MSG_FOLDER_FLAG_SENTMAIL)) {
324          if (this._msgHdr.folder.flags & MSG_FOLDER_FLAG_INBOX)
325            Log.debug("reply from Sent folder. Folder is INBOX, assuming Reply-Case.");
326          else {
327            Log.debug("reply from Sent folder. Using SmartDraft.");
328            this.ReplyOnSent();
329            return;
330          }
331        }
332      }
333    }
334
335    if (this.__ignoreID()) return;
336
337    var storageIdentities = new identityCollection();
338    this._rdfDatasourceAccess.getVIdentityFromAllRecipients(storageIdentities, this._recipients);
339
340    if (storageIdentities.number == 0 || !vIprefs.get("idSelection_storage_ignore_smart_reply"))
341      this.__SmartReply();
342    else Log.debug("SmartReply skipped, Identities in Storage found.");
343
344    // merge SmartReply-Identities and Storage-Identites
345    if (vIprefs.get("idSelection_storage_prefer_smart_reply")) {
346      this._allIdentities.mergeWithoutDuplicates(storageIdentities);
347    } else {
348      var smartIdentities = this._allIdentities;
349      this._allIdentities = storageIdentities;
350      this._allIdentities.mergeWithoutDuplicates(smartIdentities);
351    }
352
353    Log.debug("merged SmartReply & Storage, " + this._allIdentities.number + " address(es) left")
354  },
355
356  // this function checks if we have a reply-case and Smart-Reply should replace the Identity
357  __SmartReply: function () {
358    if (!vIprefs.get("smart_reply")) {
359      Log.debug("SmartReply deactivated");
360      return;
361    }
362    if (this._newsgroup && !vIprefs.get("smart_reply_for_newsgroups")) {
363      Log.debug("SmartReply, answering to a newsgroup, aborting");
364      return;
365    }
366
367    Log.debug("__SmartReply()");
368    Log.debug("----------------------------------------------------------")
369    if (this._msgHdr) {
370      /* first step: collect addresses */
371      this.__smartReplyCollectAddresses();
372      Log.debug("" + this._allIdentities.number + " address(es) after parsing, before filtering")
373
374      /* second step: filter (and sort) addresses */
375      this.__filterAddresses();
376
377      Log.debug("filtering done, " + this._allIdentities.number + " address(es) left")
378
379      /* set default FullName */
380      var smart_reply_defaultFullName = this._unicodeConverter.ConvertToUnicode(vIprefs.get("smart_reply_defaultFullName"))
381      if (smart_reply_defaultFullName != "") {
382        for (var index = 0; index < this._allIdentities.number; index++) {
383          if (this._allIdentities.identityDataCollection[index].fullName == "") {
384            this._allIdentities.identityDataCollection[index].fullName = smart_reply_defaultFullName
385            Log.debug("added default FullName '" +
386              smart_reply_defaultFullName + "' to '" + this._allIdentities.identityDataCollection[index].email + "'")
387          }
388        }
389      }
390
391      /* smart_reply_ignoreFullName: compare email with other Identities            */
392      /* if match replace FullName with existing one, keep identity in list by now      */
393      /* will not be added to the menu but probably choosen with __smartIdentitySelection   */
394      if (vIprefs.get("smart_reply_ignoreFullName")) {
395        Log.debug("compare with existing Identities (ignoring FullNames).")
396
397        for (var index = 0; index < this._allIdentities.number; index++) {
398          var idKey = this._allIdentities.identityDataCollection[index].isExistingIdentity(true);
399          if (idKey) {
400            var AccountManager = Components.classes["@mozilla.org/messenger/account-manager;1"]
401              .getService(Components.interfaces.nsIMsgAccountManager);
402            var newFullName = AccountManager.getIdentity(idKey).fullName;
403            this._allIdentities.identityDataCollection[index].fullName = newFullName;
404            Log.debug("replaced Fullname of '" + this._allIdentities.identityDataCollection[index].email + "' with '" + newFullName + "'");
405          }
406        }
407      }
408
409      /* smart_reply_searchBaseIdentity: compare email with other Identities          */
410      /* to find matching domain. Use first found as base identity (smtp etc) */
411      if (vIprefs.get("smart_reply_searchBaseIdentity")) {
412        Log.debug("compare domain name with existing accounts.")
413
414        for (var index = 0; index < this._allIdentities.number; index++) {
415          var idKey = this._allIdentities.identityDataCollection[index].hasMatchingDomainIdentity();
416          if (idKey) {
417            Log.debug("use id with matching domain as base ID");
418            this._allIdentities.identityDataCollection[index].id.key = idKey;
419          }
420        }
421      }
422
423    } else Log.debug("SmartReply skipped. No Header-information found.");
424
425    Log.debug("----------------------------------------------------------")
426  },
427
428
429};
Note: See TracBrowser for help on using the repository browser.