parent
0ba0ded728
commit
8028070aaa
@ -0,0 +1,183 @@ |
|||||||
|
/* |
||||||
|
* This file contains the weechat models and various |
||||||
|
* helper methods to work with them. |
||||||
|
*/ |
||||||
|
var models = angular.module('weechatModels', []); |
||||||
|
|
||||||
|
models.service('models', ['colors', function(colors) { |
||||||
|
/* |
||||||
|
* Buffer class |
||||||
|
*/ |
||||||
|
this.Buffer = function(message) { |
||||||
|
// weechat properties
|
||||||
|
var fullName = message['full_name'] |
||||||
|
var shortName = message['short_name'] |
||||||
|
var title = message['title'] |
||||||
|
var number = message['number'] |
||||||
|
var pointer = message['pointers'][0] |
||||||
|
var lines = [] |
||||||
|
var active = false; |
||||||
|
var notification = false; |
||||||
|
var unread = ''; |
||||||
|
|
||||||
|
/* |
||||||
|
* Adds a line to this buffer |
||||||
|
*
|
||||||
|
* @param line the BufferLine object |
||||||
|
* @return undefined |
||||||
|
*/ |
||||||
|
var addLine = function(line) { |
||||||
|
lines.push(line); |
||||||
|
} |
||||||
|
|
||||||
|
return { |
||||||
|
id: pointer, |
||||||
|
fullName: fullName, |
||||||
|
shortName: shortName, |
||||||
|
number: number, |
||||||
|
title: title, |
||||||
|
lines: lines, |
||||||
|
addLine: addLine |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* BufferLine class |
||||||
|
*/ |
||||||
|
this.BufferLine = function(message) { |
||||||
|
|
||||||
|
/* |
||||||
|
* Parse the text elements from the buffer line added |
||||||
|
* |
||||||
|
* @param message weechat message |
||||||
|
*/ |
||||||
|
function parseLineAddedTextElements(message) { |
||||||
|
var prefix = colors.parse(message['prefix']); |
||||||
|
|
||||||
|
var buffer = message['buffer']; |
||||||
|
text_elements = _.union(prefix, text); |
||||||
|
text_elements =_.map(text_elements, function(text_element) { |
||||||
|
if (text_element && ('fg' in text_element)) { |
||||||
|
text_element['fg'] = colors.prepareCss(text_element['fg']); |
||||||
|
} |
||||||
|
// TODO: parse background as well
|
||||||
|
|
||||||
|
return text_element; |
||||||
|
}); |
||||||
|
return text_elements; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
var buffer = message['buffer']; |
||||||
|
var date = message['date']; |
||||||
|
var text = colors.parse(message['message']); |
||||||
|
var tags_array = message['tags_array']; |
||||||
|
var displayed = message['displayed']; |
||||||
|
var highlight = message['highlight']; |
||||||
|
var content = parseLineAddedTextElements(message); |
||||||
|
var text = ""; |
||||||
|
if(text[0] != undefined) { |
||||||
|
text = text[0]['text']; |
||||||
|
} |
||||||
|
|
||||||
|
return { |
||||||
|
content: content, |
||||||
|
date: date, |
||||||
|
buffer: buffer, |
||||||
|
tags: tags_array, |
||||||
|
highlight: highlight, |
||||||
|
displayed: displayed, |
||||||
|
text: text, |
||||||
|
} |
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
var BufferList = [] |
||||||
|
activeBuffer = null; |
||||||
|
|
||||||
|
this.model = { 'buffers': {} } |
||||||
|
|
||||||
|
/* |
||||||
|
* Adds a buffer to the list |
||||||
|
* |
||||||
|
* @param buffer buffer object |
||||||
|
* @return undefined |
||||||
|
*/ |
||||||
|
this.addBuffer = function(buffer) { |
||||||
|
BufferList[buffer.id] = buffer; |
||||||
|
if (BufferList.length == 1) { |
||||||
|
activeBuffer = buffer.id; |
||||||
|
} |
||||||
|
this.model.buffers[buffer.id] = buffer; |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* Returns the current active buffer |
||||||
|
* |
||||||
|
* @return active buffer object |
||||||
|
*/ |
||||||
|
this.getActiveBuffer = function() { |
||||||
|
return activeBuffer; |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* Sets the buffer specifiee by bufferId as active. |
||||||
|
* Deactivates the previous current buffer. |
||||||
|
* |
||||||
|
* @param bufferId id of the new active buffer |
||||||
|
* @return undefined |
||||||
|
*/ |
||||||
|
this.setActiveBuffer = function(bufferId) { |
||||||
|
|
||||||
|
if (this.getActiveBuffer()) { |
||||||
|
this.getActiveBuffer().active = false; |
||||||
|
} |
||||||
|
|
||||||
|
activeBuffer = _.find(this.model['buffers'], function(buffer) { |
||||||
|
if (buffer['id'] == bufferId) { |
||||||
|
return buffer; |
||||||
|
} |
||||||
|
}); |
||||||
|
activeBuffer.notification = false; |
||||||
|
activeBuffer.active = true; |
||||||
|
activeBuffer.unread = ''; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* Returns the buffer list |
||||||
|
*/ |
||||||
|
this.getBuffers = function() { |
||||||
|
return BufferList; |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* Returns a specific buffer object |
||||||
|
* |
||||||
|
* @param bufferId id of the buffer |
||||||
|
* @return the buffer object |
||||||
|
*/ |
||||||
|
this.getBuffer = function(bufferId) { |
||||||
|
return _.find(this.model['buffers'], function(buffer) { |
||||||
|
if (buffer['id'] == bufferId) { |
||||||
|
return buffer; |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* Closes a weechat buffer. Sets the first buffer |
||||||
|
* as active. |
||||||
|
* |
||||||
|
* @param bufferId id of the buffer to close |
||||||
|
* @return undefined |
||||||
|
*/ |
||||||
|
this.closeBuffer = function(bufferId) { |
||||||
|
|
||||||
|
delete(this.model['buffers'][bufferId.id]); |
||||||
|
var firstBuffer = _.keys(this.model['buffers'])[0]; |
||||||
|
this.setActiveBuffer(firstBuffer); |
||||||
|
} |
||||||
|
}]); |
@ -0,0 +1,132 @@ |
|||||||
|
/* |
||||||
|
* This file contains the plugin definitions |
||||||
|
*/ |
||||||
|
|
||||||
|
plugins = angular.module('plugins', []); |
||||||
|
|
||||||
|
/* |
||||||
|
* Definition of a user provided plugin with sensible default values |
||||||
|
* |
||||||
|
* User plugins are created by providing a contentForMessage function |
||||||
|
* that parses a string and return any additional content. |
||||||
|
*/ |
||||||
|
var Plugin = function(contentForMessage) { |
||||||
|
|
||||||
|
return { |
||||||
|
contentForMessage: contentForMessage, |
||||||
|
exclusive: false, |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* This service provides access to the plugin manager |
||||||
|
* |
||||||
|
* The plugin manager is where the various user provided plugins |
||||||
|
* are registered. It is responsible for finding additional content |
||||||
|
* to display when messages are received. |
||||||
|
* |
||||||
|
*/ |
||||||
|
plugins.service('plugins', ['userPlugins', function(userPlugins) { |
||||||
|
|
||||||
|
/* |
||||||
|
* Defines the plugin manager object |
||||||
|
*/ |
||||||
|
var PluginManagerObject = function() { |
||||||
|
|
||||||
|
var plugins = []; |
||||||
|
|
||||||
|
/* |
||||||
|
* Register the user provides plugins |
||||||
|
* |
||||||
|
* @param userPlugins user provided plugins |
||||||
|
*/ |
||||||
|
var registerPlugins = function(userPlugins) { |
||||||
|
for (var i = 0; i < userPlugins.length; i++) { |
||||||
|
plugins.push(userPlugins[i]); |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* Iterates through all the registered plugins |
||||||
|
* and run their contentForMessage function. |
||||||
|
*/ |
||||||
|
var contentForMessage = function(message) { |
||||||
|
|
||||||
|
var content = []; |
||||||
|
for (var i = 0; i < plugins.length; i++) { |
||||||
|
var pluginContent = plugins[i].contentForMessage(message); |
||||||
|
if (pluginContent) { |
||||||
|
var pluginContent = {'visible': false,
|
||||||
|
'content': pluginContent } |
||||||
|
content.push(pluginContent); |
||||||
|
|
||||||
|
if (plugins[i].exclusive) { |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
return content; |
||||||
|
} |
||||||
|
|
||||||
|
return { |
||||||
|
registerPlugins: registerPlugins, |
||||||
|
contentForMessage: contentForMessage |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Instanciates and registers the plugin manager.
|
||||||
|
this.PluginManager = new PluginManagerObject(); |
||||||
|
this.PluginManager.registerPlugins(userPlugins.plugins); |
||||||
|
|
||||||
|
}]); |
||||||
|
|
||||||
|
/* |
||||||
|
* This factory exposes the collection of user provided plugins. |
||||||
|
* |
||||||
|
* To create your own plugin, you need to: |
||||||
|
* |
||||||
|
* 1. Define it's contentForMessage function. The contentForMessage |
||||||
|
* function takes a string as a parameter and returns a HTML string. |
||||||
|
* |
||||||
|
* 2. Instanciate a Plugin object with contentForMessage function as it's |
||||||
|
* argument. |
||||||
|
* |
||||||
|
* 3. Add it to the plugins array. |
||||||
|
* |
||||||
|
*/ |
||||||
|
plugins.factory('userPlugins', function() { |
||||||
|
|
||||||
|
var youtubePlugin = new Plugin(function(message) { |
||||||
|
|
||||||
|
if (message.indexOf('youtube.com') != -1) { |
||||||
|
var index = message.indexOf("?v="); |
||||||
|
var token = message.substr(index+3); |
||||||
|
return '<iframe width="560" height="315" src="http://www.youtube.com/embed/' + token + '" frameborder="0" allowfullscreen></iframe>' |
||||||
|
} |
||||||
|
|
||||||
|
return null; |
||||||
|
}); |
||||||
|
|
||||||
|
var urlPlugin = new Plugin(function(message) { |
||||||
|
var urlPattern = /(http|ftp|https):\/\/[\w-]+(\.[\w-]+)+([\w.,@?^=%&:\/~+#-]*[\w@?^=%&\/~+#-])?/; |
||||||
|
var url = message.match(urlPattern); |
||||||
|
if (url) { |
||||||
|
return '<a href="' + url[0] + '">' + message + '</a>'; |
||||||
|
} |
||||||
|
return null; |
||||||
|
|
||||||
|
}); |
||||||
|
|
||||||
|
var imagePlugin = new Plugin(function(message) { |
||||||
|
var urls = message.match(/https?:\/\/[^\s]*\.(jpg|png|gif)\b/) |
||||||
|
if (urls != null) { |
||||||
|
var url = urls[0]; /* Actually parse one url per message */ |
||||||
|
return '<img src="' + url + '" height="300">'; |
||||||
|
} |
||||||
|
return null; |
||||||
|
}); |
||||||
|
|
||||||
|
return { |
||||||
|
plugins: [youtubePlugin, urlPlugin, imagePlugin] |
||||||
|
} |
||||||
|
}); |
@ -1,180 +0,0 @@ |
|||||||
var Protocol = function() { |
|
||||||
var self = this; |
|
||||||
|
|
||||||
var getInfo = function() { |
|
||||||
var info = {}; |
|
||||||
info.key = getString(); |
|
||||||
info.value = getString(); |
|
||||||
return info; |
|
||||||
}; |
|
||||||
|
|
||||||
var getHdata = function() { |
|
||||||
var paths; |
|
||||||
var count; |
|
||||||
var objs = []; |
|
||||||
var hpath = getString(); |
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
keys = getString().split(','); |
|
||||||
paths = hpath.split('/'); |
|
||||||
count = getInt(); |
|
||||||
|
|
||||||
keys = keys.map(function(key) { |
|
||||||
return key.split(':'); |
|
||||||
}); |
|
||||||
var i; |
|
||||||
for (i = 0; i < count; i++) { |
|
||||||
var tmp = {}; |
|
||||||
|
|
||||||
tmp.pointers = paths.map(function(path) { |
|
||||||
return getPointer(); |
|
||||||
}); |
|
||||||
|
|
||||||
keys.forEach(function(key) { |
|
||||||
tmp[key[0]] = runType(key[1]); |
|
||||||
}); |
|
||||||
objs.push(tmp); |
|
||||||
}; |
|
||||||
return objs; |
|
||||||
}; |
|
||||||
|
|
||||||
function getPointer() { |
|
||||||
var l = getChar(); |
|
||||||
|
|
||||||
var pointer = getSlice(l) |
|
||||||
var parsed_data = new Uint8Array(pointer); |
|
||||||
return _uiatos(parsed_data); |
|
||||||
|
|
||||||
}; |
|
||||||
|
|
||||||
var _uiatos =function(uia) { |
|
||||||
var _str = []; |
|
||||||
for (var c = 0; c < uia.length; c++) { |
|
||||||
_str[c] = String.fromCharCode(uia[c]); |
|
||||||
} |
|
||||||
return decodeURIComponent(escape(_str.join(""))); |
|
||||||
}; |
|
||||||
|
|
||||||
var getInt = function() { |
|
||||||
var parsed_data = new Uint8Array(getSlice(4)); |
|
||||||
var i = ((parsed_data[0] & 0xff) << 24) | ((parsed_data[1] & 0xff) << 16) | ((parsed_data[2] & 0xff) << 8) | (parsed_data[3] & 0xff); |
|
||||||
return i; |
|
||||||
|
|
||||||
}; |
|
||||||
|
|
||||||
var getChar = function() { |
|
||||||
var parsed_data = new Uint8Array(getSlice(1)); |
|
||||||
return parsed_data[0]; |
|
||||||
}; |
|
||||||
|
|
||||||
var getString = function() { |
|
||||||
var l = getInt(); |
|
||||||
if (l > 0) { |
|
||||||
var s = getSlice(l); |
|
||||||
var parsed_data = new Uint8Array(s); |
|
||||||
return _uiatos(parsed_data); |
|
||||||
} |
|
||||||
return ""; |
|
||||||
}; |
|
||||||
|
|
||||||
var getSlice = function(length) { |
|
||||||
var slice = self.data.slice(0,length); |
|
||||||
self.data = self.data.slice(length); |
|
||||||
return slice; |
|
||||||
}; |
|
||||||
|
|
||||||
var getType = function() { |
|
||||||
var t = getSlice(3); |
|
||||||
return _uiatos(new Uint8Array(t)); |
|
||||||
}; |
|
||||||
|
|
||||||
var runType = function(type) { |
|
||||||
if (type in types) { |
|
||||||
return types[type](); |
|
||||||
} |
|
||||||
0; |
|
||||||
}; |
|
||||||
|
|
||||||
var getHeader = function() { |
|
||||||
return { |
|
||||||
length: getInt(), |
|
||||||
compression: getChar(), |
|
||||||
} |
|
||||||
}; |
|
||||||
|
|
||||||
var getId = function() { |
|
||||||
return getString(); |
|
||||||
} |
|
||||||
|
|
||||||
var getObject = function() { |
|
||||||
var type = getType(); |
|
||||||
if (type) { |
|
||||||
return object = { |
|
||||||
type: type, |
|
||||||
content: runType(type), |
|
||||||
} |
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
self.parse = function(data) { |
|
||||||
self.setData(data); |
|
||||||
var header = getHeader(); |
|
||||||
var id = getId(); |
|
||||||
var objects = []; |
|
||||||
var object = getObject(); |
|
||||||
while(object) { |
|
||||||
objects.push(object); |
|
||||||
object = getObject(); |
|
||||||
} |
|
||||||
return { |
|
||||||
header: header, |
|
||||||
id: id, |
|
||||||
objects: objects,
|
|
||||||
} |
|
||||||
} |
|
||||||
|
|
||||||
self.setData = function (data) { |
|
||||||
self.data = data; |
|
||||||
}; |
|
||||||
|
|
||||||
function array() { |
|
||||||
var type; |
|
||||||
var count; |
|
||||||
var values; |
|
||||||
|
|
||||||
type = getType(); |
|
||||||
count = getInt(); |
|
||||||
values = []; |
|
||||||
var i; |
|
||||||
for (i = 0; i < count; i++) { |
|
||||||
values.push(runType(type)); |
|
||||||
}; |
|
||||||
return values; |
|
||||||
} |
|
||||||
|
|
||||||
var types = { |
|
||||||
chr: getChar, |
|
||||||
"int": getInt, |
|
||||||
str: getString, |
|
||||||
inf: getInfo, |
|
||||||
hda: getHdata, |
|
||||||
ptr: getPointer, |
|
||||||
lon: getPointer, |
|
||||||
tim: getPointer, |
|
||||||
buf: getString, |
|
||||||
arr: array |
|
||||||
}; |
|
||||||
//TODO: IMPLEMENT THIS STUFF
|
|
||||||
// chr: this.getChar,
|
|
||||||
// 'int': getInt,
|
|
||||||
// hacks
|
|
||||||
|
|
||||||
// hacks
|
|
||||||
// htb: getHashtable,
|
|
||||||
// inf: Protocol.getInfo,
|
|
||||||
// inl: getInfolist,
|
|
||||||
|
|
||||||
// },
|
|
||||||
|
|
||||||
} |
|
@ -0,0 +1,655 @@ |
|||||||
|
/** |
||||||
|
* WeeChat protocol handling. |
||||||
|
* |
||||||
|
* This object parses messages and formats commands for the WeeChat |
||||||
|
* protocol. It's independent from the communication layer and thus |
||||||
|
* may be used with any network mechanism. |
||||||
|
*/ |
||||||
|
var WeeChatProtocol = function() { |
||||||
|
// specific parsing for each message type
|
||||||
|
this._types = { |
||||||
|
'chr': this._getChar, |
||||||
|
'int': this._getInt, |
||||||
|
'str': this._getString, |
||||||
|
'inf': this._getInfo, |
||||||
|
'hda': this._getHdata, |
||||||
|
'ptr': this._getPointer, |
||||||
|
'lon': this._getStrNumber, |
||||||
|
'tim': this._getTime, |
||||||
|
'buf': this._getString, |
||||||
|
'arr': this._getArray, |
||||||
|
'htb': this._getHashTable, |
||||||
|
'inl': function() { |
||||||
|
this._warnUnimplemented('infolist'); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
// string value for some message types
|
||||||
|
this._typesStr = { |
||||||
|
'chr': this._strDirect, |
||||||
|
'str': this._strDirect, |
||||||
|
'int': this._strToString, |
||||||
|
'tim': this._strToString, |
||||||
|
'ptr': this._strDirect |
||||||
|
}; |
||||||
|
}; |
||||||
|
|
||||||
|
/** |
||||||
|
* Unsigned integer array to string. |
||||||
|
* |
||||||
|
* @param uia Unsigned integer array |
||||||
|
* @return Decoded string |
||||||
|
*/ |
||||||
|
WeeChatProtocol._uia2s = function(uia) { |
||||||
|
var str = []; |
||||||
|
|
||||||
|
for (var c = 0; c < uia.length; c++) { |
||||||
|
str.push(String.fromCharCode(uia[c])); |
||||||
|
} |
||||||
|
|
||||||
|
return decodeURIComponent(escape(str.join(''))); |
||||||
|
}; |
||||||
|
|
||||||
|
/** |
||||||
|
* Merges default parameters with overriding parameters. |
||||||
|
* |
||||||
|
* @param defaults Default parameters |
||||||
|
* @param override Overriding parameters |
||||||
|
* @return Merged parameters |
||||||
|
*/ |
||||||
|
WeeChatProtocol._mergeParams = function(defaults, override) { |
||||||
|
for (var v in override) { |
||||||
|
defaults[v] = override[v]; |
||||||
|
} |
||||||
|
|
||||||
|
return defaults; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Formats a command. |
||||||
|
* |
||||||
|
* @param id Command ID (null for no ID) |
||||||
|
* @param name Command name |
||||||
|
* @param parts Command parts |
||||||
|
* @return Formatted command string |
||||||
|
*/ |
||||||
|
WeeChatProtocol._formatCmd = function(id, name, parts) { |
||||||
|
var cmdIdName; |
||||||
|
var cmd; |
||||||
|
|
||||||
|
cmdIdName = (id !== null) ? '(' + id + ') ' : ''; |
||||||
|
cmdIdName += name; |
||||||
|
parts.unshift(cmdIdName); |
||||||
|
cmd = parts.join(' '); |
||||||
|
cmd += '\n'; |
||||||
|
|
||||||
|
return cmd; |
||||||
|
}; |
||||||
|
|
||||||
|
/** |
||||||
|
* Formats an init command. |
||||||
|
* |
||||||
|
* @param params Parameters: |
||||||
|
* password: password (optional) |
||||||
|
* compression: compression ('off' or 'zlib') (optional) |
||||||
|
* @return Formatted init command string |
||||||
|
*/ |
||||||
|
WeeChatProtocol.formatInit = function(params) { |
||||||
|
var defaultParams = { |
||||||
|
password: null, |
||||||
|
compression: 'off' |
||||||
|
}; |
||||||
|
var keys = []; |
||||||
|
var parts = []; |
||||||
|
|
||||||
|
params = WeeChatProtocol._mergeParams(defaultParams, params); |
||||||
|
keys.push('compression=' + params.compression); |
||||||
|
if (params.password !== null) { |
||||||
|
keys.push('password=' + params.password); |
||||||
|
} |
||||||
|
parts.push(keys.join(',')); |
||||||
|
|
||||||
|
return WeeChatProtocol._formatCmd(null, 'init', parts); |
||||||
|
}; |
||||||
|
|
||||||
|
/** |
||||||
|
* Formats an hdata command. |
||||||
|
* |
||||||
|
* @param params Parameters: |
||||||
|
* id: command ID (optional) |
||||||
|
* path: hdata path (mandatory) |
||||||
|
* keys: array of keys (optional) |
||||||
|
* @return Formatted hdata command string |
||||||
|
*/ |
||||||
|
WeeChatProtocol.formatHdata = function(params) { |
||||||
|
var defaultParams = { |
||||||
|
id: null, |
||||||
|
keys: null |
||||||
|
}; |
||||||
|
var parts = []; |
||||||
|
|
||||||
|
params = WeeChatProtocol._mergeParams(defaultParams, params); |
||||||
|
parts.push(params.path); |
||||||
|
if (params.keys !== null) { |
||||||
|
parts.push(params.keys.join(',')); |
||||||
|
} |
||||||
|
|
||||||
|
return WeeChatProtocol._formatCmd(params.id, 'hdata', parts); |
||||||
|
}; |
||||||
|
|
||||||
|
/** |
||||||
|
* Formats an info command. |
||||||
|
* |
||||||
|
* @param params Parameters: |
||||||
|
* id: command ID (optional) |
||||||
|
* name: info name (mandatory) |
||||||
|
* @return Formatted info command string |
||||||
|
*/ |
||||||
|
WeeChatProtocol.formatInfo = function(params) { |
||||||
|
var defaultParams = { |
||||||
|
id: null |
||||||
|
}; |
||||||
|
var parts = []; |
||||||
|
|
||||||
|
params = WeeChatProtocol._mergeParams(defaultParams, params); |
||||||
|
parts.push(params.name); |
||||||
|
|
||||||
|
return WeeChatProtocol._formatCmd(params.id, 'info', parts); |
||||||
|
}; |
||||||
|
|
||||||
|
/** |
||||||
|
* Formats a nicklist command. |
||||||
|
* |
||||||
|
* @param params Parameters: |
||||||
|
* id: command ID (optional) |
||||||
|
* buffer: buffer name (optional) |
||||||
|
* @return Formatted nicklist command string |
||||||
|
*/ |
||||||
|
WeeChatProtocol.formatNicklist = function(params) { |
||||||
|
var defaultParams = { |
||||||
|
id: null, |
||||||
|
buffer: null |
||||||
|
}; |
||||||
|
var parts = []; |
||||||
|
|
||||||
|
params = WeeChatProtocol._mergeParams(defaultParams, params); |
||||||
|
if (params.buffer !== null) { |
||||||
|
parts.push(params.buffer); |
||||||
|
} |
||||||
|
|
||||||
|
return WeeChatProtocol._formatCmd(params.id, 'nicklist', parts); |
||||||
|
}; |
||||||
|
|
||||||
|
/** |
||||||
|
* Formats an input command. |
||||||
|
* |
||||||
|
* @param params Parameters: |
||||||
|
* id: command ID (optional) |
||||||
|
* buffer: target buffer (mandatory) |
||||||
|
* data: input data (mandatory) |
||||||
|
* @return Formatted input command string |
||||||
|
*/ |
||||||
|
WeeChatProtocol.formatInput = function(params) { |
||||||
|
var defaultParams = { |
||||||
|
id: null |
||||||
|
}; |
||||||
|
var parts = []; |
||||||
|
|
||||||
|
params = WeeChatProtocol._mergeParams(defaultParams, params); |
||||||
|
parts.push(params.buffer); |
||||||
|
parts.push(params.data); |
||||||
|
|
||||||
|
return WeeChatProtocol._formatCmd(params.id, 'input', parts); |
||||||
|
}; |
||||||
|
|
||||||
|
/** |
||||||
|
* Formats a sync or a desync command. |
||||||
|
* |
||||||
|
* @param params Parameters (see _formatSync and _formatDesync) |
||||||
|
* @return Formatted sync/desync command string |
||||||
|
*/ |
||||||
|
WeeChatProtocol._formatSyncDesync = function(cmdName, params) { |
||||||
|
var defaultParams = { |
||||||
|
id: null, |
||||||
|
buffers: null, |
||||||
|
options: null |
||||||
|
}; |
||||||
|
var parts = []; |
||||||
|
|
||||||
|
params = WeeChatProtocol._mergeParams(defaultParams, params); |
||||||
|
if (params.buffers !== null) { |
||||||
|
parts.push(params.buffers.join(',')); |
||||||
|
if (params.options !== null) { |
||||||
|
parts.push(params.options.join(',')); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
return WeeChatProtocol._formatCmd(params.id, cmdName, parts); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Formats a sync command. |
||||||
|
* |
||||||
|
* @param params Parameters: |
||||||
|
* id: command ID (optional) |
||||||
|
* buffers: array of buffers to sync (optional) |
||||||
|
* options: array of options (optional) |
||||||
|
* @return Formatted sync command string |
||||||
|
*/ |
||||||
|
WeeChatProtocol.formatSync = function(params) { |
||||||
|
return WeeChatProtocol._formatSyncDesync('sync', params); |
||||||
|
}; |
||||||
|
|
||||||
|
/** |
||||||
|
* Formats a desync command. |
||||||
|
* |
||||||
|
* @param params Parameters: |
||||||
|
* id: command ID (optional) |
||||||
|
* buffers: array of buffers to desync (optional) |
||||||
|
* options: array of options (optional) |
||||||
|
* @return Formatted desync command string |
||||||
|
*/ |
||||||
|
WeeChatProtocol.formatDesync = function(params) { |
||||||
|
return WeeChatProtocol._formatSyncDesync('desync', params); |
||||||
|
}; |
||||||
|
|
||||||
|
/** |
||||||
|
* Formats a test command. |
||||||
|
* |
||||||
|
* @param params Parameters: |
||||||
|
* id: command ID (optional) |
||||||
|
* @return Formatted test command string |
||||||
|
*/ |
||||||
|
WeeChatProtocol.formatTest = function(params) { |
||||||
|
var defaultParams = { |
||||||
|
id: null |
||||||
|
}; |
||||||
|
var parts = []; |
||||||
|
|
||||||
|
params = WeeChatProtocol._mergeParams(defaultParams, params); |
||||||
|
|
||||||
|
return WeeChatProtocol._formatCmd(params.id, 'test', parts); |
||||||
|
}; |
||||||
|
|
||||||
|
/** |
||||||
|
* Formats a quit command. |
||||||
|
* |
||||||
|
* @return Formatted quit command string |
||||||
|
*/ |
||||||
|
WeeChatProtocol.formatQuit = function() { |
||||||
|
return WeeChatProtocol._formatCmd(null, 'quit', []); |
||||||
|
}; |
||||||
|
|
||||||
|
/** |
||||||
|
* Formats a ping command. |
||||||
|
* |
||||||
|
* @param params Parameters: |
||||||
|
* id: command ID (optional) |
||||||
|
* args: array of custom arguments (optional) |
||||||
|
* @return Formatted ping command string |
||||||
|
*/ |
||||||
|
WeeChatProtocol.formatPing = function(params) { |
||||||
|
var defaultParams = { |
||||||
|
id: null, |
||||||
|
args: null |
||||||
|
}; |
||||||
|
var parts = []; |
||||||
|
|
||||||
|
params = WeeChatProtocol._mergeParams(defaultParams, params); |
||||||
|
if (params.args !== null) { |
||||||
|
parts.push(params.args.join(' ')); |
||||||
|
} |
||||||
|
|
||||||
|
return WeeChatProtocol._formatCmd(params.id, 'ping', parts); |
||||||
|
}; |
||||||
|
|
||||||
|
WeeChatProtocol.prototype = { |
||||||
|
/** |
||||||
|
* Warns that message parsing is not implemented for a |
||||||
|
* specific type. |
||||||
|
* |
||||||
|
* @param type Message type to display |
||||||
|
*/ |
||||||
|
_warnUnimplemented: function(type) { |
||||||
|
console.log('Warning: ' + type + ' message parsing is not implemented'); |
||||||
|
}, |
||||||
|
|
||||||
|
/** |
||||||
|
* Reads a 3-character message type token value from current |
||||||
|
* set data. |
||||||
|
* |
||||||
|
* @return Type |
||||||
|
*/ |
||||||
|
_getType: function() { |
||||||
|
var t = this._getSlice(3); |
||||||
|
|
||||||
|
if (!t) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
return WeeChatProtocol._uia2s(new Uint8Array(t)); |
||||||
|
}, |
||||||
|
|
||||||
|
/** |
||||||
|
* Runs the appropriate read routine for the specified message type. |
||||||
|
* |
||||||
|
* @param type Message type |
||||||
|
* @return Data value |
||||||
|
*/ |
||||||
|
_runType: function(type) { |
||||||
|
var cb = this._types[type]; |
||||||
|
var boundCb = cb.bind(this); |
||||||
|
|
||||||
|
return boundCb(); |
||||||
|
}, |
||||||
|
|
||||||
|
/** |
||||||
|
* Reads a "number as a string" token value from current set data. |
||||||
|
* |
||||||
|
* @return Number as a string |
||||||
|
*/ |
||||||
|
_getStrNumber: function() { |
||||||
|
var len = this._getByte(); |
||||||
|
var str = this._getSlice(len); |
||||||
|
|
||||||
|
return WeeChatProtocol._uia2s(new Uint8Array(str)); |
||||||
|
}, |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the passed object. |
||||||
|
* |
||||||
|
* @param obj Object |
||||||
|
* @return Passed object |
||||||
|
*/ |
||||||
|
_strDirect: function(obj) { |
||||||
|
return obj; |
||||||
|
}, |
||||||
|
|
||||||
|
/** |
||||||
|
* Calls toString() on the passed object and returns the value. |
||||||
|
* |
||||||
|
* @param obj Object to call toString() on |
||||||
|
* @return String value of object |
||||||
|
*/ |
||||||
|
_strToString: function(obj) { |
||||||
|
return obj.toString(); |
||||||
|
}, |
||||||
|
|
||||||
|
/** |
||||||
|
* Gets the string value of an object representing the message |
||||||
|
* value for a specified type. |
||||||
|
* |
||||||
|
* @param obj Object for which to get the string value |
||||||
|
* @param type Message type |
||||||
|
* @return String value of object |
||||||
|
*/ |
||||||
|
_objToString: function(obj, type) { |
||||||
|
var cb = this._typesStr[type]; |
||||||
|
var boundCb = cb.bind(this); |
||||||
|
|
||||||
|
return boundCb(obj); |
||||||
|
}, |
||||||
|
|
||||||
|
/** |
||||||
|
* Reads an info token value from current set data. |
||||||
|
* |
||||||
|
* @return Info object |
||||||
|
*/ |
||||||
|
_getInfo: function() { |
||||||
|
var info = {}; |
||||||
|
info.key = this._getString(); |
||||||
|
info.value = this._getString(); |
||||||
|
|
||||||
|
return info; |
||||||
|
}, |
||||||
|
|
||||||
|
/** |
||||||
|
* Reads an hdata token value from current set data. |
||||||
|
* |
||||||
|
* @return Hdata object |
||||||
|
*/ |
||||||
|
_getHdata: function() { |
||||||
|
var self = this; |
||||||
|
var paths; |
||||||
|
var count; |
||||||
|
var objs = []; |
||||||
|
var hpath = this._getString(); |
||||||
|
|
||||||
|
keys = this._getString().split(','); |
||||||
|
paths = hpath.split('/'); |
||||||
|
count = this._getInt(); |
||||||
|
|
||||||
|
keys = keys.map(function(key) { |
||||||
|
return key.split(':'); |
||||||
|
}); |
||||||
|
|
||||||
|
for (var i = 0; i < count; i++) { |
||||||
|
var tmp = {}; |
||||||
|
|
||||||
|
tmp.pointers = paths.map(function(path) { |
||||||
|
return self._getPointer(); |
||||||
|
}); |
||||||
|
keys.forEach(function(key) { |
||||||
|
tmp[key[0]] = self._runType(key[1]); |
||||||
|
}); |
||||||
|
objs.push(tmp); |
||||||
|
}; |
||||||
|
|
||||||
|
return objs; |
||||||
|
}, |
||||||
|
|
||||||
|
/** |
||||||
|
* Reads a pointer token value from current set data. |
||||||
|
* |
||||||
|
* @return Pointer value |
||||||
|
*/ |
||||||
|
_getPointer: function() { |
||||||
|
return this._getStrNumber(); |
||||||
|
}, |
||||||
|
|
||||||
|
/** |
||||||
|
* Reads a time token value from current set data. |
||||||
|
* |
||||||
|
* @return Time value (Date) |
||||||
|
*/ |
||||||
|
_getTime: function() { |
||||||
|
var str = this._getStrNumber(); |
||||||
|
|
||||||
|
return new Date(parseInt(str) * 1000); |
||||||
|
}, |
||||||
|
|
||||||
|
/** |
||||||
|
* Reads an integer token value from current set data. |
||||||
|
* |
||||||
|
* @return Integer value |
||||||
|
*/ |
||||||
|
_getInt: function() { |
||||||
|
var parsedData = new Uint8Array(this._getSlice(4)); |
||||||
|
|
||||||
|
return ((parsedData[0] & 0xff) << 24) | |
||||||
|
((parsedData[1] & 0xff) << 16) | |
||||||
|
((parsedData[2] & 0xff) << 8) | |
||||||
|
(parsedData[3] & 0xff); |
||||||
|
}, |
||||||
|
|
||||||
|
/** |
||||||
|
* Reads a byte from current set data. |
||||||
|
* |
||||||
|
* @return Byte value (integer) |
||||||
|
*/ |
||||||
|
_getByte: function() { |
||||||
|
var parsedData = new Uint8Array(this._getSlice(1)); |
||||||
|
|
||||||
|
return parsedData[0]; |
||||||
|
}, |
||||||
|
|
||||||
|
/** |
||||||
|
* Reads a character token value from current set data. |
||||||
|
* |
||||||
|
* @return Character (string) |
||||||
|
*/ |
||||||
|
_getChar: function() { |
||||||
|
return this._getByte(); |
||||||
|
}, |
||||||
|
|
||||||
|
/** |
||||||
|
* Reads a string token value from current set data. |
||||||
|
* |
||||||
|
* @return String value |
||||||
|
*/ |
||||||
|
_getString: function() { |
||||||
|
var l = this._getInt(); |
||||||
|
|
||||||
|
if (l > 0) { |
||||||
|
var s = this._getSlice(l); |
||||||
|
var parsedData = new Uint8Array(s); |
||||||
|
|
||||||
|
return WeeChatProtocol._uia2s(parsedData); |
||||||
|
} |
||||||
|
|
||||||
|
return ""; |
||||||
|
}, |
||||||
|
|
||||||
|
/** |
||||||
|
* Reads a message header from current set data. |
||||||
|
* |
||||||
|
* @return Header object |
||||||
|
*/ |
||||||
|
_getHeader: function() { |
||||||
|
var len = this._getInt(); |
||||||
|
var comp = this._getByte(); |
||||||
|
|
||||||
|
return { |
||||||
|
length: len, |
||||||
|
compression: comp, |
||||||
|
}; |
||||||
|
}, |
||||||
|
|
||||||
|
/** |
||||||
|
* Reads a message header ID from current set data. |
||||||
|
* |
||||||
|
* @return Message ID (string) |
||||||
|
*/ |
||||||
|
_getId: function() { |
||||||
|
return this._getString(); |
||||||
|
}, |
||||||
|
|
||||||
|
/** |
||||||
|
* Reads an arbitrary object token from current set data. |
||||||
|
* |
||||||
|
* @return Object value |
||||||
|
*/ |
||||||
|
_getObject: function() { |
||||||
|
var self = this; |
||||||
|
var type = this._getType(); |
||||||
|
|
||||||
|
if (type) { |
||||||
|
return { |
||||||
|
type: type, |
||||||
|
content: self._runType(type), |
||||||
|
}; |
||||||
|
} |
||||||
|
}, |
||||||
|
|
||||||
|
/** |
||||||
|
* Reads an hash table token from current set data. |
||||||
|
* |
||||||
|
* @return Hash table |
||||||
|
*/ |
||||||
|
_getHashTable: function() { |
||||||
|
var self = this; |
||||||
|
var typeKeys, typeValues, count; |
||||||
|
var dict = {}; |
||||||
|
|
||||||
|
typeKeys = this._getType(); |
||||||
|
typeValues = this._getType(); |
||||||
|
count = this._getInt(); |
||||||
|
|
||||||
|
for (var i = 0; i < count; ++i) { |
||||||
|
var key = self._runType(typeKeys); |
||||||
|
var keyStr = self._objToString(key, typeKeys); |
||||||
|
var value = self._runType(typeValues); |
||||||
|
dict[keyStr] = value; |
||||||
|
} |
||||||
|
|
||||||
|
return dict; |
||||||
|
}, |
||||||
|
|
||||||
|
/** |
||||||
|
* Reads an array token from current set data. |
||||||
|
* |
||||||
|
* @return Array |
||||||
|
*/ |
||||||
|
_getArray: function() { |
||||||
|
var self = this; |
||||||
|
var type; |
||||||
|
var count; |
||||||
|
var values; |
||||||
|
|
||||||
|
type = this._getType(); |
||||||
|
count = this._getInt(); |
||||||
|
values = []; |
||||||
|
|
||||||
|
for (var i = 0; i < count; i++) { |
||||||
|
values.push(self._runType(type)); |
||||||
|
}; |
||||||
|
|
||||||
|
return values; |
||||||
|
}, |
||||||
|
|
||||||
|
/** |
||||||
|
* Reads a specified number of bytes from current set data. |
||||||
|
* |
||||||
|
* @param length Number of bytes to read |
||||||
|
* @return Sliced array |
||||||
|
*/ |
||||||
|
_getSlice: function(length) { |
||||||
|
if (this.dataAt + length > this._data.byteLength) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
var slice = this._data.slice(this._dataAt, this._dataAt + length); |
||||||
|
|
||||||
|
this._dataAt += length; |
||||||
|
|
||||||
|
return slice; |
||||||
|
}, |
||||||
|
|
||||||
|
/** |
||||||
|
* Sets the current data. |
||||||
|
* |
||||||
|
* @param data Current data |
||||||
|
*/ |
||||||
|
_setData: function (data) { |
||||||
|
this._data = data; |
||||||
|
}, |
||||||
|
|
||||||
|
/** |
||||||
|
* Parses a WeeChat message. |
||||||
|
* |
||||||
|
* @param data Message data (ArrayBuffer) |
||||||
|
* @return Message value |
||||||
|
*/ |
||||||
|
parse: function(data) { |
||||||
|
var self = this; |
||||||
|
|
||||||
|
this._setData(data); |
||||||
|
this._dataAt = 0; |
||||||
|
|
||||||
|
var header = this._getHeader(); |
||||||
|
var id = this._getId(); |
||||||
|
var objects = []; |
||||||
|
var object = this._getObject(); |
||||||
|
|
||||||
|
while (object) { |
||||||
|
objects.push(object); |
||||||
|
object = self._getObject(); |
||||||
|
} |
||||||
|
|
||||||
|
return { |
||||||
|
header: header, |
||||||
|
id: id, |
||||||
|
objects: objects, |
||||||
|
}; |
||||||
|
} |
||||||
|
}; |
Loading…
Reference in new issue