<commit_before>
/*
 * Tag parsing library for music files. It supports ID3 (mp3 files)
 * and MPEG4 (m4a files) tags
 *
 * It is based on the information found in specification documents and
 * other libraries that can be found at following links:
 *
 * http://atomicparsley.sourceforge.net/mpeg-4files.html
 * Source code of AtomicParsley
 * https://github.com/antimatter15/player/blob/master/id3v2.js
 * http://www.tumblr.com/tagged/filereader
 * http://code.google.com/p/mutagen/source/browse/trunk/mutagen/
 */

(function ($) {
var app = $.app;

var ID3_2_GENRES = {
  "0": "Blues",
  "1": "Classic Rock",
  "2": "Country",
  "3": "Dance",
  "4": "Disco",
  "5": "Funk",
  "6": "Grunge",
  "7": "Hip-Hop",
  "8": "Jazz",
  "9": "Metal",
  "10": "New Age",
  "11": "Oldies",
  "12": "Other",
  "13": "Pop",
  "14": "R&B",
  "15": "Rap",
  "16": "Reggae",
  "17": "Rock",
  "18": "Techno",
  "19": "Industrial",
  "20": "Alternative",
  "21": "Ska",
  "22": "Death Metal",
  "23": "Pranks",
  "24": "Soundtrack",
  "25": "Euro-Techno",
  "26": "Ambient",
  "27": "Trip-Hop",
  "28": "Vocal",
  "29": "Jazz+Funk",
  "30": "Fusion",
  "31": "Trance",
  "32": "Classical",
  "33": "Instrumental",
  "34": "Acid",
  "35": "House",
  "36": "Game",
  "37": "Sound Clip",
  "38": "Gospel",
  "39": "Noise",
  "40": "AlternRock",
  "41": "Bass",
  "42": "Soul",
  "43": "Punk",
  "44": "Space",
  "45": "Meditative",
  "46": "Instrumental Pop",
  "47": "Instrumental Rock",
  "48": "Ethnic",
  "49": "Gothic",
  "50": "Darkwave",
  "51": "Techno-Industrial",
  "52": "Electronic",
  "53": "Pop-Folk",
  "54": "Eurodance",
  "55": "Dream",
  "56": "Southern Rock",
  "57": "Comedy",
  "58": "Cult",
  "59": "Gangsta",
  "60": "Top 40",
  "61": "Christian Rap",
  "62": "Pop/Funk",
  "63": "Jungle",
  "64": "Native American",
  "65": "Cabaret",
  "66": "New Wave",
  "67": "Psychadelic",
  "68": "Rave",
  "69": "Showtunes",
  "70": "Trailer",
  "71": "Lo-Fi",
  "72": "Tribal",
  "73": "Acid Punk",
  "74": "Acid Jazz",
  "75": "Polka",
  "76": "Retro",
  "77": "Musical",
  "78": "Rock & Roll",
  "79": "Hard Rock",
  "80": "Folk",
  "81": "Folk-Rock",
  "82": "National Folk",
  "83": "Swing",
  "84": "Fast Fusion",
  "85": "Bebob",
  "86": "Latin",
  "87": "Revival",
  "88": "Celtic",
  "89": "Bluegrass",
  "90": "Avantgarde",
  "91": "Gothic Rock",
  "92": "Progressive Rock",
  "93": "Psychedelic Rock",
  "94": "Symphonic Rock",
  "95": "Slow Rock",
  "96": "Big Band",
  "97": "Chorus",
  "98": "Easy Listening",
  "99": "Acoustic",
  "100": "Humour",
  "101": "Speech",
  "102": "Chanson",
  "103": "Opera",
  "104": "Chamber Music",
  "105": "Sonata",
  "106": "Symphony",
  "107": "Booty Bass",
  "108": "Primus",
  "109": "Porn Groove",
  "110": "Satire",
  "111": "Slow Jam",
  "112": "Club",
  "113": "Tango",
  "114": "Samba",
  "115": "Folklore",
  "116": "Ballad",
  "117": "Power Ballad",
  "118": "Rhythmic Soul",
  "119": "Freestyle",
  "120": "Duet",
  "121": "Punk Rock",
  "122": "Drum Solo",
  "123": "A capella",
  "124": "Euro-House",
  "125": "Dance Hall"
};

function fileSlice(file, start, length){
  if(file.mozSlice) return file.mozSlice(start, start + length);
  if(file.webkitSlice) return file.webkitSlice(start, start + length);
  if(file.slice) return file.slice(start, length);
}

function cleanText(str){
  if(str.indexOf('http://') != 0){
    var TextEncoding = str.charCodeAt(0);
    str = str.substr(1);
  }
  return str.replace(
    /[^A-Za-z0-9\(\)\{\}\[\]\!\@\#\$\%\^\&\* \/\"\'\;\>\<\?\,\~\`\.\n\t]/g,'');
}

var ITER_LIMIT = 100;
function parseID3v2(view, callback) {
  var tags = { version:2, other:[] }
  try {
    tags.revision = view.getInt8(3);
    var id3Flags = view.getInt8(5);
    var tagSize = view.getUint32(6, littleEndian=false);
    var cursor = 10;

    if(tags.revision < 3) {
      var iter = 0;
      while(cursor < tagSize && iter < ITER_LIMIT) {
        var header = view.getString(3, cursor);
        var sbytes = [
          view.getUint8(cursor+3),
          view.getUint8(cursor+4),
          view.getUint8(cursor+5)
        ];
        var frameSize = (sbytes[0] << 16) + (sbytes[1] << 8) + sbytes[2];
        var content = view.getString(frameSize, cursor+6);
        switch(header) {
        case 'TT2':
          tags.title = cleanText(content); break;
        case 'TAL':
          tags.album = cleanText(content); break;
        case 'TP1':
          tags.artist = cleanText(content); break;
        case 'TYE':
          tags.year = cleanText(content); break;
        case 'TCO':
          s = cleanText(content);
          if(/\([0-9]+\)/.test(s)) {
            tags.genre = ID3_2_GENRES[parseInt(s.replace(/[\(\)]/g,''), 10)];
          } else {
            tags.genre = s;
          }
          break;
        default:
          if(header && header.trim().length > 0) {
            tags.other.push({ header:header, content:cleanText(content) });
          }
          break;
        }
        cursor += (6+frameSize);
        iter++;
      }
    } else {
      var iter = 0;
      while(cursor < tagSize && iter < ITER_LIMIT) {
        var header = view.getString(4, cursor);
        var frameSize = view.getUint32(cursor+4, littleEndian=false);
        var flags = view.getUint16(cursor+8, littleEndian=false);
        var content = view.getString(frameSize, cursor+10);
        switch(header) {
        case 'TIT2':
          tags.title = cleanText(content); break;
        case 'TALB':
          tags.album = cleanText(content); break;
        case 'TPE1':
          tags.artist = cleanText(content); break;
        case 'TYER':
          tags.year = cleanText(content); break;
        case 'TCON':
          s = cleanText(content);
          if(/\([0-9]+\)/.test(s)) {
            tags.genre = ID3_2_GENRES[parseInt(s.replace(/[\(\)]/g,''), 10)];
          } else {
            tags.genre = s;
          }
          break;
        default:
          if(header && header.trim().length > 0) {
            tags.other.push({ header:header, content:cleanText(content) });
          }
          break;
        }
        cursor += (10+frameSize);
        iter++;
      }
    }
    callback(tags);
  } catch(e) {
    callback(tags);
  }
}

function parseID3v1(view, callback) {
  callback({
    version : 1,
    title : view.getString(30, view.tell()),
    artist : view.getString(30, view.tell()),
    album : view.getString(30, view.tell()),
    year : view.getString(4, view.tell())
  });
}

function parseMpeg4(view, callback) {

  var cursor = 0;
  var depth = 0;
  var pattern = ['moov','udta','meta','ilst']
  var endpos = view.length;
  var tags = {};

  function processTagAtom(name, size) {
    var localcursor = cursor+8;
    var dataSize = view.getUint32(localcursor, littleEndian=false);
    var data = view.getString(dataSize-8, localcursor+8);
    if(name.indexOf('alb') > 0) {
      tags.album = data;
    } else if(name.indexOf('art') > 0) {
      tags.artist = data;
    } else if(name.indexOf('ART') > 0) {
      if(!tags.artist) { tags.artist = data; }
    } else if(name.indexOf('wrt') > 0) {
      if(!tags.artist) { tags.artist = data; }
    } else if(name.indexOf('gen') > 0 || name.indexOf('gnre') == 0) {
      tags.genre = data;
    } else if(name.indexOf('nam') > 0) {
      tags.title = data;
    }
  }

  function findAtomPattern() {
    if(cursor >= endpos) { return tags; }

    var atomSize = view.getUint32(cursor, littleEndian=false);
    var atomName = view.getString(4, cursor+4);
    if(atomName == pattern[depth]) {
      depth++;
      if(atomName == 'ilst') { endpos = cursor + atomSize; }
      if(depth == 3) { cursor += 4; }
      cursor += 8;
      return findAtomPattern();
    } else {
      if(depth == pattern.length) {
        processTagAtom(atomName, atomSize);
      }
      cursor += atomSize;
      return findAtomPattern();
    }
  }

  callback(findAtomPattern());
}

var id3v1Count = 0;
var id3v2Count = 0;
var m4aCount = 0;
var unknownTagCount = 0;

app.parseTags = function (file, callback) {
  var reader = new FileReader();
  if(/\.mp3$/.test(file.webkitRelativePath.toLowerCase())) {

    reader.onload = function (e) {
      var view = new jDataView(this.result);
      if(view.getString(3,0) == 'ID3') {
        parseID3v2(view, callback);
        id3v2Count++;
      } else {

        reader = new FileReader();
        reader.onload = function (e) {
          var view = new jDataView(this.result);
          if (view.getString(3,0) == 'TAG') {
            parseID3v1(view, callback);
            id3v1Count++;
          } else {
            callback({});
            console.log('Unknown tags: '+file.webkitRelativePath.toLowerCase());
            unknownTagCount++;
          }
        }
        reader.readAsArrayBuffer(fileSlice(file, file.fileSize-128, 128));
      }
    };
    reader.readAsArrayBuffer(fileSlice(file, 0, 128*1024));

  } else if(/\.m4a$/.test(file.webkitRelativePath.toLowerCase())) {
    reader.onload = function (e) {
      var view = new jDataView(this.result);
      if(view.getString(4,4) == 'ftyp') {
        parseMpeg4(view, callback);
        m4aCount++;
      } else {
        console.log('Unknown Tags: '+file.webkitRelativePath.toLowerCase());
        callback({});
        unknownTagCount++;
      }
    };
    reader.readAsArrayBuffer(file);
  } else {
    console.log(file.webkitRelativePath.toLowerCase());
    unknownTagCount++;
  }
};

app.printParseReport = function () {
  console.log('Tag parsing report');
  console.log('------------------');
  console.log('ID3v1 '+id3v1Count);
  console.log('ID3v2 '+id3v2Count);
  console.log('M4A '+m4aCount);
  console.log('Unknown '+unknownTagCount);
}

})(jQuery);

<commit_msg>cleanup the text in tags for ID3 v1<commit_after>
/*
 * Tag parsing library for music files. It supports ID3 (mp3 files)
 * and MPEG4 (m4a files) tags
 *
 * It is based on the information found in specification documents and
 * other libraries that can be found at following links:
 *
 * http://atomicparsley.sourceforge.net/mpeg-4files.html
 * Source code of AtomicParsley
 * https://github.com/antimatter15/player/blob/master/id3v2.js
 * http://www.tumblr.com/tagged/filereader
 * http://code.google.com/p/mutagen/source/browse/trunk/mutagen/
 */

(function ($) {
var app = $.app;

var ID3_2_GENRES = {
  "0": "Blues",
  "1": "Classic Rock",
  "2": "Country",
  "3": "Dance",
  "4": "Disco",
  "5": "Funk",
  "6": "Grunge",
  "7": "Hip-Hop",
  "8": "Jazz",
  "9": "Metal",
  "10": "New Age",
  "11": "Oldies",
  "12": "Other",
  "13": "Pop",
  "14": "R&B",
  "15": "Rap",
  "16": "Reggae",
  "17": "Rock",
  "18": "Techno",
  "19": "Industrial",
  "20": "Alternative",
  "21": "Ska",
  "22": "Death Metal",
  "23": "Pranks",
  "24": "Soundtrack",
  "25": "Euro-Techno",
  "26": "Ambient",
  "27": "Trip-Hop",
  "28": "Vocal",
  "29": "Jazz+Funk",
  "30": "Fusion",
  "31": "Trance",
  "32": "Classical",
  "33": "Instrumental",
  "34": "Acid",
  "35": "House",
  "36": "Game",
  "37": "Sound Clip",
  "38": "Gospel",
  "39": "Noise",
  "40": "AlternRock",
  "41": "Bass",
  "42": "Soul",
  "43": "Punk",
  "44": "Space",
  "45": "Meditative",
  "46": "Instrumental Pop",
  "47": "Instrumental Rock",
  "48": "Ethnic",
  "49": "Gothic",
  "50": "Darkwave",
  "51": "Techno-Industrial",
  "52": "Electronic",
  "53": "Pop-Folk",
  "54": "Eurodance",
  "55": "Dream",
  "56": "Southern Rock",
  "57": "Comedy",
  "58": "Cult",
  "59": "Gangsta",
  "60": "Top 40",
  "61": "Christian Rap",
  "62": "Pop/Funk",
  "63": "Jungle",
  "64": "Native American",
  "65": "Cabaret",
  "66": "New Wave",
  "67": "Psychadelic",
  "68": "Rave",
  "69": "Showtunes",
  "70": "Trailer",
  "71": "Lo-Fi",
  "72": "Tribal",
  "73": "Acid Punk",
  "74": "Acid Jazz",
  "75": "Polka",
  "76": "Retro",
  "77": "Musical",
  "78": "Rock & Roll",
  "79": "Hard Rock",
  "80": "Folk",
  "81": "Folk-Rock",
  "82": "National Folk",
  "83": "Swing",
  "84": "Fast Fusion",
  "85": "Bebob",
  "86": "Latin",
  "87": "Revival",
  "88": "Celtic",
  "89": "Bluegrass",
  "90": "Avantgarde",
  "91": "Gothic Rock",
  "92": "Progressive Rock",
  "93": "Psychedelic Rock",
  "94": "Symphonic Rock",
  "95": "Slow Rock",
  "96": "Big Band",
  "97": "Chorus",
  "98": "Easy Listening",
  "99": "Acoustic",
  "100": "Humour",
  "101": "Speech",
  "102": "Chanson",
  "103": "Opera",
  "104": "Chamber Music",
  "105": "Sonata",
  "106": "Symphony",
  "107": "Booty Bass",
  "108": "Primus",
  "109": "Porn Groove",
  "110": "Satire",
  "111": "Slow Jam",
  "112": "Club",
  "113": "Tango",
  "114": "Samba",
  "115": "Folklore",
  "116": "Ballad",
  "117": "Power Ballad",
  "118": "Rhythmic Soul",
  "119": "Freestyle",
  "120": "Duet",
  "121": "Punk Rock",
  "122": "Drum Solo",
  "123": "A capella",
  "124": "Euro-House",
  "125": "Dance Hall"
};

function fileSlice(file, start, length){
  if(file.mozSlice) return file.mozSlice(start, start + length);
  if(file.webkitSlice) return file.webkitSlice(start, start + length);
  if(file.slice) return file.slice(start, length);
}

function cleanText(str){
  return str.replace(
    /[^A-Za-z0-9\(\)\{\}\[\]\!\@\#\$\%\^\&\* \/\"\'\;\>\<\?\,\~\`\.\n\t]/g,'');
}

var ITER_LIMIT = 100;
function parseID3v2(view, callback) {
  var tags = { version:2, other:[] }
  try {
    tags.revision = view.getInt8(3);
    var id3Flags = view.getInt8(5);
    var tagSize = view.getUint32(6, littleEndian=false);
    var cursor = 10;

    if(tags.revision < 3) {
      var iter = 0;
      while(cursor < tagSize && iter < ITER_LIMIT) {
        var header = view.getString(3, cursor);
        var sbytes = [
          view.getUint8(cursor+3),
          view.getUint8(cursor+4),
          view.getUint8(cursor+5)
        ];
        var frameSize = (sbytes[0] << 16) + (sbytes[1] << 8) + sbytes[2];
        var content = view.getString(frameSize, cursor+6);
        switch(header) {
        case 'TT2':
          tags.title = cleanText(content); break;
        case 'TAL':
          tags.album = cleanText(content); break;
        case 'TP1':
          tags.artist = cleanText(content); break;
        case 'TYE':
          tags.year = cleanText(content); break;
        case 'TCO':
          s = cleanText(content);
          if(/\([0-9]+\)/.test(s)) {
            tags.genre = ID3_2_GENRES[parseInt(s.replace(/[\(\)]/g,''), 10)];
          } else {
            tags.genre = s;
          }
          break;
        default:
          if(header && header.trim().length > 0) {
            tags.other.push({ header:header, content:cleanText(content) });
          }
          break;
        }
        cursor += (6+frameSize);
        iter++;
      }
    } else {
      var iter = 0;
      while(cursor < tagSize && iter < ITER_LIMIT) {
        var header = view.getString(4, cursor);
        var frameSize = view.getUint32(cursor+4, littleEndian=false);
        var flags = view.getUint16(cursor+8, littleEndian=false);
        var content = view.getString(frameSize, cursor+10);
        switch(header) {
        case 'TIT2':
          tags.title = cleanText(content); break;
        case 'TALB':
          tags.album = cleanText(content); break;
        case 'TPE1':
          tags.artist = cleanText(content); break;
        case 'TYER':
          tags.year = cleanText(content); break;
        case 'TCON':
          s = cleanText(content);
          if(/\([0-9]+\)/.test(s)) {
            tags.genre = ID3_2_GENRES[parseInt(s.replace(/[\(\)]/g,''), 10)];
          } else {
            tags.genre = s;
          }
          break;
        default:
          if(header && header.trim().length > 0) {
            tags.other.push({ header:header, content:cleanText(content) });
          }
          break;
        }
        cursor += (10+frameSize);
        iter++;
      }
    }
    callback(tags);
  } catch(e) {
    callback(tags);
  }
}

function parseID3v1(view, callback) {
  callback({
    version : 1,
    title : cleanText(view.getString(30, view.tell())),
    artist : cleanText(view.getString(30, view.tell())),
    album : cleanText(view.getString(30, view.tell())),
    year : cleanText(view.getString(4, view.tell()))
  });
}

function parseMpeg4(view, callback) {

  var cursor = 0;
  var depth = 0;
  var pattern = ['moov','udta','meta','ilst']
  var endpos = view.length;
  var tags = {};

  function processTagAtom(name, size) {
    var localcursor = cursor+8;
    var dataSize = view.getUint32(localcursor, littleEndian=false);
    var data = view.getString(dataSize-8, localcursor+8);
    if(name.indexOf('alb') > 0) {
      tags.album = data;
    } else if(name.indexOf('art') > 0) {
      tags.artist = data;
    } else if(name.indexOf('ART') > 0) {
      if(!tags.artist) { tags.artist = data; }
    } else if(name.indexOf('wrt') > 0) {
      if(!tags.artist) { tags.artist = data; }
    } else if(name.indexOf('gen') > 0 || name.indexOf('gnre') == 0) {
      tags.genre = data;
    } else if(name.indexOf('nam') > 0) {
      tags.title = data;
    }
  }

  function findAtomPattern() {
    if(cursor >= endpos) { return tags; }

    var atomSize = view.getUint32(cursor, littleEndian=false);
    var atomName = view.getString(4, cursor+4);
    if(atomName == pattern[depth]) {
      depth++;
      if(atomName == 'ilst') { endpos = cursor + atomSize; }
      if(depth == 3) { cursor += 4; }
      cursor += 8;
      return findAtomPattern();
    } else {
      if(depth == pattern.length) {
        processTagAtom(atomName, atomSize);
      }
      cursor += atomSize;
      return findAtomPattern();
    }
  }

  callback(findAtomPattern());
}

var id3v1Count = 0;
var id3v2Count = 0;
var m4aCount = 0;
var unknownTagCount = 0;

app.parseTags = function (file, callback) {
  var reader = new FileReader();
  if(/\.mp3$/.test(file.webkitRelativePath.toLowerCase())) {

    reader.onload = function (e) {
      var view = new jDataView(this.result);
      if(view.getString(3,0) == 'ID3') {
        parseID3v2(view, callback);
        id3v2Count++;
      } else {

        reader = new FileReader();
        reader.onload = function (e) {
          var view = new jDataView(this.result);
          if (view.getString(3,0) == 'TAG') {
            parseID3v1(view, callback);
            id3v1Count++;
          } else {
            callback({});
            console.log('Unknown tags: '+file.webkitRelativePath.toLowerCase());
            unknownTagCount++;
          }
        }
        reader.readAsArrayBuffer(fileSlice(file, file.fileSize-128, 128));
      }
    };
    reader.readAsArrayBuffer(fileSlice(file, 0, 128*1024));

  } else if(/\.m4a$/.test(file.webkitRelativePath.toLowerCase())) {
    reader.onload = function (e) {
      var view = new jDataView(this.result);
      if(view.getString(4,4) == 'ftyp') {
        parseMpeg4(view, callback);
        m4aCount++;
      } else {
        console.log('Unknown Tags: '+file.webkitRelativePath.toLowerCase());
        callback({});
        unknownTagCount++;
      }
    };
    reader.readAsArrayBuffer(file);
  } else {
    console.log(file.webkitRelativePath.toLowerCase());
    unknownTagCount++;
  }
};

app.printParseReport = function () {
  console.log('Tag parsing report');
  console.log('------------------');
  console.log('ID3v1 '+id3v1Count);
  console.log('ID3v2 '+id3v2Count);
  console.log('M4A '+m4aCount);
  console.log('Unknown '+unknownTagCount);
}

})(jQuery);

<|endoftext|>


<commit_before>define(['require', 'exports', './runView', './os/lib/autocomplete'], function(require, exports, runView, autoComplete) {
	var AutoCompleter = autoComplete.AutoCompleter;
	var RunView = runView.RunView;

	function merge(dest, source) {
		for(key in source) {
			dest[key] = source[key];
		}

		return dest;
	}

	function getCaret(el) {
	  if (el.selectionStart) {
		return el.selectionStart;
	  } else if (document.selection) {
		el.focus();

		var r = document.selection.createRange();
		if (r == null) {
		  return 0;
		}

		var re = el.createTextRange(),
			rc = re.duplicate();
		re.moveToBookmark(r.getBookmark());
		rc.setEndPoint('EndToStart', re);

		return rc.text.length;
	  }
	  return 0;
	}

	var View = exports.View = (function() {
		function View() {
			var self = this;

			this.el = $('<div>').addClass('view');//.appendTo(document.body);

			// Way to run commands through the browser
			this.runEl = $('<div>').addClass('view-run-cmd').appendTo(this.el);

			this.runCMDEl = $('<textarea>').keyup(function() {
				self.updateAutoComplete();
			}).appendTo(this.runEl);

			this.runBtnEl = $('<button>').text('Run').click(function() {
				self.terminal.runCMD(self.runCMDEl.val());
				self.runCMDEl.val('');
			}).appendTo(this.runEl);

			this.autoCompleteEl = $('<ul>').text('Autocomplete:').appendTo(this.runEl);

			this.autoCompleter = new AutoCompleter(this.terminal);

			return self = merge(this.el, this);
		}

		View.prototype.updateAutoComplete = function updateAutoComplete() {
			var completions = this.autoCompleter.autoComplete(this.runCMDEl.val(), getCaret(this.runCMDEl[0]), this.terminal);
			this.autoCompleteEl.text('Autocomplete:');

			for(var i = 0; i < completions.length; i++) {
				this.autoCompleteEl.append($('<li>')
					.text(completions[i].name)
					.click((function(full) {
						return (function() {
							this.runCMDEl.val(full);
						}).bind(this);
					}).call(this, completions[i].full)));
			}

			return this;
		};

		View.prototype.setTerminal = function setTerminal(terminal) {
			this.terminal = terminal;
			this.fs = this.terminal.fs;
			this.currentDir = this.terminal.currentDir;

			this.updateAutoComplete();
		};

		View.prototype.createRunView = function createRunView(runContext, cmdLine) {
			return new RunView(this, runContext, cmdLine);
		};

		return View;
	})();
});
<commit_msg>Add liveParse<commit_after>define(['require', 'exports', './runView', './os/lib/autocomplete'], function(require, exports, runView, autoComplete) {
	var AutoCompleter = autoComplete.AutoCompleter;
	var RunView = runView.RunView;

	function merge(dest, source) {
		for(key in source) {
			dest[key] = source[key];
		}

		return dest;
	}

	function getCaret(el) {
	  if (el.selectionStart) {
		return el.selectionStart;
	  } else if (document.selection) {
		el.focus();

		var r = document.selection.createRange();
		if (r == null) {
		  return 0;
		}

		var re = el.createTextRange(),
			rc = re.duplicate();
		re.moveToBookmark(r.getBookmark());
		rc.setEndPoint('EndToStart', re);

		return rc.text.length;
	  }
	  return 0;
	}

	var View = exports.View = (function() {
		function View() {
			var self = this;

			this.el = $('<div>').addClass('view');//.appendTo(document.body);

			// Way to run commands through the browser
			this.runEl = $('<div>').addClass('view-run-cmd').appendTo(this.el);

			this.runCMDEl = $('<textarea>').keyup(function() {
				//self.updateAutoComplete(); // Auto complete
				self.liveParse();
			}).appendTo(this.runEl);

			this.runBtnEl = $('<button>').text('Run').click(function() {
				self.terminal.runCMD(self.runCMDEl.val());
				self.runCMDEl.val('');
			}).appendTo(this.runEl);

			this.autoCompleteEl = $('<ul>').text('Autocomplete:').appendTo(this.runEl);

			this.autoCompleter = new AutoCompleter(this.terminal);

			return self = merge(this.el, this);
		}

		View.prototype.updateAutoComplete = function updateAutoComplete() {
			if(!this.parsed) {
				this.liveParse();
				return this;
			}

			var completions = this.autoCompleter.autoComplete(/*this.runCMDEl.val()*/this.parsed, getCaret(this.runCMDEl[0]), this.terminal);
			this.autoCompleteEl.text('Autocomplete:');

			for(var i = 0; i < completions.length; i++) {
				this.autoCompleteEl.append($('<li>')
					.text(completions[i].name)
					.click((function(full) {
						return (function() {
							this.runCMDEl.val(full);
						}).bind(this);
					}).call(this, completions[i].full)));
			}

			return this;
		};

		View.prototype.liveParse = function liveParse() {
			this.parsed = this.autoCompleter.parse(this.runCMDEl.val());

			this.updateAutoComplete();
		};

		View.prototype.setTerminal = function setTerminal(terminal) {
			this.terminal = terminal;
			this.fs = this.terminal.fs;
			this.currentDir = this.terminal.currentDir;

			this.liveParse();
		};

		View.prototype.createRunView = function createRunView(runContext, cmdLine) {
			return new RunView(this, runContext, cmdLine);
		};

		return View;
	})();
});
<|endoftext|>


<commit_before>/*jslint es5: true */

/*
 * #%L
 * %%
 * Copyright (C) 2011 - 2016 BMW Car IT GmbH
 * %%
 * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */

define(
        "joynr/dispatching/RequestReplyManager",
        [
            "global/Promise",
            "joynr/dispatching/types/Reply",
            "joynr/messaging/MessagingQos",
            "joynr/messaging/inprocess/InProcessAddress",
            "joynr/util/Typing",
            "joynr/util/UtilInternal",
            "joynr/util/JSONSerializer",
            "joynr/util/LongTimer",
            "joynr/exceptions/MethodInvocationException",
            "joynr/exceptions/ProviderRuntimeException",
            "joynr/types/Version",
            "joynr/system/LoggerFactory"
        ],
        function(
                Promise,
                Reply,
                MessagingQos,
                InProcessAddress,
                Typing,
                Util,
                JSONSerializer,
                LongTimer,
                MethodInvocationException,
                ProviderRuntimeException,
                Version,
                LoggerFactory) {
            /**
             * The RequestReplyManager is responsible maintaining a list of providers that wish to
             * receive incoming requests, and also a list of requestReplyIds which is used to match
             * an incoming message with an expected reply.
             *
             * @name RequestReplyManager
             * @constructor
             *
             * @param {Dispatcher}
             *            dispatcher
             * @param {TypeRegistry}
             *            typeRegistry - the global type registry that records the type names
             *            together with their constructor.
             */
            function RequestReplyManager(dispatcher, typeRegistry) {
                var log = LoggerFactory.getLogger("joynr.dispatching.RequestReplyManager");

                var providers = {};
                var replyCallers = {};
                //var deletedReplyCallers = {};

                /**
                 * @name RequestReplyManager#sendRequest
                 * @function
                 *
                 * @param {Object}
                 *            settings
                 * @param {String}
                 *            settings.from participantId of the sender
                 * @param {String}
                 *            settings.to participantId of the receiver
                 * @param {MessagingQos}
                 *            settings.messagingQos quality-of-service parameters such as time-to-live
                 * @param {Request}
                 *            settings.request the Request to send
                 * @returns {Promise} the Promise for the Request
                 */
                this.sendRequest = function sendRequest(settings) {
                    var addReplyCaller = this.addReplyCaller;
                    return new Promise(function(resolve, reject) {
                        addReplyCaller(settings.request.requestReplyId, {
                            resolve : resolve,
                            reject : reject
                        }, settings.messagingQos.ttl);
                        // resolve will be called upon successful response
                        dispatcher.sendRequest(settings).catch(function(error) {
                            delete replyCallers[settings.request.requestReplyId];
                            reject(error);
                        });
                    });
                };

                /**
                 * @name RequestReplyManager#sendOneWayRequest
                 * @function
                 *
                 * @param {Object}
                 *            settings
                 * @param {String}
                 *            settings.from participantId of the sender
                 * @param {String}
                 *            settings.to participantId of the receiver
                 * @param {MessagingQos}
                 *            settings.messagingQos quality-of-service parameters such as time-to-live
                 * @param {OneWayRequest}
                 *            settings.request the Request to send
                 * @returns {Promise} the Promise for the Request
                 */
                this.sendOneWayRequest = function sendOneWayRequest(settings) {
                    return new Promise(function(resolve, reject) {
                        dispatcher.sendOneWayRequest(settings).then(resolve).catch(reject);
                    });
                };

                /**
                 * The function addRequestCaller is called when a provider wishes to receive
                 * incoming requests for the given participantId
                 *
                 * @name RequestReplyManager#addRequestCaller
                 * @function
                 *
                 * @param {String}
                 *            participantId of the provider receiving the incoming requests
                 * @param {Provider}
                 *            provider
                 */
                this.addRequestCaller = function addRequestCaller(participantId, provider) {
                    providers[participantId] = provider;
                };

                /**
                 * The function addReplyCaller is called when a proxy get/set or rpc is called and
                 * is waiting for a reply The reply caller is automatically
                 * removed when the ttl expires.
                 *
                 * @name RequestReplyManager#addReplyCaller
                 * @function
                 *
                 * @param {String}
                 *            requestReplyId
                 * @param {ReplyCaller}
                 *            replyCaller
                 * @param {Number}
                 *            ttl_ms relative number of milliseconds to wait for the reply.
                 *            The replycaller will be removed in ttl_ms and and Error will be passed
                 *            to the replyCaller
                 */
                this.addReplyCaller = function addReplyCaller(requestReplyId, replyCaller, ttl_ms) {
                    replyCallers[requestReplyId] = replyCaller;
                    LongTimer.setTimeout(function replyCallMissed() {
                        var replyCaller = replyCallers[requestReplyId];
                        if (replyCaller === undefined) {
                            return;
                        }
                        replyCaller.reject(new Error("Request with id \"" + requestReplyId + "\" failed: ttl expired"));
                        // remove the replyCaller from replyCallers in
                        // ttl_ms
                        // deletedReplyCallers[requestReplyId] = replyCaller;
                        delete replyCallers[requestReplyId];
                    }, ttl_ms);
                };

                /**
                 * The function removeRequestCaller is called when a provider no longer wishes to
                 * receive incoming requests
                 *
                 * @name RequestReplyManager#removeRequestCaller
                 * @function
                 *
                 * @param {String}
                 *            participantId
                 */
                this.removeRequestCaller =
                        function removeRequestCaller(participantId) {
                            try {
                                delete providers[participantId];
                            } catch (error) {
                                log.error("error removing provider with participantId: "
                                    + participantId
                                    + " error: "
                                    + error);
                            }
                        };

                /**
                 * @name RequestReplyManager#handleRequest
                 * @function
                 *
                 * @param {Request}
                 *            request
                 */
                this.handleRequest =
                        function handleRequest(providerParticipantId, request, callbackDispatcher) {
                            var provider = providers[providerParticipantId];
                            var exception;
                            if (!provider) {
                                // TODO error handling request
                                // TODO what if no provider is found in the mean time?
                                // Do we need to add a task to handleRequest later?
                                exception = new MethodInvocationException({
                                    detailMessage: "error handling request: "
                                        + JSONSerializer.stringify(request)
                                        + " for providerParticipantId "
                                        + providerParticipantId
                                });
                                callbackDispatcher(new Reply({
                                    error : exception,
                                    requestReplyId : request.requestReplyId
                                }));
                                return;
                            }

                            // augment the type information
                            //var typedArgs = Typing.augmentTypes(request.params, typeRegistry);

                            // if there's an operation available to call
                            var result;
                            if (provider[request.methodName]
                                && provider[request.methodName].callOperation) {
                                // may throw an immediate exception when callOperation checks the
                                // arguments, in this case exception must be caught.
                                // If final customer provided method implementation gets called,
                                // that one may return either promise (preferred) or direct result
                                // and may possibly also throw exception in the latter case.
                                try {
                                    result =
                                        provider[request.methodName].callOperation(
                                            request.params,
                                            request.paramDatatypes);
                                } catch(internalException) {
                                    exception = internalException;
                                }
                            // otherwise, check whether request is an attribute get, set or an operation
                            } else {
                                var match = request.methodName.match(/([gs]et)?(\w+)/);
                                var getSet = match[1];
                                if (getSet) {
                                    var attributeName = match[2];
                                    var attributeObject = provider[attributeName] || provider[Util.firstLower(attributeName)];
                                    // if the attribute exists in the provider
                                    if (attributeObject && !attributeObject.callOperation) {
                                        try {
                                            if (getSet === "get") {
                                                result = attributeObject.get();
                                            } else if (getSet === "set") {
                                                result = attributeObject.set(request.params[0]);
                                            }
                                        } catch(internalGetterSetterException) {
                                            if (internalGetterSetterException instanceof ProviderRuntimeException) {
                                                exception = internalGetterSetterException;
                                            } else {
                                                exception = new ProviderRuntimeException({
                                                    detailMessage: "getter/setter method of attribute " +
                                                        attributeName + " reported an error"
                                                });
                                            }
                                        }
                                    }
                                    // if neither an operation nor an attribute exists in the
                                    // provider => deliver MethodInvocationException
                                    else {
                                        exception = new MethodInvocationException({
                                            detailMessage: "Could not find an operation \""
                                                + request.methodName
                                                + "\" or an attribute \""
                                                + attributeName
                                                + "\" in the provider",
                                            providerVersion: new Version({
                                                majorVersion: provider.constructor.MAJOR_VERSION,
                                                minorVersion: provider.constructor.MINOR_VERSION
                                            })
                                        });
                                    }
                                }
                                // if no operation was found and methodName didn't start with "get"
                                // or "set" => deliver MethodInvocationException
                                else {
                                    exception = new MethodInvocationException({
                                        detailMessage: "Could not find an operation \""
                                            + request.methodName + "\" in the provider",
                                        providerVersion: new Version({
                                            majorVersion: provider.constructor.MAJOR_VERSION,
                                            minorVersion: provider.constructor.MINOR_VERSION
                                        })
                                    });
                                }
                            }

                            /* Asynchronously pass the result back to the dispatcher
                             *
                             * Call operations can be a sync or async method. In the sync case,
                             * the return value of the call operation
                             * is simply the result of the call. In the async case, the provider has
                             * the possibility to return a promise
                             * object. In this case, we wait until the promise object is resolved
                             * and call then the callbackDispatcher
                             */
                            if (!exception && Util.isPromise(result)) {
                                result.then(function(response) {
                                    callbackDispatcher(new Reply({
                                        response : response,
                                        requestReplyId : request.requestReplyId
                                    }));
                                    return response;
                                }).catch(function(internalException) {
                                    callbackDispatcher(new Reply({
                                        error : internalException,
                                        requestReplyId : request.requestReplyId
                                    }));
                                    return internalException;
                                });
                            } else {
                                if (exception) {
                                    // return stored exception
                                    LongTimer.setTimeout(function asyncCallbackDispatcher() {
                                        callbackDispatcher(new Reply({
                                            error : exception,
                                            requestReplyId : request.requestReplyId
                                        }));
                                    }, 0);
                                } else {
                                    // return result of call
                                    LongTimer.setTimeout(function asyncCallbackDispatcher() {
                                        callbackDispatcher(new Reply({
                                            response : result,
                                            requestReplyId : request.requestReplyId
                                        }));
                                    }, 0);
                                }
                            }
                        };

                        /**
                         * @name RequestReplyManager#handleOneWayRequest
                         * @function
                         *
                         * @param {String}
                         *            providerParticipantId
                         * @param {OneWayRequest}
                         *            request
                         */
                        this.handleOneWayRequest =
                                function handleOneWayRequest(providerParticipantId, request) {
                                    var provider = providers[providerParticipantId];
                                    if (!provider) {
                                        throw new MethodInvocationException({
                                            detailMessage: "error handling one-way request: "
                                                + JSONSerializer.stringify(request)
                                                + " for providerParticipantId "
                                                + providerParticipantId
                                        });
                                    }

                                    // if there's an operation available to call
                                    if (provider[request.methodName]
                                        && provider[request.methodName].callOperation) {
                                        // If final customer provided method implementation gets called,
                                        // that one may return either promise (preferred) or direct result
                                        // and may possibly also throw exception in the latter case.
                                        provider[request.methodName].callOperation(
                                            request.params,
                                            request.paramDatatypes);
                                    } else {
                                        throw new MethodInvocationException({
                                            detailMessage: "Could not find an operation \""
                                                + request.methodName + "\" in the provider",
                                            providerVersion: new Version({
                                                majorVersion: provider.constructor.MAJOR_VERSION,
                                                minorVersion: provider.constructor.MINOR_VERSION
                                            })
                                        });
                                    }
                                };

                /**
                 * @name RequestReplyManager#handleReply
                 * @function
                 *
                 * @param {Reply}
                 *            reply
                 */
                this.handleReply =
                        function handleReply(reply) {
                            var replyCaller = replyCallers[reply.requestReplyId];

                            if (replyCaller === undefined) {
                                log
                                        .error("error handling reply resolve, because replyCaller could not be found: "
                                            + JSONSerializer.stringify(reply, undefined, 4));
                                return;
                            }

                            try {
                                if (reply.error) {
                                    if (reply.error instanceof Error) {
                                        replyCaller.reject(reply.error);
                                    } else {
                                        replyCaller.reject(Typing.augmentTypes(
                                                reply.error,
                                                typeRegistry));
                                    }

                                } else {
                                    replyCaller.resolve(reply.response);
                                }
                                // deletedReplyCallers[reply.requestReplyId] = replyCallers[reply.requestReplyId];
                                delete replyCallers[reply.requestReplyId];
                            } catch (e) {
                                log.error("exception thrown during handling reply "
                                    + JSONSerializer.stringify(reply, undefined, 4)
                                    + ":\n"
                                    + e.stack);
                            }
                        };
            }

            return RequestReplyManager;

        });
<commit_msg>[JS] Remove commented code from RequestReplyManager<commit_after>/*jslint es5: true */

/*
 * #%L
 * %%
 * Copyright (C) 2011 - 2016 BMW Car IT GmbH
 * %%
 * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 * #L%
 */

define(
        "joynr/dispatching/RequestReplyManager",
        [
            "global/Promise",
            "joynr/dispatching/types/Reply",
            "joynr/messaging/MessagingQos",
            "joynr/messaging/inprocess/InProcessAddress",
            "joynr/util/Typing",
            "joynr/util/UtilInternal",
            "joynr/util/JSONSerializer",
            "joynr/util/LongTimer",
            "joynr/exceptions/MethodInvocationException",
            "joynr/exceptions/ProviderRuntimeException",
            "joynr/types/Version",
            "joynr/system/LoggerFactory"
        ],
        function(
                Promise,
                Reply,
                MessagingQos,
                InProcessAddress,
                Typing,
                Util,
                JSONSerializer,
                LongTimer,
                MethodInvocationException,
                ProviderRuntimeException,
                Version,
                LoggerFactory) {
            /**
             * The RequestReplyManager is responsible maintaining a list of providers that wish to
             * receive incoming requests, and also a list of requestReplyIds which is used to match
             * an incoming message with an expected reply.
             *
             * @name RequestReplyManager
             * @constructor
             *
             * @param {Dispatcher}
             *            dispatcher
             * @param {TypeRegistry}
             *            typeRegistry - the global type registry that records the type names
             *            together with their constructor.
             */
            function RequestReplyManager(dispatcher, typeRegistry) {
                var log = LoggerFactory.getLogger("joynr.dispatching.RequestReplyManager");

                var providers = {};
                var replyCallers = {};

                /**
                 * @name RequestReplyManager#sendRequest
                 * @function
                 *
                 * @param {Object}
                 *            settings
                 * @param {String}
                 *            settings.from participantId of the sender
                 * @param {String}
                 *            settings.to participantId of the receiver
                 * @param {MessagingQos}
                 *            settings.messagingQos quality-of-service parameters such as time-to-live
                 * @param {Request}
                 *            settings.request the Request to send
                 * @returns {Promise} the Promise for the Request
                 */
                this.sendRequest = function sendRequest(settings) {
                    var addReplyCaller = this.addReplyCaller;
                    return new Promise(function(resolve, reject) {
                        addReplyCaller(settings.request.requestReplyId, {
                            resolve : resolve,
                            reject : reject
                        }, settings.messagingQos.ttl);
                        // resolve will be called upon successful response
                        dispatcher.sendRequest(settings).catch(function(error) {
                            delete replyCallers[settings.request.requestReplyId];
                            reject(error);
                        });
                    });
                };

                /**
                 * @name RequestReplyManager#sendOneWayRequest
                 * @function
                 *
                 * @param {Object}
                 *            settings
                 * @param {String}
                 *            settings.from participantId of the sender
                 * @param {String}
                 *            settings.to participantId of the receiver
                 * @param {MessagingQos}
                 *            settings.messagingQos quality-of-service parameters such as time-to-live
                 * @param {OneWayRequest}
                 *            settings.request the Request to send
                 * @returns {Promise} the Promise for the Request
                 */
                this.sendOneWayRequest = function sendOneWayRequest(settings) {
                    return new Promise(function(resolve, reject) {
                        dispatcher.sendOneWayRequest(settings).then(resolve).catch(reject);
                    });
                };

                /**
                 * The function addRequestCaller is called when a provider wishes to receive
                 * incoming requests for the given participantId
                 *
                 * @name RequestReplyManager#addRequestCaller
                 * @function
                 *
                 * @param {String}
                 *            participantId of the provider receiving the incoming requests
                 * @param {Provider}
                 *            provider
                 */
                this.addRequestCaller = function addRequestCaller(participantId, provider) {
                    providers[participantId] = provider;
                };

                /**
                 * The function addReplyCaller is called when a proxy get/set or rpc is called and
                 * is waiting for a reply The reply caller is automatically
                 * removed when the ttl expires.
                 *
                 * @name RequestReplyManager#addReplyCaller
                 * @function
                 *
                 * @param {String}
                 *            requestReplyId
                 * @param {ReplyCaller}
                 *            replyCaller
                 * @param {Number}
                 *            ttl_ms relative number of milliseconds to wait for the reply.
                 *            The replycaller will be removed in ttl_ms and and Error will be passed
                 *            to the replyCaller
                 */
                this.addReplyCaller = function addReplyCaller(requestReplyId, replyCaller, ttl_ms) {
                    replyCallers[requestReplyId] = replyCaller;
                    LongTimer.setTimeout(function replyCallMissed() {
                        var replyCaller = replyCallers[requestReplyId];
                        if (replyCaller === undefined) {
                            return;
                        }
                        replyCaller.reject(new Error("Request with id \"" + requestReplyId + "\" failed: ttl expired"));
                        delete replyCallers[requestReplyId];
                    }, ttl_ms);
                };

                /**
                 * The function removeRequestCaller is called when a provider no longer wishes to
                 * receive incoming requests
                 *
                 * @name RequestReplyManager#removeRequestCaller
                 * @function
                 *
                 * @param {String}
                 *            participantId
                 */
                this.removeRequestCaller =
                        function removeRequestCaller(participantId) {
                            try {
                                delete providers[participantId];
                            } catch (error) {
                                log.error("error removing provider with participantId: "
                                    + participantId
                                    + " error: "
                                    + error);
                            }
                        };

                /**
                 * @name RequestReplyManager#handleRequest
                 * @function
                 *
                 * @param {Request}
                 *            request
                 */
                this.handleRequest =
                        function handleRequest(providerParticipantId, request, callbackDispatcher) {
                            var provider = providers[providerParticipantId];
                            var exception;
                            if (!provider) {
                                // TODO error handling request
                                // TODO what if no provider is found in the mean time?
                                // Do we need to add a task to handleRequest later?
                                exception = new MethodInvocationException({
                                    detailMessage: "error handling request: "
                                        + JSONSerializer.stringify(request)
                                        + " for providerParticipantId "
                                        + providerParticipantId
                                });
                                callbackDispatcher(new Reply({
                                    error : exception,
                                    requestReplyId : request.requestReplyId
                                }));
                                return;
                            }

                            // augment the type information
                            //var typedArgs = Typing.augmentTypes(request.params, typeRegistry);

                            // if there's an operation available to call
                            var result;
                            if (provider[request.methodName]
                                && provider[request.methodName].callOperation) {
                                // may throw an immediate exception when callOperation checks the
                                // arguments, in this case exception must be caught.
                                // If final customer provided method implementation gets called,
                                // that one may return either promise (preferred) or direct result
                                // and may possibly also throw exception in the latter case.
                                try {
                                    result =
                                        provider[request.methodName].callOperation(
                                            request.params,
                                            request.paramDatatypes);
                                } catch(internalException) {
                                    exception = internalException;
                                }
                            // otherwise, check whether request is an attribute get, set or an operation
                            } else {
                                var match = request.methodName.match(/([gs]et)?(\w+)/);
                                var getSet = match[1];
                                if (getSet) {
                                    var attributeName = match[2];
                                    var attributeObject = provider[attributeName] || provider[Util.firstLower(attributeName)];
                                    // if the attribute exists in the provider
                                    if (attributeObject && !attributeObject.callOperation) {
                                        try {
                                            if (getSet === "get") {
                                                result = attributeObject.get();
                                            } else if (getSet === "set") {
                                                result = attributeObject.set(request.params[0]);
                                            }
                                        } catch(internalGetterSetterException) {
                                            if (internalGetterSetterException instanceof ProviderRuntimeException) {
                                                exception = internalGetterSetterException;
                                            } else {
                                                exception = new ProviderRuntimeException({
                                                    detailMessage: "getter/setter method of attribute " +
                                                        attributeName + " reported an error"
                                                });
                                            }
                                        }
                                    }
                                    // if neither an operation nor an attribute exists in the
                                    // provider => deliver MethodInvocationException
                                    else {
                                        exception = new MethodInvocationException({
                                            detailMessage: "Could not find an operation \""
                                                + request.methodName
                                                + "\" or an attribute \""
                                                + attributeName
                                                + "\" in the provider",
                                            providerVersion: new Version({
                                                majorVersion: provider.constructor.MAJOR_VERSION,
                                                minorVersion: provider.constructor.MINOR_VERSION
                                            })
                                        });
                                    }
                                }
                                // if no operation was found and methodName didn't start with "get"
                                // or "set" => deliver MethodInvocationException
                                else {
                                    exception = new MethodInvocationException({
                                        detailMessage: "Could not find an operation \""
                                            + request.methodName + "\" in the provider",
                                        providerVersion: new Version({
                                            majorVersion: provider.constructor.MAJOR_VERSION,
                                            minorVersion: provider.constructor.MINOR_VERSION
                                        })
                                    });
                                }
                            }

                            /* Asynchronously pass the result back to the dispatcher
                             *
                             * Call operations can be a sync or async method. In the sync case,
                             * the return value of the call operation
                             * is simply the result of the call. In the async case, the provider has
                             * the possibility to return a promise
                             * object. In this case, we wait until the promise object is resolved
                             * and call then the callbackDispatcher
                             */
                            if (!exception && Util.isPromise(result)) {
                                result.then(function(response) {
                                    callbackDispatcher(new Reply({
                                        response : response,
                                        requestReplyId : request.requestReplyId
                                    }));
                                    return response;
                                }).catch(function(internalException) {
                                    callbackDispatcher(new Reply({
                                        error : internalException,
                                        requestReplyId : request.requestReplyId
                                    }));
                                    return internalException;
                                });
                            } else {
                                if (exception) {
                                    // return stored exception
                                    LongTimer.setTimeout(function asyncCallbackDispatcher() {
                                        callbackDispatcher(new Reply({
                                            error : exception,
                                            requestReplyId : request.requestReplyId
                                        }));
                                    }, 0);
                                } else {
                                    // return result of call
                                    LongTimer.setTimeout(function asyncCallbackDispatcher() {
                                        callbackDispatcher(new Reply({
                                            response : result,
                                            requestReplyId : request.requestReplyId
                                        }));
                                    }, 0);
                                }
                            }
                        };

                        /**
                         * @name RequestReplyManager#handleOneWayRequest
                         * @function
                         *
                         * @param {String}
                         *            providerParticipantId
                         * @param {OneWayRequest}
                         *            request
                         */
                        this.handleOneWayRequest =
                                function handleOneWayRequest(providerParticipantId, request) {
                                    var provider = providers[providerParticipantId];
                                    if (!provider) {
                                        throw new MethodInvocationException({
                                            detailMessage: "error handling one-way request: "
                                                + JSONSerializer.stringify(request)
                                                + " for providerParticipantId "
                                                + providerParticipantId
                                        });
                                    }

                                    // if there's an operation available to call
                                    if (provider[request.methodName]
                                        && provider[request.methodName].callOperation) {
                                        // If final customer provided method implementation gets called,
                                        // that one may return either promise (preferred) or direct result
                                        // and may possibly also throw exception in the latter case.
                                        provider[request.methodName].callOperation(
                                            request.params,
                                            request.paramDatatypes);
                                    } else {
                                        throw new MethodInvocationException({
                                            detailMessage: "Could not find an operation \""
                                                + request.methodName + "\" in the provider",
                                            providerVersion: new Version({
                                                majorVersion: provider.constructor.MAJOR_VERSION,
                                                minorVersion: provider.constructor.MINOR_VERSION
                                            })
                                        });
                                    }
                                };

                /**
                 * @name RequestReplyManager#handleReply
                 * @function
                 *
                 * @param {Reply}
                 *            reply
                 */
                this.handleReply =
                        function handleReply(reply) {
                            var replyCaller = replyCallers[reply.requestReplyId];

                            if (replyCaller === undefined) {
                                log
                                        .error("error handling reply resolve, because replyCaller could not be found: "
                                            + JSONSerializer.stringify(reply, undefined, 4));
                                return;
                            }

                            try {
                                if (reply.error) {
                                    if (reply.error instanceof Error) {
                                        replyCaller.reject(reply.error);
                                    } else {
                                        replyCaller.reject(Typing.augmentTypes(
                                                reply.error,
                                                typeRegistry));
                                    }

                                } else {
                                    replyCaller.resolve(reply.response);
                                }
                                delete replyCallers[reply.requestReplyId];
                            } catch (e) {
                                log.error("exception thrown during handling reply "
                                    + JSONSerializer.stringify(reply, undefined, 4)
                                    + ":\n"
                                    + e.stack);
                            }
                        };
            }

            return RequestReplyManager;

        });
<|endoftext|>


<commit_before>/* 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 http://mozilla.org/MPL/2.0/. */

// VERSION 1.0.3

this.TabCenter = {
	id: 'tabcentertest1@mozilla.com',

	enabled: false,

	onEnabled: function(addon) {
		if(addon.id == this.id) { this.enable(); }
	},

	onDisabled: function(addon) {
		if(addon.id == this.id) { this.disable(); }
	},

	listen: function() {
		AddonManager.addAddonListener(this);
		AddonManager.getAddonByID(this.id, (addon) => {
			if(addon && addon.isActive) {
				this.enable();
			}
		});
	},

	unlisten: function() {
		AddonManager.removeAddonListener(this);
		this.disable();
	},

	enable: function() {
		if(!this.enabled) {
			this.enabled = true;

			Styles.load('TabCenter', 'compatibilityFix/TabCenter');

			if(window.VerticalTabs) {
				this.init();
			} else {
				window.__defineGetter__('VerticalTabs', function() { return undefined; });
				window.__defineSetter__('VerticalTabs', (v) => {
					delete window.VerticalTabs;
					window.VerticalTabs = v;
					this.init(true);
				})
			}
		}
	},

	disable: function() {
		if(this.enabled) {
			this.enabled = false;

			Styles.unload('TabCenter', 'compatibilityFix/TabCenter');

			// Make sure our setter handler is removed.
			if(!window.VerticalTabs) {
				delete window.VerticalTabs;
			}
			// Otherwise we have to undo our fixes properly.
			else {
				this.uninit();
			}
		}
	},

	get findInput() { return $('find-input'); },

	attrWatcher: function() {
		toggleAttribute($('TabsToolbar'), 'tabCenterInputFocused', trueAttribute($('find-input'), 'focused'));
	},

	init: function(justCreated) {
		window.VerticalTabs._lastInputValue = '';

		Piggyback.add('TabCenter', window.VerticalTabs, 'filtertabs', function() {
			// There's no need to re-filter the tabs if the correct ones are already showing.
			// This saves precious cycles on startup, by not initializing TabView immediately.
			let hidden_tab = $('filler-tab');
			let find_input = $('find-input');
			let input_value = find_input.value.toLowerCase();
			if(!input_value && !this._lastInputValue) {
				hidden_tab.setAttribute('hidden', 'true');
				Timers.init('TabCenter.filtertabs', () => {
					this.actuallyResizeTabs();
				}, 300);
				return;
			}

			TabView._initFrame(() => {
				Timers.init('TabCenter.filtertabs', () => {
					this._lastInputValue = input_value;

					// If there's no filter term, show all the tabs in the current group.
					if(!input_value) {
						TabView._window.UI.updateShownTabs();
						hidden_tab.setAttribute('hidden', 'true');
						this.actuallyResizeTabs();
						return;
					}

					// Only filter tabs from the current group.
					let tabs;
					let activeGroup = TabView._window.GroupItems.getActiveGroupItem();
					if(activeGroup) {
						// Pinned tabs are always shown, regardless of group.
						tabs = Tabs.pinned.concat(activeGroup.children.map((tabItem) => { return tabItem.tab; }));
					} else {
						// The few cases where there is no active group, it's safe to assume all tabs are visble.
						tabs = Tabs.all;
					}

					let hidden_counter = 0;
					for(let tab of tabs) {
						if(tab.label.toLowerCase().match(input_value) || this.getUri(tab).spec.toLowerCase().match(input_value)) {
							tab.removeAttribute('hidden');
						}
						else {
							tab.setAttribute('hidden', 'true');
							hidden_counter++;
						}
					}

					let hidden_tab_label = hidden_tab.children[0];

					if(hidden_counter > 0) {
						hidden_tab_label.setAttribute('value', `${hidden_counter} more tab${hidden_counter > 1 ? 's' : ''}...`);
						hidden_tab.removeAttribute('hidden');
					} else {
						hidden_tab.setAttribute('hidden', 'true');
					}
					this.actuallyResizeTabs();
				}, 300);
			});
		});

		// We have to call this at least once now, to make sure that when it was enabled before, we hide tabs from other groups.
		if(!justCreated) {
			window.VerticalTabs.filtertabs();
		}

		let setupTextbox = () => {
			Watchers.addAttributeWatcher(this.findInput, 'focused', this, false, false);
			this.attrWatcher();
		};

		// Hide our button when Tab Center's find textbox is focused.
		if(this.findInput) {
			setupTextbox();
		} else {
			Piggyback.add('TabCenter', window.VerticalTabs, 'rearrangeXUL', () => {
				setupTextbox();
			}, Piggyback.MODE_AFTER);
		}
	},

	uninit: function() {
		Timers.cancel('TabCenter.filtertabs');
		Piggyback.revert('TabCenter', window.VerticalTabs, 'filtertabs');
		Piggyback.revert('TabCenter', window.VerticalTabs, 'rearrangeXUL');
		delete window.VerticalTabs._lastInputValue;

		if(this.findInput) {
			Watchers.removeAttributeWatcher(this.findInput, 'focused', this, false, false);
		}
		removeAttribute($('TabsToolbar'), 'tabCenterInputFocused');

		// TabCenter should show any tabs it wants to now.
		window.VerticalTabs.filtertabs();
	}
};

Modules.LOADMODULE = function() {
	TabCenter.listen();
};

Modules.UNLOADMODULE = function() {
	TabCenter.unlisten();
};
<commit_msg>extra fixes for Tab Center<commit_after>/* 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 http://mozilla.org/MPL/2.0/. */

// VERSION 1.0.4

this.TabCenter = {
	id: 'tabcentertest1@mozilla.com',

	enabled: false,

	onEnabled: function(addon) {
		if(addon.id == this.id) { this.enable(); }
	},

	onDisabled: function(addon) {
		if(addon.id == this.id) { this.disable(); }
	},

	listen: function() {
		AddonManager.addAddonListener(this);
		AddonManager.getAddonByID(this.id, (addon) => {
			if(addon && addon.isActive) {
				this.enable();
			}
		});
	},

	unlisten: function() {
		AddonManager.removeAddonListener(this);
		this.disable();
	},

	enable: function() {
		if(!this.enabled) {
			this.enabled = true;

			Styles.load('TabCenter', 'compatibilityFix/TabCenter');

			if(window.VerticalTabs) {
				this.init();
			} else {
				window.__defineGetter__('VerticalTabs', function() { return undefined; });
				window.__defineSetter__('VerticalTabs', (v) => {
					delete window.VerticalTabs;
					window.VerticalTabs = v;
					this.init(true);
				})
			}
		}
	},

	disable: function() {
		if(this.enabled) {
			this.enabled = false;

			Styles.unload('TabCenter', 'compatibilityFix/TabCenter');

			// Make sure our setter handler is removed.
			if(!window.VerticalTabs) {
				delete window.VerticalTabs;
			}
			// Otherwise we have to undo our fixes properly.
			else {
				this.uninit();
			}
		}
	},

	get findInput() { return $('find-input'); },

	handleEvent: function(e) {
		switch(e.type) {
			case 'TabBarUpdated':
				window.VerticalTabs.clearFind('tabGroupChange');
				break;
		}
	},

	attrWatcher: function() {
		toggleAttribute($('TabsToolbar'), 'tabCenterInputFocused', trueAttribute($('find-input'), 'focused'));
	},

	init: function(justCreated) {
		window.VerticalTabs._lastInputValue = '';

		Piggyback.add('TabCenter', window.VerticalTabs, 'filtertabs', function() {
			// There's no need to re-filter the tabs if the correct ones are already showing.
			// This saves precious cycles on startup, by not initializing TabView immediately.
			let hidden_tab = $('filler-tab');
			let find_input = $('find-input');
			let input_value = find_input.value.toLowerCase();
			if(!input_value && !this._lastInputValue) {
				hidden_tab.setAttribute('hidden', 'true');
				Timers.init('TabCenter.filtertabs', () => {
					this.actuallyResizeTabs();
				}, 300);
				return;
			}

			TabView._initFrame(() => {
				Timers.init('TabCenter.filtertabs', () => {
					this._lastInputValue = input_value;

					// If there's no filter term, show all the tabs in the current group.
					if(!input_value) {
						TabView._window.UI.updateShownTabs();
						hidden_tab.setAttribute('hidden', 'true');
						this.actuallyResizeTabs();
						return;
					}

					// Only filter tabs from the current group.
					let tabs;
					let activeGroup = TabView._window.GroupItems.getActiveGroupItem();
					if(activeGroup) {
						// Pinned tabs are always shown, regardless of group.
						tabs = Tabs.pinned.concat(activeGroup.children.map((tabItem) => { return tabItem.tab; }));
					} else {
						// The few cases where there is no active group, it's safe to assume all tabs are visble.
						tabs = Tabs.all;
					}

					let hidden_counter = 0;
					for(let tab of tabs) {
						let label = tab.label || '';
						if(label.toLowerCase().match(input_value) || this.getUri(tab).spec.toLowerCase().match(input_value)) {
							tab.removeAttribute('hidden');
						}
						else {
							tab.setAttribute('hidden', 'true');
							hidden_counter++;
						}
					}

					let hidden_tab_label = hidden_tab.children[0];

					if(hidden_counter > 0) {
						hidden_tab_label.setAttribute('value', `${hidden_counter} more tab${hidden_counter > 1 ? 's' : ''}...`);
						hidden_tab.removeAttribute('hidden');
					} else {
						hidden_tab.setAttribute('hidden', 'true');
					}
					this.actuallyResizeTabs();
				}, 300);
			});
		});

		// We have to call this at least once now, to make sure that when it was enabled before, we hide tabs from other groups.
		if(!justCreated) {
			window.VerticalTabs.filtertabs();
		}

		Tabs.listen('TabBarUpdated', this);

		let setupTextbox = () => {
			Watchers.addAttributeWatcher(this.findInput, 'focused', this, false, false);
			this.attrWatcher();
		};

		// Hide our button when Tab Center's find textbox is focused.
		if(this.findInput) {
			setupTextbox();
		} else {
			Piggyback.add('TabCenter', window.VerticalTabs, 'rearrangeXUL', () => {
				setupTextbox();
			}, Piggyback.MODE_AFTER);
		}
	},

	uninit: function() {
		Timers.cancel('TabCenter.filtertabs');
		Piggyback.revert('TabCenter', window.VerticalTabs, 'filtertabs');
		Piggyback.revert('TabCenter', window.VerticalTabs, 'rearrangeXUL');
		delete window.VerticalTabs._lastInputValue;

		Tabs.unlisten('TabBarUpdated', this);
		if(this.findInput) {
			Watchers.removeAttributeWatcher(this.findInput, 'focused', this, false, false);
		}
		removeAttribute($('TabsToolbar'), 'tabCenterInputFocused');

		// TabCenter should show any tabs it wants to now.
		window.VerticalTabs.filtertabs();
	}
};

Modules.LOADMODULE = function() {
	TabCenter.listen();
};

Modules.UNLOADMODULE = function() {
	TabCenter.unlisten();
};
<|endoftext|>


<commit_before>var queryString = require('querystring');
var http = require('http');
var Object2File = require(__dirname + '/object2file.js');

// communications functions
var NoxClient = require(__dirname + '/nox-client.js');
var myNoxClient = new NoxClient();

var dataDir = __dirname + '/noxious-data';
var contactList = new Object2File(dataDir, 'contacts.json');
var contactRequestList = new Object2File(dataDir, 'contact-requests.json');

var app = require('app');  // Module to control application life.
var BrowserWindow = require('browser-window');  // Module to create native browser window.

var thsBuilder = require('ths');
var ths = new thsBuilder();
// crypto related

var NoxCrypto = require(__dirname + '/nox-crypto.js');
var myCrypto = new NoxCrypto({ dataDir: dataDir, fileName: 'privatekey.json'});

var myAddress;

var person = function (lastName) {
  this.lastName = lastName;
}

function notifyGUI(msg) {
  // TODO, needs improvement?
  if(!mainWindow.webContents.isLoading()) {
    mainWindow.webContents.send(msg.method, msg.content);
  }
}

function isEmptyObject(obj) {
  return !Object.keys(obj).length;
}

function getContacts() {
  // do nothing if contact list is empty
  contactList.getContent(function(content) {
    if (!isEmptyObject(content)) {
      var msgObj = {};
      msgObj.method = 'contact';
      msgObj.content = { type: 'initContactList', contactList: content };
      notifyGUI(msgObj);
    }
  });
}

function getContactRequests() {
  contactRequestList.getContent(function(content) {
    if (!isEmptyObject(content)) {
      var msgObj = {};
      msgObj.method = 'contact';
      msgObj.content = { type: 'initContactRequestList', contactRequestList: content };
      notifyGUI(msgObj);
    }
  });
}

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the javascript object is GCed.
var mainWindow = null;
var pageLoaded = false;

var server = http.createServer(function (req, res){
  if (req.method === 'GET') {
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.end('Hello world!');
  } else if (req.method === 'POST') {
    if (req.url === '/') {
      var reqBody = '';
      req.on('data', function(d) {
        reqBody += d;
        if (reqBody.length > 1e7) {
          res.writeHead(413, 'Request Entity Too Large', {'Content-Type': 'text/html'});
          res.end('<!doctype html><title>413</title>413: Request Entity Too Large');
        }
      });
      req.on('end', function() {
        res.writeHead(200, {'Content-Type': 'text/html'});
        res.write('Thanks for the data, ');
        res.end();
        processMessage(reqBody);
      });
    }
  }
});
server.listen(1111, '127.0.0.1');
console.log('Server running at http://127.0.0.1:1111');

function logSomething() {
  console.log('something');
}

function relayMessage(msg) {
  mainWindow.webContents.send('msg', 'from: ' + msg.name + ' message: ' + msg.message);
}

function registerContactRequest(req) {
  // add to list of other contact requests for saving to disk
  // build object
  // TODO is a date/time wanted or needed here? Other Data?
  // this same data structure is copied to the contact list upon acceptance.
  var tmpObj = {};
  tmpObj.pubKey = req.pubKey;
  tmpObj.contactAddress = req.from;
  tmpObj.direction = 'incoming';
  // check for dups in requests list and contact list
  if(contactRequestList.getKey[req.from] == null && contactList.getKey[req.from] == null) {
    contactRequestList.addKey(req.from, tmpObj);
    var msgObj={};
    msgObj.method = 'contact';
    msgObj.content = { type: 'contactRequest', from: req.from, direction: 'incoming' };
    notifyGUI(msgObj);
  }
}

function processMessage(msg) {
  msgObj = JSON.parse(msg);
  var content = msgObj.content;
  var signature = msgObj.signature;
  switch (content.type) {
    case 'introduction':
      tmpCrypto = new NoxCrypto({'pubPEM': content.pubPEM});
      if (tmpCrypto.signatureVerified(JSON.stringify(content), signature)) {
        console.log('Introduction is properly signed.');
        // TODO enhance from address checking, for now, not null, and not myAddress
        if (content.to==myAddress && content.from!=='undefined' && content.from && content.from!==myAddress) {
          // content.to is part of the signed content.
          console.log('Introduction is properly addressed.');
          // Contact request is valid, register it, TODO check for dups?
          registerContactRequest(content);
        }
      } else {
        console.log('Introduction is NOT properly signed.  Disregarding.');
      }
      break;
  }
}

function startHiddenService() {
  // we know that tor is loaded and web page is loaded.
  var serviceList = ths.getServices();
  console.log('Service List: %j',serviceList);

  function noxiousExists(element) {
    return element.name=='noxious';
  }

  noxiousProperties=serviceList.filter(noxiousExists);
  if (noxiousProperties==0) {
    // does not exist, create it
    console.log('Creating new noxious service');
    ths.createHiddenService('noxious','1111', true);
    // TODO tor needs some time to reload after new service, wait an run again.  more elegant solution?\
    setTimeout(function () { startHiddenService(); }, 2000);
  } else {
    console.log('Noxious Service Exists: %j', noxiousProperties);
    myAddress=ths.getOnionAddress('noxious');
    var msgObj = {};
    msgObj.method = 'status';
    msgObj.content = { type:'onionAddress', content: myAddress };
    notifyGUI(msgObj);
  }
}

// Quit when all windows are closed.
app.on('window-all-closed', function() {
  if (process.platform != 'darwin')
    app.quit();
});

// This method will be called when atom-shell has done everything
// initialization and ready for creating browser windows.
app.on('ready', function() {
  // handles communication between browser and io.js (webpage)
  var ipc = require('ipc');

  // Create the browser window.
  mainWindow = new BrowserWindow({width: 800, height: 600});
  mainWindow.openDevTools();

  ths.start(false, function () {
    console.log("tor Started!");
    if(!mainWindow.webContents.isLoading()) {
      mainWindow.webContents.send('ping', 'Tor is ready');
      startHiddenService();
    }
  });

  // and load the index.html of the app.
  mainWindow.loadUrl('file://' + __dirname + '/index.html');
  mainWindow.webContents.on('did-finish-load', function() {
    console.log('did finish loading.');
    getContacts();
    getContactRequests();
  });

  ipc.on('contact', function(event, content) {
    console.log('[contact event] ', content);
    switch (content.type) {
      case 'acceptContactRequest':
        // user has chosen to accept the contact request
        // pull the info from the contactRequestList and make a new conact.
        contactList.addKey(content.contactAddress, contactRequestList.getKey(content.contactAddress));
        // remove the contact request and save
        contactRequestList.delKey(content.contactAddress);
        // for now, just reinit the contact list
        getContacts();
        // now send encrypted message back to contact containing this Public Key.
        break;
      case 'sendContactRequest':
        // do not send request to myAddress
        // TODO display error message if to=myAddress, for now, discard
        if(content.contactAddress!==myAddress) {
          var introObj = {};
          introObj.type = 'introduction';
          introObj.from = myAddress;
          introObj.to = content.contactAddress;
          introObj.pubPEM = myCrypto.pubPEM;
          var signature = myCrypto.signString(JSON.stringify(introObj));
          var msgObj = {};
          msgObj.content = introObj;
          msgObj.signature = signature;
          myNoxClient.transmitObject(content.contactAddress, msgObj);
        }
        break;
    }
  });

  // test ipc communications
  ipc.on('asynchronous-message', function(event, arg) {
    console.log(arg);  // prints "ping"
    event.sender.send('asynchronous-reply', 'pong');
  });

  ipc.on('synchronous-message', function(event, arg) {
    console.log(arg);  // prints "ping"
    event.returnValue = 'pong';
  });

  // Emitted when the window is closed.
  mainWindow.on('closed', function() {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    mainWindow = null;
  });
});

app.on('before-quit', function(e) {
  if (ths.isTorRunning()) {
    e.preventDefault();
    ths.stop(function () {
      console.log("tor has been stopped");
      app.quit();
    });
  }
  console.log('I\'m quitting.');
});
<commit_msg>fix ths directory<commit_after>var queryString = require('querystring');
var http = require('http');
var Object2File = require(__dirname + '/object2file.js');

// communications functions
var NoxClient = require(__dirname + '/nox-client.js');
var myNoxClient = new NoxClient();

var dataDir = __dirname + '/noxious-data';
var contactList = new Object2File(dataDir, 'contacts.json');
var contactRequestList = new Object2File(dataDir, 'contact-requests.json');

var app = require('app');  // Module to control application life.
var BrowserWindow = require('browser-window');  // Module to create native browser window.

var thsBuilder = require('ths');
var ths = new thsBuilder(__dirname);
// crypto related

var NoxCrypto = require(__dirname + '/nox-crypto.js');
var myCrypto = new NoxCrypto({ dataDir: dataDir, fileName: 'privatekey.json'});

var myAddress;

var person = function (lastName) {
  this.lastName = lastName;
}

function notifyGUI(msg) {
  // TODO, needs improvement?
  if(!mainWindow.webContents.isLoading()) {
    mainWindow.webContents.send(msg.method, msg.content);
  }
}

function isEmptyObject(obj) {
  return !Object.keys(obj).length;
}

function getContacts() {
  // do nothing if contact list is empty
  contactList.getContent(function(content) {
    if (!isEmptyObject(content)) {
      var msgObj = {};
      msgObj.method = 'contact';
      msgObj.content = { type: 'initContactList', contactList: content };
      notifyGUI(msgObj);
    }
  });
}

function getContactRequests() {
  contactRequestList.getContent(function(content) {
    if (!isEmptyObject(content)) {
      var msgObj = {};
      msgObj.method = 'contact';
      msgObj.content = { type: 'initContactRequestList', contactRequestList: content };
      notifyGUI(msgObj);
    }
  });
}

// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the javascript object is GCed.
var mainWindow = null;
var pageLoaded = false;

var server = http.createServer(function (req, res){
  if (req.method === 'GET') {
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.end('Hello world!');
  } else if (req.method === 'POST') {
    if (req.url === '/') {
      var reqBody = '';
      req.on('data', function(d) {
        reqBody += d;
        if (reqBody.length > 1e7) {
          res.writeHead(413, 'Request Entity Too Large', {'Content-Type': 'text/html'});
          res.end('<!doctype html><title>413</title>413: Request Entity Too Large');
        }
      });
      req.on('end', function() {
        res.writeHead(200, {'Content-Type': 'text/html'});
        res.write('Thanks for the data, ');
        res.end();
        processMessage(reqBody);
      });
    }
  }
});
server.listen(1111, '127.0.0.1');
console.log('Server running at http://127.0.0.1:1111');

function logSomething() {
  console.log('something');
}

function relayMessage(msg) {
  mainWindow.webContents.send('msg', 'from: ' + msg.name + ' message: ' + msg.message);
}

function registerContactRequest(req) {
  // add to list of other contact requests for saving to disk
  // build object
  // TODO is a date/time wanted or needed here? Other Data?
  // this same data structure is copied to the contact list upon acceptance.
  var tmpObj = {};
  tmpObj.pubKey = req.pubKey;
  tmpObj.contactAddress = req.from;
  tmpObj.direction = 'incoming';
  // check for dups in requests list and contact list
  if(contactRequestList.getKey[req.from] == null && contactList.getKey[req.from] == null) {
    contactRequestList.addKey(req.from, tmpObj);
    var msgObj={};
    msgObj.method = 'contact';
    msgObj.content = { type: 'contactRequest', from: req.from, direction: 'incoming' };
    notifyGUI(msgObj);
  }
}

function processMessage(msg) {
  msgObj = JSON.parse(msg);
  var content = msgObj.content;
  var signature = msgObj.signature;
  switch (content.type) {
    case 'introduction':
      tmpCrypto = new NoxCrypto({'pubPEM': content.pubPEM});
      if (tmpCrypto.signatureVerified(JSON.stringify(content), signature)) {
        console.log('Introduction is properly signed.');
        // TODO enhance from address checking, for now, not null, and not myAddress
        if (content.to==myAddress && content.from!=='undefined' && content.from && content.from!==myAddress) {
          // content.to is part of the signed content.
          console.log('Introduction is properly addressed.');
          // Contact request is valid, register it, TODO check for dups?
          registerContactRequest(content);
        }
      } else {
        console.log('Introduction is NOT properly signed.  Disregarding.');
      }
      break;
  }
}

function startHiddenService() {
  // we know that tor is loaded and web page is loaded.
  var serviceList = ths.getServices();
  console.log('Service List: %j',serviceList);

  function noxiousExists(element) {
    return element.name=='noxious';
  }

  noxiousProperties=serviceList.filter(noxiousExists);
  if (noxiousProperties==0) {
    // does not exist, create it
    console.log('Creating new noxious service');
    ths.createHiddenService('noxious','1111', true);
    // TODO tor needs some time to reload after new service, wait an run again.  more elegant solution?\
    setTimeout(function () { startHiddenService(); }, 2000);
  } else {
    console.log('Noxious Service Exists: %j', noxiousProperties);
    myAddress=ths.getOnionAddress('noxious');
    var msgObj = {};
    msgObj.method = 'status';
    msgObj.content = { type:'onionAddress', content: myAddress };
    notifyGUI(msgObj);
  }
}

// Quit when all windows are closed.
app.on('window-all-closed', function() {
  if (process.platform != 'darwin')
    app.quit();
});

// This method will be called when atom-shell has done everything
// initialization and ready for creating browser windows.
app.on('ready', function() {
  // handles communication between browser and io.js (webpage)
  var ipc = require('ipc');

  // Create the browser window.
  mainWindow = new BrowserWindow({width: 800, height: 600});
  mainWindow.openDevTools();

  ths.start(false, function () {
    console.log("tor Started!");
    if(!mainWindow.webContents.isLoading()) {
      mainWindow.webContents.send('ping', 'Tor is ready');
      startHiddenService();
    }
  });

  // and load the index.html of the app.
  mainWindow.loadUrl('file://' + __dirname + '/index.html');
  mainWindow.webContents.on('did-finish-load', function() {
    console.log('did finish loading.');
    getContacts();
    getContactRequests();
  });

  ipc.on('contact', function(event, content) {
    console.log('[contact event] ', content);
    switch (content.type) {
      case 'acceptContactRequest':
        // user has chosen to accept the contact request
        // pull the info from the contactRequestList and make a new conact.
        contactList.addKey(content.contactAddress, contactRequestList.getKey(content.contactAddress));
        // remove the contact request and save
        contactRequestList.delKey(content.contactAddress);
        // for now, just reinit the contact list
        getContacts();
        // now send encrypted message back to contact containing this Public Key.
        break;
      case 'sendContactRequest':
        // do not send request to myAddress
        // TODO display error message if to=myAddress, for now, discard
        if(content.contactAddress!==myAddress) {
          var introObj = {};
          introObj.type = 'introduction';
          introObj.from = myAddress;
          introObj.to = content.contactAddress;
          introObj.pubPEM = myCrypto.pubPEM;
          var signature = myCrypto.signString(JSON.stringify(introObj));
          var msgObj = {};
          msgObj.content = introObj;
          msgObj.signature = signature;
          myNoxClient.transmitObject(content.contactAddress, msgObj);
        }
        break;
    }
  });

  // test ipc communications
  ipc.on('asynchronous-message', function(event, arg) {
    console.log(arg);  // prints "ping"
    event.sender.send('asynchronous-reply', 'pong');
  });

  ipc.on('synchronous-message', function(event, arg) {
    console.log(arg);  // prints "ping"
    event.returnValue = 'pong';
  });

  // Emitted when the window is closed.
  mainWindow.on('closed', function() {
    // Dereference the window object, usually you would store windows
    // in an array if your app supports multi windows, this is the time
    // when you should delete the corresponding element.
    mainWindow = null;
  });
});

app.on('before-quit', function(e) {
  if (ths.isTorRunning()) {
    e.preventDefault();
    ths.stop(function () {
      console.log("tor has been stopped");
      app.quit();
    });
  }
  console.log('I\'m quitting.');
});
<|endoftext|>