1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package io.netty.handler.codec.smtp;
17
18 import io.netty.buffer.ByteBuf;
19 import io.netty.channel.ChannelHandlerContext;
20 import io.netty.handler.codec.DecoderException;
21 import io.netty.handler.codec.LineBasedFrameDecoder;
22 import io.netty.util.CharsetUtil;
23 import io.netty.util.internal.UnstableApi;
24
25 import java.util.ArrayList;
26 import java.util.Collections;
27 import java.util.List;
28
29
30
31
32 @UnstableApi
33 public final class SmtpResponseDecoder extends LineBasedFrameDecoder {
34
35 private List<CharSequence> details;
36
37
38
39
40 public SmtpResponseDecoder(int maxLineLength) {
41 super(maxLineLength);
42 }
43
44 @Override
45 protected SmtpResponse decode(ChannelHandlerContext ctx, ByteBuf buffer) throws Exception {
46 ByteBuf frame = (ByteBuf) super.decode(ctx, buffer);
47 if (frame == null) {
48
49 return null;
50 }
51 try {
52 final int readable = frame.readableBytes();
53 final int readerIndex = frame.readerIndex();
54 if (readable < 3) {
55 throw newDecoderException(buffer, readerIndex, readable);
56 }
57 final int code = parseCode(frame);
58 final int separator = frame.readByte();
59 final CharSequence detail = frame.isReadable() ? frame.toString(CharsetUtil.US_ASCII) : null;
60
61 List<CharSequence> details = this.details;
62
63 switch (separator) {
64 case ' ':
65
66 this.details = null;
67 if (details != null) {
68 if (detail != null) {
69 details.add(detail);
70 }
71 } else {
72 if (detail == null) {
73 details = Collections.emptyList();
74 } else {
75 details = Collections.singletonList(detail);
76 }
77 }
78 return new DefaultSmtpResponse(code, details);
79 case '-':
80
81 if (detail != null) {
82 if (details == null) {
83
84
85 this.details = details = new ArrayList<CharSequence>(4);
86 }
87 details.add(detail);
88 }
89 break;
90 default:
91 throw newDecoderException(buffer, readerIndex, readable);
92 }
93 } finally {
94 frame.release();
95 }
96 return null;
97 }
98
99 private static DecoderException newDecoderException(ByteBuf buffer, int readerIndex, int readable) {
100 return new DecoderException(
101 "Received invalid line: '" + buffer.toString(readerIndex, readable, CharsetUtil.US_ASCII) + '\'');
102 }
103
104
105
106
107 private static int parseCode(ByteBuf buffer) {
108 final int first = parseNumber(buffer.readByte()) * 100;
109 final int second = parseNumber(buffer.readByte()) * 10;
110 final int third = parseNumber(buffer.readByte());
111 return first + second + third;
112 }
113
114 private static int parseNumber(byte b) {
115 return Character.digit((char) b, 10);
116 }
117 }