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