/*global Components: false*/
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at https://mozilla.org/MPL/2.0/. */

"use strict";

var EXPORTED_SYMBOLS = ["EnigmailPEPKeySync"];

const Cc = Components.classes;
const Ci = Components.interfaces;
const Cu = Components.utils;

Cu.import("resource://enigmail/rng.jsm"); /*global EnigmailRNG: false */
Cu.import("resource://enigmail/mime.jsm"); /*global EnigmailMime: false */
Cu.import("resource:///modules/jsmime.jsm"); /*global jsmime: false*/
Cu.import("resource://enigmail/data.jsm"); /*global EnigmailData: false */
Cu.import("resource://enigmail/files.jsm"); /*global EnigmailFiles: false */
Cu.import("resource://enigmail/log.jsm"); /*global EnigmailLog: false */
Cu.import("resource://enigmail/send.jsm"); /*global EnigmailSend: false */
Cu.import("resource://enigmail/locale.jsm"); /*global EnigmailLocale: false */
Cu.import("resource://enigmail/pEp.jsm"); /*global EnigmailpEp: false */
Cu.import("resource://enigmail/lazy.jsm"); /*global EnigmailLazy: false */
Cu.import("resource://gre/modules/PromiseUtils.jsm"); /* global PromiseUtils: false */


const getWindows = EnigmailLazy.loader("enigmail/windows.jsm", "EnigmailWindows");


const testMessage = {
  "dir": 1,
  "shortmsg": "pEp",
  "longmsg": "this message was encrypted with p≡p https://pEp-project.org",
  "attachments": [{
    "value": "VmVyc2lvbjogMQ==",
    "size": 10,
    "mime_type": "application/pgp-encrypted"
  }, {
    "value": "[encoded data, 12228 characters]",
    "size": 9170,
    "mime_type": "application/octet-stream",
    "filename": "msg.asc"
  }],
  "from": {
    "address": "enigtest@brunschwig.net",
    "fpr": "35639B7D397A4737F11C6160CA45EF9C1C17AB90",
    "user_id": "pEp_own_userId",
    "username": "anonymous",
    "comm_type": 255,
    "me": true,
    "flags": 1
  },
  "to": [{
    "address": "enigtest@brunschwig.net",
    "fpr": "F871CDB8990483FD6B305B8F319B7AE82E21E970",
    "user_id": "f827eb96-2f4f-11e7-8fa4-4be0b4159ac2",
    "username": "Patrick Brunschwig",
    "comm_type": 56,
    "lang": "en",
    "me": false,
    "flags": 0
  }],
  "opt_fields": [{
    "key": "pEp-auto-consume",
    "value": "yes"
  }, {
    "key": "X-pEp-Version",
    "value": "1.0"
  }],
  "enc_format": 3
};

const keySyncMsg = {
  "jsonrpc": "2.0",
  "id": 2002,
  "security_token": "mmhqlMwmlFBwd5NO3UK7jD18FRs7wW0rm5KetnSe",
  "method": "notifyHandshake",
  "params": [{
    "address": "enigtest@brunschwig.net",
    "fpr": "7A0D51844B9C06849E3C313F9B299A39D1CCD0BD",
    "user_id": "pEp_own_userId",
    "username": "anonymous",
    "comm_type": 255,
    "me": false,
    "flags": 0
  }, {
    "address": "enigtest@brunschwig.net",
    "fpr": "F871CDB8990483FD6B305B8F319B7AE82E21E970",
    "user_id": "fcb950d2-3931-11e7-a0bf-97c07b2bb40e",
    "username": "anonymous",
    "comm_type": 255,
    "lang": "en",
    "me": false,
    "flags": 0
  }, {
    "sync_handshake_signal": 1
  }]
};

const CRLF = "\r\n";

var EnigmailPEPKeySync = {


  notifyHandshake: function(pepParams) {
    EnigmailLog.DEBUG("pEpMessage.notifyHandshake()\n");

    let myId = pepParams[0];
    let partnerId = pepParams[1];

    let uiLocale = EnigmailLocale.getUILocale().substr(0, 2).toLowerCase();
    let useLocale = uiLocale;
    let supportedLocale = [];

    EnigmailpEp.getLanguageList().then(function _success(res) {
      let deferred = PromiseUtils.defer();
      EnigmailLog.DEBUG("pEpMessage.notifyHandshake: got language list 1: " + JSON.stringify(res) + "\n");

      let localeList = EnigmailpEp.processLanguageList(res);
      supportedLocale = localeList;

      for (let i = 0; i < localeList.length; i++) {
        if (localeList[i].short === uiLocale) {
          useLocale = localeList[i].short;
        }
      }

      return EnigmailpEp.getTrustWords(myId, partnerId, useLocale, false);

    }).then(function _displayDialog(data) {
      // open trustwords dialog
      if (("result" in data) && typeof data.result === "object" && typeof data.result.outParams[1] === "string") {
        try {
          let trustWords = data.result.outParams[1];

          let win = getWindows().getBestParentWin();
          let inputObj = {
            supportedLocale: supportedLocale,
            locale: useLocale,
            trustWords: trustWords,
            dialogMode: 1,
            ownId: myId,
            otherId: partnerId
          };
          win.openDialog("chrome://enigmail/content/pepTrustWords.xul",
            "", "dialog,modal,centerscreen", inputObj);
        }
        catch (ex) {
          EnigmailLog.DEBUG("pEpMessage.notifyHandshake: caught exception: " + ex.toString() + "\n");
        }
      }

    }).catch(function _err(err) {
      EnigmailLog.DEBUG("pEpMessage.notifyHandshake: caught error: " + JSON.stringify(err) + "\n");
    });


  },


  /**
   * Convert a pEp message into a regular MIME string
   *
   * @param pepMessage: Object - pEp message object
   *
   * @return Object:
   *   - data:       String - message string
   *   - compFields: nsIMsgCompFields object
   */
  mimeStringFromMessage: function(pepMessage) {
    EnigmailLog.DEBUG("pEpMessage.mimeStringFromMessage()\n");

    let boundary = EnigmailMime.createBoundary();
    let msgFormat = "plain";
    let now = new Date();
    let composeFields = Cc["@mozilla.org/messengercompose/composefields;1"].createInstance(Ci.nsIMsgCompFields);
    composeFields.characterSet = "UTF-8";
    composeFields.messageId = EnigmailRNG.generateRandomString(27) + "-enigmail";

    let mimeStr = "Message-Id: " + composeFields.messageId + CRLF;
    mimeStr += "Date: " + now.toUTCString() + CRLF;

    if ("enc_format" in pepMessage && pepMessage.enc_format === 3) {
      msgFormat = "pgpmime";
    }

    if ("from" in pepMessage) {
      let m = this.createAddress(pepMessage.from);
      let addr = jsmime.headerparser.parseAddressingHeader(m, false);
      mimeStr += jsmime.headeremitter.emitStructuredHeader("From", addr, {});
      composeFields.from = pepMessage.from.address;
    }

    if ("to" in pepMessage) {
      let m = "";
      for (let i of pepMessage.to) {
        if (m.length > 0) {
          m += ", ";
        }

        m += this.createAddress(i);
      }

      let addr = jsmime.headerparser.parseAddressingHeader(m, false);
      mimeStr += jsmime.headeremitter.emitStructuredHeader("To", addr, {});
      composeFields.to = m;
    }

    if ("cc" in pepMessage) {
      let m = "";
      for (let i of pepMessage.to) {
        if (m.length > 0) {
          m += ", ";
        }

        m += this.createAddress(i);
      }
      let addr = jsmime.headerparser.parseAddressingHeader(m, false);
      mimeStr += jsmime.headeremitter.emitStructuredHeader("Cc", addr, {});
      composeFields.cc = m;
    }

    if ("shortmsg" in pepMessage) {
      mimeStr += jsmime.headeremitter.emitStructuredHeader("Subject", pepMessage.shortmsg, {});
    }

    if ("opt_fields" in pepMessage) {
      for (let i of pepMessage.opt_fields) {
        mimeStr += i.key + ": " + i.value + CRLF;
      }
    }

    if (msgFormat === "pgpmime") {
      mimeStr += 'Content-Type: multipart/encrypted;' + CRLF +
        ' protocol="application/pgp-encrypted";' + CRLF +
        ' boundary="' + boundary + '"' + CRLF;
    }
    else if ("attachments" in pepMessage) {
      msgFormat = "multipart";
      mimeStr += 'Content-Type: multipart/mixed;' + CRLF + ' boundary="' + boundary + '"' + CRLF;
    }
    else {
      mimeStr += 'Content-Type: text/plain; charset="UTF-8"' + CRLF;
    }

    mimeStr += CRLF;

    if ("longmsg" in pepMessage && msgFormat !== "multipart") {
      mimeStr += EnigmailData.convertFromUnicode(pepMessage.longmsg, "utf-8") + CRLF;
    }

    if (msgFormat !== "plain") {

      if ("longmsg" in pepMessage && msgFormat === "multipart") {
        mimeStr += "--" + boundary + CRLF;
        mimeStr += 'Content-Type: text/plain; charset="UTF-8"' + CRLF + CRLF;
        mimeStr += EnigmailData.convertFromUnicode(pepMessage.longmsg, "utf-8") + CRLF;
      }

      if ("attachments" in pepMessage) {
        for (let att of pepMessage.attachments) {
          mimeStr += "--" + boundary + CRLF;
          mimeStr += "Content-Type: " + att.mime_type;
          if ("filename" in att) {
            att.filename = att.filename.replace(/^file:\/\//i, "");
            mimeStr += '; name="' + att.filename + '"';
          }
          mimeStr += CRLF + "Content-Transfer-Encoding: base64" + CRLF + CRLF;

          mimeStr += att.value.replace(/(.{72})/g, "$1\r\n") + CRLF;
        }
      }

      mimeStr += "--" + boundary + "--" + CRLF;
    }

    return {
      data: mimeStr,
      compFields: composeFields
    };
  },

  createAddress: function(pepUserId) {
    let m = "";
    if ("username" in pepUserId) {
      m = pepUserId.username + " ";
    }
    m += "<" + pepUserId.address + ">";

    return m;
  },

  sendMessage: function(pepMessage, listener = null) {
    EnigmailLog.DEBUG("pEpMessage.sendMessage()\n");

    let msg = this.mimeStringFromMessage(pepMessage);

    return EnigmailSend.sendMessage(msg.data, msg.compFields, listener);
  },


  getTestMessage: function() {
    return testMessage;
  },

  getTestKeySync: function() {
    return keySyncMsg;
  }
};
