function ComposeStartup()

in suite/mailnews/components/compose/content/MsgComposeCommands.js [1198:1563]


function ComposeStartup(aParams)
{
  var params = null; // New way to pass parameters to the compose window as a nsIMsgComposeParameters object
  var args = null;   // old way, parameters are passed as a string
  gBodyFromArgs = false;

  if (aParams)
    params = aParams;
  else if (window.arguments && window.arguments[0]) {
    try {
      if (window.arguments[0] instanceof Ci.nsIMsgComposeParams)
        params = window.arguments[0];
      else
        params = handleMailtoArgs(window.arguments[0]);
    }
    catch(ex) { dump("ERROR with parameters: " + ex + "\n"); }

    // if still no dice, try and see if the params is an old fashioned list of string attributes
    // XXX can we get rid of this yet?
    if (!params)
    {
      args = GetArgs(window.arguments[0]);
    }
  }

  // Set the document language to the preference as early as possible.
  document.documentElement
          .setAttribute("lang", Services.prefs.getCharPref("spellchecker.dictionary"));

  var identityList = GetMsgIdentityElement();

  document.addEventListener("paste", onPasteOrDrop);
  document.addEventListener("drop", onPasteOrDrop);

  if (identityList)
    FillIdentityList(identityList);

  if (!params) {
    // This code will go away soon as now arguments are passed to the window
    // using a object of type nsMsgComposeParams instead of a string.
    params = Cc["@mozilla.org/messengercompose/composeparams;1"]
               .createInstance(Ci.nsIMsgComposeParams);
    params.composeFields = Cc["@mozilla.org/messengercompose/composefields;1"]
                             .createInstance(Ci.nsIMsgCompFields);

    if (args) { //Convert old fashion arguments into params
      var composeFields = params.composeFields;
      if (args.bodyislink && args.bodyislink == "true")
        params.bodyIsLink = true;
      if (args.type)
        params.type = args.type;
      if (args.format) {
        // Only use valid values.
        if (args.format == Ci.nsIMsgCompFormat.PlainText ||
            args.format == Ci.nsIMsgCompFormat.HTML ||
            args.format == Ci.nsIMsgCompFormat.OppositeOfDefault)
          params.format = args.format;
        else if (args.format.toLowerCase().trim() == "html")
          params.format = Ci.nsIMsgCompFormat.HTML;
        else if (args.format.toLowerCase().trim() == "text")
          params.format = Ci.nsIMsgCompFormat.PlainText;
      }
      if (args.originalMsgURI)
        params.originalMsgURI = args.originalMsgURI;
      if (args.preselectid)
        params.identity = getIdentityForKey(args.preselectid);
      if (args.from)
        composeFields.from = args.from;
      if (args.to)
        composeFields.to = args.to;
      if (args.cc)
        composeFields.cc = args.cc;
      if (args.bcc)
        composeFields.bcc = args.bcc;
      if (args.newsgroups)
        composeFields.newsgroups = args.newsgroups;
      if (args.subject)
        composeFields.subject = args.subject;
      if (args.attachment)
      {
        var attachmentList = args.attachment.split(",");
        var commandLine = Cc["@mozilla.org/toolkit/command-line;1"]
                            .createInstance();
        for (let i = 0; i < attachmentList.length; i++)
        {
          let attachmentStr = attachmentList[i];
          let uri = commandLine.resolveURI(attachmentStr);
          let attachment = Cc["@mozilla.org/messengercompose/attachment;1"]
                             .createInstance(Ci.nsIMsgAttachment);

          if (uri instanceof Ci.nsIFileURL)
          {
            if (uri.file.exists())
              attachment.size = uri.file.fileSize;
            else
              attachment = null;
          }

          // Only want to attach if a file that exists or it is not a file.
          if (attachment)
          {
            attachment.url = uri.spec;
            composeFields.addAttachment(attachment);
          }
          else
          {
            let title = sComposeMsgsBundle.getString("errorFileAttachTitle");
            let msg = sComposeMsgsBundle.getFormattedString("errorFileAttachMessage",
                                                            [attachmentStr]);
            Services.prompt.alert(null, title, msg);
          }
        }
      }
      if (args.newshost)
        composeFields.newshost = args.newshost;
      if (args.message) {
        let msgFile = Cc["@mozilla.org/file/local;1"]
                        .createInstance(Ci.nsIFile);
        if (OS.Path.dirname(args.message) == ".") {
          let workingDir = Services.dirsvc.get("CurWorkD", Ci.nsIFile);
          args.message = OS.Path.join(workingDir.path, OS.Path.basename(args.message));
        }
        msgFile.initWithPath(args.message);

        if (!msgFile.exists()) {
          let title = sComposeMsgsBundle.getString("errorFileMessageTitle");
          let msg = sComposeMsgsBundle.getFormattedString("errorFileMessageMessage",
                                                          [args.message]);
          Services.prompt.alert(null, title, msg);
        } else {
          let data = "";
          let fstream = null;
          let cstream = null;

          try {
            fstream = Cc["@mozilla.org/network/file-input-stream;1"]
                        .createInstance(Ci.nsIFileInputStream);
            cstream = Cc["@mozilla.org/intl/converter-input-stream;1"]
                        .createInstance(Ci.nsIConverterInputStream);
            fstream.init(msgFile, -1, 0, 0); // Open file in default/read-only mode.
            cstream.init(fstream, "UTF-8", 0, 0);

            let str = {};
            let read = 0;

            do {
              // Read as much as we can and put it in str.value.
              read = cstream.readString(0xffffffff, str);
              data += str.value;
            } while (read != 0);
          } catch (e) {
            let title = sComposeMsgsBundle.getString("errorFileMessageTitle");
            let msg = sComposeMsgsBundle.getFormattedString("errorLoadFileMessageMessage",
                                                            [args.message]);
            Services.prompt.alert(null, title, msg);

          } finally {
            if (cstream)
              cstream.close();
            if (fstream)
              fstream.close();
          }

          if (data) {
            let pos = data.search(/\S/); // Find first non-whitespace character.

            if (params.format != Ci.nsIMsgCompFormat.PlainText &&
                (args.message.endsWith(".htm") ||
                 args.message.endsWith(".html") ||
                 data.substr(pos, 14).toLowerCase() == "<!doctype html" ||
                 data.substr(pos, 5).toLowerCase() == "<html")) {
              // We replace line breaks because otherwise they'll be converted
              // to <br> in nsMsgCompose::BuildBodyMessageAndSignature().
              // Don't do the conversion if the user asked explicitly for plain
              // text.
              data = data.replace(/\r?\n/g, " ");
            }
            gBodyFromArgs = true;
            composeFields.body = data;
          }
        }
      } else if (args.body) {
        gBodyFromArgs = true;
        composeFields.body = args.body;
      }
    }
  }

  gComposeType = params.type;

  // Detect correct identity when missing or mismatched.
  // An identity with no email is likely not valid.
  // When editing a draft, 'params.identity' is pre-populated with the identity
  // that created the draft or the identity owning the draft folder for a
  // "foreign", draft, see ComposeMessage() in mailCommands.js. We don't want
  // the latter, so use the creator identity which could be null.
  if (gComposeType == Ci.nsIMsgCompType.Draft) {
    let creatorKey = params.composeFields.creatorIdentityKey;
    params.identity = creatorKey ? getIdentityForKey(creatorKey) : null;
  }
  let from = [];
  if (params.composeFields.from)
    from = MailServices.headerParser
                       .parseEncodedHeader(params.composeFields.from, null);
  from = (from.length && from[0] && from[0].email) ?
    from[0].email.toLowerCase().trim() : null;
  if (!params.identity || !params.identity.email ||
      (from && !emailSimilar(from, params.identity.email))) {
    let identities = MailServices.accounts.allIdentities;
    let suitableCount = 0;

    // Search for a matching identity.
    if (from) {
      for (let ident of identities) {
        if (ident.email && from == ident.email.toLowerCase()) {
          if (suitableCount == 0)
            params.identity = ident;
          suitableCount++;
          if (suitableCount > 1)
            break; // No need to find more, it's already not unique.
        }
      }
    }

    if (!params.identity || !params.identity.email) {
      let identity = null;
      // No preset identity and no match, so use the default account.
      let defaultAccount = MailServices.accounts.defaultAccount;
      if (defaultAccount) {
        identity = defaultAccount.defaultIdentity;
      }
      if (!identity) {
        // Get the first identity we have in the list.
        let identitykey = identityList.getItemAtIndex(0).getAttribute("identitykey");
        identity = MailServices.accounts.getIdentity(identitykey);
      }
      params.identity = identity;
    }

    // Warn if no or more than one match was found.
    // But don't warn for +suffix additions (a+b@c.com).
    if (from && (suitableCount > 1 ||
        (suitableCount == 0 && !emailSimilar(from, params.identity.email))))
      gComposeNotificationBar.setIdentityWarning(params.identity.identityName);
  }

  identityList.selectedItem =
    identityList.getElementsByAttribute("identitykey", params.identity.key)[0];
  if (params.composeFields.from)
    identityList.value = MailServices.headerParser.parseDecodedHeader(params.composeFields.from)[0].toString();
  LoadIdentity(true);

  // Get the <editor> element to startup an editor
  var editorElement = GetCurrentEditorElement();

  // Remember the original message URI. When editing a draft which is a reply
  // or forwarded message, this gets overwritten by the ancestor's message URI
  // so the disposition flags ("replied" or "forwarded") can be set on the
  // ancestor.
  // For our purposes we need the URI of the message being processed, not its
  // original ancestor.
  gOriginalMsgURI = params.originalMsgURI;
  gMsgCompose = MailServices.compose.initCompose(params, window,
                                                 editorElement.docShell);

  document.getElementById("returnReceiptMenu")
          .setAttribute("checked", gMsgCompose.compFields.returnReceipt);
  document.getElementById("dsnMenu")
          .setAttribute('checked', gMsgCompose.compFields.DSN);
  document.getElementById("cmd_attachVCard")
          .setAttribute("checked", gMsgCompose.compFields.attachVCard);
  document.getElementById("menu_inlineSpellCheck")
          .setAttribute("checked",
                        Services.prefs.getBoolPref("mail.spellcheck.inline"));

  let editortype = gMsgCompose.composeHTML ? "htmlmail" : "textmail";
  editorElement.makeEditable(editortype, true);

  // setEditorType MUST be call before setContentWindow
  if (gMsgCompose.composeHTML) {
    initLocalFontFaceMenu(document.getElementById("FontFacePopup"));
  } else {
    //Remove HTML toolbar, format and insert menus as we are editing in plain
    //text mode.
    let toolbar = document.getElementById("FormatToolbar");
    toolbar.hidden = true;
    toolbar.setAttribute("hideinmenu", "true");
    document.getElementById("outputFormatMenu").setAttribute("hidden", true);
    document.getElementById("formatMenu").setAttribute("hidden", true);
    document.getElementById("insertMenu").setAttribute("hidden", true);
  }

  // Do setup common to Message Composer and Web Composer.
  EditorSharedStartup();

  if (params.bodyIsLink) {
    let body = gMsgCompose.compFields.body;
    if (gMsgCompose.composeHTML) {
      let cleanBody;
      try {
        cleanBody = decodeURI(body);
      } catch(e) {
        cleanBody = body;
      }

      body = body.replace(/&/g, "&amp;");
      gMsgCompose.compFields.body =
        "<br /><a href=\"" + body + "\">" + cleanBody + "</a><br />";
    } else {
      gMsgCompose.compFields.body = "\n<" + body + ">\n";
    }
  }

  GetMsgSubjectElement().value = gMsgCompose.compFields.subject;

  var attachments = gMsgCompose.compFields.attachments;
  while (attachments.hasMoreElements()) {
    AddAttachment(attachments.getNext().QueryInterface(Ci.nsIMsgAttachment));
  }

  var event = document.createEvent('Events');
  event.initEvent('compose-window-init', false, true);
  document.getElementById("msgcomposeWindow").dispatchEvent(event);

  gMsgCompose.RegisterStateListener(stateListener);

  // Add an observer to be called when document is done loading,
  // which creates the editor.
  try {
    GetCurrentCommandManager().addCommandObserver(gMsgEditorCreationObserver,
                                                  "obs_documentCreated");

    // Load empty page to create the editor
    editorElement.webNavigation.loadURI("about:blank",
                     Ci.nsIWebNavigation.LOAD_FLAGS_NONE,
                     null,                             // referrer
                     null,                             // post-data stream
                     null,                             // HTTP headers
                     Services.scriptSecurityManager.getSystemPrincipal());
  } catch (e) {
    dump(" Failed to startup editor: "+e+"\n");
  }

  // create URI of the folder from draftId
  var draftId = gMsgCompose.compFields.draftId;
  var folderURI = draftId.substring(0, draftId.indexOf("#")).replace("-message", "");

  try {
    var folder = sRDF.GetResource(folderURI);

    gEditingDraft = (folder instanceof Ci.nsIMsgFolder) &&
                    (folder.flags & Ci.nsMsgFolderFlags.Drafts);
  }
  catch (ex) {
    gEditingDraft = false;
  }

  gAutoSaveKickedIn = false;

  gAutoSaveInterval = Services.prefs.getBoolPref("mail.compose.autosave")
    ? Services.prefs.getIntPref("mail.compose.autosaveinterval") * 60000
    : 0;

  if (gAutoSaveInterval)
    gAutoSaveTimeout = setTimeout(AutoSave, gAutoSaveInterval);
}