Advertisement
Aluf

Chatango Derplib.py [ch_room.js]

Feb 1st, 2015
468
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 18.16 KB | None | 0 0
  1. 'use strict';
  2. // Chatango Derplib.py //
  3. // By Aluf //
  4. ///////////////////
  5. // Base requires //
  6. var util = require('util'),
  7. events = require('events'),
  8. url = require('url'),
  9. http = require('http'),
  10. querystring = require('querystring'),
  11. _ = require('underscore'),
  12. colors = require('colors');
  13.  
  14. var MM = module.parent,
  15. DerpLib = MM.parent,
  16. socket = MM.libary.load('socket'),
  17. weights = MM.libary.load('weights'),
  18. utils = MM.libary.load('utils'),
  19. frame = MM.libary.load('frame'),
  20. request = MM.libary.load('request'),
  21. eventModule = MM.libary.load('eventModule');
  22.  
  23. ///////////////////
  24. // Chatango Room //
  25.  
  26. function Room(options) {
  27. events.EventEmitter.call(this);
  28.  
  29. options = options || {};
  30. // Available options: account, password, uid, host, reconnect
  31. if(!options.room) return;
  32.  
  33. // Public vars
  34. this.name = options.room.toLowerCase();
  35. this.ispm = false;
  36. this.admin = false;
  37. this.mods = [];
  38. this.users = {};
  39. this.usercount = 0;
  40. // Private vars
  41. this._account = options.account || false;
  42. this._accountLC = this._account ? this._account.toLowerCase() : false;
  43. this._password = options.password || false;
  44. this._loggedIn = false;
  45. this._uid = options.uid || utils.genUid();
  46. this._user_id = String(this._uid).substr(0, 8);
  47. this._host = options.host || weights.getServerHost(this.name);
  48. this._writeLock = false;
  49. this._isAdmin = false;
  50. this._isModerator = false;
  51. this._messages = [];
  52. this._bans = {};
  53. this._bannedWordsPartly = [];
  54. this._bannedWordsExact = [];
  55. this._settings = {
  56. type: 'room',
  57. active: true,
  58. blocked: false,
  59. autoReconnect: options.reconnect || true,
  60. reconnectDelay: 5,
  61. consoleFilter: ['i', 'b', 'u', 'n', 'g_participants', 'participant', 'premium'],
  62. g_participants: true,
  63. maxConTime: 0,
  64. useBackground: true,
  65. useRecording: false,
  66. nameColor: '000',
  67. textSize: '11',
  68. textColor: 'F00',
  69. textFont: '8',
  70. htmlEntenyConert: true,
  71. };
  72.  
  73. var self = this;
  74.  
  75. eventModule.emit("event", "newRoom", this, function(){
  76. // May not be changed
  77. self._settings.type = 'room';
  78.  
  79. if(self._settings.blocked){
  80. console.log('['+self.name+'] This room is blocked, aborting join.');
  81. return;
  82. }
  83.  
  84. self._settings.active = true;
  85.  
  86. self._sock = new socket.Instance( self._host );
  87. self._onAuth();
  88. });
  89.  
  90.  
  91. }
  92.  
  93. util.inherits(Room, events.EventEmitter);
  94.  
  95. Room.prototype._onAuth = function(){
  96.  
  97. var self = this;
  98.  
  99. /////////////////////
  100. // Socket Handlers //
  101.  
  102. this._sock.on('onconnect', function() {
  103.  
  104. if(!self._settings.active){
  105. self.disconnect();
  106. return;
  107. }
  108.  
  109. if(self._account)
  110. self.write(['bauth', self.name, self._uid, self._account, self._password]);
  111. else
  112. self.write(['bauth', self.name, self._uid, '', '']);
  113.  
  114. self._sock.setWriteLock(true);
  115.  
  116. if(self._settings.maxConTime){
  117. setTimeout(function(){
  118. self.reconnect();
  119. }, self._settings.maxConTime * 1000);
  120. }
  121.  
  122. });
  123.  
  124. this._sock.on('error', function(exception) {
  125. console.log(('['+self.name+'] Socket ERROR:').bold.red, exception);
  126. });
  127.  
  128. this._sock.on('timeout', function(exception) {
  129. console.log(('['+self.name+'] Socket TIMEOUT:').bold.red, exception);
  130. });
  131.  
  132. this._sock.on('close', function() {
  133. if(self._settings.autoReconnect){
  134. console.log(('['+self.name+'] Socket closed, reconnecting...').bold.red);
  135. setTimeout(function(){
  136. self._sock.connect();
  137. }, self._settings.reconnectDelay * 1000);
  138. }else{
  139. console.log(('['+self.name+'] Socket closed, reconnect is off').bold.red);
  140. }
  141. });
  142.  
  143. this._sock.on('data', function(data) {
  144.  
  145. data = data.replace(/[\r\n\0]+$/, "");
  146.  
  147. var args = data.split(':');
  148.  
  149. if(self._settings.consoleFilter.indexOf(args[0]) == -1 && self._settings.consoleFilter.indexOf('all') == -1)
  150. console.log('['+self.name+']', data);
  151.  
  152. var _frame = frame.parseFrameRoom(data);
  153.  
  154. if(_frame && self.listeners('frame_'+_frame.type).length > 0){
  155. try {
  156. self.emit('frame_'+_frame.type, _frame);
  157. }
  158. catch(e){
  159. console.log('['+self.name+'] Error:', e.stack.split('\n').slice(0,4).join(''));
  160. }
  161. }
  162. });
  163.  
  164. this._sock.on('write', function(data){
  165. if(data) console.log('['+self.name+'][WRITE]', data);
  166. });
  167.  
  168. ///////////////////////
  169. // Chatango handlers //
  170.  
  171. this.on('frame_denied', function(_frame){
  172. console.log(('['+this.name+'] Socket connection denied!').bold.red);
  173. this._settings.autoReconnect = false;
  174. this.disconnect();
  175. });
  176.  
  177. this.on('frame_ok', function(_frame) {
  178.  
  179. // M = logged in, C = bad login
  180. this._loggedIn = _frame.mystatus == 'M';
  181.  
  182. if(this._account && !this._loggedIn){
  183. console.log(('['+this.name+'] Login Failed!').bold.red);
  184. this._settings.autoReconnect = false;
  185. this.disconnect();
  186. return;
  187. }
  188. self.bans = {};
  189. self.users = {};
  190. self.admin = _frame.owner;
  191. self.mods = _frame.mods;
  192. self.checkModStatus();
  193. });
  194.  
  195. this.on('frame_pwdok', function(_frame) {
  196. self._loggedIn = true;
  197. self.write(['getpremium', '1']);
  198. self.checkModStatus();
  199. self.emit('loggedin');
  200. });
  201.  
  202. this.on('frame_logoutok', function(_frame) {
  203. self._loggedIn = false;
  204. self.emit('logout');
  205. });
  206.  
  207. this.on('frame_inited', function(args) {
  208.  
  209. self._sock.setWriteLock(false);
  210.  
  211. self.write(['getpremium', '1']);
  212. self.write(['g_participants','start']);
  213. self.getBannedWords();
  214. self.getBans();
  215. self.emit('joined');
  216. });
  217.  
  218. /////////////////////
  219. // Data management //
  220.  
  221. this.on('frame_i', function(_frame) {
  222. var req = new request.make(self);
  223. req.parseMessage(_frame);
  224.  
  225. self._messages.push(req.message);
  226. if(self._messages.length > 100)
  227. self._messages.shift();
  228.  
  229. var users = _.filter(self.users, function(user){ return user.id == req.user.id; });
  230. _.each(users, function(user){
  231. if(req.user.key) user.key = req.user.key;
  232. if(req.user.ip) user.ip = req.user.ip;
  233. });
  234. if(users.length === 0){
  235. self.users[req.user.id] = req.user;
  236. }
  237.  
  238. eventModule.emit('event', 'RoomOffMsg', req);
  239. });
  240.  
  241. this.on('frame_b', function(_frame) {
  242.  
  243. // Parse Room
  244. var req = new request.make(self);
  245. // Parse Message
  246. req.parseMessage(_frame);
  247.  
  248. self._messages.push(req.message);
  249. if(self._messages.length > 100)
  250. self._messages.shift();
  251.  
  252. var users = _.filter(self.users, function(user){ return user.id == req.user.id; });
  253. _.each(users, function(user){
  254. user.name = req.user.name;
  255. if(req.user.key) user.key = req.user.key;
  256. if(req.user.ip) user.ip = req.user.ip;
  257. });
  258. if(users.length === 0){
  259. console.log('['+req.room.name+'] Error: could not find user id in user list for ', req.user.name);
  260. }
  261.  
  262. // Don't reply to self
  263. if(req.room._user_id == req.user.id) return;
  264.  
  265. eventModule.emit('beforeRequest', req);
  266. eventModule.emit('event', 'request', req);
  267. });
  268.  
  269. this.on('frame_u', function(_frame) {
  270. var msg = _.find(self._messages, function(msg){ return msg.number == _frame.number; });
  271. if(msg) msg.id = _frame.msgid;
  272. });
  273.  
  274. ///////////////
  275. // Utilities //
  276.  
  277. this.on('frame_n', function(_frame){
  278. self.usercount = _frame.count;
  279. });
  280.  
  281. this.on('frame_g_participants', function(_frame) {
  282. _.each(_frame.users, function(user){
  283. if(_.has(self.users, user.id)){
  284. self.users[user.sess] = _.extend(user, self.users[user.id]);
  285. delete self.users[user.id];
  286. }else{
  287. self.users[user.sess] = user;
  288. }
  289. });
  290. if(!self._settings.g_participants)
  291. self.write(['g_participants', 'stop']);
  292. });
  293.  
  294. this.on('frame_participant', function(_frame) {
  295. if(_frame.mode == 'leave'){
  296. if(_.has(self.users, _frame.user.sess))
  297. delete self.users[_frame.user.sess];
  298. }
  299. else if(_frame.mode == 'join'){
  300. if(!_.has(self.users, _frame.user.sess))
  301. self.users[_frame.user.sess] = _frame.user;
  302. }
  303. else if(_frame.mode == 'change'){
  304. //log in or out
  305. self.users[_frame.user.sess] = _frame.user;
  306. if(undefined === _frame.user.name){
  307. eventModule.emit('event', 'userLogout', _frame.user);
  308. }else{
  309. eventModule.emit('event', 'userLogin', _frame.user);
  310. }
  311. }
  312. });
  313.  
  314. this.on('frame_premium', function(_frame) {
  315. if(_frame.expire > +new Date/1000){
  316. if(self._settings.useBackground)
  317. self.write(['msgbg', '1']);
  318. if(self._settings.useRecording)
  319. self.write(['msgmedia', '1']);
  320. }
  321. });
  322.  
  323. this.on('frame_show_fw', function() {
  324. console.log(('['+self.name+'] Flood warning. Going in lockdown').bold.red);
  325. self._writeLock = true;
  326. self.emit('start_fw');
  327. setTimeout(function(){
  328. self._writeLock = false;
  329. }, 15000);
  330. });
  331.  
  332. this.on('frame_end_fw', function() {
  333. self._writeLock = false;
  334. self.emit('end_fw');
  335. });
  336.  
  337. this.on('frame_show_tb', function(_frame) {
  338. // 15 minutes, result of flooding
  339. self.emit('show_tempban', _frame.seconds);
  340. });
  341.  
  342. this.on('frame_tb', function(_frame){
  343. self.emit('tempban', _frame.time);
  344. });
  345.  
  346. this.on('frame_clearall', function(_frame){
  347. if(_frame.answer == 'ok'){
  348. _.each(self.messages, function(message){
  349. message.deleted = true;
  350. });
  351. self.emit('clearall');
  352. }
  353. });
  354.  
  355. this.on('frame_delete', function(_frame){
  356. var msg = _.find(self._messages, function(x){ return (x.id == _frame.msgid); });
  357. if(msg){
  358. msg.deleted = true;
  359. eventModule.emit('event', 'messageDeleted', msg, this);
  360. }
  361. });
  362.  
  363. this.on('frame_deleteall', function(_frame){
  364. _.each(_frame.msgids, function(msgid){
  365. var msg = _.find(self._messages, function(x){ return (x.id == _frame.msgid); });
  366. if(msg){
  367. msg.deleted = true;
  368. }
  369. });
  370. });
  371.  
  372. this.on('frame_updateprofile', function(_frame) {
  373. self.emit('profileupdate', _frame.name);
  374. });
  375.  
  376. this.on('frame_mods', function(_frame) {
  377. self.mods = _frame.mods;
  378. var added = _.find(self.mods, function(x){ return self.mods.indexOf(x) > -1; });
  379. var removed = _.find(self.mods, function(x){ return self.mods.indexOf(x) < 0; });
  380.  
  381. if(added){
  382. self.emit('mod_added', added);
  383. }else if(removed){
  384. self.emit('mod_removed', removed);
  385. }
  386. self.checkModStatus();
  387. });
  388.  
  389. this.on('frame_blocklist', function(_frame) {
  390. self._bans = _frame.bans;
  391. });
  392.  
  393. this.on('frame_blocked', function(_frame) {
  394. self._bans[_frame.ban.name] = _frame.ban;
  395. eventModule.emit('event', 'ban', self, _frame.ban);
  396. });
  397.  
  398. this.on('frame_unblocked', function(_frame) {
  399. delete self._bans[_frame.unban.name];
  400. self.emit('unban', _frame.unban);
  401. });
  402.  
  403. this.on('frame_bansearchresult', function(_frame) {
  404. self.emit('banSearchResult', _frame.result);
  405. });
  406.  
  407. this.on('frame_getbannedwords', function(_frame) {
  408. self._bannedWordsPartly = _frame.partly;
  409. self._bannedWordsExact = _frame.exact;
  410. });
  411.  
  412. this.on('frame_bw', function(_frame) {
  413. self._bannedWordsPartly = _frame.partly;
  414. self._bannedWordsExact = _frame.exact;
  415. });
  416.  
  417. this.on('frame_ubw', function() {
  418. self.getBannedWords();
  419. });
  420.  
  421. }
  422.  
  423. // Usable functions
  424.  
  425. Room.prototype.connect = function(){
  426. if(!this._sock._connected)
  427. this._sock.connect();
  428. }
  429.  
  430. Room.prototype.disconnect = function() {
  431. this._settings.active = false;
  432. this._settings.autoReconnect = false;
  433. if(this._sock._connected){
  434. this._sock.disconnect();
  435. }
  436. }
  437.  
  438. Room.prototype.reconnect = function(){
  439. if(this._sock._connected){
  440. this._settings.autoReconnect = true;
  441. this._sock.disconnect();
  442. }
  443. }
  444.  
  445. Room.prototype.write = function(args) {
  446. if(!this._writeLock){
  447. this._sock.write(_.isArray(args) ? args : _.toArray(arguments));
  448. }
  449. }
  450.  
  451. function stringConvertEnteties(string, all){
  452. all = all || false;
  453. return _.reduce(string, function(x,y,i){
  454. var code = string.charCodeAt(i);
  455. return x += code = (all || code > 127) ? '&#'+code+';' : string.charAt(i);
  456. },'');
  457. }
  458.  
  459. Room.prototype.message = function(body) {
  460.  
  461. if(this._writeLock || !body) return;
  462.  
  463. var self = this;
  464.  
  465. if(_.isArray(body)){
  466. //Multi-line message
  467. var output = _.reduce(body, function(output, msg, i){
  468. return output += self.font() + String(msg) + self.fontEnd() + '</p>' + (i == body.length-1 ? '' : '<p>');
  469. }, '');
  470.  
  471. output = output.replace(/(\n\r|\r\n|\n|\r|\0)/g, '<br/>');
  472. _.each(output.match(/.{1,2950}/gm), function(msg){
  473. self.write('bmsg', 'l33t', '<n'+self._settings.nameColor+'/>'+msg);
  474. });
  475. }
  476. else{
  477. body = String(body).replace(/(\n\r|\r\n|\n|\r|\0)/g, '<br/>');
  478. _.each(body.match(/.{1,2950}/gm), function(msg){
  479. self.write('bmsg', 'l33t', '<n'+self._settings.nameColor+'/>' + self.font() + msg + self.fontEnd());
  480. });
  481. }
  482. };
  483.  
  484. Room.prototype.multiLine = function(array){
  485. if(_.isArray(array)) {
  486. return _.reduce(array, function(output, msg, i){
  487. return output += this.font() + String(msg) + this.fontEnd() + '</p>' + (i == array.length-1 ? '' : '<p>');
  488. }.bind(this), '');
  489. } else if(_.isString(array)) {
  490. return array;
  491. }
  492. }
  493.  
  494. Room.prototype.font = function(color, size, face) {
  495. color = color || this._settings.textColor;
  496. size = size || this._settings.textSize;
  497. face = face || this._settings.textFont;
  498. return '<f x'+String(size)+String(color)+'="'+String(face)+'">';
  499. }
  500.  
  501. Room.prototype.fontEnd = function() {
  502. return '</f>';
  503. }
  504.  
  505.  
  506. // Chatango functions
  507.  
  508. Room.prototype.login = function(account){
  509. if(!account) return;
  510. this._account = account;
  511. this._accountLC = account.toLowerCase();
  512. this._password = MM.parent._data.accounts[this._accountLC];
  513. if(!this._loggedIn)
  514. this.write(['blogin', this._account, this._password]);
  515. }
  516.  
  517. Room.prototype.logout = function(){
  518. if(this._loggedIn)
  519. this.write(['blogout']);
  520. }
  521.  
  522. Room.prototype.checkModStatus = function(){
  523. this._isAdmin = (this.admin == this._accountLC);
  524. this._isModerator = (this.mods.indexOf(this._accountLC) != -1 || this._isAdmin);
  525. }
  526.  
  527. Room.prototype.addMod = function(name) {
  528. if(this._isAdmin){
  529. this.write(['addmod', name]);
  530. return true;
  531. }
  532. return false;
  533. }
  534.  
  535. Room.prototype.removeMod = function(name) {
  536. if(this.isAdmin){
  537. this.write(['removemod', name]);
  538. return true;
  539. }
  540. return false;
  541. }
  542.  
  543. Room.prototype.flag = function(message) {
  544. if(message.id){
  545. this.write(['g_flag', message.id]);
  546. }
  547. }
  548.  
  549. Room.prototype.userTime = function(user, cb){
  550. var pm = _.find(MM.parent._data.pms, function(pm){
  551. return pm._sock && pm._sock._connected;
  552. });
  553. if(pm){
  554. pm.userTime(user, function(contact){
  555. cb(contact);
  556. });
  557. }else{
  558. cb(false);
  559. }
  560. }
  561.  
  562. Room.prototype.del = function(message) {
  563. if(this._isModerator){
  564. if(message.id){
  565. this.write(['delmsg', message.id]);
  566. }else{
  567. var self = this;
  568. var count = 0;
  569. var inter = setInterval(function(){
  570. if(count > 200){
  571. clearInterval(inter);
  572. }
  573. if(message.id){
  574. self.write(['delmsg', message.id]);
  575. clearInterval(inter);
  576. }
  577. count++;
  578. }, 50);
  579. }
  580. }
  581. }
  582.  
  583. Room.prototype.delLast = function(amount) {
  584. if(this._isModerator){
  585. amount = Math.max(parseInt(amount), 1) || 1;
  586. _.each(this._messages.slice(-amount), function(message){
  587. this.del(message);
  588. }.bind(this));
  589. }
  590. }
  591.  
  592. Room.prototype.delLastUser = function(name, amount) {
  593. if(this._isModerator){
  594. amount = Math.max(parseInt(amount), 1) || 1;
  595. var messages = _.filter(this._messages, function(msg){
  596. return !msg.deleted && msg.name == name.toLowerCase();
  597. });
  598. _.each(messages.slice(-amount), function(message){
  599. this.del(message);
  600. }.bind(this));
  601. }
  602. }
  603.  
  604. Room.prototype.clearUser = function(name) {
  605. if(this._isModerator && name){
  606. _.each(this.users, function(user){
  607. if(user.name == name.toLowerCase() && user.key)
  608. this.write(['delallmsg', user.key]);
  609. }.bind(this));
  610. }
  611. }
  612.  
  613. Room.prototype.modClearAll = function() {
  614. if(this._isModerator){
  615. var self = this;
  616. _.each(this.users, function(user){
  617. if(user.key) self.write(['delallmsg', user.key]);
  618. });
  619. }
  620. }
  621.  
  622. Room.prototype.clearAll = function() {
  623. if(this._isAdmin){
  624. this.write(['clearall']);
  625. }
  626. }
  627.  
  628. Room.prototype.ban = function(name) {
  629. if(this._isModerator) {
  630. var self = this;
  631. _.each(this.users, function(user){
  632. if(user.key && user.ip && user.name && user.name == name.toLowerCase())
  633. self.write(['block', user.key, user.ip, user.name]);
  634. });
  635. }
  636. }
  637.  
  638. Room.prototype.unban = function(name) {
  639. if(this._isModerator) {
  640. var ban = this._bans[name.toLowerCase()];
  641. if(ban){
  642. this.write(['removeblock', ban.key, ban.ip, ban.name]);
  643. }
  644. }
  645. }
  646.  
  647. Room.prototype.getBans = function() {
  648. if(this._isModerator){
  649. // Suffix 'anons', '1' is default behaviour - use 'anons', '0' to hide anons
  650. // 3th argument is optional timestamp showing bans after that time used for pagination
  651. this.write(['blocklist', 'block', '', 'next', '500']);
  652. }
  653. }
  654.  
  655. Room.prototype.getUnbans = function() {
  656. if(this._isModerator){
  657. // Suffix same as requestBanlist
  658. this.write(['blocklist', 'unblock', '', 'next', '500']);
  659. }
  660. }
  661.  
  662. Room.prototype.searchBan = function(query) {
  663. if(this._isModerator){
  664. this.write(['searchban', query]);
  665. }
  666. }
  667.  
  668. Room.prototype.getBannedWords = function() {
  669. this.write(['getbannedwords']);
  670. }
  671.  
  672. Room.prototype.setBannedWords = function(partly, exact) {
  673. if(this._isAdmin){
  674. this.write(['setbannedwords', '431', partly.join(','), exact.join(',')]);
  675. }
  676. }
  677.  
  678. Room.prototype.addPartlyBannedWord = function(word) {
  679. if(this._isAdmin){
  680. if(this._bannedWordsPartly.indexOf(word) < 0){
  681. this._bannedWordsPartly.push(word);
  682. this.write('setbannedwords', '431', this._bannedWordsPartly.join(','), this._bannedWordsExact.join(','));
  683. }
  684. }
  685. }
  686.  
  687. Room.prototype.addExactBannedWord = function(word) {
  688. if(this._isAdmin){
  689. if(this._bannedWordsExact.indexOf(word) < 0){
  690. this._bannedWordsExact.push(word);
  691. this.write('setbannedwords', '431', this._bannedWordsPartly.join(','), this._bannedWordsExact.join(','));
  692. }
  693. }
  694. }
  695.  
  696. Room.prototype.removePartlyBannedWord = function(word) {
  697. if(this._isAdmin){
  698. var index = this._bannedWordsPartly.indexOf(word);
  699. if(index >= 0){
  700. this._bannedWordsPartly.splice(index, 1);
  701. this.write('setbannedwords', '431', this._bannedWordsPartly.join(','), this._bannedWordsExact.join(','));
  702. }
  703. }
  704. }
  705.  
  706. Room.prototype.removeExactBannedWord = function(word) {
  707. if(this._isAdmin){
  708. var index = this._bannedWordsExact.indexOf(word);
  709. if(index >= 0){
  710. this._bannedWordsExact.splice(index, 1);
  711. this.write('setbannedwords', '431', this._bannedWordsPartly.join(','), this._bannedWordsExact.join(','));
  712. }
  713. }
  714. }
  715.  
  716. exports.Room = Room;
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement