unrealircd.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765
  1. var protocol = {
  2. connected: function(){
  3. ircSend(null, settings.ID, 'PASS', [settings.password]);
  4. ircSend(null, settings.ID, 'PROTOCTL', ['NICKv2', 'VHP', 'UMODE2', 'NICKIP', 'SJOIN', 'SJOIN2', 'SJ3', 'NOQUIT', 'TKLEXT', 'MLOCK', 'SID', 'MTAGS']);
  5. ircSend(null, settings.ID, 'PROTOCTL', ['EAUTH=' + settings.name + ',,,' + settings.version]);
  6. ircSend(null, settings.ID, 'PROTOCTL', ['SID=' + settings.ID]);
  7. ircSend(null, settings.ID, 'SERVER', [settings.name, '1', settings.description]);
  8. },
  9. processMessage: function(msg){
  10. if(!msg) return;
  11. if(msg.command in cmdBinds){
  12. cmdBinds[msg.command](msg);
  13. } else {
  14. console.log('Unhandled cmd: '+msg.command);
  15. console.log(msg);
  16. }
  17. },
  18. processSender: function(sender){
  19. if(sender.nick){
  20. if(server = handlers.findServer(sender.nick)){
  21. sender.nick = server.name;
  22. sender.server = server;
  23. } else if(user = handlers.findUser(sender.nick)){
  24. sender.nick = user.name
  25. sender.ident = user.ident;
  26. sender.host = user.host;
  27. sender.user = user;
  28. } else {
  29. handlers.killUser(sender.nick);
  30. return false;
  31. }
  32. }
  33. return sender;
  34. },
  35. setHandlers: function(newHandlers){
  36. handlers = newHandlers;
  37. },
  38. setSettings: function(newSettings){
  39. settings = newSettings;
  40. },
  41. setEvents: function(newEvents){
  42. events = newEvents;
  43. },
  44. // IRC actions
  45. introduceUser: function(user){
  46. var nick = user.name;
  47. var distance = user.distance.toString();
  48. var TS = user.TS.toString();
  49. var ident = user.ident;
  50. var host = user.host;
  51. var uid = user.uid;
  52. var account = '0';
  53. if(user.account){
  54. account = user.account;
  55. }
  56. var umodes = makeUmodeString(user.umodes, true);
  57. var vhost = '*';
  58. if(user.vhost){
  59. vhost = user.vhost;
  60. }
  61. var cloakedHost = '*';
  62. if(user.cloakedHost){
  63. cloakedHost = user.cloakedHost;
  64. }
  65. var ip = '*';
  66. if(user.ip){
  67. ip = user.ip;
  68. }
  69. var realname = user.realname;
  70. var args = [nick, distance, TS, ident, host, uid, account, umodes, vhost, cloakedHost, ip, realname];
  71. ircSend(null, settings.ID, 'UID', args);
  72. },
  73. syncChannel: function(channel){
  74. var modes = null;
  75. var modeArgs = null;
  76. // prepare list modes
  77. var listModes = [];
  78. for(m in channel.listModes){
  79. var mode = channel.listModes[m];
  80. for(var i=0; i<mode.length; i++){
  81. switch(m){
  82. case 'BAN': listModes.push('&' + mode[i]); break;
  83. case 'EXCEPT': listModes.push('"' + mode[i]); break;
  84. case 'INVEX': listModes.push('\'' + mode[i]); break;
  85. }
  86. }
  87. }
  88. // prepare users
  89. var users = [];
  90. for(var i=0; i<channel.users.length; i++){
  91. var user = channel.users[i];
  92. if(user.uplink != settings.me) continue;
  93. var status = '';
  94. if(user.uid in channel.statusModes){
  95. var statusModes = channel.statusModes[user.uid];
  96. for(var j=0; j<statusModes.length; j++){
  97. var statusMode = statusModes[j];
  98. for(c in chmodeMap){
  99. if(chmodeMap[c].name == statusMode){
  100. for(sm in connection.statusmodes){
  101. if(connection.statusmodes[sm] == c){
  102. status += sm; // assign status character to user
  103. break;
  104. }
  105. }
  106. break;
  107. }
  108. }
  109. }
  110. }
  111. users.push(status + user.uid);
  112. }
  113. var done = false;
  114. var listCount = 0;
  115. var userCount = 0;
  116. do {
  117. var text = '';
  118. var count = 0;
  119. for(; listCount < listModes.length; listCount++){
  120. if(++count > 10) break;
  121. if(text.length > 0) text += ' ';
  122. text += listModes[listCount];
  123. }
  124. for(; userCount < users.length; userCount++){
  125. if(++count > 10) break;
  126. if(text.length > 0) text += ' ';
  127. text += users[userCount];
  128. }
  129. if(text.length == 0){
  130. break;
  131. }
  132. var args = [Math.floor(new Date() / 1000).toString(10), channel.name];
  133. if(modes) args.push(modes); else args.push('+');
  134. if(modeArgs) args.push(modeArgs);
  135. args.push(text);
  136. ircSend(null, settings.ID, 'SJOIN', args);
  137. } while(true);
  138. },
  139. 'makeUid': function(){
  140. return settings.me.sid + randomID();
  141. },
  142. 'changeUmodes': function(user, umodes){
  143. if(user.uplink == settings.me){ // services bot
  144. ircSend(null, user.uid, 'UMODE2', [makeUmodeString(umodes, true)]);
  145. } else { // normal user
  146. ircSend(null, settings.ID, 'SVS2MODE', [user.uid, makeUmodeString(umodes, false)]);
  147. }
  148. user.changeUmodes(umodes);
  149. }
  150. }
  151. //>>> @time=2020-03-15T12:17:07.355Z;msgid=FhjgUp20YBKQ32TGPM28tS :143 SJOIN 1580651090 #help +nt :0931Y7O8W 093375CFR 123VTY20R
  152. function randomID(){
  153. var result = '';
  154. var length = 6;
  155. var characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
  156. var charactersLength = characters.length;
  157. for(var i=0; i<length; i++ ) {
  158. result += characters.charAt(Math.floor(Math.random() * charactersLength));
  159. }
  160. return result;
  161. }
  162. module.exports = protocol;
  163. var handlers = {
  164. sendHandler: null,
  165. findServer: null,
  166. findUser: null,
  167. killUser: null,
  168. newServer: null,
  169. newUser: null,
  170. getChannel: null,
  171. findChannel: null,
  172. quitUser: null,
  173. removeServer: null
  174. };
  175. var settings = {
  176. ID: null,
  177. password: null,
  178. name: null,
  179. description: null,
  180. version: null,
  181. me: null,
  182. maxUsers: null
  183. };
  184. var events = {};
  185. var connection = {
  186. 'protoctl': {},
  187. 'prefixes': {},
  188. 'statusmodes': [],
  189. 'chmodes': [], // 0 - list modes, 1 - argument modes, 2 - argument modes (add only), 3 - standard modes
  190. 'umodes': {}
  191. };
  192. var chmodeMap = {
  193. 'b': { 'name': 'BAN', 'user': true, 'services': true },
  194. 'e': { 'name': 'EXCEPT', 'user': true, 'services': true },
  195. 'I': { 'name': 'INVEX', 'user': true, 'services': true },
  196. 'v': { 'name': 'VOICE', 'user': true, 'services': true },
  197. 'h': { 'name': 'HALFOP', 'user': true, 'services': true },
  198. 'o': { 'name': 'OP', 'user': true, 'services': true },
  199. 'a': { 'name': 'PROTECT', 'user': true, 'services': true },
  200. 'q': { 'name': 'OWNER', 'user': true, 'services': true },
  201. 'k': { 'name': 'KEY', 'user': true, 'services': true },
  202. 'L': { 'name': 'CHANNELLINK', 'user': true, 'services': true },
  203. 'f': { 'name': 'FLOODPROT', 'user': true, 'services': true },
  204. 'l': { 'name': 'LIMIT', 'user': true, 'services': true },
  205. 'H': { 'name': 'HISTORY', 'user': true, 'services': true },
  206. 'p': { 'name': 'PRIVATE', 'user': true, 'services': true },
  207. 's': { 'name': 'SECRET', 'user': true, 'services': true },
  208. 'm': { 'name': 'MODERATED', 'user': true, 'services': true },
  209. 'n': { 'name': 'NOEXTERNAL', 'user': true, 'services': true },
  210. 't': { 'name': 'TOPIC', 'user': true, 'services': true },
  211. 'i': { 'name': 'INVITE', 'user': true, 'services': true },
  212. 'r': { 'name': 'REGISTERED', 'user': false, 'services': true },
  213. 'z': { 'name': 'SECUREONLY', 'user': true, 'services': true },
  214. 'M': { 'name': 'NONREGMODERATED', 'user': true, 'services': true },
  215. 'Q': { 'name': 'NOKICK', 'user': true, 'services': true },
  216. 'N': { 'name': 'NONICK', 'user': true, 'services': true },
  217. 'R': { 'name': 'NONREGINVITE', 'user': true, 'services': true },
  218. 'T': { 'name': 'NOCTCPS', 'user': true, 'services': true },
  219. 'O': { 'name': 'OPERS', 'user': false, 'services': true },
  220. 'V': { 'name': 'NOINVITE', 'user': true, 'services': true },
  221. 'K': { 'name': 'NOKNOCK', 'user': true, 'services': true },
  222. 'D': { 'name': 'OLDDELAYJOIN', 'user': false, 'services': false },
  223. 'd': { 'name': 'DELAYJOIN', 'user': true, 'services': true },
  224. 'G': { 'name': 'CENSOR', 'user': true, 'services': true },
  225. 'P': { 'name': 'PERMANENT', 'user': false, 'services': true },
  226. 'Z': { 'name': 'SECURE', 'user': false, 'services': false },
  227. 'S': { 'name': 'COLORFILTER', 'user': true, 'services': true },
  228. 'C': { 'name': 'NOCTCP', 'user': true, 'services': true },
  229. 'c': { 'name': 'NOCOLOR', 'user': true, 'services': true }
  230. };
  231. var umodeMap = {
  232. 'i': { 'name': 'INVISIBLE', 'user': true, 'services': true },
  233. 'o': { 'name': 'OPER', 'user': false, 'services': false },
  234. 'w': { 'name': 'WALLOP', 'user': true, 'services': true },
  235. 'r': { 'name': 'REGISTEREDNICK', 'user': false, 'services': true },
  236. 's': { 'name': 'SNOTICE', 'user': true, 'services': true },
  237. 'x': { 'name': 'CLOAK', 'user': true, 'services': true },
  238. 'z': { 'name': 'SECUREUSER', 'user': false, 'services': false },
  239. 'd': { 'name': 'DEAF', 'user': true, 'services': true },
  240. 'H': { 'name': 'HIDEIRCOP', 'user': false, 'services': false },
  241. 't': { 'name': 'VHOST', 'user': false, 'services': true },
  242. 'I': { 'name': 'HIDEIDLE', 'user': false, 'services': false },
  243. 'D': { 'name': 'PRIVDEAF', 'user': true, 'services': true },
  244. 'Z': { 'name': 'SECUREMESSAGES', 'user': true, 'services': true },
  245. 'R': { 'name': 'REGISTEREDMESSAGES', 'user': true, 'services': true },
  246. 'q': { 'name': 'UNKICKABLE', 'user': false, 'services': false },
  247. 'p': { 'name': 'HIDECHANNELS', 'user': true, 'services': true },
  248. 'W': { 'name': 'WHOISNOTICE', 'user': false, 'services': false },
  249. 'G': { 'name': 'CENSORMESSAGES', 'user': true, 'services': true },
  250. 'T': { 'name': 'NOCTCPMESSAGES', 'user': true, 'services': true },
  251. 'S': { 'name': 'SERVICEUSER', 'user': false, 'services': false },
  252. 'B': { 'name': 'BOT', 'user': true, 'services': true }
  253. };
  254. function parseChannelModes(modes, args){
  255. var plus = true;
  256. var argIndex = 0;
  257. var output = {};
  258. output['status'] = [];
  259. output['list'] = [];
  260. for(var i=0; i<modes.length; i++){
  261. var c = modes.charAt(i);
  262. if(c in chmodeMap){
  263. var name = chmodeMap[c].name;
  264. } else {
  265. var name = c;
  266. }
  267. if(c == '+'){
  268. plus = true;
  269. } else if(c == '-'){
  270. plus = false;
  271. } else if(connection.chmodes[0].indexOf(c) >= 0){
  272. output['list'].push({ 'name': name, 'value': args[argIndex++], 'status': plus });
  273. } else if(connection.chmodes[1].indexOf(c) >= 0){
  274. if(plus){
  275. output[name] = args[argIndex++];
  276. } else {
  277. output[name] = false;
  278. argIndex++;
  279. }
  280. } else if(connection.chmodes[2].indexOf(c) >= 0){
  281. if(plus){
  282. output[name] = args[argIndex++];
  283. } else {
  284. output[name] = false;
  285. }
  286. } else if(connection.statusmodes.indexOf(c) >= 0){
  287. var user = handlers.findUser(args[argIndex++]);
  288. if(user){
  289. output['status'].push({ 'name': name, 'user': user, 'status': plus });
  290. } else {
  291. throw 'User not found';
  292. }
  293. } else { // treat unknown chars as type 3
  294. if(connection.chmodes[3].indexOf(c) < 0){
  295. console.log('Unknown mode '+name);
  296. }
  297. output[name] = plus;
  298. }
  299. }
  300. return output;
  301. }
  302. function parseUmodes(modeString){
  303. var plus = true;
  304. var modes = {};
  305. for(var i=0; i<modeString.length; i++){
  306. var c = modeString.charAt(i);
  307. switch(c){
  308. case '+': plus = true; break;
  309. case '-': plus = false; break;
  310. default:
  311. var modeName = umodeMap[c].name;
  312. if(!modeName) modeName = c;
  313. modes[modeName] = plus;
  314. break;
  315. }
  316. }
  317. return modes;
  318. }
  319. function makeUmodeString(umodes, own){
  320. var out = '';
  321. var plus = false;
  322. var addPM = true;
  323. for(char in umodeMap){
  324. var name = umodeMap[char].name;
  325. if(name in umodes){
  326. if(own || umodeMap[char].services){
  327. if(umodes[name] && (addPM || !plus)){
  328. addPM = false;
  329. plus = true;
  330. out += '+';
  331. } else if(!umodes[name] && (addPM || plus)){
  332. addPM = false;
  333. plus = false;
  334. out += '-';
  335. }
  336. out += char;
  337. } else {
  338. console.log('Attempted to set umode ' + char + ' which is not settable by services');
  339. }
  340. }
  341. }
  342. return out;
  343. }
  344. function parseModePrefix(text){
  345. var modes = {'status': [], 'list': [] };
  346. var isUser = false;
  347. var c = text.charAt(0);
  348. if(c == '&'){ // +b
  349. modes.list.push({ 'name': 'BAN', 'value': text.substring(1), 'status': true });
  350. } else if(c == '"'){ // +e
  351. modes.list.push({ 'name': 'EXCEPT', 'value': text.substring(1), 'status': true });
  352. } else if(c == '\''){ // +I
  353. modes.list.push({ 'name': 'INVEX', 'value': text.substring(1), 'status': true });
  354. } else {
  355. isUser = true;
  356. for(var i=0; i<text.length; i++){
  357. c = text.charAt(i);
  358. if(c in connection.prefixes){
  359. modes.status.push({ 'name': chmodeMap[connection.prefixes[c]].name, 'user': false /* setting it later */, 'status': true });
  360. // can be more than 1
  361. } else {
  362. break;
  363. }
  364. }
  365. }
  366. var user = null;
  367. if(isUser){
  368. var uid = text.substring(i);
  369. user = handlers.findUser(uid);
  370. if(!user){
  371. handlers.killUser(uid);
  372. modes.status = [];
  373. }
  374. for(var i=0; i<modes.status.length; i++){
  375. modes.status[i].user = user;
  376. }
  377. }
  378. return { 'modes': modes, 'user': user };
  379. }
  380. function ircSend(tags, from, cmd, args){
  381. handlers.send(tags, from, cmd, args);
  382. }
  383. var cmdBinds = {
  384. 'PROTOCTL': function(msg){
  385. for(var i=0; i<msg.args.length; i++){
  386. var arg = msg.args[i];
  387. if(arg.indexOf('=') >= 0){
  388. var arg = arg.split('=');
  389. connection.protoctl[arg[0]] = arg[1];
  390. switch(arg[0]){
  391. case 'PREFIX':
  392. var data = arg[1].substring(1).split(')');
  393. var modes = data[0].split('');
  394. var chars = data[1].split('');
  395. for(var i=0; i<modes.length; i++){
  396. connection.prefixes[chars[i]] = modes[i];
  397. connection.statusmodes.push(modes[i]);
  398. }
  399. break;
  400. case 'CHANMODES':
  401. connection.chmodes = arg[1].split(',');
  402. break;
  403. case 'USERMODES':
  404. connection.umodes = arg[1];
  405. break;
  406. }
  407. } else {
  408. connection.protoctl[arg] = true;
  409. }
  410. }
  411. },
  412. 'SERVER': function(msg){
  413. var expr = /^([^-]+)-([^-]+)-([^ ]+) (.*)$/;
  414. var match = expr.exec(msg.args[2]);
  415. if(match){
  416. settings.me.uplink = handlers.newServer(msg.args[0], match[3], match[4], msg.args[1], settings.me);
  417. } else {
  418. throw 'Unknown SERVER message';
  419. }
  420. events.doEvent('netSynced');
  421. ircSend(null, settings.ID, 'EOS');
  422. },
  423. 'MD': function(msg){
  424. switch(msg.args[0]){
  425. case 'client':
  426. var user = handlers.findUser(msg.args[1]);
  427. if(!user) return;
  428. switch(msg.args[2]){
  429. case 'certfp':
  430. if(!msg.args[3] || msg.args[3].length == 0) break;
  431. user.setSecure(true);
  432. user.setFingerprint(msg.args[3]);
  433. break;
  434. default: break;
  435. }
  436. break;
  437. default: break;
  438. }
  439. },
  440. 'SMOD': function(msg){ // ignore
  441. },
  442. 'EOS': function(msg){ // ?
  443. console.log(connection);
  444. },
  445. 'SINFO': function(msg){
  446. console.log(msg);
  447. },
  448. 'SID': function(msg){
  449. handlers.newServer(msg.args[0], msg.args[2], msg.args[3], msg.args[1], msg.sender.server);
  450. },
  451. 'UID': function(msg){
  452. var nick = msg.args[0];
  453. var distance = msg.args[1];
  454. var TS = msg.args[2];
  455. var ident = msg.args[3];
  456. var host = msg.args[4];
  457. var uid = msg.args[5];
  458. var account = msg.args[6];
  459. var umodes = msg.args[7];
  460. var vhost = msg.args[8];
  461. var cloakedHost = msg.args[9];
  462. var ip = msg.args[10];
  463. var realname = msg.args[11];
  464. if(ip != '*'){
  465. var ipBinary = Buffer.from(ip, 'base64');
  466. if(ipBinary.byteLength == 4){ // IPv4
  467. ip = ipBinary[0].toString(10) + '.' + ipBinary[1].toString(10) + '.' + ipBinary[2].toString(10) + '.' + ipBinary[3].toString(10);
  468. } else if(ipBinary.byteLength == 16){ // IPv6
  469. ip = '';
  470. for(var i=0; i<8; i++){
  471. if(i > 0) ip += ':';
  472. ip += ipBinary[i*2].toString(16).padStart(2, '0') + ipBinary[i*2+1].toString(16).padStart(2, '0');
  473. }
  474. } else {
  475. throw 'unknown IP format';
  476. }
  477. } else {
  478. ip = null;
  479. }
  480. if(vhost == '*'){
  481. vhost = null;
  482. }
  483. if(cloakedHost == '*'){
  484. cloakedHost = null;
  485. }
  486. if(account == '0'){
  487. account = null;
  488. }
  489. handlers.newUser(nick, distance, TS, ident, host, uid, account, parseUmodes(umodes), vhost, cloakedHost, ip, realname, msg.sender.server);
  490. },
  491. 'SJOIN': function(msg){
  492. var channel = handlers.getChannel(msg.args[1]);
  493. channel.setTS(msg.args[0]);
  494. if(msg.args.length > 3){
  495. var modeArgs = [];
  496. for(var i=3; i<msg.args.length - 1; i++){
  497. modeArgs.push(msg.args[i]);
  498. }
  499. channel.changeModes(parseChannelModes(msg.args[2], modeArgs));
  500. }
  501. var members = msg.text.split(' ');
  502. for(var i=0; i<members.length; i++){
  503. var member = members[i];
  504. var c = member.charAt(0);
  505. var udata = parseModePrefix(member);
  506. if(udata.user){
  507. console.log(udata.user.name + ' joined ' + msg.args[1]);
  508. channel.joinUser(udata.user);
  509. }
  510. channel.changeModes(udata.modes);
  511. }
  512. },
  513. 'SENDUMODE': function(msg){ // ignore
  514. },
  515. 'SENDSNO': function(msg){ // ignore
  516. },
  517. 'PASS': function(msg){ // ignore
  518. },
  519. 'SWHOIS': function(msg){
  520. console.log(msg);
  521. //TODO
  522. },
  523. 'MODE': function(msg){
  524. var channel = handlers.findChannel(msg.args[0]);
  525. if(channel){
  526. var modeArgs = [];
  527. for(var i=2; i<msg.args.length; i++){
  528. modeArgs.push(msg.args[i]);
  529. }
  530. var chmodes = parseChannelModes(msg.args[1], modeArgs);
  531. channel.changeModes(chmodes);
  532. }
  533. },
  534. 'TKL': function(msg){
  535. // console.log(msg);
  536. //TODO
  537. },
  538. 'METADATA': function(msg){
  539. var what = msg.args[0];
  540. var name = msg.args[1];
  541. var visibility = msg.args[2];
  542. if(msg.args.length > 3){
  543. var value = msg.args[3];
  544. } else {
  545. var value = null;
  546. }
  547. var channel = handlers.findChannel(what);
  548. if(channel){
  549. channel.setMetadata(name, visibility, value);
  550. return;
  551. }
  552. var user = handlers.findUser(what);
  553. if(user){
  554. user.setMetadata(name, visibility, value);
  555. }
  556. },
  557. 'NETINFO': function(msg){
  558. ircSend(null, null, 'NETINFO', [settings.maxUsers.toString(10), Math.floor(new Date() / 1000).toString(10), msg.args[2], msg.args[3], "0", "0", "0", msg.args[7]]);
  559. },
  560. 'SASL': function(msg){
  561. console.log(msg);
  562. //TODO
  563. },
  564. 'PING': function(msg){
  565. msg.reply(null, 'PONG', msg.args);
  566. },
  567. 'QUIT': function(msg){
  568. handlers.quitUser(msg.sender.user);
  569. },
  570. 'PART': function(msg){
  571. var channel = handlers.getChannel(msg.args[0]);
  572. channel.removeUser(msg.sender.user);
  573. },
  574. 'CHGHOST': function(msg){
  575. var user = handlers.findUser(msg.args[0]);
  576. if(!user) return;
  577. user.changeVHost(msg.args[1]);
  578. },
  579. 'CHGIDENT': function(msg){
  580. var user = handlers.findUser(msg.args[0]);
  581. if(!user) return;
  582. user.changeVIdent(msg.args[1]);
  583. },
  584. 'CHGNAME': function(msg){
  585. var user = handlers.findUser(msg.args[0]);
  586. if(!user) return;
  587. user.setRealname(msg.args[1]);
  588. },
  589. 'SETNAME': function(msg){
  590. msg.sender.user.setRealname(msg.args[0]);
  591. },
  592. 'SETHOST': function(msg){
  593. msg.sender.user.changeVHost(msg.args[0]);
  594. },
  595. 'SETIDENT': function(msg){
  596. msg.sender.user.changeVIdent(msg.args[0]);
  597. },
  598. 'NICK': function(msg){
  599. msg.sender.user.changeNick(msg.args[0]);
  600. },
  601. 'SDESC': function(msg){
  602. msg.sender.uplink.setDescription(msg.args[0]);
  603. },
  604. 'TOPIC': function(msg){
  605. var channel = handlers.findChannel(msg.args[0]);
  606. if(!channel) return;
  607. var setter = msg.args[1];
  608. var TS = msg.args[2];
  609. var text = msg.args[3];
  610. channel.setTopic({'setter': setter, 'TS': TS, 'text': text });
  611. },
  612. /*
  613. messagedata {
  614. text: '0',
  615. args: [ '183.89.186.94', '0' ],
  616. tags: [],
  617. command: 'REPUTATION',
  618. sender: {
  619. nick: 'test1.pirc.pl',
  620. ident: '',
  621. host: '',
  622. server: server {
  623. name: 'test1.pirc.pl',
  624. sid: '093',
  625. description: 'serwer testowy!',
  626. distance: '3',
  627. uplink: [Object],
  628. introduce: [Function]
  629. },
  630. user: false
  631. },
  632. time: 2020-03-14T10:48:06.207Z,
  633. reply: [Function],
  634. originalString: ':093 REPUTATION 183.89.186.94 0'
  635. }
  636. */
  637. 'REPUTATION': function(msg){
  638. //TODO
  639. },
  640. 'UMODE2': function(msg){
  641. msg.sender.user.changeUmodes(parseUmodes(msg.args[0]));
  642. },
  643. 'KILL': function(msg){
  644. var user = handlers.findUser(msg.args[0]);
  645. if(!user) return;
  646. handlers.quitUser(user);
  647. },
  648. 'SQUIT': function(msg){
  649. var server = handlers.findServer(msg.args[0]);
  650. if(!server) return;
  651. handlers.removeServer(server);
  652. },
  653. /*messagedata {
  654. text: 'TestServ',
  655. args: [ '11K3R1VLH', 'TestServ' ],
  656. tags: [],
  657. command: 'WHOIS',
  658. sender: {
  659. nick: 'k4be',
  660. ident: 'testowy',
  661. host: 'localhost',
  662. server: false,
  663. user: user {
  664. name: 'k4be',
  665. TS: '1583056052',
  666. ident: 'testowy',
  667. host: 'localhost',
  668. account: null,
  669. umodes: [Object],
  670. vhost: 'staff:netadmin',
  671. cloakedHost: 'ukryty-18D8A42D',
  672. ip: '0000:0000:0000:0000:0000:0000:0000:0001',
  673. realname: 'realname',
  674. uid: '143ZQ0B02',
  675. distance: '0',
  676. uplink: [server],
  677. secure: false,
  678. certfp: null,
  679. vident: null,
  680. metadata: {},
  681. introduce: [Function],
  682. setSecure: [Function],
  683. setFingerprint: [Function],
  684. changeVHost: [Function],
  685. changeVIdent: [Function],
  686. setRealname: [Function],
  687. changeNick: [Function],
  688. changeUmodes: [Function],
  689. setMetadata: [Function]
  690. }
  691. },
  692. time: 2020-03-16T14:02:45.252Z,
  693. reply: [Function],
  694. originalString: ':143ZQ0B02 WHOIS 11K3R1VLH :TestServ'
  695. }*/
  696. 'WHOIS': function(msg){
  697. },
  698. 'PRIVMSG': function(msg){
  699. if(msg.args[0].charAt(0) == '#'){
  700. events.doEvent('channelMessage', msg);
  701. } else {
  702. events.doEvent('botMessage', msg);
  703. }
  704. },
  705. 'NOTICE': function(msg){
  706. if(msg.args[0].charAt(0) == '#'){
  707. events.doEvent('channelNotice', msg);
  708. } else {
  709. events.doEvent('botNotice', msg);
  710. }
  711. }
  712. };