Skip to content
This repository has been archived by the owner on Jul 23, 2021. It is now read-only.

Commit

Permalink
inital import of codebase
Browse files Browse the repository at this point in the history
  • Loading branch information
johnnyapol committed Apr 25, 2018
1 parent 52d29b5 commit 9080f30
Show file tree
Hide file tree
Showing 9 changed files with 905 additions and 0 deletions.
6 changes: 6 additions & 0 deletions Shane/.classpath
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8"/>
<classpathentry kind="src" path="src"/>
<classpathentry kind="output" path="bin"/>
</classpath>
1 change: 1 addition & 0 deletions Shane/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/bin/
17 changes: 17 additions & 0 deletions Shane/.project
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>Shane</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>
11 changes: 11 additions & 0 deletions Shane/.settings/org.eclipse.jdt.core.prefs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.debug.lineNumber=generate
org.eclipse.jdt.core.compiler.debug.localVariable=generate
org.eclipse.jdt.core.compiler.debug.sourceFile=generate
org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
org.eclipse.jdt.core.compiler.source=1.8
17 changes: 17 additions & 0 deletions Shane/shane.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#Shane IRC Bouncer Configuration File
# General Settings
afk-msg=Sorry! I'm currently away from my computer right now. I'll get back to you as soon as I can.
password=shanebouncer2490.739101114047
bouncer-ssl-enable=false
#The following only need to be changed if you intend on using SSL on your bouncer.
bouncer-ssl-keystore=path
bouncer-ssl-password=password
#IRC networks are denoted by a [network name] and ended with an [end] block
[freenode]
ip=irc.freenode.net
port=6667
use-ssl=false
nick=shanebouncer
channels=##networking,#general
bouncer-port=6667
[end]
250 changes: 250 additions & 0 deletions Shane/src/me/johnnyapol/shane/IRCConnection.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,250 @@
/**
* Copyright (c) 2018 John Christopher Allwein (johnnyapol)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package me.johnnyapol.shane;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.net.ssl.SSLSocketFactory;

import me.johnnyapol.shane.IRCServer.IRCClient;

public class IRCConnection implements Runnable {

private Socket socket = null;
private BufferedReader reader = null;
private BufferedWriter writer = null;

private String nickName = null;

private IRCServer server = null;

private final Logger log = Logger.getLogger("Shane");

// takes a nick and holds a msg queue for when that client reconnects
private Map<String, ArrayList<String>> missedMessages = new ConcurrentHashMap<String, ArrayList<String>>();
// messages excluding PRIVMSG and PINGs, for some reason clients need these to function properly. I'm probably messing something up too
private List<String> serverMsgs = new CopyOnWriteArrayList<String>();

private String[] channels;
private String networkName;

private boolean useSSL = false;
private String ipAddress;
private int port;
private String afkMsg = "";

private boolean isRunning = true;

public IRCConnection(String networkName, String ipAddress, int port, IRCServer server, String nick, String[] channels, boolean useSSL, String afk) throws IOException {
this.networkName = networkName;
this.ipAddress = ipAddress;
this.port = port;
this.server = server;
this.nickName = nick;
this.channels = channels;
this.useSSL = useSSL;
this.afkMsg = afk;

this.socket = (useSSL ? (((SSLSocketFactory)SSLSocketFactory.getDefault()).createSocket(ipAddress, port)) : new Socket(ipAddress, port));
try {
init();
} catch(Throwable t) {
t.printStackTrace();
}
}

private void init() throws IOException {
log.info("[" + this.networkName + "] Connecting to: " + socket.getRemoteSocketAddress().toString());
if (useSSL)
log.info("[" + this.networkName + "] Using SSL for connection");

this.reader = new BufferedReader(new InputStreamReader(this.socket.getInputStream()));
this.writer = new BufferedWriter(new OutputStreamWriter(this.socket.getOutputStream()));

this.sendMesssage("NICK " + this.nickName);
this.sendMesssage("USER shanebouncer 8 * : " + this.nickName);

for (String channel : this.channels) {
this.sendMesssage("JOIN " + channel);
}
this.server.setIRCConnection(this);
}

@Override
public void run() {
while (this.isRunning) {
try {
Thread.sleep(50);
String msg = null;

while ((msg = this.reader.readLine()) != null) {
String[] split = msg.split(" ");
if (msg.contains("PING")) {
int dataIndex = 1;

for (int i = 0; i < split.length; i++) {
if (split[i].equalsIgnoreCase("PING")) {
dataIndex = i;
break;
}
}
this.sendMesssage("PONG " + split[dataIndex + 1]);
continue;
}

// block WHO responses since they lag us really bad
if (!msg.contains("PRIVMSG") && !(msg.startsWith(":") && split[1].equals("352"))) {
this.serverMsgs.add(msg);
}

// Afk functionality
if (msg.contains("PRIVMSG") && msg.contains(this.nickName) && this.server.getConnectedClients().size() == 0) {
// We're afk, let them know
String user = msg.split("!")[0].substring(1);

this.sendMesssage("PRIVMSG " + user + " :" + this.afkMsg);
}

log.info("[" + this.networkName + "] [msg] " + msg);

this.server.distributeMessage(msg);

List<String> nicksOnline = new ArrayList<String>();

for (IRCClient c : this.server.getConnectedClients()) {
nicksOnline.add(c.getNick());
}

Iterator<String> clients = this.missedMessages.keySet().iterator();
while (clients.hasNext()) {
String nick = clients.next();
if (!nicksOnline.contains(nick)) {
// store msg for later
// block WHO responses, they lag up the place
if ((msg.startsWith(":") && split[1].equals("352"))) {
continue;
}
this.missedMessages.get(nick).add(msg);
}
}
}
} catch (Throwable t) {
log.log(Level.SEVERE, "Throwable while processing message", t);

if (t instanceof IOException) {
// we've probably lost connection
while (true) {
log.log(Level.WARNING, "[" + this.networkName + "] Lost connection to " + this.socket.getRemoteSocketAddress().toString());
log.info("[" + this.networkName + "] Attempting to reconnect...");

this.serverMsgs.clear();

try {
this.socket = (useSSL ? (((SSLSocketFactory)SSLSocketFactory.getDefault()).createSocket(ipAddress, port)) : new Socket(ipAddress, port));
while (!this.socket.isConnected()) {
Thread.sleep(50);
}

init();
return; // kill off this thread
} catch (Exception e) {
log.log(Level.SEVERE, "[" + this.networkName + "] Failed to connect to " + ipAddress + ", sleeping for 30 seconds and trying again..");
try {
Thread.sleep(1000 * 30);
} catch (InterruptedException e1) {
// ignored
}
}
}
}
}
}
}

public void sendMesssage(String msg) throws IOException {
this.writer.write(msg + "\r\n");
this.writer.flush();
}

public void onClientConnect(IRCClient client) {
for (String msg : this.serverMsgs) {
try {
client.sendMessage(msg);
} catch (IOException e) {
// TODO: autogenerated
e.printStackTrace();
}
}

ArrayList<String> msgs = this.missedMessages.get(client.getNick());

if (msgs == null) {
msgs = new ArrayList<String>();
this.missedMessages.put(client.getNick(), msgs);
return;
}

for (String msg : msgs) {
try {
client.sendMessage(msg);
} catch (IOException e) {
log.log(Level.SEVERE, "[" + this.networkName + "] Lost connection to client " + client.getConnection().getRemoteSocketAddress() + ", an IOException occurred while writing", e);
this.server.getConnectedClients().remove(client);
}
}

// cleanup
msgs.clear();
}
public String getNickName() {
return this.nickName;
}

public IRCServer getServer() {
return this.server;
}

public void stop() {
this.isRunning = false;

try {
this.sendMesssage("QUIT :ShaneBouncer shutting down!");
this.socket.close();
} catch (IOException e) {
log.log(Level.SEVERE, "IOException occurred while shutting down connection to: " + this.networkName, e);
} finally {
try {
this.socket.close();
} catch (IOException e) {
// ignored
}
}

this.getServer().stop();
}
}
Loading

0 comments on commit 9080f30

Please sign in to comment.