unrealircd.js 21 KB

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