129 |
* port. |
* port. |
130 |
* @param host the server hostname |
* @param host the server hostname |
131 |
*/ |
*/ |
132 |
public SMTPConnection(String host) |
public SMTPConnection(String host) throws IOException |
|
throws IOException |
|
133 |
{ |
{ |
134 |
this(host, DEFAULT_PORT); |
this(host, DEFAULT_PORT); |
135 |
} |
} |
136 |
|
|
137 |
/** |
/** |
138 |
* Creates a new connection to the specified host, using the specified |
* Creates a new connection to the specified host, using the specified |
139 |
* port. |
* port. |
140 |
* @param host the server hostname |
* @param host the server hostname |
141 |
* @param port the port to connect to |
* @param port the port to connect to |
142 |
*/ |
*/ |
143 |
public SMTPConnection(String host, int port) |
public SMTPConnection(String host, int port) throws IOException |
|
throws IOException |
|
144 |
{ |
{ |
145 |
this(host, port, -1, -1, false); |
this(host, port, -1, -1, false); |
146 |
} |
} |
147 |
|
|
148 |
/** |
/** |
149 |
* Creates a new connection to the specified host, using the specified |
* Creates a new connection to the specified host, using the specified |
150 |
* port. |
* port. |
154 |
* @param timeout the I/O timeout in milliseconds |
* @param timeout the I/O timeout in milliseconds |
155 |
* @param debug whether to log progress |
* @param debug whether to log progress |
156 |
*/ |
*/ |
157 |
public SMTPConnection(String host, int port, |
public SMTPConnection(String host, int port, |
158 |
int connectionTimeout, int timeout, boolean debug) |
int connectionTimeout, int timeout, boolean debug) |
159 |
throws IOException |
throws IOException |
160 |
{ |
{ |
161 |
if (port<=0) |
if (port <= 0) |
162 |
port = DEFAULT_PORT; |
port = DEFAULT_PORT; |
163 |
response = null; |
response = null; |
164 |
continuation = false; |
continuation = false; |
165 |
this.debug = debug; |
this.debug = debug; |
166 |
|
|
167 |
// Initialise socket |
// Initialise socket |
168 |
// TODO connectionTimeout |
// TODO connectionTimeout |
169 |
socket = new Socket(host, port); |
socket = new Socket(host, port); |
170 |
if (timeout>0) |
if (timeout > 0) |
171 |
socket.setSoTimeout(timeout); |
socket.setSoTimeout(timeout); |
172 |
|
|
173 |
// Initialise streams |
// Initialise streams |
174 |
InputStream in = socket.getInputStream(); |
InputStream in = socket.getInputStream(); |
175 |
in = new BufferedInputStream(in); |
in = new BufferedInputStream(in); |
176 |
in = new CRLFInputStream(in); |
in = new CRLFInputStream(in); |
177 |
this.in = new LineInputStream(in); |
this.in = new LineInputStream(in); |
178 |
OutputStream out = socket.getOutputStream(); |
OutputStream out = socket.getOutputStream(); |
179 |
out = new BufferedOutputStream(out); |
out = new BufferedOutputStream(out); |
180 |
this.out = new CRLFOutputStream(out); |
this.out = new CRLFOutputStream(out); |
181 |
|
|
182 |
// Greeting |
// Greeting |
183 |
if (getResponse()!=READY) |
if (getResponse() != READY) |
184 |
throw new ProtocolException(response); |
throw new ProtocolException(response); |
185 |
} |
} |
186 |
|
|
196 |
throws IOException |
throws IOException |
197 |
{ |
{ |
198 |
StringBuffer command = new StringBuffer(MAIL_FROM); |
StringBuffer command = new StringBuffer(MAIL_FROM); |
199 |
command.append('<'); |
command.append('<'); |
200 |
command.append(reversePath); |
command.append(reversePath); |
201 |
command.append('>'); |
command.append('>'); |
202 |
if (parameters!=null) |
if (parameters != null) |
203 |
{ |
{ |
204 |
command.append(SP); |
command.append(SP); |
205 |
command.append(parameters); |
command.append(parameters); |
207 |
send(command.toString()); |
send(command.toString()); |
208 |
switch (getResponse()) |
switch (getResponse()) |
209 |
{ |
{ |
210 |
case OK: |
case OK: |
211 |
case OK_NOT_LOCAL: |
case OK_NOT_LOCAL: |
212 |
case OK_UNVERIFIED: |
case OK_UNVERIFIED: |
213 |
return true; |
return true; |
214 |
default: |
default:return false; |
|
return false; |
|
215 |
} |
} |
216 |
} |
} |
217 |
|
|
225 |
throws IOException |
throws IOException |
226 |
{ |
{ |
227 |
StringBuffer command = new StringBuffer(RCPT_TO); |
StringBuffer command = new StringBuffer(RCPT_TO); |
228 |
command.append('<'); |
command.append('<'); |
229 |
command.append(forwardPath); |
command.append(forwardPath); |
230 |
command.append('>'); |
command.append('>'); |
231 |
if (parameters!=null) |
if (parameters != null) |
232 |
{ |
{ |
233 |
command.append(SP); |
command.append(SP); |
234 |
command.append(parameters); |
command.append(parameters); |
236 |
send(command.toString()); |
send(command.toString()); |
237 |
switch (getResponse()) |
switch (getResponse()) |
238 |
{ |
{ |
239 |
case OK: |
case OK: |
240 |
case OK_NOT_LOCAL: |
case OK_NOT_LOCAL: |
241 |
case OK_UNVERIFIED: |
case OK_UNVERIFIED: |
242 |
return true; |
return true; |
243 |
default: |
default: |
244 |
return false; |
return false; |
245 |
} |
} |
246 |
} |
} |
247 |
|
|
254 |
* must be called to complete the transfer and determine its success. |
* must be called to complete the transfer and determine its success. |
255 |
* @return a stream for writing messages to |
* @return a stream for writing messages to |
256 |
*/ |
*/ |
257 |
public OutputStream data() |
public OutputStream data() throws IOException |
|
throws IOException |
|
258 |
{ |
{ |
259 |
send(DATA); |
send(DATA); |
260 |
switch (getResponse()) |
switch (getResponse()) |
261 |
{ |
{ |
262 |
case SEND_DATA: |
case SEND_DATA: |
263 |
return new MessageOutputStream(out); |
return new MessageOutputStream(out); |
264 |
default: |
default:throw new ProtocolException(response); |
|
throw new ProtocolException(response); |
|
265 |
} |
} |
266 |
} |
} |
267 |
|
|
270 |
* @see #data |
* @see #data |
271 |
* @return true id transfer was successful, false otherwise |
* @return true id transfer was successful, false otherwise |
272 |
*/ |
*/ |
273 |
public boolean finishData() |
public boolean finishData() throws IOException |
|
throws IOException |
|
274 |
{ |
{ |
275 |
send(FINISH_DATA); |
send(FINISH_DATA); |
276 |
switch (getResponse()) |
switch (getResponse()) |
277 |
{ |
{ |
278 |
case OK: |
case OK: |
279 |
return true; |
return true; |
280 |
default: |
default:return false; |
|
return false; |
|
281 |
} |
} |
282 |
} |
} |
283 |
|
|
284 |
/** |
/** |
285 |
* Aborts the current mail transaction. |
* Aborts the current mail transaction. |
286 |
*/ |
*/ |
287 |
public void rset() |
public void rset() throws IOException |
|
throws IOException |
|
288 |
{ |
{ |
289 |
send(RSET); |
send(RSET); |
290 |
if (getResponse()!=OK) |
if (getResponse() != OK) |
291 |
throw new ProtocolException(response); |
throw new ProtocolException(response); |
292 |
} |
} |
293 |
|
|
298 |
* null on failure. |
* null on failure. |
299 |
* @param address a mailbox, or real name and mailbox |
* @param address a mailbox, or real name and mailbox |
300 |
*/ |
*/ |
301 |
public List vrfy(String address) |
public List vrfy(String address) throws IOException |
|
throws IOException |
|
302 |
{ |
{ |
303 |
String command = new StringBuffer(VRFY) |
String command = |
304 |
.append(' ') |
new StringBuffer(VRFY).append(' ').append(address).toString(); |
305 |
.append(address) |
send(command); |
|
.toString(); |
|
|
send(command); |
|
306 |
List list = new ArrayList(); |
List list = new ArrayList(); |
307 |
do |
do |
308 |
{ |
{ |
309 |
switch (getResponse()) |
switch (getResponse()) |
310 |
{ |
{ |
311 |
case OK: |
case OK: |
312 |
case AMBIGUOUS: |
case AMBIGUOUS: |
313 |
response = response.trim(); |
response = response.trim(); |
314 |
if (response.indexOf('@')!=-1) |
if (response.indexOf('@') != -1) |
315 |
list.add(response); |
list.add(response); |
316 |
else if (response.indexOf('<')!=-1) |
else if (response.indexOf('<') != -1) |
317 |
list.add(response); |
list.add(response); |
318 |
else if (response.indexOf(' ')==-1) |
else if (response.indexOf(' ') == -1) |
319 |
list.add(response); |
list.add(response); |
320 |
break; |
break; |
321 |
default: |
default:return null; |
|
return null; |
|
322 |
} |
} |
323 |
} |
} |
324 |
while (continuation); |
while (continuation); |
330 |
* or null on failure. |
* or null on failure. |
331 |
* @param address a mailing list name |
* @param address a mailing list name |
332 |
*/ |
*/ |
333 |
public List expn(String address) |
public List expn(String address) throws IOException |
|
throws IOException |
|
334 |
{ |
{ |
335 |
String command = new StringBuffer(EXPN) |
String command = |
336 |
.append(' ') |
new StringBuffer(EXPN).append(' ').append(address).toString(); |
337 |
.append(address) |
send(command); |
|
.toString(); |
|
|
send(command); |
|
338 |
List list = new ArrayList(); |
List list = new ArrayList(); |
339 |
do |
do |
340 |
{ |
{ |
341 |
switch (getResponse()) |
switch (getResponse()) |
342 |
{ |
{ |
343 |
case OK: |
case OK: |
344 |
response = response.trim(); |
response = response.trim(); |
345 |
list.add(response); |
list.add(response); |
346 |
break; |
break; |
347 |
default: |
default:return null; |
|
return null; |
|
348 |
} |
} |
349 |
} |
} |
350 |
while (continuation); |
while (continuation); |
358 |
* @return a list of possibly useful information, or null if the command |
* @return a list of possibly useful information, or null if the command |
359 |
* failed. |
* failed. |
360 |
*/ |
*/ |
361 |
public List help(String arg) |
public List help(String arg) throws IOException |
|
throws IOException |
|
362 |
{ |
{ |
363 |
String command = (arg==null) ? HELP : |
String command = (arg == null) ? HELP : |
364 |
new StringBuffer(HELP).append(' ').append(arg).toString(); |
new StringBuffer(HELP).append(' ').append(arg).toString(); |
365 |
send(command); |
send(command); |
366 |
List list = new ArrayList(); |
List list = new ArrayList(); |
367 |
do |
do |
368 |
{ |
{ |
369 |
switch (getResponse()) |
switch (getResponse()) |
370 |
{ |
{ |
371 |
case INFO: |
case INFO: |
372 |
list.add(response); |
list.add(response); |
373 |
break; |
break; |
374 |
default: |
default:return null; |
|
return null; |
|
375 |
} |
} |
376 |
} |
} |
377 |
while (continuation); |
while (continuation); |
378 |
return Collections.unmodifiableList(list); |
return Collections.unmodifiableList(list); |
379 |
} |
} |
380 |
|
|
381 |
/** |
/** |
382 |
* Issues a NOOP command. |
* Issues a NOOP command. |
383 |
* This does nothing, but can be used to keep the connection alive. |
* This does nothing, but can be used to keep the connection alive. |
384 |
*/ |
*/ |
385 |
public void noop() |
public void noop() throws IOException |
|
throws IOException |
|
386 |
{ |
{ |
387 |
send(NOOP); |
send(NOOP); |
388 |
do |
do |
395 |
/** |
/** |
396 |
* Close the connection to the server. |
* Close the connection to the server. |
397 |
*/ |
*/ |
398 |
public void quit() |
public void quit() throws IOException |
|
throws IOException |
|
399 |
{ |
{ |
400 |
try |
try |
401 |
{ |
{ |
405 |
* many don't: postfix, for instance, sends 221. |
* many don't: postfix, for instance, sends 221. |
406 |
* In any case we have done our best. */ |
* In any case we have done our best. */ |
407 |
} |
} |
408 |
catch (IOException e) |
catch(IOException e) |
409 |
{ |
{ |
410 |
} |
} |
411 |
finally |
finally |
419 |
* Issues a HELO command. |
* Issues a HELO command. |
420 |
* @param hostname the local host name |
* @param hostname the local host name |
421 |
*/ |
*/ |
422 |
public boolean helo(String hostname) |
public boolean helo(String hostname) throws IOException |
|
throws IOException |
|
423 |
{ |
{ |
424 |
String command = new StringBuffer(HELO) |
String command = |
425 |
.append(' ') |
new StringBuffer(HELO).append(' ').append(hostname).toString(); |
426 |
.append(hostname) |
send(command); |
427 |
.toString(); |
return (getResponse() == OK); |
|
send(command); |
|
|
return (getResponse()==OK); |
|
428 |
} |
} |
429 |
|
|
430 |
/** |
/** |
434 |
* Otherwise returns null, and HELO should be called. |
* Otherwise returns null, and HELO should be called. |
435 |
* @param hostname the local host name |
* @param hostname the local host name |
436 |
*/ |
*/ |
437 |
public List ehlo(String hostname) |
public List ehlo(String hostname) throws IOException |
|
throws IOException |
|
438 |
{ |
{ |
439 |
String command = new StringBuffer(EHLO) |
String command = |
440 |
.append(' ') |
new StringBuffer(EHLO).append(' ').append(hostname).toString(); |
441 |
.append(hostname) |
send(command); |
|
.toString(); |
|
|
send(command); |
|
442 |
List extensions = new ArrayList(); |
List extensions = new ArrayList(); |
443 |
do |
do |
444 |
{ |
{ |
445 |
switch (getResponse()) |
switch (getResponse()) |
446 |
{ |
{ |
447 |
case OK: |
case OK: |
448 |
extensions.add(response); |
extensions.add(response); |
449 |
break; |
break; |
450 |
default: |
default:return null; |
|
return null; |
|
451 |
} |
} |
452 |
} |
} |
453 |
while (continuation); |
while (continuation); |
459 |
* This depends on many features, such as the JSSE classes being in the |
* This depends on many features, such as the JSSE classes being in the |
460 |
* classpath. Returns true if successful, false otherwise. |
* classpath. Returns true if successful, false otherwise. |
461 |
*/ |
*/ |
462 |
public boolean starttls() |
public boolean starttls() throws IOException |
|
throws IOException |
|
463 |
{ |
{ |
464 |
try |
try |
465 |
{ |
{ |
466 |
// Use SSLSocketFactory to negotiate a TLS session and wrap the |
// Use SSLSocketFactory to negotiate a TLS session and wrap the |
467 |
// current socket. |
// current socket. |
468 |
SSLSocketFactory factory = |
SSLSocketFactory factory = |
469 |
(SSLSocketFactory)SSLSocketFactory.getDefault(); |
(SSLSocketFactory) SSLSocketFactory.getDefault(); |
470 |
|
|
471 |
send(STARTTLS); |
send(STARTTLS); |
472 |
if (getResponse()!=OK) |
if (getResponse() != OK) |
473 |
return false; |
return false; |
474 |
|
|
475 |
socket = factory.createSocket(socket, |
socket = factory.createSocket(socket, |
476 |
socket.getInetAddress().getHostName(), |
socket.getInetAddress().getHostName(), |
477 |
socket.getPort(), |
socket.getPort(), true); |
|
true); |
|
478 |
// Set up streams |
// Set up streams |
479 |
InputStream in = socket.getInputStream(); |
InputStream in = socket.getInputStream(); |
480 |
in = new BufferedInputStream(in); |
in = new BufferedInputStream(in); |
481 |
in = new CRLFInputStream(in); |
in = new CRLFInputStream(in); |
482 |
this.in = new LineInputStream(in); |
this.in = new LineInputStream(in); |
483 |
OutputStream out = socket.getOutputStream(); |
OutputStream out = socket.getOutputStream(); |
484 |
out = new BufferedOutputStream(out); |
out = new BufferedOutputStream(out); |
485 |
this.out = new CRLFOutputStream(out); |
this.out = new CRLFOutputStream(out); |
486 |
return true; |
return true; |
487 |
} |
} |
488 |
catch (ClassNotFoundException e) |
catch(ClassNotFoundException e) |
489 |
{ |
{ |
490 |
return false; // No javax.net classes in runtime |
return false; // No javax.net classes in runtime |
491 |
} |
} |
492 |
} |
} |
493 |
|
|
494 |
// -- Authentication -- |
// -- Authentication -- |
495 |
|
|
496 |
/** |
/** |
497 |
* Authenticates the connection using the specified SASL mechanism, |
* Authenticates the connection using the specified SASL mechanism, |
498 |
* username, and password. |
* username, and password. |
499 |
* @param mechanism a SASL authentication mechanism, e.g. LOGIN, PLAIN, |
* @param mechanism a SASL authentication mechanism, e.g. LOGIN, PLAIN, |
502 |
* @param password the authentication credentials |
* @param password the authentication credentials |
503 |
* @return true if authentication was successful, false otherwise |
* @return true if authentication was successful, false otherwise |
504 |
*/ |
*/ |
505 |
public boolean authenticate(String mechanism, String username, String password) |
public boolean authenticate(String mechanism, String username, |
506 |
throws IOException |
String password) throws IOException |
507 |
{ |
{ |
508 |
try |
try |
509 |
{ |
{ |
510 |
String[] m = new String[] { mechanism }; |
String[]m = new String[] |
511 |
CallbackHandler ch = new SaslCallbackHandler(username, password); |
{ |
512 |
// Avoid lengthy callback procedure for GNU Crypto |
mechanism}; |
513 |
Properties p = new Properties(); |
CallbackHandler ch = new SaslCallbackHandler(username, password); |
514 |
p.put("gnu.crypto.sasl.username", username); |
// Avoid lengthy callback procedure for GNU Crypto |
515 |
p.put("gnu.crypto.sasl.password", password); |
Properties p = new Properties(); |
516 |
SaslClient sasl = Sasl.createSaslClient(m, null, "smtp", |
p.put("gnu.crypto.sasl.username", username); |
517 |
socket.getInetAddress().getHostName(), p, ch); |
p.put("gnu.crypto.sasl.password", password); |
518 |
|
SaslClient sasl = Sasl.createSaslClient(m, null, "smtp", |
519 |
StringBuffer cmd = new StringBuffer(AUTH); |
socket.getInetAddress(). |
520 |
cmd.append(' '); |
getHostName(), p, ch); |
521 |
cmd.append(mechanism); |
|
522 |
if (sasl.hasInitialResponse()) |
StringBuffer cmd = new StringBuffer(AUTH); |
523 |
{ |
cmd.append(' '); |
524 |
cmd.append(' '); |
cmd.append(mechanism); |
525 |
byte[] init = sasl.evaluateChallenge(new byte[0]); |
if (sasl.hasInitialResponse()) |
526 |
cmd.append(new String(init, "US-ASCII")); |
{ |
527 |
} |
cmd.append(' '); |
528 |
send(cmd.toString()); |
byte[]init = sasl.evaluateChallenge(new byte[0]); |
529 |
while (true) |
cmd.append(new String(init, "US-ASCII")); |
530 |
{ |
} |
531 |
switch (getResponse()) |
send(cmd.toString()); |
532 |
{ |
while (true) |
533 |
case 334: |
{ |
534 |
try |
switch (getResponse()) |
535 |
{ |
{ |
536 |
byte[] c0 = response.getBytes("US-ASCII"); |
case 334: |
537 |
byte[] c1 = BASE64.decode(c0); // challenge |
try |
538 |
byte[] r0 = sasl.evaluateChallenge(c1); |
{ |
539 |
byte[] r1 = BASE64.encode(r0); // response |
byte[]c0 = response.getBytes("US-ASCII"); |
540 |
out.write(r1); |
byte[]c1 = BASE64.decode(c0); // challenge |
541 |
out.write(0x0d); |
byte[]r0 = sasl.evaluateChallenge(c1); |
542 |
out.flush(); |
byte[]r1 = BASE64.encode(r0); // response |
543 |
} |
out.write(r1); |
544 |
catch (SaslException e) |
out.write(0x0d); |
545 |
{ |
out.flush(); |
546 |
// Error in SASL challenge evaluation - cancel exchange |
} |
547 |
out.write(0x2a); |
catch(SaslException e) |
548 |
out.write(0x0d); |
{ |
549 |
out.flush(); |
// Error in SASL challenge evaluation - cancel exchange |
550 |
} |
out.write(0x2a); |
551 |
break; |
out.write(0x0d); |
552 |
case 235: |
out.flush(); |
553 |
String qop = (String)sasl.getNegotiatedProperty(Sasl.QOP); |
} |
554 |
if ("auth-int".equalsIgnoreCase(qop) |
break; |
555 |
|| "auth-conf".equalsIgnoreCase(qop)) |
case 235: |
556 |
{ |
String qop = (String) sasl.getNegotiatedProperty(Sasl.QOP); |
557 |
InputStream in = socket.getInputStream(); |
if ("auth-int".equalsIgnoreCase(qop) |
558 |
in = new BufferedInputStream(in); |
|| "auth-conf".equalsIgnoreCase(qop)) |
559 |
in = new SaslInputStream(sasl, in); |
{ |
560 |
in = new CRLFInputStream(in); |
InputStream in = socket.getInputStream(); |
561 |
this.in = new LineInputStream(in); |
in = new BufferedInputStream(in); |
562 |
OutputStream out = socket.getOutputStream(); |
in = new SaslInputStream(sasl, in); |
563 |
out = new BufferedOutputStream(out); |
in = new CRLFInputStream(in); |
564 |
out = new SaslOutputStream(sasl, out); |
this.in = new LineInputStream(in); |
565 |
this.out = new CRLFOutputStream(out); |
OutputStream out = socket.getOutputStream(); |
566 |
} |
out = new BufferedOutputStream(out); |
567 |
return true; |
out = new SaslOutputStream(sasl, out); |
568 |
default: |
this.out = new CRLFOutputStream(out); |
569 |
return false; |
} |
570 |
} |
return true; |
571 |
} |
default: |
572 |
} |
return false; |
573 |
catch (SaslException e) |
} |
574 |
{ |
} |
575 |
return false; // No provider for mechanism |
} |
576 |
} |
catch(SaslException e) |
577 |
catch (ClassNotFoundException e) |
{ |
578 |
{ |
return false; // No provider for mechanism |
579 |
return false; // No javax.security.sasl classes |
} |
580 |
} |
catch(ClassNotFoundException e) |
581 |
} |
{ |
582 |
|
return false; // No javax.security.sasl classes |
583 |
|
} |
584 |
|
} |
585 |
|
|
586 |
/** |
/** |
587 |
* LOGIN authentication mechanism. |
* LOGIN authentication mechanism. |
588 |
* If this returns true, EHLO should be re-issued. |
* If this returns true, EHLO should be re-issued. |
637 |
* Send the specified command string to the server. |
* Send the specified command string to the server. |
638 |
* @param command the command to send |
* @param command the command to send |
639 |
*/ |
*/ |
640 |
protected void send(String command) |
protected void send(String command) throws IOException |
641 |
throws IOException |
{ |
642 |
{ |
if (debug) |
643 |
if (debug) |
{ |
644 |
{ |
Logger logger = Logger.getInstance(); |
645 |
Logger logger = Logger.getInstance(); |
logger.log("smtp", "> " + command); |
646 |
logger.log("smtp", "> "+command); |
} |
647 |
} |
out.write(command.getBytes("US-ASCII")); // TODO check encoding |
648 |
out.write(command.getBytes("US-ASCII")); // TODO check encoding |
out.write(0x0d); |
649 |
out.write(0x0d); |
out.flush(); |
650 |
out.flush(); |
} |
|
} |
|
651 |
|
|
652 |
/** |
/** |
653 |
* Returns the next response from the server. |
* Returns the next response from the server. |
654 |
*/ |
*/ |
655 |
protected int getResponse() |
protected int getResponse() throws IOException |
656 |
throws IOException |
{ |
657 |
{ |
String line = null; |
658 |
String line = null; |
try |
659 |
try |
{ |
660 |
{ |
line = in.readLine(); |
661 |
line = in.readLine(); |
// Handle special case eg 334 where CRLF occurs after code. |
662 |
// Handle special case eg 334 where CRLF occurs after code. |
if (line.length() < 4) |
663 |
if (line.length()<4) |
line = |
664 |
line = new StringBuffer(line) |
new StringBuffer(line).append('\n').append(in.readLine()). |
665 |
.append('\n') |
toString(); |
666 |
.append(in.readLine()) |
if (debug) |
667 |
.toString(); |
{ |
668 |
if (debug) |
Logger logger = Logger.getInstance(); |
669 |
{ |
logger.log("smtp", "< " + line); |
670 |
Logger logger = Logger.getInstance(); |
} |
671 |
logger.log("smtp", "< "+line); |
int code = Integer.parseInt(line.substring(0, 3)); |
672 |
} |
continuation = (line.charAt(3) == '-'); |
673 |
int code = Integer.parseInt(line.substring(0, 3)); |
response = line.substring(4); |
674 |
continuation = (line.charAt(3)=='-'); |
return code; |
675 |
response = line.substring(4); |
} |
676 |
return code; |
catch(NumberFormatException e) |
677 |
} |
{ |
678 |
catch (NumberFormatException e) |
throw new ProtocolException("Unexpected response: " + line); |
679 |
{ |
} |
680 |
throw new ProtocolException("Unexpected response: "+line); |
} |
|
} |
|
|
} |
|
681 |
|
|
682 |
} |
} |