chg: Make these classes static to optimize memory usage
[cacert-votebot.git] / src / org / cacert / votebot / IRCClient.java
1 package org.cacert.votebot;
2
3 import java.io.BufferedReader;
4 import java.io.FileOutputStream;
5 import java.io.IOException;
6 import java.io.InputStreamReader;
7 import java.io.PrintWriter;
8 import java.net.Socket;
9 import java.util.HashMap;
10 import java.util.HashSet;
11 import java.util.concurrent.Semaphore;
12
13 import javax.net.ssl.SSLSocketFactory;
14
15 public class IRCClient {
16
17 private Semaphore loggedin = new Semaphore(0);
18
19 private PrintWriter out;
20
21 private Socket s;
22
23 private String nick;
24
25 class ServerReader implements Runnable {
26
27 private BufferedReader br;
28
29 public ServerReader(BufferedReader br) {
30 this.br = br;
31
32 new Thread(this).start();
33 }
34
35 @Override
36 public void run() {
37 String l;
38
39 try {
40 while ((l = br.readLine()) != null) {
41 String fullline = l;
42 // System.out.println(l);
43
44 if (l.startsWith("PING ")) {
45 System.out.println("PONG");
46 out.println("PONG " + l.substring(5));
47 }
48
49 String referent = "";
50
51 if (l.startsWith(":")) {
52 String[] parts = l.split(" ", 2);
53 referent = parts[0];
54 l = parts[1];
55 }
56
57 String[] command = l.split(" ", 3);
58
59 if (command[0].equals("001")) {
60 loggedin.release();
61 }
62
63 if (command[0].equals("PRIVMSG")) {
64 String msg = command[2].substring(1);
65 String chnl = command[1];
66
67 if ( !chnl.startsWith("#")) {
68 handlePrivMsg(referent, msg);
69 } else {
70 handleMsg(referent, chnl, msg);
71 }
72
73 log(chnl, fullline);
74 } else if (command[0].equals("JOIN")) {
75 String chn = command[1].substring(1);
76 targetBot.join(cleanReferent(referent), chn.substring(1));
77 log(chn, fullline);
78 } else if (command[0].equals("PART")) {
79 String chn = command[1];
80 targetBot.part(cleanReferent(referent), chn);
81 log(chn, fullline);
82 } else {
83 System.out.println("unknown line: ");
84 System.out.println(l);
85 }
86 }
87 } catch (IOException e) {
88 e.printStackTrace();
89 }
90
91 }
92
93 private String cleanReferent(String referent) {
94 String[] parts = referent.split("!");
95
96 if ( !parts[0].startsWith(":")) {
97 System.err.println("invalid public message");
98 return "unknown";
99 }
100
101 return parts[0];
102 }
103
104 HashMap<String, PrintWriter> logs = new HashMap<String, PrintWriter>();
105
106 private void log(String chn, String l) throws IOException {
107 if ( true ) {
108 return;
109 }
110
111 PrintWriter log = logs.get(chn);
112
113 if (log == null) {
114 log = new PrintWriter(new FileOutputStream("irc/log_" + chn), true);
115 logs.put(chn, log);
116 }
117
118 log.println(l);
119 }
120
121 private void handlePrivMsg(String referent, String msg) {
122 String[] parts = referent.split("!");
123
124 if ( !parts[0].startsWith(":")) {
125 System.err.println("invalid private message");
126 return;
127 }
128
129 if (targetBot == null) {
130 System.out.println("dropping message");
131 return;
132 }
133
134 targetBot.privateMessage(parts[0].substring(1), msg);
135 }
136
137 private void handleMsg(String referent, String chnl, String msg) {
138 String[] parts = referent.split("!");
139
140 if ( !parts[0].startsWith(":")) {
141 System.err.println("invalid public message");
142 return;
143 }
144
145 if (targetBot == null) {
146 System.out.println("dropping message");
147 return;
148 }
149
150 if ( !chnl.startsWith("#")) {
151 System.err.println("invalid public message (chnl)");
152 return;
153 }
154
155 targetBot.publicMessage(parts[0].substring(1), chnl.substring(1), msg);
156 }
157
158 }
159
160 public IRCClient(String nick, String server, int port, boolean ssl) throws IOException, InterruptedException {
161 if ( !nick.matches("[a-zA-Z0-9_-]+")) {
162 throw new Error("malformed");
163 }
164
165 if (ssl) {
166 s = SSLSocketFactory.getDefault().createSocket(server, port);//default-ssl = 7000
167 // default-ssl = 7000
168 } else {
169 s = new Socket(server, port);
170 // default-plain = 6667
171 }
172
173 out = new PrintWriter(s.getOutputStream(), true);
174 BufferedReader in = new BufferedReader(new InputStreamReader(s.getInputStream()));
175
176 new ServerReader(in);
177
178 out.println("USER " + nick + " 0 * :unknown");
179 out.println("NICK " + nick);
180
181 loggedin.acquire();
182 }
183
184 HashSet<String> joined = new HashSet<String>();
185
186 private IRCBot targetBot;
187
188 public void join(String channel) {
189 if ( !channel.matches("[a-zA-Z0-9_-]+")) {
190 return;
191 }
192
193 if (joined.add(channel)) {
194 out.println("JOIN #" + channel);
195 }
196 }
197
198 public void leave(String channel) {
199 if ( !channel.matches("[a-zA-Z0-9_-]+")) {
200 return;
201 }
202
203 if (joined.remove(channel)) {
204 out.println("PART #" + channel);
205 }
206 }
207
208 public void send(String msg, String channel) {
209 if ( !channel.matches("[a-zA-Z0-9_-]+")) {
210 return;
211 }
212
213 out.println("PRIVMSG #" + channel + " :" + msg);
214 }
215
216 public void sendPrivate(String msg, String to) {
217 if ( !to.matches("[a-zA-Z0-9_-]+")) {
218 return;
219 }
220
221 out.println("PRIVMSG " + to + " :" + msg);
222 }
223
224 public void setBot(IRCBot bot) {
225 this.targetBot = bot;
226 }
227
228 public static IRCClient parseCommandLine(String[] commandLine, String nick) throws IOException, InterruptedException {
229 this.nick = nick;
230
231 String host = null;
232 int port = 7000;
233 boolean ssl = true;
234
235 for (int i = 0; i < commandLine.length; i++) {
236 String cmd = commandLine[i];
237
238 if (cmd.equals("--no-ssl") || cmd.equals("-u")) {
239 ssl = false;
240 } else if (cmd.equals("--ssl") || cmd.equals("-s")) {
241 ssl = true;
242 } else if (cmd.equals("--host") || cmd.equals("-h")) {
243 host = commandLine[++i];
244 } else if (cmd.equals("--port") || cmd.equals("-p")) {
245 port = Integer.parseInt(commandLine[++i]);
246 } else if (cmd.equals("--nick") || cmd.equals("-n")) {
247 nick = commandLine[++i];
248 } else if (cmd.equals("--help") || cmd.equals("-h")) {
249 System.out.println("Options: [--no-ssl|-u|--ssl|-s|[--host|-h] <host>|[--port|-p] <port>|[--nick|-n] <nick>]*");
250 System.out.println("Requires the -host argument, --ssl is default, last argument of a kind is significant.");
251 throw new Error("Operation caneled");
252 } else {
253 throw new Error("Invalid option (usage with --help): " + cmd);
254 }
255 }
256
257 if (host == null) {
258 throw new Error("--host <host> is missing");
259 }
260
261 return new IRCClient(nick, host, port, ssl);
262 }
263
264 }