%line | %branch | |||||||||
---|---|---|---|---|---|---|---|---|---|---|
org.apache.commons.net.telnet.Telnet |
|
|
1 | /* |
|
2 | * Copyright 2003-2004 The Apache Software Foundation |
|
3 | * |
|
4 | * Licensed under the Apache License, Version 2.0 (the "License"); |
|
5 | * you may not use this file except in compliance with the License. |
|
6 | * You may obtain a copy of the License at |
|
7 | * |
|
8 | * http://www.apache.org/licenses/LICENSE-2.0 |
|
9 | * |
|
10 | * Unless required by applicable law or agreed to in writing, software |
|
11 | * distributed under the License is distributed on an "AS IS" BASIS, |
|
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
13 | * See the License for the specific language governing permissions and |
|
14 | * limitations under the License. |
|
15 | */ |
|
16 | package org.apache.commons.net.telnet; |
|
17 | ||
18 | import java.io.BufferedInputStream; |
|
19 | import java.io.BufferedOutputStream; |
|
20 | import java.io.OutputStream; |
|
21 | import java.io.IOException; |
|
22 | import org.apache.commons.net.SocketClient; |
|
23 | ||
24 | /** |
|
25 | * @author Daniel F. Savarese |
|
26 | * @author Bruno D'Avanzo |
|
27 | */ |
|
28 | ||
29 | class Telnet extends SocketClient |
|
30 | { |
|
31 | static final boolean debug = /*true;*/ false; |
|
32 | ||
33 | static final boolean debugoptions = /*true;*/ false; |
|
34 | ||
35 | 1 | static final byte[] _COMMAND_DO = { |
36 | (byte)TelnetCommand.IAC, (byte)TelnetCommand.DO |
|
37 | }; |
|
38 | ||
39 | 1 | static final byte[] _COMMAND_DONT = { |
40 | (byte)TelnetCommand.IAC, (byte)TelnetCommand.DONT |
|
41 | }; |
|
42 | ||
43 | 1 | static final byte[] _COMMAND_WILL = { |
44 | (byte)TelnetCommand.IAC, (byte)TelnetCommand.WILL |
|
45 | }; |
|
46 | ||
47 | 1 | static final byte[] _COMMAND_WONT = { |
48 | (byte)TelnetCommand.IAC, (byte)TelnetCommand.WONT |
|
49 | }; |
|
50 | ||
51 | 1 | static final byte[] _COMMAND_SB = { |
52 | (byte)TelnetCommand.IAC, (byte)TelnetCommand.SB |
|
53 | }; |
|
54 | ||
55 | 1 | static final byte[] _COMMAND_SE = { |
56 | (byte)TelnetCommand.IAC, (byte)TelnetCommand.SE |
|
57 | }; |
|
58 | ||
59 | static final int _WILL_MASK = 0x01, _DO_MASK = 0x02, |
|
60 | _REQUESTED_WILL_MASK = 0x04, _REQUESTED_DO_MASK = 0x08; |
|
61 | ||
62 | /* public */ |
|
63 | static final int DEFAULT_PORT = 23; |
|
64 | ||
65 | int[] _doResponse, _willResponse, _options; |
|
66 | ||
67 | /* TERMINAL-TYPE option (start)*/ |
|
68 | /*** |
|
69 | * Terminal type option |
|
70 | ***/ |
|
71 | protected static final int TERMINAL_TYPE = 24; |
|
72 | ||
73 | /*** |
|
74 | * Send (for subnegotiation) |
|
75 | ***/ |
|
76 | protected static final int TERMINAL_TYPE_SEND = 1; |
|
77 | ||
78 | /*** |
|
79 | * Is (for subnegotiation) |
|
80 | ***/ |
|
81 | protected static final int TERMINAL_TYPE_IS = 0; |
|
82 | ||
83 | /*** |
|
84 | * Is sequence (for subnegotiation) |
|
85 | ***/ |
|
86 | 1 | static final byte[] _COMMAND_IS = { |
87 | (byte) TERMINAL_TYPE, (byte) TERMINAL_TYPE_IS |
|
88 | }; |
|
89 | ||
90 | /*** |
|
91 | * Terminal type |
|
92 | ***/ |
|
93 | 32 | private String terminalType = null; |
94 | /* TERMINAL-TYPE option (end)*/ |
|
95 | ||
96 | /* open TelnetOptionHandler functionality (start)*/ |
|
97 | /*** |
|
98 | * Array of option handlers |
|
99 | ***/ |
|
100 | private TelnetOptionHandler optionHandlers[]; |
|
101 | ||
102 | /* open TelnetOptionHandler functionality (end)*/ |
|
103 | ||
104 | /* Code Section added for supporting AYT (start)*/ |
|
105 | /*** |
|
106 | * AYT sequence |
|
107 | ***/ |
|
108 | 1 | static final byte[] _COMMAND_AYT = { |
109 | (byte) TelnetCommand.IAC, (byte) TelnetCommand.AYT |
|
110 | }; |
|
111 | ||
112 | /*** |
|
113 | * monitor to wait for AYT |
|
114 | ***/ |
|
115 | 32 | private Object aytMonitor = new Object(); |
116 | ||
117 | /*** |
|
118 | * flag for AYT |
|
119 | ***/ |
|
120 | 32 | private boolean aytFlag = true; |
121 | /* Code Section added for supporting AYT (end)*/ |
|
122 | ||
123 | /*** |
|
124 | * The stream on which to spy |
|
125 | ***/ |
|
126 | 32 | private OutputStream spyStream = null; |
127 | ||
128 | /*** |
|
129 | * The notification handler |
|
130 | ***/ |
|
131 | 32 | private TelnetNotificationHandler __notifhand = null; |
132 | /*** |
|
133 | * Empty Constructor |
|
134 | ***/ |
|
135 | Telnet() |
|
136 | 0 | { |
137 | 0 | setDefaultPort(DEFAULT_PORT); |
138 | 0 | _doResponse = new int[TelnetOption.MAX_OPTION_VALUE + 1]; |
139 | 0 | _willResponse = new int[TelnetOption.MAX_OPTION_VALUE + 1]; |
140 | 0 | _options = new int[TelnetOption.MAX_OPTION_VALUE + 1]; |
141 | 0 | optionHandlers = |
142 | new TelnetOptionHandler[TelnetOption.MAX_OPTION_VALUE + 1]; |
|
143 | 0 | } |
144 | ||
145 | /* TERMINAL-TYPE option (start)*/ |
|
146 | /*** |
|
147 | * This constructor lets you specify the terminal type. |
|
148 | * <p> |
|
149 | * @param termtype - terminal type to be negotiated (ej. VT100) |
|
150 | ***/ |
|
151 | Telnet(String termtype) |
|
152 | 32 | { |
153 | 32 | setDefaultPort(DEFAULT_PORT); |
154 | 32 | _doResponse = new int[TelnetOption.MAX_OPTION_VALUE + 1]; |
155 | 32 | _willResponse = new int[TelnetOption.MAX_OPTION_VALUE + 1]; |
156 | 32 | _options = new int[TelnetOption.MAX_OPTION_VALUE + 1]; |
157 | 32 | terminalType = termtype; |
158 | 32 | optionHandlers = |
159 | new TelnetOptionHandler[TelnetOption.MAX_OPTION_VALUE + 1]; |
|
160 | 32 | } |
161 | /* TERMINAL-TYPE option (end)*/ |
|
162 | ||
163 | /*** |
|
164 | * Looks for the state of the option. |
|
165 | * <p> |
|
166 | * @return returns true if a will has been acknowledged |
|
167 | * <p> |
|
168 | * @param option - option code to be looked up. |
|
169 | ***/ |
|
170 | boolean _stateIsWill(int option) |
|
171 | { |
|
172 | 35 | return ((_options[option] & _WILL_MASK) != 0); |
173 | } |
|
174 | ||
175 | /*** |
|
176 | * Looks for the state of the option. |
|
177 | * <p> |
|
178 | * @return returns true if a wont has been acknowledged |
|
179 | * <p> |
|
180 | * @param option - option code to be looked up. |
|
181 | ***/ |
|
182 | boolean _stateIsWont(int option) |
|
183 | { |
|
184 | 1 | return !_stateIsWill(option); |
185 | } |
|
186 | ||
187 | /*** |
|
188 | * Looks for the state of the option. |
|
189 | * <p> |
|
190 | * @return returns true if a do has been acknowledged |
|
191 | * <p> |
|
192 | * @param option - option code to be looked up. |
|
193 | ***/ |
|
194 | boolean _stateIsDo(int option) |
|
195 | { |
|
196 | 23 | return ((_options[option] & _DO_MASK) != 0); |
197 | } |
|
198 | ||
199 | /*** |
|
200 | * Looks for the state of the option. |
|
201 | * <p> |
|
202 | * @return returns true if a dont has been acknowledged |
|
203 | * <p> |
|
204 | * @param option - option code to be looked up. |
|
205 | ***/ |
|
206 | boolean _stateIsDont(int option) |
|
207 | { |
|
208 | 3 | return !_stateIsDo(option); |
209 | } |
|
210 | ||
211 | /*** |
|
212 | * Looks for the state of the option. |
|
213 | * <p> |
|
214 | * @return returns true if a will has been reuqested |
|
215 | * <p> |
|
216 | * @param option - option code to be looked up. |
|
217 | ***/ |
|
218 | boolean _requestedWill(int option) |
|
219 | { |
|
220 | 67 | return ((_options[option] & _REQUESTED_WILL_MASK) != 0); |
221 | } |
|
222 | ||
223 | /*** |
|
224 | * Looks for the state of the option. |
|
225 | * <p> |
|
226 | * @return returns true if a wont has been reuqested |
|
227 | * <p> |
|
228 | * @param option - option code to be looked up. |
|
229 | ***/ |
|
230 | boolean _requestedWont(int option) |
|
231 | { |
|
232 | 24 | return !_requestedWill(option); |
233 | } |
|
234 | ||
235 | /*** |
|
236 | * Looks for the state of the option. |
|
237 | * <p> |
|
238 | * @return returns true if a do has been reuqested |
|
239 | * <p> |
|
240 | * @param option - option code to be looked up. |
|
241 | ***/ |
|
242 | boolean _requestedDo(int option) |
|
243 | { |
|
244 | 25 | return ((_options[option] & _REQUESTED_DO_MASK) != 0); |
245 | } |
|
246 | ||
247 | /*** |
|
248 | * Looks for the state of the option. |
|
249 | * <p> |
|
250 | * @return returns true if a dont has been reuqested |
|
251 | * <p> |
|
252 | * @param option - option code to be looked up. |
|
253 | ***/ |
|
254 | boolean _requestedDont(int option) |
|
255 | { |
|
256 | 5 | return !_requestedDo(option); |
257 | } |
|
258 | ||
259 | /*** |
|
260 | * Sets the state of the option. |
|
261 | * <p> |
|
262 | * @param option - option code to be set. |
|
263 | ***/ |
|
264 | void _setWill(int option) |
|
265 | { |
|
266 | 13 | _options[option] |= _WILL_MASK; |
267 | ||
268 | /* open TelnetOptionHandler functionality (start)*/ |
|
269 | 13 | if (_requestedWill(option)) |
270 | { |
|
271 | 8 | if (optionHandlers[option] != null) |
272 | { |
|
273 | 7 | optionHandlers[option].setWill(true); |
274 | ||
275 | 7 | int subneg[] = |
276 | optionHandlers[option].startSubnegotiationLocal(); |
|
277 | ||
278 | 7 | if (subneg != null) |
279 | { |
|
280 | try |
|
281 | { |
|
282 | 0 | _sendSubnegotiation(subneg); |
283 | } |
|
284 | 0 | catch (Exception e) |
285 | { |
|
286 | 0 | System.err.println( |
287 | "Exception in option subnegotiation" |
|
288 | + e.getMessage()); |
|
289 | 0 | } |
290 | } |
|
291 | } |
|
292 | } |
|
293 | /* open TelnetOptionHandler functionality (end)*/ |
|
294 | 13 | } |
295 | ||
296 | /*** |
|
297 | * Sets the state of the option. |
|
298 | * <p> |
|
299 | * @param option - option code to be set. |
|
300 | ***/ |
|
301 | void _setDo(int option) |
|
302 | { |
|
303 | 5 | _options[option] |= _DO_MASK; |
304 | ||
305 | /* open TelnetOptionHandler functionality (start)*/ |
|
306 | 5 | if (_requestedDo(option)) |
307 | { |
|
308 | 1 | if (optionHandlers[option] != null) |
309 | { |
|
310 | 1 | optionHandlers[option].setDo(true); |
311 | ||
312 | 1 | int subneg[] = |
313 | optionHandlers[option].startSubnegotiationRemote(); |
|
314 | ||
315 | 1 | if (subneg != null) |
316 | { |
|
317 | try |
|
318 | { |
|
319 | 0 | _sendSubnegotiation(subneg); |
320 | } |
|
321 | 0 | catch (Exception e) |
322 | { |
|
323 | 0 | System.err.println("Exception in option subnegotiation" |
324 | + e.getMessage()); |
|
325 | 0 | } |
326 | } |
|
327 | } |
|
328 | } |
|
329 | /* open TelnetOptionHandler functionality (end)*/ |
|
330 | 5 | } |
331 | ||
332 | /*** |
|
333 | * Sets the state of the option. |
|
334 | * <p> |
|
335 | * @param option - option code to be set. |
|
336 | ***/ |
|
337 | void _setWantWill(int option) |
|
338 | { |
|
339 | 19 | _options[option] |= _REQUESTED_WILL_MASK; |
340 | 19 | } |
341 | ||
342 | /*** |
|
343 | * Sets the state of the option. |
|
344 | * <p> |
|
345 | * @param option - option code to be set. |
|
346 | ***/ |
|
347 | void _setWantDo(int option) |
|
348 | { |
|
349 | 8 | _options[option] |= _REQUESTED_DO_MASK; |
350 | 8 | } |
351 | ||
352 | /*** |
|
353 | * Sets the state of the option. |
|
354 | * <p> |
|
355 | * @param option - option code to be set. |
|
356 | ***/ |
|
357 | void _setWont(int option) |
|
358 | { |
|
359 | 4 | _options[option] &= ~_WILL_MASK; |
360 | ||
361 | /* open TelnetOptionHandler functionality (start)*/ |
|
362 | 4 | if (optionHandlers[option] != null) |
363 | { |
|
364 | 4 | optionHandlers[option].setWill(false); |
365 | } |
|
366 | /* open TelnetOptionHandler functionality (end)*/ |
|
367 | 4 | } |
368 | ||
369 | /*** |
|
370 | * Sets the state of the option. |
|
371 | * <p> |
|
372 | * @param option - option code to be set. |
|
373 | ***/ |
|
374 | void _setDont(int option) |
|
375 | { |
|
376 | 3 | _options[option] &= ~_DO_MASK; |
377 | ||
378 | /* open TelnetOptionHandler functionality (start)*/ |
|
379 | 3 | if (optionHandlers[option] != null) |
380 | { |
|
381 | 3 | optionHandlers[option].setDo(false); |
382 | } |
|
383 | /* open TelnetOptionHandler functionality (end)*/ |
|
384 | 3 | } |
385 | ||
386 | /*** |
|
387 | * Sets the state of the option. |
|
388 | * <p> |
|
389 | * @param option - option code to be set. |
|
390 | ***/ |
|
391 | void _setWantWont(int option) |
|
392 | { |
|
393 | 5 | _options[option] &= ~_REQUESTED_WILL_MASK; |
394 | 5 | } |
395 | ||
396 | /*** |
|
397 | * Sets the state of the option. |
|
398 | * <p> |
|
399 | * @param option - option code to be set. |
|
400 | ***/ |
|
401 | void _setWantDont(int option) |
|
402 | { |
|
403 | 4 | _options[option] &= ~_REQUESTED_DO_MASK; |
404 | 4 | } |
405 | ||
406 | /*** |
|
407 | * Processes a DO request. |
|
408 | * <p> |
|
409 | * @throws IOException - Exception in I/O. |
|
410 | * <p> |
|
411 | * @param option - option code to be set. |
|
412 | ***/ |
|
413 | void _processDo(int option) throws IOException |
|
414 | { |
|
415 | if (debugoptions) |
|
416 | { |
|
417 | System.err.println("RECEIVED DO: " |
|
418 | + TelnetOption.getOption(option)); |
|
419 | } |
|
420 | ||
421 | 13 | if (__notclass="keyword">ifhand != null) |
422 | { |
|
423 | 2 | __notifhand.receivedNegotiation( |
424 | TelnetNotificationHandler.RECEIVED_DO, |
|
425 | option); |
|
426 | } |
|
427 | ||
428 | 13 | boolean acceptNewState = false; |
429 | ||
430 | ||
431 | /* open TelnetOptionHandler functionality (start)*/ |
|
432 | 13 | if (optionHandlers[option] != null) |
433 | { |
|
434 | 7 | acceptNewState = optionHandlers[option].getAcceptLocal(); |
435 | } |
|
436 | else |
|
437 | { |
|
438 | /* open TelnetOptionHandler functionality (end)*/ |
|
439 | /* TERMINAL-TYPE option (start)*/ |
|
440 | 6 | if (option == TERMINAL_TYPE) |
441 | { |
|
442 | 1 | if ((terminalType != null) && (terminalType.length() > 0)) |
443 | { |
|
444 | 1 | acceptNewState = true; |
445 | } |
|
446 | } |
|
447 | /* TERMINAL-TYPE option (end)*/ |
|
448 | /* open TelnetOptionHandler functionality (start)*/ |
|
449 | } |
|
450 | /* open TelnetOptionHandler functionality (end)*/ |
|
451 | ||
452 | 13 | if (_willResponse[option] > 0) |
453 | { |
|
454 | 0 | --_willResponse[option]; |
455 | 0 | if (_willResponse[option] > 0 && _stateIsWill(option)) |
456 | { |
|
457 | 0 | --_willResponse[option]; |
458 | } |
|
459 | } |
|
460 | ||
461 | 13 | if (_willResponse[option] == 0) |
462 | { |
|
463 | 13 | if (_requestedWont(option)) |
464 | { |
|
465 | ||
466 | 8 | switch (option) |
467 | { |
|
468 | ||
469 | default: |
|
470 | break; |
|
471 | ||
472 | } |
|
473 | ||
474 | ||
475 | 8 | if (acceptNewState) |
476 | { |
|
477 | 3 | _setWantWill(option); |
478 | 3 | _sendWill(option); |
479 | } |
|
480 | else |
|
481 | { |
|
482 | 5 | ++_willResponse[option]; |
483 | 5 | _sendWont(option); |
484 | } |
|
485 | } |
|
486 | else |
|
487 | { |
|
488 | // Other end has acknowledged option. |
|
489 | ||
490 | 5 | switch (option) |
491 | { |
|
492 | ||
493 | default: |
|
494 | break; |
|
495 | ||
496 | } |
|
497 | ||
498 | } |
|
499 | } |
|
500 | ||
501 | 13 | _setWill(option); |
502 | 13 | } |
503 | ||
504 | /*** |
|
505 | * Processes a DONT request. |
|
506 | * <p> |
|
507 | * @throws IOException - Exception in I/O. |
|
508 | * <p> |
|
509 | * @param option - option code to be set. |
|
510 | ***/ |
|
511 | void _processDont(int option) throws IOException |
|
512 | { |
|
513 | if (debugoptions) |
|
514 | { |
|
515 | System.err.println("RECEIVED DONT: " |
|
516 | + TelnetOption.getOption(option)); |
|
517 | } |
|
518 | 4 | if (__notclass="keyword">ifhand != null) |
519 | { |
|
520 | 1 | __notifhand.receivedNegotiation( |
521 | TelnetNotificationHandler.RECEIVED_DONT, |
|
522 | option); |
|
523 | } |
|
524 | 4 | if (_willResponse[option] > 0) |
525 | { |
|
526 | 0 | --_willResponse[option]; |
527 | 0 | if (_willResponse[option] > 0 && _stateIsWont(option)) |
528 | { |
|
529 | 0 | --_willResponse[option]; |
530 | } |
|
531 | } |
|
532 | ||
533 | 4 | if (_willResponse[option] == 0 && _requestedWill(option)) |
534 | { |
|
535 | ||
536 | 4 | switch (option) |
537 | { |
|
538 | ||
539 | default: |
|
540 | break; |
|
541 | ||
542 | } |
|
543 | ||
544 | /* FIX for a BUG in the negotiation (start)*/ |
|
545 | 4 | if ((_stateIsWill(option)) || (_requestedWill(option))) |
546 | { |
|
547 | 4 | _sendWont(option); |
548 | } |
|
549 | ||
550 | 4 | _setWantWont(option); |
551 | /* FIX for a BUG in the negotiation (end)*/ |
|
552 | } |
|
553 | ||
554 | 4 | _setWont(option); |
555 | 4 | } |
556 | ||
557 | ||
558 | /*** |
|
559 | * Processes a WILL request. |
|
560 | * <p> |
|
561 | * @throws IOException - Exception in I/O. |
|
562 | * <p> |
|
563 | * @param option - option code to be set. |
|
564 | ***/ |
|
565 | void _processWill(int option) throws IOException |
|
566 | { |
|
567 | if (debugoptions) |
|
568 | { |
|
569 | System.err.println("RECEIVED WILL: " |
|
570 | + TelnetOption.getOption(option)); |
|
571 | } |
|
572 | ||
573 | 5 | if (__notclass="keyword">ifhand != null) |
574 | { |
|
575 | 0 | __notifhand.receivedNegotiation( |
576 | TelnetNotificationHandler.RECEIVED_WILL, |
|
577 | option); |
|
578 | } |
|
579 | ||
580 | 5 | boolean acceptNewState = false; |
581 | ||
582 | /* open TelnetOptionHandler functionality (start)*/ |
|
583 | 5 | if (optionHandlers[option] != null) |
584 | { |
|
585 | 1 | acceptNewState = optionHandlers[option].getAcceptRemote(); |
586 | } |
|
587 | /* open TelnetOptionHandler functionality (end)*/ |
|
588 | ||
589 | 5 | if (_doResponse[option] > 0) |
590 | { |
|
591 | 1 | --_doResponse[option]; |
592 | 1 | if (_doResponse[option] > 0 && _stateIsDo(option)) |
593 | { |
|
594 | 0 | --_doResponse[option]; |
595 | } |
|
596 | } |
|
597 | ||
598 | 5 | if (_doResponse[option] == 0 && _requestedDont(option)) |
599 | { |
|
600 | ||
601 | 4 | switch (option) |
602 | { |
|
603 | ||
604 | default: |
|
605 | break; |
|
606 | ||
607 | } |
|
608 | ||
609 | ||
610 | 4 | if (acceptNewState) |
611 | { |
|
612 | 0 | _setWantDo(option); |
613 | 0 | _sendDo(option); |
614 | } |
|
615 | else |
|
616 | { |
|
617 | 4 | ++_doResponse[option]; |
618 | 4 | _sendDont(option); |
619 | } |
|
620 | } |
|
621 | ||
622 | 5 | _setDo(option); |
623 | 5 | } |
624 | ||
625 | /*** |
|
626 | * Processes a WONT request. |
|
627 | * <p> |
|
628 | * @throws IOException - Exception in I/O. |
|
629 | * <p> |
|
630 | * @param option - option code to be set. |
|
631 | ***/ |
|
632 | void _processWont(int option) throws IOException |
|
633 | { |
|
634 | if (debugoptions) |
|
635 | { |
|
636 | System.err.println("RECEIVED WONT: " |
|
637 | + TelnetOption.getOption(option)); |
|
638 | } |
|
639 | ||
640 | 3 | if (__notclass="keyword">ifhand != null) |
641 | { |
|
642 | 1 | __notifhand.receivedNegotiation( |
643 | TelnetNotificationHandler.RECEIVED_WONT, |
|
644 | option); |
|
645 | } |
|
646 | ||
647 | 3 | if (_doResponse[option] > 0) |
648 | { |
|
649 | 3 | --_doResponse[option]; |
650 | 3 | if (_doResponse[option] > 0 && _stateIsDont(option)) |
651 | { |
|
652 | 3 | --_doResponse[option]; |
653 | } |
|
654 | } |
|
655 | ||
656 | 3 | if (_doResponse[option] == 0 && _requestedDo(option)) |
657 | { |
|
658 | ||
659 | 3 | switch (option) |
660 | { |
|
661 | ||
662 | default: |
|
663 | break; |
|
664 | ||
665 | } |
|
666 | ||
667 | /* FIX for a BUG in the negotiation (start)*/ |
|
668 | 3 | if ((_stateIsDo(option)) || (_requestedDo(option))) |
669 | { |
|
670 | 3 | _sendDont(option); |
671 | } |
|
672 | ||
673 | 3 | _setWantDont(option); |
674 | /* FIX for a BUG in the negotiation (end)*/ |
|
675 | } |
|
676 | ||
677 | 3 | _setDont(option); |
678 | 3 | } |
679 | ||
680 | /* TERMINAL-TYPE option (start)*/ |
|
681 | /*** |
|
682 | * Processes a suboption negotiation. |
|
683 | * <p> |
|
684 | * @throws IOException - Exception in I/O. |
|
685 | * <p> |
|
686 | * @param suboption - subnegotiation data received |
|
687 | * @param suboptionLength - length of data received |
|
688 | ***/ |
|
689 | void _processSuboption(int suboption[], class="keyword">int suboptionLength) |
|
690 | throws IOException |
|
691 | { |
|
692 | if (debug) |
|
693 | { |
|
694 | System.err.println("PROCESS SUBOPTION."); |
|
695 | } |
|
696 | ||
697 | /* open TelnetOptionHandler functionality (start)*/ |
|
698 | 2 | if (suboptionLength > 0) |
699 | { |
|
700 | 2 | if (optionHandlers[suboption[0]] != null) |
701 | { |
|
702 | 1 | int responseSuboption[] = |
703 | optionHandlers[suboption[0]].answerSubnegotiation(suboption, |
|
704 | suboptionLength); |
|
705 | 1 | _sendSubnegotiation(responseSuboption); |
706 | } |
|
707 | else |
|
708 | { |
|
709 | 1 | if (suboptionLength > 1) |
710 | { |
|
711 | if (debug) |
|
712 | { |
|
713 | for (int ii = 0; ii < suboptionLength; ii++) |
|
714 | { |
|
715 | System.err.println("SUB[" + ii + "]: " |
|
716 | + suboption[ii]); |
|
717 | } |
|
718 | } |
|
719 | 1 | if ((suboption[0] == TERMINAL_TYPE) |
720 | && (suboption[1] == TERMINAL_TYPE_SEND)) |
|
721 | { |
|
722 | 1 | _sendTerminalType(); |
723 | } |
|
724 | } |
|
725 | } |
|
726 | } |
|
727 | /* open TelnetOptionHandler functionality (end)*/ |
|
728 | 2 | } |
729 | ||
730 | /*** |
|
731 | * Sends terminal type information. |
|
732 | * <p> |
|
733 | * @throws IOException - Exception in I/O. |
|
734 | ***/ |
|
735 | final synchronized void _sendTerminalType() |
|
736 | throws IOException |
|
737 | { |
|
738 | if (debug) |
|
739 | { |
|
740 | System.err.println("SEND TERMINAL-TYPE: " + terminalType); |
|
741 | } |
|
742 | 1 | if (terminalType != null) |
743 | { |
|
744 | 1 | _output_.write(_COMMAND_SB); |
745 | 1 | _output_.write(_COMMAND_IS); |
746 | 1 | _output_.write(terminalType.getBytes()); |
747 | 1 | _output_.write(_COMMAND_SE); |
748 | 1 | _output_.flush(); |
749 | } |
|
750 | 1 | } |
751 | ||
752 | /* TERMINAL-TYPE option (end)*/ |
|
753 | ||
754 | /* open TelnetOptionHandler functionality (start)*/ |
|
755 | /*** |
|
756 | * Manages subnegotiation for Terminal Type. |
|
757 | * <p> |
|
758 | * @throws IOException - Exception in I/O. |
|
759 | * <p> |
|
760 | * @param subn - subnegotiation data to be sent |
|
761 | ***/ |
|
762 | final synchronized void _sendSubnegotiation(int subn[]) |
|
763 | throws IOException |
|
764 | { |
|
765 | if (debug) |
|
766 | { |
|
767 | System.err.println("SEND SUBNEGOTIATION: "); |
|
768 | if (subn != null) |
|
769 | { |
|
770 | for (int ii = 0; ii < subn.length; ii++) |
|
771 | { |
|
772 | System.err.println("subn[" + ii + "]=" + subn[ii]); |
|
773 | } |
|
774 | } |
|
775 | } |
|
776 | 1 | if (subn != null) |
777 | { |
|
778 | 1 | byte byteresp[] = new byte[subn.length]; |
779 | 8 | for (int ii = 0; ii < subn.length; ii++) |
780 | { |
|
781 | 7 | byteresp[ii] = (byte) subn[ii]; |
782 | } |
|
783 | ||
784 | 1 | _output_.write(_COMMAND_SB); |
785 | 1 | _output_.write(byteresp); |
786 | 1 | _output_.write(_COMMAND_SE); |
787 | ||
788 | /* Code Section added for sending the negotiation ASAP (start)*/ |
|
789 | 1 | _output_.flush(); |
790 | /* Code Section added for sending the negotiation ASAP (end)*/ |
|
791 | } |
|
792 | 1 | } |
793 | /* open TelnetOptionHandler functionality (end)*/ |
|
794 | ||
795 | /* Code Section added for supporting AYT (start)*/ |
|
796 | /*** |
|
797 | * Processes the response of an AYT |
|
798 | ***/ |
|
799 | final synchronized void _processAYTResponse() |
|
800 | { |
|
801 | 103 | if (!aytFlag) |
802 | { |
|
803 | 1 | synchronized (aytMonitor) |
804 | { |
|
805 | 1 | aytFlag = true; |
806 | try |
|
807 | { |
|
808 | 1 | aytMonitor.notifyAll(); |
809 | } |
|
810 | 0 | catch (Exception e) |
811 | { |
|
812 | 0 | System.err.println("Exception notifying:" + e.getMessage()); |
813 | 1 | } |
814 | 1 | } |
815 | } |
|
816 | 103 | } |
817 | /* Code Section added for supporting AYT (end)*/ |
|
818 | ||
819 | /*** |
|
820 | * Called upon connection. |
|
821 | * <p> |
|
822 | * @throws IOException - Exception in I/O. |
|
823 | ***/ |
|
824 | protected void _connectAction_() throws IOException |
|
825 | { |
|
826 | /* (start). BUGFIX: clean the option info for each connection*/ |
|
827 | 8224 | for (int ii = 0; ii < TelnetOption.MAX_OPTION_VALUE + 1; ii++) |
828 | { |
|
829 | 8192 | _doResponse[ii] = 0; |
830 | 8192 | _willResponse[ii] = 0; |
831 | 8192 | _options[ii] = 0; |
832 | 8192 | if (optionHandlers[ii] != null) |
833 | { |
|
834 | 24 | optionHandlers[ii].setDo(false); |
835 | 24 | optionHandlers[ii].setWill(false); |
836 | } |
|
837 | } |
|
838 | /* (end). BUGFIX: clean the option info for each connection*/ |
|
839 | ||
840 | 32 | super._connectAction_(); |
841 | 32 | _input_ = new BufferedInputStream(_input_); |
842 | 32 | _output_ = new BufferedOutputStream(_output_); |
843 | ||
844 | /* open TelnetOptionHandler functionality (start)*/ |
|
845 | 8224 | for (int ii = 0; ii < TelnetOption.MAX_OPTION_VALUE + 1; ii++) |
846 | { |
|
847 | 8192 | if (optionHandlers[ii] != null) |
848 | { |
|
849 | 24 | if (optionHandlers[ii].getInitLocal()) |
850 | { |
|
851 | try |
|
852 | { |
|
853 | 16 | _requestWill(optionHandlers[ii].getOptionCode()); |
854 | } |
|
855 | 0 | catch (IOException e) |
856 | { |
|
857 | 0 | System.err.println( |
858 | "Exception while initializing option: " |
|
859 | + e.getMessage()); |
|
860 | 16 | } |
861 | } |
|
862 | ||
863 | 24 | if (optionHandlers[ii].getInitRemote()) |
864 | { |
|
865 | try |
|
866 | { |
|
867 | 8 | _requestDo(optionHandlers[ii].getOptionCode()); |
868 | } |
|
869 | 0 | catch (IOException e) |
870 | { |
|
871 | 0 | System.err.println( |
872 | "Exception while initializing option: " |
|
873 | + e.getMessage()); |
|
874 | 8 | } |
875 | } |
|
876 | } |
|
877 | } |
|
878 | /* open TelnetOptionHandler functionality (end)*/ |
|
879 | 32 | } |
880 | ||
881 | /*** |
|
882 | * Sends a DO. |
|
883 | * <p> |
|
884 | * @throws IOException - Exception in I/O. |
|
885 | * <p> |
|
886 | * @param option - Option code. |
|
887 | ***/ |
|
888 | final synchronized void _sendDo(int option) |
|
889 | throws IOException |
|
890 | { |
|
891 | if (debug || debugoptions) |
|
892 | { |
|
893 | System.err.println("DO: " + TelnetOption.getOption(option)); |
|
894 | } |
|
895 | 8 | _output_.write(_COMMAND_DO); |
896 | 8 | _output_.write(option); |
897 | ||
898 | /* Code Section added for sending the negotiation ASAP (start)*/ |
|
899 | 8 | _output_.flush(); |
900 | /* Code Section added for sending the negotiation ASAP (end)*/ |
|
901 | 8 | } |
902 | ||
903 | /*** |
|
904 | * Requests a DO. |
|
905 | * <p> |
|
906 | * @throws IOException - Exception in I/O. |
|
907 | * <p> |
|
908 | * @param option - Option code. |
|
909 | ***/ |
|
910 | final synchronized void _requestDo(int option) |
|
911 | throws IOException |
|
912 | { |
|
913 | 8 | if ((_doResponse[option] == 0 && _stateIsDo(option)) |
914 | || _requestedDo(option)) |
|
915 | { |
|
916 | 0 | return ; |
917 | } |
|
918 | 8 | _setWantDo(option); |
919 | 8 | ++_doResponse[option]; |
920 | 8 | _sendDo(option); |
921 | 8 | } |
922 | ||
923 | /*** |
|
924 | * Sends a DONT. |
|
925 | * <p> |
|
926 | * @throws IOException - Exception in I/O. |
|
927 | * <p> |
|
928 | * @param option - Option code. |
|
929 | ***/ |
|
930 | final synchronized void _sendDont(int option) |
|
931 | throws IOException |
|
932 | { |
|
933 | if (debug || debugoptions) |
|
934 | { |
|
935 | System.err.println("DONT: " + TelnetOption.getOption(option)); |
|
936 | } |
|
937 | 8 | _output_.write(_COMMAND_DONT); |
938 | 8 | _output_.write(option); |
939 | ||
940 | /* Code Section added for sending the negotiation ASAP (start)*/ |
|
941 | 8 | _output_.flush(); |
942 | /* Code Section added for sending the negotiation ASAP (end)*/ |
|
943 | 8 | } |
944 | ||
945 | /*** |
|
946 | * Requests a DONT. |
|
947 | * <p> |
|
948 | * @throws IOException - Exception in I/O. |
|
949 | * <p> |
|
950 | * @param option - Option code. |
|
951 | ***/ |
|
952 | final synchronized void _requestDont(int option) |
|
953 | throws IOException |
|
954 | { |
|
955 | 1 | if ((_doResponse[option] == 0 && _stateIsDont(option)) |
956 | || _requestedDont(option)) |
|
957 | { |
|
958 | 0 | return ; |
959 | } |
|
960 | 1 | _setWantDont(option); |
961 | 1 | ++_doResponse[option]; |
962 | 1 | _sendDont(option); |
963 | 1 | } |
964 | ||
965 | ||
966 | /*** |
|
967 | * Sends a WILL. |
|
968 | * <p> |
|
969 | * @throws IOException - Exception in I/O. |
|
970 | * <p> |
|
971 | * @param option - Option code. |
|
972 | ***/ |
|
973 | final synchronized void _sendWill(int option) |
|
974 | throws IOException |
|
975 | { |
|
976 | if (debug || debugoptions) |
|
977 | { |
|
978 | System.err.println("WILL: " + TelnetOption.getOption(option)); |
|
979 | } |
|
980 | 19 | _output_.write(_COMMAND_WILL); |
981 | 19 | _output_.write(option); |
982 | ||
983 | /* Code Section added for sending the negotiation ASAP (start)*/ |
|
984 | 19 | _output_.flush(); |
985 | /* Code Section added for sending the negotiation ASAP (end)*/ |
|
986 | 19 | } |
987 | ||
988 | /*** |
|
989 | * Requests a WILL. |
|
990 | * <p> |
|
991 | * @throws IOException - Exception in I/O. |
|
992 | * <p> |
|
993 | * @param option - Option code. |
|
994 | ***/ |
|
995 | final synchronized void _requestWill(int option) |
|
996 | throws IOException |
|
997 | { |
|
998 | 16 | if ((_willResponse[option] == 0 && _stateIsWill(option)) |
999 | || _requestedWill(option)) |
|
1000 | { |
|
1001 | 0 | return ; |
1002 | } |
|
1003 | 16 | _setWantWill(option); |
1004 | 16 | ++_doResponse[option]; |
1005 | 16 | _sendWill(option); |
1006 | 16 | } |
1007 | ||
1008 | /*** |
|
1009 | * Sends a WONT. |
|
1010 | * <p> |
|
1011 | * @throws IOException - Exception in I/O. |
|
1012 | * <p> |
|
1013 | * @param option - Option code. |
|
1014 | ***/ |
|
1015 | final synchronized void _sendWont(int option) |
|
1016 | throws IOException |
|
1017 | { |
|
1018 | if (debug || debugoptions) |
|
1019 | { |
|
1020 | System.err.println("WONT: " + TelnetOption.getOption(option)); |
|
1021 | } |
|
1022 | 10 | _output_.write(_COMMAND_WONT); |
1023 | 10 | _output_.write(option); |
1024 | ||
1025 | /* Code Section added for sending the negotiation ASAP (start)*/ |
|
1026 | 10 | _output_.flush(); |
1027 | /* Code Section added for sending the negotiation ASAP (end)*/ |
|
1028 | 10 | } |
1029 | ||
1030 | /*** |
|
1031 | * Requests a WONT. |
|
1032 | * <p> |
|
1033 | * @throws IOException - Exception in I/O. |
|
1034 | * <p> |
|
1035 | * @param option - Option code. |
|
1036 | ***/ |
|
1037 | final synchronized void _requestWont(int option) |
|
1038 | throws IOException |
|
1039 | { |
|
1040 | 1 | if ((_willResponse[option] == 0 && _stateIsWont(option)) |
1041 | || _requestedWont(option)) |
|
1042 | { |
|
1043 | 0 | return ; |
1044 | } |
|
1045 | 1 | _setWantWont(option); |
1046 | 1 | ++_doResponse[option]; |
1047 | 1 | _sendWont(option); |
1048 | 1 | } |
1049 | ||
1050 | /*** |
|
1051 | * Sends a byte. |
|
1052 | * <p> |
|
1053 | * @throws IOException - Exception in I/O. |
|
1054 | * <p> |
|
1055 | * @param b - byte to send |
|
1056 | ***/ |
|
1057 | final synchronized void _sendByte(int b) |
|
1058 | throws IOException |
|
1059 | { |
|
1060 | 10 | _output_.write(b); |
1061 | ||
1062 | /* Code Section added for supporting spystreams (start)*/ |
|
1063 | 10 | _spyWrite(b); |
1064 | /* Code Section added for supporting spystreams (end)*/ |
|
1065 | ||
1066 | 10 | } |
1067 | ||
1068 | /* Code Section added for supporting AYT (start)*/ |
|
1069 | /*** |
|
1070 | * Sends an Are You There sequence and waits for the result. |
|
1071 | * <p> |
|
1072 | * @throws IOException - Exception in I/O. |
|
1073 | * @throws IllegalArgumentException - Illegal argument |
|
1074 | * @throws InterruptedException - Interrupted during wait. |
|
1075 | * <p> |
|
1076 | * @param timeout - Time to wait for a response (millis.) |
|
1077 | * <p> |
|
1078 | * @return true if AYT received a response, false otherwise |
|
1079 | ***/ |
|
1080 | final boolean _sendAYT(long timeout) |
|
1081 | throws IOException, IllegalArgumentException, InterruptedException |
|
1082 | { |
|
1083 | 2 | boolean retValue = false; |
1084 | 2 | synchronized (aytMonitor) |
1085 | { |
|
1086 | 2 | synchronized (this) |
1087 | { |
|
1088 | 2 | aytFlag = false; |
1089 | 2 | _output_.write(_COMMAND_AYT); |
1090 | 2 | _output_.flush(); |
1091 | 2 | } |
1092 | ||
1093 | try |
|
1094 | { |
|
1095 | 2 | aytMonitor.wait(timeout); |
1096 | 2 | if (aytFlag == false) |
1097 | { |
|
1098 | 1 | retValue = false; |
1099 | 1 | aytFlag = true; |
1100 | } |
|
1101 | else |
|
1102 | { |
|
1103 | 1 | retValue = true; |
1104 | } |
|
1105 | } |
|
1106 | 0 | catch (IllegalMonitorStateException e) |
1107 | { |
|
1108 | 0 | System.err.println("Exception processing AYT:" |
1109 | + e.getMessage()); |
|
1110 | 2 | } |
1111 | 2 | } |
1112 | ||
1113 | 2 | return (retValue); |
1114 | } |
|
1115 | /* Code Section added for supporting AYT (end)*/ |
|
1116 | ||
1117 | /* open TelnetOptionHandler functionality (start)*/ |
|
1118 | ||
1119 | /*** |
|
1120 | * Registers a new TelnetOptionHandler for this telnet to use. |
|
1121 | * <p> |
|
1122 | * @throws InvalidTelnetOptionException - The option code is invalid. |
|
1123 | * <p> |
|
1124 | * @param opthand - option handler to be registered. |
|
1125 | ***/ |
|
1126 | void addOptionHandler(TelnetOptionHandler opthand) |
|
1127 | throws InvalidTelnetOptionException |
|
1128 | { |
|
1129 | 26 | int optcode = opthand.getOptionCode(); |
1130 | 26 | if (TelnetOption.isValidOption(optcode)) |
1131 | { |
|
1132 | 24 | if (optionHandlers[optcode] == null) |
1133 | { |
|
1134 | 24 | optionHandlers[optcode] = opthand; |
1135 | 24 | if (isConnected()) |
1136 | { |
|
1137 | 0 | if (opthand.getInitLocal()) |
1138 | { |
|
1139 | try |
|
1140 | { |
|
1141 | 0 | _requestWill(optcode); |
1142 | } |
|
1143 | 0 | catch (IOException e) |
1144 | { |
|
1145 | 0 | System.err.println( |
1146 | "Exception while initializing option: " |
|
1147 | + e.getMessage()); |
|
1148 | 0 | } |
1149 | } |
|
1150 | ||
1151 | 0 | if (opthand.getInitRemote()) |
1152 | { |
|
1153 | try |
|
1154 | { |
|
1155 | 0 | _requestDo(optcode); |
1156 | } |
|
1157 | 0 | catch (IOException e) |
1158 | { |
|
1159 | 0 | System.err.println( |
1160 | "Exception while initializing option: " |
|
1161 | + e.getMessage()); |
|
1162 | 0 | } |
1163 | } |
|
1164 | } |
|
1165 | } |
|
1166 | else |
|
1167 | { |
|
1168 | 0 | throw (new InvalidTelnetOptionException( |
1169 | "Already registered option", optcode)); |
|
1170 | } |
|
1171 | } |
|
1172 | else |
|
1173 | { |
|
1174 | 2 | throw (new InvalidTelnetOptionException( |
1175 | "Invalid Option Code", optcode)); |
|
1176 | } |
|
1177 | 24 | } |
1178 | ||
1179 | /*** |
|
1180 | * Unregisters a TelnetOptionHandler. |
|
1181 | * <p> |
|
1182 | * @throws InvalidTelnetOptionException - The option code is invalid. |
|
1183 | * <p> |
|
1184 | * @param optcode - Code of the option to be unregistered. |
|
1185 | ***/ |
|
1186 | void deleteOptionHandler(int optcode) |
|
1187 | throws InvalidTelnetOptionException |
|
1188 | { |
|
1189 | 3 | if (TelnetOption.isValidOption(optcode)) |
1190 | { |
|
1191 | 2 | if (optionHandlers[optcode] == null) |
1192 | { |
|
1193 | 1 | throw (new InvalidTelnetOptionException( |
1194 | "Unregistered option", optcode)); |
|
1195 | } |
|
1196 | else |
|
1197 | { |
|
1198 | 1 | TelnetOptionHandler opthand = optionHandlers[optcode]; |
1199 | 1 | optionHandlers[optcode] = null; |
1200 | ||
1201 | 1 | if (opthand.getWill()) |
1202 | { |
|
1203 | try |
|
1204 | { |
|
1205 | 1 | _requestWont(optcode); |
1206 | } |
|
1207 | 0 | catch (IOException e) |
1208 | { |
|
1209 | 0 | System.err.println( |
1210 | "Exception while turning off option: " |
|
1211 | + e.getMessage()); |
|
1212 | 1 | } |
1213 | } |
|
1214 | ||
1215 | 1 | if (opthand.getDo()) |
1216 | { |
|
1217 | try |
|
1218 | { |
|
1219 | 1 | _requestDont(optcode); |
1220 | } |
|
1221 | 0 | catch (IOException e) |
1222 | { |
|
1223 | 0 | System.err.println( |
1224 | "Exception while turning off option: " |
|
1225 | + e.getMessage()); |
|
1226 | 2 | } |
1227 | } |
|
1228 | } |
|
1229 | } |
|
1230 | else |
|
1231 | { |
|
1232 | 1 | throw (new InvalidTelnetOptionException( |
1233 | "Invalid Option Code", optcode)); |
|
1234 | } |
|
1235 | 1 | } |
1236 | /* open TelnetOptionHandler functionality (end)*/ |
|
1237 | ||
1238 | /* Code Section added for supporting spystreams (start)*/ |
|
1239 | /*** |
|
1240 | * Registers an OutputStream for spying what's going on in |
|
1241 | * the Telnet session. |
|
1242 | * <p> |
|
1243 | * @param spystream - OutputStream on which session activity |
|
1244 | * will be echoed. |
|
1245 | ***/ |
|
1246 | void _registerSpyStream(OutputStream spystream) |
|
1247 | { |
|
1248 | 1 | spyStream = spystream; |
1249 | 1 | } |
1250 | ||
1251 | /*** |
|
1252 | * Stops spying this Telnet. |
|
1253 | * <p> |
|
1254 | ***/ |
|
1255 | void _stopSpyStream() |
|
1256 | { |
|
1257 | 1 | spyStream = null; |
1258 | 1 | } |
1259 | ||
1260 | /*** |
|
1261 | * Sends a read char on the spy stream. |
|
1262 | * <p> |
|
1263 | * @param ch - character read from the session |
|
1264 | ***/ |
|
1265 | void _spyRead(int ch) |
|
1266 | { |
|
1267 | 103 | if (spyStream != null) |
1268 | { |
|
1269 | try |
|
1270 | { |
|
1271 | 5 | if (ch != (int) '\r') |
1272 | { |
|
1273 | 5 | spyStream.write(ch); |
1274 | 5 | if (ch == (int) '\n') |
1275 | { |
|
1276 | 0 | spyStream.write((int) '\r'); |
1277 | } |
|
1278 | 5 | spyStream.flush(); |
1279 | } |
|
1280 | } |
|
1281 | 0 | catch (Exception e) |
1282 | { |
|
1283 | 0 | spyStream = null; |
1284 | 5 | } |
1285 | } |
|
1286 | 103 | } |
1287 | ||
1288 | /*** |
|
1289 | * Sends a written char on the spy stream. |
|
1290 | * <p> |
|
1291 | * @param ch - character written to the session |
|
1292 | ***/ |
|
1293 | void _spyWrite(int ch) |
|
1294 | { |
|
1295 | 10 | if (!(_stateIsDo(TelnetOption.ECHO) |
1296 | && _requestedDo(TelnetOption.ECHO))) |
|
1297 | { |
|
1298 | 10 | if (spyStream != null) |
1299 | { |
|
1300 | try |
|
1301 | { |
|
1302 | 5 | spyStream.write(ch); |
1303 | 5 | spyStream.flush(); |
1304 | } |
|
1305 | 0 | catch (Exception e) |
1306 | { |
|
1307 | 0 | spyStream = null; |
1308 | 5 | } |
1309 | } |
|
1310 | } |
|
1311 | 10 | } |
1312 | /* Code Section added for supporting spystreams (end)*/ |
|
1313 | ||
1314 | /*** |
|
1315 | * Registers a notification handler to which will be sent |
|
1316 | * notifications of received telnet option negotiation commands. |
|
1317 | * <p> |
|
1318 | * @param notifhand - TelnetNotificationHandler to be registered |
|
1319 | ***/ |
|
1320 | public void registerNotifHandler(TelnetNotificationHandler notifhand) |
|
1321 | { |
|
1322 | 1 | __notifhand = notifhand; |
1323 | 1 | } |
1324 | ||
1325 | /*** |
|
1326 | * Unregisters the current notification handler. |
|
1327 | * <p> |
|
1328 | ***/ |
|
1329 | public void unregisterNotifHandler() |
|
1330 | { |
|
1331 | 0 | __notifhand = null; |
1332 | 0 | } |
1333 | } |
This report is generated by jcoverage, Maven and Maven JCoverage Plugin. |