initial support for config instrumentation, preffed off, r=bwinton, bug 632639
authorDavid Bienvenu <bienvenu@nventure.com>
Sat, 12 Mar 2011 05:33:58 -0800
changeset 7334 478ab6a5e8d5c2f5508aa657577774e3b4a8bc5a
parent 7333 977bed463e8bc1a3e2176f73bbe4fda229c5184b
child 7335 149df5731ea6b4d9a29c6801476bf8fbcb16bac6
push idunknown
push userunknown
push dateunknown
reviewersbwinton, bug
bugs632639
initial support for config instrumentation, preffed off, r=bwinton, bug 632639
mail/app/profile/all-thunderbird.js
mail/base/content/msgMail3PaneWindow.js
mail/base/modules/Makefile.in
mail/components/compose/content/MsgComposeCommands.js
mail/test/mozmill/instrumentation/test-instrument-setup.js
mail/test/mozmill/instrumentation/wrapper.py
mail/test/mozmill/mozmilltests.list
--- a/mail/app/profile/all-thunderbird.js
+++ b/mail/app/profile/all-thunderbird.js
@@ -460,16 +460,24 @@ pref("toolbar.customization.usesheet", f
 // Check for missing attachments?
 pref("mail.compose.attachment_reminder", true);
 // Words that should trigger a missing attachments warning.
 pref("mail.compose.attachment_reminder_keywords", "chrome://messenger/locale/messengercompose/composeMsgs.properties");
 // When no action is taken on the inline missing attachement notification,
 // show an alert on send?
 pref("mail.compose.attachment_reminder_aggressive", true);
 
+// Set this to false to prevent instrumentation from happening, e.g., user
+// has opted out, or an enterprise wants to disable it from the git go.
+pref("mail.instrumentation.askUser", true);
+pref("mail.instrumentation.userOptedIn", false);
+pref("mail.instrumentation.postUrl", "https://www.mozillamessaging.com/instrumentation");
+// not sure how this will be formatted - would be nice to make it extensible.
+pref("mail.instrumentation.lastNotificationSent", "");
+
 pref("browser.formfill.enable", true);
 
 // Disable autoplay as we don't handle audio elements in emails very well.
 // See bug 515082.
 pref("media.autoplay.enabled", false);
 
 // whether to hide the timeline view by default in the faceted search display
 pref("gloda.facetview.hidetimeline", true);
--- a/mail/base/content/msgMail3PaneWindow.js
+++ b/mail/base/content/msgMail3PaneWindow.js
@@ -46,16 +46,17 @@
 Components.utils.import("resource://gre/modules/folderUtils.jsm");
 Components.utils.import("resource:///modules/activity/activityModules.js");
 Components.utils.import("resource:///modules/jsTreeSelection.js");
 Components.utils.import("resource:///modules/MailConsts.js");
 Components.utils.import("resource:///modules/errUtils.js");
 Components.utils.import("resource:///modules/IOUtils.js");
 Components.utils.import("resource:///modules/mailnewsMigrator.js");
 Components.utils.import("resource:///modules/sessionStoreManager.js");
+Components.utils.import("resource:///modules/mailInstrumentation.js");
 
 /* This is where functions related to the 3 pane window are kept */
 
 // from MailNewsTypes.h
 const nsMsgKey_None = 0xFFFFFFFF;
 const nsMsgViewIndex_None = 0xFFFFFFFF;
 const kMailCheckOncePrefName = "mail.startup.enabledMailCheckOnce";
 
@@ -348,16 +349,21 @@ function OnLoadMessenger()
   gPrefBranch.addObserver("mail.pane_config.dynamic", MailPrefObserver, false);
   gPrefBranch.addObserver("mail.showCondensedAddresses", MailPrefObserver,
                           false);
 
   MailOfflineMgr.init();
   CreateMailWindowGlobals();
   GetMessagePane().collapsed = true;
 
+  // This needs to be before we throw up the account wizard on first run.
+  try {
+    mailInstrumentationManager.init();
+  } catch(ex) {logException(ex);}
+
   // - initialize tabmail system
   // Do this before LoadPostAccountWizard since that code selects the first
   //  folder for display, and we want gFolderDisplay setup and ready to handle
   //  that event chain.
   // Also, we definitely need to register the tab type prior to the call to
   //  specialTabs.openSpecialTabsOnStartup below.
   let tabmail = document.getElementById('tabmail');
   if (tabmail)
@@ -445,16 +451,18 @@ function LoadPostAccountWizard()
         arg0 = arg0.wrappedJSObject;
       startMsgHdr = ("msgHdr" in arg0) ? arg0.msgHdr : null;
     }
   }
 
   function completeStartup() {
     // Check whether we need to show the default client dialog
     // First, check the shell service
+    let obs = Components.classes["@mozilla.org/observer-service;1"]
+                        .getService(Components.interfaces.nsIObserverService);
     var nsIShellService = Components.interfaces.nsIShellService;
     if (nsIShellService) {
       var shellService;
       var defaultAccount;
       try {
         shellService = Components.classes["@mozilla.org/mail/shell-service;1"].getService(nsIShellService);
         defaultAccount = accountManager.defaultAccount;
       } catch (ex) {}
@@ -468,24 +476,26 @@ function LoadPostAccountWizard()
       // for mail,
       // OR: we have the search integration module, the OS version is suitable,
       // and the first run hasn't already been completed.
       // Needs to be shown outside the he normal load sequence so it doesn't appear
       // before any other displays, in the wrong place of the screen.
       if ((shellService && defaultAccount && shellService.shouldCheckDefaultClient
            && !shellService.isDefaultClient(true, nsIShellService.MAIL)) ||
         (SearchIntegration && !SearchIntegration.osVersionTooLow &&
-         !SearchIntegration.osComponentsNotRunning && !SearchIntegration.firstRunDone))
+         !SearchIntegration.osComponentsNotRunning && !SearchIntegration.firstRunDone)) {
         window.openDialog("chrome://messenger/content/systemIntegrationDialog.xul",
                           "SystemIntegration", "modal,centerscreen,chrome,resizable=no");
+        // On windows, there seems to be a delay between setting TB as the
+        // default client, and the isDefaultClient check succeeding.
+        if (shellService.isDefaultClient(true, nsIShellService.MAIL))
+          obs.notifyObservers(window, "mail:setAsDefault", null);
+      }
     }
-
     // All core modal dialogs are done, the user can now interact with the 3-pane window
-    var obs = Components.classes["@mozilla.org/observer-service;1"]
-                        .getService(Components.interfaces.nsIObserverService);
     obs.notifyObservers(window, "mail-startup-done", null);
   }
 
   setTimeout(completeStartup, 0);
 
   // FIX ME - later we will be able to use onload from the overlay
   OnLoadMsgHeaderPane();
 
@@ -564,16 +574,18 @@ function OnUnloadMessenger()
 {
   accountManager.removeIncomingServerListener(gThreePaneIncomingServerListener);
   gPrefBranch.QueryInterface(Components.interfaces.nsIPrefBranch2);
   gPrefBranch.removeObserver("mail.pane_config.dynamic", MailPrefObserver);
   gPrefBranch.removeObserver("mail.showCondensedAddresses", MailPrefObserver);
 
   sessionStoreManager.unloadingWindow(window);
 
+  mailInstrumentationManager.uninit();
+
   let tabmail = document.getElementById("tabmail");
   tabmail._teardown();
 
   var mailSession = Components.classes["@mozilla.org/messenger/services/session;1"]
                               .getService(Components.interfaces.nsIMsgMailSession);
   mailSession.RemoveFolderListener(folderListener);
 
   gPhishingDetector.shutdown();
--- a/mail/base/modules/Makefile.in
+++ b/mail/base/modules/Makefile.in
@@ -49,11 +49,12 @@ EXTRA_JS_MODULES = \
   attachmentChecker.js \
   dbViewWrapper.js \
   mailViewManager.js \
   quickFilterManager.js \
   searchSpec.js \
   MsgHdrSyntheticView.js \
   sessionStoreManager.js \
   mailMigrator.js \
+  mailInstrumentation.js \
   $(NULL)
 
 include $(topsrcdir)/config/rules.mk
--- a/mail/components/compose/content/MsgComposeCommands.js
+++ b/mail/components/compose/content/MsgComposeCommands.js
@@ -316,16 +316,32 @@ var stateListener = {
     gCloseWindowAfterSave = false;
   },
 
   SaveInFolderDone: function(folderURI) {
     DisplaySaveFolderDlg(folderURI);
   }
 };
 
+var gSendListener = {
+  // nsIMsgSendListener
+  onStartSending: function (aMsgID, aMsgSize) {},
+  onProgress: function (aMsgID, aProgress, aProgressMax) {},
+  onStatus: function (aMsgID, aMsg) {},
+  onStopSending: function (aMsgID, aStatus, aMsg, aReturnFile) {
+    if (Components.isSuccessCode(aStatus)) {
+      Components.classes["@mozilla.org/observer-service;1"]
+      .getService(Components.interfaces.nsIObserverService)
+      .notifyObservers(null, "mail:composeSendSucceeded", null);
+    }
+  },
+  onGetDraftFolderURI: function (aFolderURI) {},
+  onSendNotPerformed: function (aMsgID, aStatus) {},
+};
+
 // all progress notifications are done through the nsIWebProgressListener implementation...
 var progressListener = {
     onStateChange: function(aWebProgress, aRequest, aStateFlags, aStatus)
     {
       if (aStateFlags & Components.interfaces.nsIWebProgressListener.STATE_START)
       {
         document.getElementById('compose-progressmeter').setAttribute( "mode", "undetermined" );
         document.getElementById("statusbar-progresspanel").collapsed = false;
@@ -1551,17 +1567,17 @@ function ComposeStartup(recycled, aParam
 
   // Get the <editor> element to startup an editor
   var editorElement = GetCurrentEditorElement();
   gMsgCompose = composeSvc.initCompose(params, window, editorElement.docShell);
   if (gMsgCompose)
   {
     // set the close listener
     gMsgCompose.recyclingListener = gComposeRecyclingListener;
-
+    gMsgCompose.addMsgSendListener(gSendListener);
     //Lets the compose object knows that we are dealing with a recycled window
     gMsgCompose.recycledWindow = recycled;
 
     document.getElementById("returnReceiptMenu")
             .setAttribute('checked', gMsgCompose.compFields.returnReceipt);
     document.getElementById("dsnMenu")
             .setAttribute('checked', gMsgCompose.compFields.DSN);
     document.getElementById("cmd_attachVCard")
@@ -1798,16 +1814,18 @@ function ComposeUnload()
 {
   UnloadCommandUpdateHandlers();
 
   // Stop gSpellChecker so personal dictionary is saved
   enableInlineSpellCheck(false);
 
   EditorCleanup();
 
+  if (gMsgCompose)
+    gMsgCompose.removeMsgSendListener(gSendListener);
   RemoveMessageComposeOfflineObserver();
   RemoveDirectoryServerObserver(null);
   if (gCurrentIdentity)
     RemoveDirectoryServerObserver("mail.identity." + gCurrentIdentity.key);
   if (gCurrentAutocompleteDirectory)
     RemoveDirectorySettingsObserver(gCurrentAutocompleteDirectory);
   if (gMsgCompose)
     gMsgCompose.UnregisterStateListener(stateListener);
new file mode 100644
--- /dev/null
+++ b/mail/test/mozmill/instrumentation/test-instrument-setup.js
@@ -0,0 +1,131 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is
+ * The Mozilla Foundation.
+ * Portions created by the Initial Developer are Copyright (C) 2011
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   David Bienvenu<bienvenu@mozillamessaging.com>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+var MODULE_NAME = "test-instrument-setup";
+
+var RELATIVE_ROOT = "../shared-modules";
+var MODULE_REQUIRES = ["folder-display-helpers", "window-helpers",
+                       "account-manager-helpers", "keyboard-helpers" ];
+
+var mozmill = {};
+Components.utils.import("resource://mozmill/modules/mozmill.js", mozmill);
+var controller = {};
+Components.utils.import("resource://mozmill/modules/controller.js", controller);
+var elib = {};
+Components.utils.import("resource://mozmill/modules/elementslib.js", elib);
+
+var wh, awc, account, incoming, outgoing;
+
+var user = {
+  name: "Roger Sterling",
+  email: "roger.sterling@example.com",
+  incomingHost: "testin.example.com",
+  outgoingHost: "testout.example.com",
+};
+
+function setupModule(module) {
+  let pref = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
+  wh = collector.getModule("window-helpers");
+  wh.installInto(module);
+  var fdh = collector.getModule("folder-display-helpers");
+  fdh.installInto(module);
+  var amh = collector.getModule("account-manager-helpers");
+  amh.installInto(module);
+  var kh = collector.getModule("keyboard-helpers");
+  kh.installInto(module);
+}
+
+function test_mail_account_setup() {
+  // Set the pref to load a local autoconfig file.
+  let pref = Cc["@mozilla.org/preferences-service;1"].getService(Ci.nsIPrefBranch);
+  let pref_name = "mailnews.auto_config_url";
+  let url = collector.addHttpResource("../account/xml", "autoconfig");
+  pref.setCharPref(pref_name, url);
+
+  // Force .com MIME-Type to text/xml
+  collector.httpd.registerContentType("com", "text/xml");
+
+  awc = wh.wait_for_existing_window("mail:autoconfig");
+
+  // Input user's account information
+  awc.e("realname").focus();
+  input_value(awc, user.name);
+  awc.keypress(null, "VK_TAB", {});
+  input_value(awc, user.email);
+
+  // Load the autoconfig file from http://localhost:433**/autoconfig/example.com
+  awc.e("next_button").click();
+
+  let config = null;
+
+  // XXX: This should probably use a notification, once we fix bug 561143.
+  awc.waitForEval("subject._currentConfig != null", 8000, 600,
+                  awc.window.gEmailConfigWizard);
+  config = awc.window.gEmailConfigWizard._currentConfig;
+  plan_for_window_close(awc);
+  awc.e("create_button").click();
+
+  // Clean up
+  pref.clearUserPref(pref_name);
+  wait_for_window_close();
+  remove_account();
+  let events = mc.window.mailInstrumentationManager._currentState.events;
+  // we expect to have accountAdded and smtpServerAdded events.
+  if (! (events["accountAdded"].data))
+    throw new Error("failed to add an account");
+  else if (! (events["smtpServerAdded"].data))
+    throw new Error("failed to add an smtp server");
+}
+
+
+// Remove the account we added.
+function remove_account() {
+  let am = Cc["@mozilla.org/messenger/account-manager;1"]
+      .getService(Ci.nsIMsgAccountManager);
+  let smtpService = Cc["@mozilla.org/messengercompose/smtp;1"]
+                     .getService(Ci.nsISmtpService);
+
+  let incomingServer = am.FindServer("roger.sterling", "testin.example.com", "pop3");
+  let account = am.FindAccountForServer(incomingServer)
+
+  let identity = account.defaultIdentity;
+  am.removeIncomingServer(incomingServer, true);
+  outgoing = smtpService.getServerByKey(identity.smtpServerKey);
+  smtpService.deleteSmtpServer(outgoing);
+  am.removeAccount(account);
+}
+
new file mode 100644
--- /dev/null
+++ b/mail/test/mozmill/instrumentation/wrapper.py
@@ -0,0 +1,1 @@
+NO_ACCOUNTS = True
--- a/mail/test/mozmill/mozmilltests.list
+++ b/mail/test/mozmill/mozmilltests.list
@@ -2,16 +2,17 @@ account
 composition
 content-policy
 content-tabs
 cookies
 folder-display
 folder-pane
 folder-tree-modes
 folder-widget
+instrumentation
 junk-commands
 message-header
 message-window
 migration
 migration-from-tb2
 pref-window
 quick-filter-bar
 search-window