]> git.somenet.org - irc/pjirc-ng.git/blob - src/main/java/irc/dcc/prv/DCCFileHandler.java
Pjirc 2.2.1 as available on the net, reformatted and made it compile.
[irc/pjirc-ng.git] / src / main / java / irc / dcc / prv / DCCFileHandler.java
1 /*****************************************************/\r
2 /*          This java file is a part of the          */\r
3 /*                                                   */\r
4 /*           -  Plouf's Java IRC Client  -           */\r
5 /*                                                   */\r
6 /*   Copyright (C)  2002 - 2005 Philippe Detournay   */\r
7 /*                                                   */\r
8 /*         All contacts : theplouf@yahoo.com         */\r
9 /*                                                   */\r
10 /*  PJIRC is free software; you can redistribute     */\r
11 /*  it and/or modify it under the terms of the GNU   */\r
12 /*  General Public License as published by the       */\r
13 /*  Free Software Foundation; version 2 or later of  */\r
14 /*  the License.                                     */\r
15 /*                                                   */\r
16 /*  PJIRC is distributed in the hope that it will    */\r
17 /*  be useful, but WITHOUT ANY WARRANTY; without     */\r
18 /*  even the implied warranty of MERCHANTABILITY or  */\r
19 /*  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU   */\r
20 /*  General Public License for more details.         */\r
21 /*                                                   */\r
22 /*  You should have received a copy of the GNU       */\r
23 /*  General Public License along with PJIRC; if      */\r
24 /*  not, write to the Free Software Foundation,      */\r
25 /*  Inc., 59 Temple Place, Suite 330, Boston,        */\r
26 /*  MA  02111-1307  USA                              */\r
27 /*                                                   */\r
28 /*****************************************************/\r
29 \r
30 package irc.dcc.prv;\r
31 \r
32 import irc.IRCConfiguration;\r
33 import irc.IRCObject;\r
34 import irc.IRCTextProvider;\r
35 import irc.ListenerGroup;\r
36 import irc.Server;\r
37 import irc.ServerListener;\r
38 import irc.Source;\r
39 import irc.dcc.DCCFile;\r
40 \r
41 import java.io.BufferedInputStream;\r
42 import java.io.BufferedOutputStream;\r
43 import java.io.File;\r
44 import java.io.IOException;\r
45 import java.io.InputStream;\r
46 import java.io.OutputStream;\r
47 import java.net.InetAddress;\r
48 import java.net.ServerSocket;\r
49 import java.net.Socket;\r
50 import java.util.Enumeration;\r
51 import java.util.Vector;\r
52 \r
53 /**\r
54  * The dcc file handler. There is a handler for each file transfert.\r
55  */\r
56 public class DCCFileHandler extends IRCObject implements Server, Runnable {\r
57         private Socket _socket;\r
58         private ServerSocket _serverSocket;\r
59         private Thread _thread;\r
60 \r
61         private OutputStream _os;\r
62         private InputStream _is;\r
63         private DCCFile _file;\r
64 \r
65         private int _action;\r
66         private int _size;\r
67         private boolean _listening;\r
68         private boolean _connected;\r
69         private ListenerGroup _listeners;\r
70 \r
71         /**\r
72          * Create a new DCCFileHandler.\r
73          * \r
74          * @param config\r
75          *          the global configuration.\r
76          * @param remoteNick\r
77          *          the remote nick.\r
78          * @param f\r
79          *          the file to send or receive.\r
80          */\r
81         public DCCFileHandler(IRCConfiguration config, String remoteNick, File f) {\r
82                 super(config);\r
83                 _action = 0;\r
84                 _size = 0;\r
85                 _connected = false;\r
86                 _file = new DCCFile(config, f, this);\r
87                 _listeners = new ListenerGroup();\r
88         }\r
89 \r
90         @Override\r
91         public void release() {\r
92                 cleanup();\r
93                 _file = null;\r
94                 super.release();\r
95         }\r
96 \r
97         /**\r
98          * Receive the file.\r
99          * \r
100          * @param ip\r
101          *          the remote ip.\r
102          * @param port\r
103          *          the remote port.\r
104          * @param size\r
105          *          the file size.\r
106          */\r
107         public void receive(String ip, String port, String size) {\r
108                 _size = new Integer(size).intValue();\r
109                 _file.prepareReceive(_size);\r
110                 _serverSocket = null;\r
111                 _action = 1;\r
112                 long iip = new Long(ip).longValue();\r
113                 int b1 = (int) (iip & 255);\r
114                 int b2 = (int) ((iip >> 8) & 255);\r
115                 int b3 = (int) ((iip >> 16) & 255);\r
116                 int b4 = (int) ((iip >> 24) & 255);\r
117                 ip = b4 + "." + b3 + "." + b2 + "." + b1;\r
118 \r
119                 try {\r
120                         _socket = _ircConfiguration.getSecurityProvider().getSocket(ip, new Integer(port).intValue());\r
121                         _is = new BufferedInputStream(_socket.getInputStream());\r
122                         _os = new BufferedOutputStream(_socket.getOutputStream());\r
123                         _thread = new Thread(this, "DCCFile thread");\r
124                         _thread.start();\r
125                 } catch (Exception e) {\r
126                         _ircConfiguration.internalError("receive failure", e, "plouf@pjirc.com");\r
127                 }\r
128 \r
129         }\r
130 \r
131         /**\r
132          * Send the file in passive mode.\r
133          * \r
134          * @return the string to send to the remote peer to initiate the transfert.\r
135          */\r
136         public String send() {\r
137                 _action = 2;\r
138                 _socket = null;\r
139                 try {\r
140                         _serverSocket = _ircConfiguration.getSecurityProvider().getServerSocket(0);\r
141                         int port = _serverSocket.getLocalPort();\r
142 \r
143                         InetAddress addr = _ircConfiguration.getSecurityProvider().getLocalHost();\r
144                         byte[] ip = addr.getAddress();\r
145 \r
146                         int b1 = ip[0];\r
147                         if (b1 < 0)\r
148                                 b1 += 256;\r
149                         int b2 = ip[1];\r
150                         if (b2 < 0)\r
151                                 b2 += 256;\r
152                         int b3 = ip[2];\r
153                         if (b3 < 0)\r
154                                 b3 += 256;\r
155                         int b4 = ip[3];\r
156                         if (b4 < 0)\r
157                                 b4 += 256;\r
158 \r
159                         long high = (b1 << 24) + (b2 << 16) + (b3 << 8) + b4;\r
160 \r
161                         _file.prepareSend();\r
162                         int size = _file.getSize();\r
163                         String sip = "" + high;\r
164                         _listening = false;\r
165                         _thread = new Thread(this, "DCCFile thread");\r
166                         _thread.start();\r
167                         while (!_listening)\r
168                                 Thread.yield();\r
169                         return sip + " " + port + " " + size;\r
170                 } catch (Exception e) {\r
171                         return "";\r
172                 }\r
173         }\r
174 \r
175         private void writeConf(OutputStream os, int v) throws IOException {\r
176                 os.write((v >> 24) & 255);\r
177                 os.write((v >> 16) & 255);\r
178                 os.write((v >> 8) & 255);\r
179                 os.write((v) & 255);\r
180                 os.flush();\r
181         }\r
182 \r
183         private int readConf(InputStream is) throws IOException {\r
184                 int b1 = is.read();\r
185                 if (b1 < 0)\r
186                         b1 += 256;\r
187                 int b2 = is.read();\r
188                 if (b2 < 0)\r
189                         b2 += 256;\r
190                 int b3 = is.read();\r
191                 if (b3 < 0)\r
192                         b3 += 256;\r
193                 int b4 = is.read();\r
194                 if (b4 < 0)\r
195                         b4 += 256;\r
196                 return (b1 << 24) + (b2 << 16) + (b3 << 8) + b4;\r
197         }\r
198 \r
199         private void connected() {\r
200                 _connected = true;\r
201                 _listeners.sendEventAsync("serverConnected", this);\r
202         }\r
203 \r
204         private void disconnected() {\r
205                 _connected = false;\r
206                 _listeners.sendEventAsync("serverDisconnected", this);\r
207         }\r
208 \r
209         @Override\r
210         public void run() {\r
211                 byte[] buffer = new byte[4096];\r
212                 if (_action == 1) // receive\r
213                 {\r
214                         try {\r
215                                 connected();\r
216                                 int read = 0;\r
217                                 while (_size - read > 0) {\r
218                                         int r = _is.read(buffer, 0, buffer.length);\r
219                                         if (r == -1)\r
220                                                 throw new Exception(getText(IRCTextProvider.DCC_STREAM_CLOSED));\r
221                                         read += r;\r
222                                         _file.bytesReceived(buffer, 0, r);\r
223                                         Thread.yield();\r
224                                         writeConf(_os, read);\r
225                                 }\r
226                                 writeConf(_os, _size);\r
227                                 _file.fileReceived();\r
228                         } catch (Exception e) {\r
229                                 e.printStackTrace();\r
230                                 _file.fileReceiveFailed();\r
231                         }\r
232                         disconnected();\r
233                         cleanup();\r
234                 } else if (_action == 2) // send\r
235                 {\r
236                         _listening = true;\r
237                         try {\r
238                                 _serverSocket.setSoTimeout(30000);\r
239                                 _socket = _serverSocket.accept();\r
240                                 _os = new BufferedOutputStream(_socket.getOutputStream());\r
241                                 _is = new BufferedInputStream(_socket.getInputStream());\r
242                                 connected();\r
243                                 int size = _file.getSize();\r
244                                 int toread = size;\r
245                                 int rec = 0;\r
246                                 while (toread > 0) {\r
247                                         int r = _file.readBytes(buffer, 0, buffer.length);\r
248                                         if (r < 0)\r
249                                                 throw new Exception(getText(IRCTextProvider.DCC_STREAM_CLOSED));\r
250                                         _os.write(buffer, 0, r);\r
251                                         toread -= r;\r
252 \r
253                                         if (_is.available() > 0)\r
254                                                 rec = readConf(_is);\r
255                                 }\r
256                                 _os.flush();\r
257                                 while (rec != size) {\r
258                                         rec = readConf(_is);\r
259                                 }\r
260                                 _os.close();\r
261                                 _file.fileSent();\r
262                         } catch (Exception e) {\r
263                                 e.printStackTrace();\r
264                                 _file.fileSentFailed();\r
265                         }\r
266                         disconnected();\r
267                         cleanup();\r
268 \r
269                 }\r
270         }\r
271 \r
272         private void cleanup() {\r
273                 try {\r
274                         if (_socket != null)\r
275                                 _socket.close();\r
276                         if (_serverSocket != null)\r
277                                 _serverSocket.close();\r
278                         _is.close();\r
279                         _os.close();\r
280                 } catch (Exception e) {\r
281                         _ircConfiguration.internalError("cleanup failure", e, "plouf@pjirc.com");\r
282                 }\r
283         }\r
284 \r
285         /**\r
286          * Close the current transfert.\r
287          */\r
288         public void close() {\r
289                 cleanup();\r
290         }\r
291 \r
292         @Override\r
293         public void say(String destination, String str) {\r
294                 // nothing here\r
295         }\r
296 \r
297         @Override\r
298         public void execute(String str) {\r
299                 // nothing here\r
300         }\r
301 \r
302         @Override\r
303         public void sendStatusMessage(String str) {\r
304                 // nothing here\r
305         }\r
306 \r
307         @Override\r
308         public String getNick() {\r
309                 return "";\r
310         }\r
311 \r
312         @Override\r
313         public String getUserName() {\r
314                 return "";\r
315         }\r
316 \r
317         @Override\r
318         public void connect() {\r
319                 // nothing here...\r
320         }\r
321 \r
322         @Override\r
323         public void disconnect() {\r
324                 close();\r
325         }\r
326 \r
327         @Override\r
328         public boolean isConnected() {\r
329                 return _connected;\r
330         }\r
331 \r
332         @Override\r
333         public Enumeration getSources() {\r
334                 Vector v = new Vector();\r
335                 if (_file != null)\r
336                         v.insertElementAt(_file, v.size());\r
337                 return v.elements();\r
338         }\r
339 \r
340         @Override\r
341         public void enumerateSourcesAsCreated(ServerListener l) {\r
342                 if (_file != null)\r
343                         l.sourceCreated(_file, this, new Boolean(true));\r
344         }\r
345 \r
346         @Override\r
347         public void enumerateSourcesAsRemoved(ServerListener l) {\r
348                 if (_file != null)\r
349                         l.sourceRemoved(_file, this);\r
350         }\r
351 \r
352         @Override\r
353         public void setDefaultSource(Source source) {\r
354                 // nothing here...\r
355         }\r
356 \r
357         @Override\r
358         public void addServerListener(ServerListener l) {\r
359                 _listeners.addListener(l);\r
360         }\r
361 \r
362         @Override\r
363         public void removeServerListener(ServerListener l) {\r
364                 _listeners.removeListener(l);\r
365         }\r
366 \r
367         @Override\r
368         public void leave() {\r
369                 disconnect();\r
370                 long time = System.currentTimeMillis();\r
371                 while (isConnected()) {\r
372                         try {\r
373                                 Thread.sleep(100);\r
374                                 if (System.currentTimeMillis() - time > 10000)\r
375                                         break;\r
376                         } catch (InterruptedException ex) {\r
377                                 // ignore it...\r
378                         }\r
379                 }\r
380                 _listeners.sendEvent("sourceRemoved", _file, this);\r
381                 _listeners.sendEvent("serverLeft", this);\r
382                 _file.release();\r
383         }\r
384 \r
385         @Override\r
386         public String getServerName() {\r
387                 return getNick();\r
388         }\r
389 }\r