diff --git a/README.md b/README.md index fb349cf..80cc05f 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,14 @@ bouncerShack: ping ack timeout bouncerDefaultOpmode: auto op/voice/hop mode default (can be turned on per client using /jbnc) bouncerTimeout: how long until after no clients connected will the user stay connected bufferMaxSize: maximum # of bytes a client buffer can hold before its terminated or 0 for unlimited +MsgRedistribution: If enabled, will override the entire old system installed by default, and it will +save the last 300 lines for both privmsgs and notices (except ctcp) and all separately by channel and by +recipient. It records everything even if the client is logged into JBNC or not. +As soon as the client reconnects to JBNC, it will send all privmsgs / notices to the client. The +IRC client should sort the msgids by checking if they are already received, if they are not received then +the client updates the new messages. Once the client has updated all the new messages, then it should +automatically send "/jbnc logclear" to remove the entire "privmsgnotice" array from the client +connected to the JBNC. ``` 3. Run diff --git a/bouncer.js b/bouncer.js index 12e013d..593ab2a 100644 --- a/bouncer.js +++ b/bouncer.js @@ -1,4 +1,4 @@ -// jbnc v0.5 +// jbnc v0.7 // Copyright (C) 2020 Andrew Lee // All Rights Reserved. const tls = require('tls'); @@ -39,6 +39,7 @@ const SERVER_TLS_CERT = config.tlsCert?config.tlsCert:'fullchain.pem'; const SERVER_PORT = BOUNCER_MODE=='gateway'?(config.serverPort?config.serverPort:0):0; const INGRESSWEBIRC = config.ingresswebircPassword?config.ingresswebircPassword:''; const SERVER = BOUNCER_MODE=='gateway'?(config.server?config.server:''):''; +const MSG_REDISTRIBUTION = config.MsgRedistribution?true:false; const DEBUG = config.debug?config.debug:false; @@ -249,15 +250,15 @@ server = doServer(tlsOptions,function(socket) { } else if(commands[1]) { this.irc.nick=commands[1].trim(); - /*if(this.irc.user) { - this.hash=hash(this.irc.nick+this.irc.user+this.irc.password+this.irc.server+this.irc.port.toString()); + if(this.irc.user) { + this.hash=hash(this.irc.nick+this.irc.password+this.irc.server+this.irc.port.toString()); if(connections[socket.hash]) { clientReconnect(this); } else { clientConnect(this); } - }*/ + } } break; case 'USER': @@ -422,6 +423,17 @@ server = doServer(tlsOptions,function(socket) { this.write(":*jbnc NOTICE * :"+connections[this.hash].parents[x].clientbuffer+" ("+connections[this.hash].parents[x].remoteAddress+")\n"); } break; + case 'LOGCLEAR': + if (connections[this.hash] && connections[this.hash].buffers) { + for(key in connections[this.hash].buffers) { + if(connections[this.hash].buffers.hasOwnProperty(key)) { + if(connections[this.hash].buffers[key] && connections[this.hash].buffers[key].privmsgnotice && connections[this.hash].buffers[key].privmsgnotice.length>0) { + connections[this.hash].buffers[key].privmsgnotice.length=0; + } + } + } + } + break; case 'BUFFERS': totalbuffers = 0; for(key in connections[this.hash].buffers) { @@ -506,10 +518,10 @@ server = doServer(tlsOptions,function(socket) { } break; default: - if(typeof connections[this.hash] === 'undefined' ) - continue; + /*if(typeof connections[this.hash] === 'undefined' ) + continue;*/ // supress joins of channels we are already in because some clients dont react properly. - if(input[i].toString().substr(0,4)=="JOIN") { + if(input[i] && connections[this.hash] && input[i].toString().substr(0,4)=="JOIN") { command=input[i].toString().trim().split(" "); if(!command[1]) break; @@ -618,7 +630,7 @@ function clientReconnect(socket) { socket.connected=true; newdevice=false; if(!connection.buffers[socket.clientbuffer]) { - connection.buffers[socket.clientbuffer]={data:'',connected:true}; + connection.buffers[socket.clientbuffer]={data:'',connected:true,privmsgnotice:[]}; newdevice=true; } else @@ -644,7 +656,13 @@ function clientReconnect(socket) { if(connection.channels.hasOwnProperty(key)) { _channel=connection.channels[key]; - socket.write("@time=2020-07-26T09:20:54.103Z;msgid=null :"+connection.nick+"!"+connection.ircuser+"@"+connection.host+" JOIN :"+_channel.name+"\n"); + if (_channel.name != "undefined" || typeof _channel.name !== 'undefined') { + socket.write("@time="+new Date().toISOString()+";msgid=back :"+connection.nick+"!"+connection.ircuser+"@"+connection.host+" JOIN :"+_channel.name+"\n"); + } else { + continue; + } + + _mode_params=''; if ( typeof _channel.modes === 'undefined' ) @@ -703,8 +721,16 @@ function clientReconnect(socket) { socket.write(":"+connection.nick+" MODE "+connection.nick+" :+"+connection.umode+"\n"); if(DEBUG) - console.log(":"+connection.nick+" MODE "+connection.nick+" :+"+connection.umode) - if(connection.buffers[socket.clientbuffer] && connection.buffers[socket.clientbuffer].data && connection.buffers[socket.clientbuffer].data.length>0) { + console.log(":"+connection.nick+" MODE "+connection.nick+" :+"+connection.umode); + + if (MSG_REDISTRIBUTION && connection.messagetags && connection.buffers[socket.clientbuffer] && connection.buffers[socket.clientbuffer].privmsgnotice && connection.buffers[socket.clientbuffer].privmsgnotice.length>0) { + socket.write(":*jbnc PRIVMSG "+connection.nick+" :Retrieving all privmsgs/notices\n"); + for(x=0; x0) { socket.write(":*jbnc PRIVMSG "+connection.nick+" :Retrieving all messages\n"); socket.write(connection.buffers[socket.clientbuffer].data+"\n"); connection.buffers[socket.clientbuffer].data=''; @@ -712,6 +738,10 @@ function clientReconnect(socket) { } else socket.write(":*jbnc PRIVMSG "+connection.nick+" :There is no new message\n"); + + if(connection.buffers[socket.clientbuffer] && connection.buffers[socket.clientbuffer].data && connection.buffers[socket.clientbuffer].data.length>0) { + connection.buffers[socket.clientbuffer].data=''; + } } } @@ -756,7 +786,7 @@ function clientConnect(socket) { // client buffers connection.buffers = {}; - connection.buffers[socket.clientbuffer] = {data:'',connected:true}; + connection.buffers[socket.clientbuffer] = {data:'',connected:true,privmsgnotice:[]}; socket.connected=true; // irc server connection data @@ -849,6 +879,9 @@ function clientConnect(socket) { this.write("CAP REQ :message-tags\n"); this.messagetags=true; } + if(lines[n].trim().indexOf("away-notify")>=0) { + this.write("CAP REQ :away-notify\n"); + } if(this.messagetags && lines[n].trim().indexOf("server-time")>=0) { this.write("CAP REQ :server-time\n"); } @@ -904,7 +937,11 @@ function clientConnect(socket) { this.write("CAP END\n"); } } - + + if(data[1]=="900") { + this.account = data[4]; + } + let s = data[1]; if ( this.messagetags && (data[2]=="JOIN" || data[2]=="PART" || data[2]=="QUIT" || data[2]=="MODE" || data[2]=="PING" || data[2]=="NICK" || data[2]=="KICK") ) { @@ -1065,10 +1102,10 @@ function clientConnect(socket) { } } else { - _regex = new RegExp(_mode[i],"g") + _regex = new RegExp(_mode[i],"g"); if(_sender==_target && _target==this.nick || _sender=="NickServ" && _target==this.nick || _sender=="OperServ" && _target==this.nick) this.umode=this.umode.replace(_regex,""); - else if(curchan != null && (_mode[i]!='o' && _mode[i]!='v' && _mode[i]!='h')) + else if(curchan != null && (_mode[i]!='o' && _mode[i]!='v' && _mode[i]!='h') && curchan.modes) curchan.modes=curchan.modes.replace(_regex,""); if((_target.indexOf("#")!=-1||_target.indexOf("&")!=-1) && (_mode[i]=='o' || _mode[i]=='k' || _mode[i]=='v' || _mode[i]=='h' || _mode[i]=='l' || _mode[i]=='e' || _mode[i]=='b' || _mode[i]=='I' || _mode[i]=='q' || _mode[i]=='f' || @@ -1172,13 +1209,13 @@ function clientConnect(socket) { if(this.channels[__channel]) { this.channels[__channel].names.push(_nick); this.channels[__channel].userhosts.push(this.userHostInNames?_userhost:"*@*"); - if(this.channels[__channel].isop && this.channels[__channel].aop.indexOf(_nick+"!"+_userhost)>=0 && this.opmode) { + if(this.channels[__channel].isop && this.channels[__channel].aop && this.channels[__channel].aop.indexOf(_nick+"!"+_userhost)>=0 && this.opmode) { this.write("MODE "+this.channels[__channel].name+" +o "+_nick+"\n"); } - if((this.channels[__channel].isop || this.channels[__channel].ishop) && this.channels[__channel].aoh.indexOf(_nick+"!"+_userhost)>=0 && this.opmode) { + if((this.channels[__channel].isop || this.channels[__channel].ishop) && this.channels[__channel].aoh && this.channels[__channel].aoh.indexOf(_nick+"!"+_userhost)>=0 && this.opmode) { this.write("MODE "+this.channels[__channel].name+" +h "+_nick+"\n"); } - if((this.channels[__channel].isop || this.channels[__channel].ishop) && this.channels[__channel].aov.indexOf(_nick+"!"+_userhost)>=0 && this.opmode) { + if((this.channels[__channel].isop || this.channels[__channel].ishop) && this.channels[__channel].aov && this.channels[__channel].aov.indexOf(_nick+"!"+_userhost)>=0 && this.opmode) { this.write("MODE "+this.channels[__channel].name+" +v "+_nick+"\n"); } } @@ -1319,9 +1356,76 @@ function clientConnect(socket) { for(m=0;m + _l = 1; + + // Number of targets found + for(x=0; x=300) { + console.log("exceeds: %s", _l); + this.buffers[key].privmsgnotice.splice(x,1); + break; + } + } + } + + // Adding all messages + this.buffers[key].privmsgnotice.push({ + target: _n, + line: lines[n]+"\n" + }); + } + } + } + + } + + + } // store clientbuf if not connected - if(lines[n].indexOf("PRIVMSG")>=0 || lines[n].indexOf("NOTICE")>=0 || lines[n].indexOf("WALLOPS")>=0 || lines[n].indexOf("GLOBOPS")>=0 || lines[n].indexOf("CHATOPS")>=0) { + else if(lines[n].indexOf("PRIVMSG")>=0 || lines[n].indexOf("NOTICE")>=0 || lines[n].indexOf("WALLOPS")>=0 || lines[n].indexOf("GLOBOPS")>=0 || lines[n].indexOf("CHATOPS")>=0) { for(key in this.buffers) { if(this.buffers.hasOwnProperty(key)) { if(!this.buffers[key].connected) {