1 /************************************************************
2 * Copyright *
3 * Portions of this software are Copyright (c) 1993 - 2002, *
4 * Chad Z. Hower (Kudzu) and the Indy Pit Crew *
5 * - http://www.nevrona.com/Indy/ *
6 ************************************************************/
7 package org.indy;
8
9 import java.io.ByteArrayInputStream;
10 import java.io.ByteArrayOutputStream;
11 import java.io.File;
12 import java.io.FileInputStream;
13 import java.io.FileNotFoundException;
14 import java.io.IOException;
15 import java.io.InputStream;
16 import java.io.UnsupportedEncodingException;
17
18 import org.indy.io.IOHandler;
19 import org.indy.io.IndyIOException;
20 import org.indy.io.MaxLineLengthExceededException;
21 import org.indy.io.NotConnectedException;
22 import org.indy.io.PeerDisconnectedException;
23 import org.indy.io.ReadTimedOutException;
24
25 import org.indy.util.IndyUtilities;
26 import org.indy.util.StringList;
27
28
29 /***
30 * Provides extended functionality for using {@link org.indy.IOHandler}s,
31 * such as reading and writing primitives, checking response codes and
32 * extracting RFC compliant messages.
33 *
34 *@author Owen Green
35 */
36 public class Connection extends IndyComponent {
37 /***
38 * The IOHandler used by this connection
39 */
40 protected IOHandler ioHandler;
41
42 /***
43 * Holds the result of the last command for reply checking
44 */
45 protected RFCReply lastCmdResult = new RFCReply();
46
47 /***
48 * Constructs a new instance of <code>TCPConnection</code>
49 *
50 * @param handler The IOHandler for this connection to use
51 */
52 public Connection(IOHandler handler) {
53 super();
54 ioHandler = handler;
55 }
56
57 /***
58 * Sets the maxLineLength attribute of the TCPConnection object
59 *
60 *@param newLen The new maxLineLength value
61 */
62 public void setMaxLineLength(int newLen) {
63 ioHandler.setMaximumLineLength(newLen);
64 }
65
66 /***
67 * Sets the timeout for read operations.
68 *
69 *@param timeout The new readTimeOut value
70 */
71 public void setReadTimeOut(int timeout) throws IndyIOException {
72 ioHandler.setReadTimeOut(timeout);
73 }
74
75 /***
76 * Sets the iOHandler attribute of the IdTCPConnection object
77 *
78 *@param handler The new iOHandler value
79 */
80 public void setIOHandler(IOHandler handler) {
81 if (handler == null) {
82 throw new NullPointerException();
83 }
84
85 ioHandler = handler;
86 }
87
88 /***
89 * Gets the maxLineLength attribute of the IdTCPConnection object
90 *
91 *@return The maxLineLength value
92 */
93 public int getMaximumLineLength() {
94 return ioHandler.getMaximumLineLength();
95 }
96
97 /***
98 * Returns the timeout for read operations.
99 *
100 *@return The readTimeOut value
101 *@returns The timeout for read operations, in milliseconds.
102 */
103 public int getReadTimeOut() throws IndyIOException {
104 return ioHandler.getReadTimeOut();
105 }
106
107 /***
108 * Checks whether this TCP connection is still connected.
109 *
110 *@return <code>true</code> if the connection is still active, false otherwise.
111 *@throws ConnectionClosedGracefullyException If the connection closes gracefully
112 */
113 public boolean isConnected() {
114 return (ioHandler == null) ? false : ioHandler.isConnected();
115 }
116
117 /***
118 * Gets the iOHandler attribute of the TCPConnection object
119 *
120 *@return The iOHandler value
121 */
122 public IOHandler getIOHandler() {
123 return ioHandler;
124 }
125
126 /***
127 *
128 * Reads lines from the connection into <code>dest</code> until <code>delim</code> is hit,
129 * and returns the number of lines read into <code>dest</code>
130 *
131 * @param dest The {@link Captureable} to add lines to
132 * @param delim The delimiter to used demarcate the message
133 * @param isRFCMessage Whether the incoming text should be treated as part of an RFC message
134 * @return The number of lines read
135 * @throws IndyIOException if an IO error occurs
136 * @throws ReadTimedOutException if the read operation times out
137 * @throws PeerDisconnectedException if the remote connection disconnects
138 * @throws MaxLineLengthExceededException if the maximum line lentgh is exceeded
139 * @throws NotConnectedException if not connected
140 */
141 protected final int performCapture(Capturable dest, String delim,
142 boolean isRFCMessage)
143 throws IndyIOException, ReadTimedOutException,
144 PeerDisconnectedException,
145 MaxLineLengthExceededException,
146 NotConnectedException {
147 if (dest == null) {
148 throw new NullPointerException();
149 }
150
151 int lineCount = 0;
152
153 doBeginWork(IndyComponent.WorkMode.READ);
154
155 try {
156 while (true) {
157 String s = readLine();
158
159 if (s.equals(delim)) {
160 break;
161 }
162
163 lineCount++;
164
165 //For RFC 822 retrives
166 if (isRFCMessage && s.startsWith("..")) {
167 s = s.substring(1);
168 }
169
170 dest.addLine(s);
171 }
172 }
173 finally {
174 doEndWork(IndyComponent.WorkMode.WRITE);
175
176 return lineCount;
177 }
178 }
179
180 /***
181 * Reads lines of text from the connection until into a {@link org.indy.util.StringList}
182 * delim is found and returns the number of lines read.
183 *
184 * @param strings The <code>StringList</code> to fill
185 * @param delim The delimter to read up to
186 * @param isRFC Whether the text should be interpreted as part of an RFC message
187 * @return The number of lines read
188 * @throws IndyIOException if an IO error occurs
189 * @throws ReadTimedOutException if the read operation times out
190 * @throws PeerDisconnectedException if the remote peer disconnects
191 * @throws MaxLineLengthExceededException if the maximum line length is exceeded
192 * @throws NotConnectedException if not connected
193 */
194 public final int capture(final StringList strings, String delim,
195 boolean isRFC) throws IndyIOException,
196 ReadTimedOutException,
197 PeerDisconnectedException,
198 MaxLineLengthExceededException,
199 NotConnectedException {
200 Capturable c = new Capturable() {
201 public void addLine(String s) {
202 strings.add(s);
203 }
204 };
205
206 return performCapture(c, delim, isRFC);
207 }
208
209 /***
210 * Reads lines of text from the connection into a <code>StringBuffer</code>
211 * until <code>delim</code> is found and returns the number of lines read.
212 *
213 * @param strings The <code>StringBuffer</code> to fill
214 * @param delim the delimiter to look for
215 * @param isRFC <code>true</code> if this should be treated as an RFC message
216 * @return the number of lines read
217 * @throws IndyIOException if an IO error occurs
218 * @throws ReadTimedOutException if the read operation times out
219 * @throws PeerDisconnectedException if the remote peer disconnects
220 * @throws MaxLineLengthExceededException if the maximum line length is exceeded
221 * @throws NotConnectedException if not connected
222 */
223 public final int capture(final StringBuffer strings, String delim,
224 boolean isRFC) throws IndyIOException,
225 ReadTimedOutException,
226 PeerDisconnectedException,
227 MaxLineLengthExceededException,
228 NotConnectedException {
229 Capturable c = new Capturable() {
230 public void addLine(String s) {
231 strings.append(s);
232 strings.append('\n');
233 }
234 };
235
236 return performCapture(c, delim, isRFC);
237 }
238
239 /***
240 * Resets this connection
241 */
242 protected void resetConnection() {
243 if (ioHandler != null) {
244 ioHandler.clearBuffer();
245 }
246 }
247
248 /***
249 * Disconnects this connection.
250 *
251 * @throws IndyIOException If an IO error occurs
252 */
253 public void disconnect() {
254 doStatus(Status.DISCONNECTING);
255 disconnectSocket();
256
257
258 // ioHandler = null;
259 doStatus(Status.DISCONNECTED);
260 }
261
262 /***
263 *
264 */
265 public void disconnectSocket() {
266 if (ioHandler != null) {
267 ioHandler.close();
268 }
269 }
270
271 /***
272 * Checks whether a numeric response code is within a desired
273 * list of responses. If so, the response is returned otherwise
274 * a {@link ProtocolException} is thrown.
275 *
276 * @param response The response being examined
277 * @param allowedResponses The allowed responses
278 * @return The response encountered
279 * @throws ProtocolException if the response is not in the allowed list
280 */
281 public int checkResponse(int response, int[] allowedResponses)
282 throws ProtocolException {
283 if (allowedResponses == null) {
284 throw new NullPointerException();
285 }
286
287 if (allowedResponses.length > 0) {
288 for (int i = 0; i < allowedResponses.length; i++) {
289 if (response == allowedResponses[i]) {
290 return response;
291 }
292 }
293
294 throw new ProtocolException(lastCmdResult);
295 }
296
297 return response;
298 }
299
300 /***
301 * Reads a response from the remote peer, typically
302 * of the form of a response code and some text,
303 * and checks that the code is within <code>allowedResponses</code>.
304 *
305 * If not a {@link ProtocolException} is thrown, otherwise the response
306 * encountered is returned.
307 *
308 * @param allowedResponses The response codes allowed
309 * @return The encountered response
310 * @throws PeerDisconnectedException If the remote host disconnects
311 * @throws ReadTimedOutException If the read operation times out
312 * @throws IndyIOException If an IO error occurs
313 * @throws ProtocolException If the response is not in allowed set
314 * @throws MaxLineLengthExceededException If the maximum line length is exceeded
315 * @throws NotConnectedException If not connected
316 */
317 public int getResponse(int[] allowedResponses)
318 throws PeerDisconnectedException, ReadTimedOutException,
319 IndyIOException, ProtocolException,
320 MaxLineLengthExceededException, NotConnectedException {
321 getInternalResponse();
322
323 return checkResponse(lastCmdResult.getNumericCode(), allowedResponses);
324 }
325
326 /***
327 * Retreives a response from the connection using {@link getInternalResponse}
328 * and checks it for validity. This is an alias for {@link getResponse(int[])}
329 *
330 * @param allowedResponse The expected response
331 * @return The response, if found
332 * @throws PeerDisconnectedException if the remote peer disconnected
333 * @throws ReadTimedOutException if the read operation timed out
334 * @throws IndyIOException if an IO error occured
335 * @throws ProtocolException if the desired response was not returned
336 * @throws MaxLineLengthExceededException if the maximum line length was exceeded
337 * @throws NotConnectedException if not connected
338 */
339 public int getResponse(int allowedResponse) throws PeerDisconnectedException,
340 ReadTimedOutException,
341 IndyIOException,
342 ProtocolException,
343 MaxLineLengthExceededException,
344 NotConnectedException {
345 return getResponse(new int[] { allowedResponse });
346 }
347
348 /***
349 * Used to implement the processing required for {@link getResponse(int[])}.
350 * A response, typically expected to be comptrised of a three digit code and
351 * some text is read and stored using {@link readLineWait()}
352 *
353 * @throws IndyIOException if an IO error occurs
354 * @throws ReadTimedOutException if the read operation times out
355 * @throws PeerDisconnectedException if the remote peer disconnectes
356 * @throws MaxLineLengthExceededException if the maximum line length is exceeded
357 * @throws NotConnectedException if not connected
358 */
359 protected void getInternalResponse() throws IndyIOException,
360 ReadTimedOutException,
361 PeerDisconnectedException,
362 MaxLineLengthExceededException,
363 NotConnectedException {
364 StringList response = new StringList();
365 String line = readLineWait();
366
367 response.add(line);
368
369 if (line.length() > 3) {
370 if (line.charAt(4) == '-') {
371 String term = line.substring(1, 4) + " ";
372
373 while ((line.length() > 4) && !line.substring(1, 5).equals(term)) {
374 line = readLineWait();
375 response.add(line);
376 }
377 }
378 }
379
380 lastCmdResult.parseResponse(response);
381 }
382
383 /***
384 * Invokes {@link readLine} and will allow upto
385 * <code>failCount</code> time outs before throwing
386 * {@link ReadTimedOutException}.
387 *
388 * @param failCount The number of time outs to allow before failing
389 * @return A line of text from the connection.
390 * @throws IndyIOException If an IO error occurs.
391 * @throws ReadTimedOutException If the operation times out more than <code>failCount</code> times
392 * @throws PeerDisconnectedException If the remote peer disconnects
393 * @throws MaxLineLengthExceededException If the maximum line length is exceeded
394 * @throws NotConnectedException If not connected
395 */
396 public String readLineWait(int failCount) throws IndyIOException,
397 ReadTimedOutException,
398 PeerDisconnectedException,
399 MaxLineLengthExceededException,
400 NotConnectedException {
401 StringBuffer sb = new StringBuffer();
402 int attempts = 0;
403
404 while ((sb.length() == 0) && (attempts < failCount)) {
405 attempts++;
406
407 try {
408 sb.append(readLine());
409 }
410 catch (ReadTimedOutException ex) {
411 if (attempts >= failCount) {
412 throw ex;
413 }
414 }
415 }
416
417 return sb.toString();
418 }
419
420 /***
421 * DOCUMENT ME!
422 *
423 * @return DOCUMENT ME!
424 *
425 * @throws IndyIOException DOCUMENT ME!
426 * @throws ReadTimedOutException DOCUMENT ME!
427 * @throws PeerDisconnectedException DOCUMENT ME!
428 * @throws MaxLineLengthExceededException DOCUMENT ME!
429 * @throws NotConnectedException DOCUMENT ME!
430 */
431 public String readLineWait() throws IndyIOException, ReadTimedOutException,
432 PeerDisconnectedException,
433 MaxLineLengthExceededException,
434 NotConnectedException {
435 return readLineWait(Integer.MAX_VALUE);
436 }
437
438 /***
439 * Reads a line of text from the connection.
440 * This wraps {@link org.indy.io.IOHandler#readLine()}/
441 *
442 * @return A line of text from the connection
443 * @throws PeerDisconnectedException If the remote peer disconnects
444 * @throws ReadTimedOutException If the read operation times out
445 * @throws IndyIOException If an IO error occurs
446 * @throws MaxLineLengthExceededException If the maximum line length is exceeded
447 * @throws NotConnectedException If not connected
448 */
449 public String readLine() throws PeerDisconnectedException,
450 ReadTimedOutException, IndyIOException,
451 MaxLineLengthExceededException,
452 NotConnectedException {
453 return ioHandler.readLine();
454 }
455
456 /***
457 *Reads a line of text from the connection. This wraps
458 * {@link org.indy.io.IOHandler#readLine(int,int)}
459 *
460 * @param timeout The timeout to allow for this read operation
461 * @param maxLineLength The maximum line lentgh to accept
462 * @return A line of text from this connection
463 * @throws IndyIOException If an IO error occurs
464 * @throws ReadTimedOutException If the operation times out
465 * @throws PeerDisconnectedException If the remote peer disonnects
466 * @throws MaxLineLengthExceededException If the maximum line length is exceeded
467 * @throws NotConnectedException If not connected
468 */
469 public String readLine(int timeout, int maxLineLength)
470 throws IndyIOException, ReadTimedOutException,
471 PeerDisconnectedException, NotConnectedException,
472 MaxLineLengthExceededException {
473 if (!isConnected()) {
474 throw new NotConnectedException(IndyUtilities.getResourceString(
475 "RSNotConnected"));
476 }
477
478 return ioHandler.readLine(timeout, maxLineLength, null);
479 }
480
481 /***
482 * Fills a buffer, <code>b</code>, with up to <code>len</code> bytes of
483 * data from the connection.
484 *
485 * @param b The buffer to fill
486 * @param len The amount of data to read
487 * @return The actual amount of data read
488 * @throws PeerDisconnectedException If the remote peer disconnects
489 * @throws ReadTimedOutException If the read operation times out
490 * @throws IndyIOException If an IOError occurs
491 * @throws NotConnectedException if not connected
492 */
493 public final int readBuffer(byte[] b, int len)
494 throws PeerDisconnectedException, ReadTimedOutException,
495 IndyIOException, NotConnectedException {
496 if (b == null) {
497 throw new NullPointerException(IndyUtilities.getResourceString(
498 "RSNullBuffer"));
499 }
500
501 if ((len > b.length) || (len < 1)) {
502 throw new IllegalArgumentException(IndyUtilities.getResourceString(
503 "RSBufferBoundsFail"));
504 }
505
506 return ioHandler.read(b, 0, len);
507 }
508
509 /***
510 * Reads an <code>int</code> from this connection.
511 *
512 * @return An <code>int</code>
513 * @throws PeerDisconnectedException If the remote peer disconnects
514 * @throws ReadTimedOutException If the read operation timed out
515 * @throws IndyIOException If an IO error occurs.
516 * @throws NotConnectedException If not connected
517 */
518 public final int readInt() throws PeerDisconnectedException,
519 ReadTimedOutException, IndyIOException,
520 NotConnectedException {
521 byte[] b = new byte[4];
522
523 ioHandler.read(b, 0, 4);
524
525 return (b[0] << 24) + (b[1] << 16) + (b[2] << 8) + b[3];
526 }
527
528 /***
529 * Reads a <code>long</code> from the connection
530 *
531 * @return A <code>long</code> from the connection
532 * @throws PeerDisconnectedException If the remote peer disconnects
533 * @throws ReadTimedOutException If the read operation times out
534 * @throws NotConnectedException If not connected
535 * @throws IndyIOException If an IO error occurs
536 */
537 public final long readLong() throws PeerDisconnectedException,
538 ReadTimedOutException, IndyIOException,
539 NotConnectedException {
540 byte[] buf = new byte[8];
541
542 ioHandler.read(buf, 0, 8);
543
544 return ((buf[0] & 0xFFL) << 56) + ((buf[1] & 0xFFL) << 48) +
545 ((buf[2] & 0xFFL) << 40) + ((buf[3] & 0xFFL) << 32) +
546 ((buf[4] & 0xFFL) << 24) + ((buf[5] & 0xFFL) << 16) +
547 ((buf[6] & 0xFFL) << 8) + ((buf[7] & 0xFFL) << 0);
548 }
549
550 /***
551 * Read a <code>char</code> from the connection
552 *
553 * @return A <code>char</code> from the connection
554 * @throws PeerDisconnectedException If the remote peer disconnects
555 * @throws ReadTimedOutException If the read operation times out
556 * @throws NotConnectedException If not connected
557 * @throws IndyIOException If an IO error occurs
558 */
559 public final char readChar() throws PeerDisconnectedException,
560 ReadTimedOutException, IndyIOException,
561 NotConnectedException {
562 byte[] b = new byte[2];
563
564 readBuffer(b, 2);
565
566 return (char) ((b[0] << 8) + (b[1] << 0));
567 }
568
569 /***
570 * Reads a short from the connection
571 *
572 * @return A <code>short</code> from the connection
573 * @throws PeerDisconnectedException If the remote peer disconnects
574 * @throws ReadTimedOutException If the read operation times out
575 * @throws NotConnectedException If not connected
576 * @throws IndyIOException If an IO error occurs
577 */
578 public final short readShort() throws PeerDisconnectedException,
579 ReadTimedOutException, IndyIOException,
580 NotConnectedException {
581 return (short) readChar();
582 }
583
584 /***
585 * Reads bytes from the socket and returns them in an InputStream.
586 * If readUntilDisconnect is true, then the method will block and return only when the connection has closed (or if an exception is thrown).
587 * If readUntilDisconnect is false, then byteCount bytes will be read.
588 * If readUntilDisconnect is false and byteCount = -1 then the first 4 bytes read from the socket will be assumed to be an integer representing the stream size, and this number of bytes will be read.
589 *
590 * @param byteCount The number of bytes to read
591 * @param readUntilDisconnect Whether <code>byteCount</code> should be ignored and the read operation should contniue until disconnected
592 * @return An <code>InputStream</code> containing bytes from the connection.
593 * @throws PeerDisconnectedException If the remote peer disconnects
594 * @throws ReadTimedOutException If the read operation times out
595 * @throws NotConnectedException If not connected
596 * @throws IndyIOException If an IO error occurs
597 */
598 public final InputStream readStream(int byteCount,
599 boolean readUntilDisconnect)
600 throws PeerDisconnectedException,
601 ReadTimedOutException,
602 NotConnectedException, IndyIOException {
603 if ((byteCount == -1) && (!readUntilDisconnect)) {
604 /*** @todo This should probably nuke if the result is negative */
605 byteCount = readInt();
606 }
607
608 if (readUntilDisconnect) {
609 return new ByteArrayInputStream(readTillDisconnect());
610 }
611 else {
612 byte[] bytes = new byte[byteCount];
613
614 readBuffer(bytes, byteCount);
615
616 return new ByteArrayInputStream(bytes);
617 }
618 }
619
620 /***
621 * Write the contents of a {@link org.indy.util.StringList} instance
622 * to this connection.
623 *
624 * This method ensures that individual lines in <code>strings</code> beginning
625 * with the response termination character '.' are converted to '..',
626 * and call WriteLn using the updated values. When all lines have been
627 * written, WriteRFCStrings calls WriteLn to send the '.' termination
628 * character to indicate the end of RFC response messages
629 *
630 * @param strings A <code>StringList</code> to write
631 * @throws IndyIOException If an IO error occurs
632 * @throws NotConnectedException If not connected
633 */
634 public final void writeRFCStrings(StringList strings)
635 throws IndyIOException {
636 for (int i = 0, n = strings.size(); i < n; i++) {
637 if (strings.get(i).equals(".")) {
638 writeLine("..");
639 }
640 else {
641 writeLine(strings.get(i));
642 }
643 }
644
645 writeLine(".");
646 }
647
648 /***
649 * Write an {@link org.indy.RFCReply} to this connection.
650 *
651 * @param reply The <code>RFCReply</code> to write
652 * @throws IndyIOException If an IO error occurs
653 * @throws NotConnectedException If not connected
654 */
655 public final void writeRFCReply(RFCReply reply) throws IndyIOException {
656 if (reply.replyExists()) {
657 write(reply.generateReply());
658 }
659 }
660
661 /***
662 * Write a <code>String</code> to this connection.
663 *
664 * @param s The <code>String</code> to write
665 * @throws IndyIOException If an IO error occurs
666 * @throws NotConnectedException If not connected
667 */
668 public final void write(String s) throws IndyIOException,
669 NotConnectedException {
670 if ((s != null) && (s.length() > 0)) {
671 writeBuffer(s.getBytes());
672 }
673 }
674
675 /***
676 * Write a buffer of bytes to this connection.
677 *
678 * @param buf The bytes to write
679 * @throws IndyIOException If an IO error occurs
680 * @throws NotConnectedException If not connected
681 */
682 public final void writeBuffer(byte[] buf) throws IndyIOException,
683 NotConnectedException {
684 if (!isConnected()) {
685 throw new NotConnectedException(IndyUtilities.getResourceString(
686 "RSNotConnected"));
687 }
688
689 if ((buf != null) && (buf.length > 0)) {
690 /*
691 * This could possibly do with changing?
692 */
693 try {
694 for (int i = 0; i < buf.length; i++) {
695 ioHandler.write(buf[i]);
696 doWork(IndyComponent.WorkMode.WRITE, i);
697 }
698
699 ioHandler.flush();
700 }
701 catch (IndyIOException ioe) {
702 disconnectSocket();
703 throw ioe;
704 }
705 }
706 }
707
708 /***
709 * Write a line of text to the connection.
710 *
711 * @param line The text to write as a line
712 * @throws IndyIOException If an IO error occurs
713 * @throws NotConnectedException If not connected
714 */
715 public final void writeLine(String line) throws IndyIOException {
716 /*** @todo Fix to use prop EOL */
717 write(line + "\n");
718 ioHandler.flush();
719 }
720
721 /***
722 * Write the contents of a {@link org.indy.util.StringList}
723 * as an RFC header, translating strings of the form
724 * <pre>name=value</pre>
725 * to
726 * <pre>name:value</pre>
727 *
728 *
729 * @todo This seems a silly way of doing it - why not use <code>java.util.Map</code>?
730 * @param header The <code>StringList</code> to write as a header
731 * @throws IndyIOException If an IO error occurs
732 * @throws NotConnectedException If not connected
733 */
734 public final void writeHeader(StringList header) throws IndyIOException {
735 if (header == null) {
736 throw new NullPointerException();
737 }
738
739 for (int i = 0, n = header.size(); i < n; i++) {
740 String line = header.get(i);
741 int pos = line.indexOf('=');
742
743 writeLine(line.substring(0, pos) + ": " + line.substring(pos + 1));
744 }
745 }
746
747 /***
748 * @throws IndyIOException If an IO error occurs
749 * @throws NotConnectedException If not connected
750 *
751 * @param value The <code>int</code> to write
752 * @throws IndyIOException If an IO error occurs
753 * @throws NotConnectedException If not connected
754 */
755 public final void writeInt(int value) throws IndyIOException {
756 ioHandler.write((value >>> 24) & 0xFF);
757 ioHandler.write((value >>> 16) & 0xFF);
758 ioHandler.write((value >>> 8) & 0xFF);
759 ioHandler.write((value >>> 0) & 0xFF);
760 }
761
762 /***
763 * Write a <code>long</code> to the connection
764 *
765 * @param value The <code>long</code> to write
766 * @throws IndyIOException If an IO error occurs
767 * @throws NotConnectedException If not connected
768 */
769 public final void writeLong(long value) throws IndyIOException {
770 byte[] buf = new byte[8];
771 int mask = 0xFF;
772
773 for (int i = 0; i < 8; i++) {
774 buf[i] = (byte) ((value & (mask << (8 * i))) >> (8 * i));
775 }
776
777 writeBuffer(buf);
778 }
779
780 /***
781 * Write a <code>short</code> to the connection
782 * @param value The <code>short</code> to write
783 * @throws IndyIOException If an IO error occurs
784 * @throws NotConnectedException If not connected
785 */
786 public final void writeShort(short value) throws IndyIOException {
787 writeBuffer(
788 new byte[] { (byte) ((value & 0xFF00) >> 8), (byte) (value & 0xFF) });
789 }
790
791 /***
792 * Write a the contents of a {@link org.indy.util.StringList} instance
793 * to the connection as individual lines.
794 *
795 * @param strings The <code>StringList</code> to write
796 * @param writeLineCount Whether to prepend the text with a int representing the number of lines
797 * @throws IndyIOException If an IO error occurs
798 * @throws NotConnectedException If not connected
799 */
800 public final void writeStrings(StringList strings, boolean writeLineCount)
801 throws IndyIOException {
802 if (writeLineCount) {
803 writeInt(strings.size());
804 }
805
806 for (int i = 0, n = strings.size(); i < n; i++) {
807 writeLine(strings.get(i));
808 }
809 }
810
811 /***
812 * Writes the contents of an <code>InputStream</code> to the connection
813 *
814 * @param stream The <code>InputStream</code> to write
815 * @param len The number of bytes to write
816 * @param writeByteCount Whether the bytes should be prepended with an int representing the byte count
817 * @throws IndyIOException If an IO error occurs
818 * @throws NotConnectedException If not connected
819 */
820 public final void writeStream(InputStream stream, int len,
821 boolean writeByteCount)
822 throws IndyIOException {
823 doBeginWork(IndyComponent.WorkMode.WRITE, len);
824
825 try {
826 if (writeByteCount) {
827 writeInt(len);
828 }
829
830 /*** @todo Must do better - this will be horrible for large data sets */
831 byte[] buf = new byte[len];
832
833 stream.read(buf);
834 writeBuffer(buf);
835 }
836 catch (IOException ioe) {
837 throw new IndyIOException(ioe);
838 }
839 finally {
840 doEndWork(IndyComponent.WorkMode.WRITE);
841 }
842 }
843
844 /***
845 * Writes a <code>File</code> object to the stream
846 *
847 * @param f The <code>File</code> to write
848 * @throws FileNotFoundException If the <code>File</code> doesn't exist
849 * @throws IndyIOException If an IO error occurs
850 * @throws NotConnectedException If not connected
851 */
852 public final void writeFile(File f) throws FileNotFoundException,
853 IndyIOException {
854 if (!f.exists()) {
855 throw new FileNotFoundException(f.getName());
856 }
857
858 writeStream(new FileInputStream(f), (int) f.length(), true);
859 }
860
861 /***
862 * Returns the current data that can be read without blocking.
863 *
864 * This wraps {@link org.indy.io.IOHandler#currentReadBuffer()}
865 *
866 * @return The data from the read buffer
867 * @throws PeerDisconnectedException If the remote peer has disconnected
868 * @throws ReadTimedOutException If the read operation times out
869 * @throws IndyIOException If an IO error occurs
870 * @throws NotConnectedException If not connected
871 */
872 public final byte[] currentReadBuffer() throws PeerDisconnectedException,
873 IndyIOException {
874 return ioHandler.currentReadBuffer();
875 }
876
877 /***
878 * DOCUMENT ME!
879 *
880 * @return DOCUMENT ME!
881 *
882 * @throws PeerDisconnectedException DOCUMENT ME!
883 * @throws ReadTimedOutException DOCUMENT ME!
884 * @throws IndyIOException DOCUMENT ME!
885 */
886 protected byte[] readTillDisconnect() throws PeerDisconnectedException,
887 ReadTimedOutException,
888 IndyIOException {
889 doBeginWork(IndyComponent.WorkMode.READ);
890
891 boolean timeoutChanged = false;
892 final ByteArrayOutputStream bytes = new ByteArrayOutputStream();
893
894 try {
895 while (true) {
896 try {
897 bytes.write(currentReadBuffer());
898 }
899 catch (PeerDisconnectedException e) {
900 break;
901 }
902 catch (IOException ex) {
903 throw new IndyIOException(ex);
904 }
905 }
906
907 return bytes.toByteArray();
908 }
909 finally {
910 doEndWork(IndyComponent.WorkMode.READ);
911 }
912 }
913
914 /***
915 * Reads all data from the connection until disconnection occurs,
916 * and returns it as a <code>String</code> using the platform character
917 * encoding.
918 *
919 * This is equivalent to <code>allData(null)</code>.
920 *
921 * @return A string representing all read data from the connection
922 * @throws ReadTimedOutException If the read operation times out
923 * @throws IndyIOException If an IO error occurs
924 * @throws NotConnectedException If not connected
925 * @see allData(String)
926 */
927 public String allData() throws ReadTimedOutException, IndyIOException,
928 NotConnectedException {
929 return allData(null);
930 }
931
932 /***
933 * Reads all data from the connection until disconnection occurs,
934 * and returns it as a <code>String</code> using the character
935 * encoding specified by <code>encoding</code>, or the platform default
936 * if <code>encoding</code> is <code>null</code>.
937 *
938 * @param encoding The character encoding to use
939 * @return A string representing all read data from the connection
940 * @throws IndyIOException If an IO error occurs
941 * @throws ReadTimedOutException If the read operation times out
942 * @throws NotConnectedException If not connected
943 */
944 public String allData(String encoding) throws IndyIOException,
945 ReadTimedOutException,
946 NotConnectedException {
947 try {
948 return (encoding == null)
949 ? new String(readTillDisconnect())
950 : new String(readTillDisconnect(), encoding);
951 }
952 catch (UnsupportedEncodingException ex) {
953 throw new IndyIOException(ex);
954 }
955 }
956
957 /***
958 * An interface that supports having lines of text input to it.
959 */
960 protected interface Capturable {
961 void addLine(String s);
962 }
963 }
This page was automatically generated by Maven