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.buffer.ByteBufUtil;
20 import io.netty.buffer.Unpooled;
21 import io.netty.channel.ChannelHandlerContext;
22 import io.netty.handler.codec.MessageToMessageEncoder;
23 import io.netty.util.LeakPresenceDetector;
24 import io.netty.util.internal.UnstableApi;
25
26 import java.util.Iterator;
27 import java.util.List;
28 import java.util.RandomAccess;
29
30
31
32
33 @UnstableApi
34 public final class SmtpRequestEncoder extends MessageToMessageEncoder<Object> {
35 private static final int CRLF_SHORT = ('\r' << 8) | '\n';
36 private static final byte SP = ' ';
37 private static final ByteBuf DOT_CRLF_BUFFER = LeakPresenceDetector.staticInitializer(() ->
38 Unpooled.unreleasableBuffer(Unpooled.directBuffer(3)
39 .writeByte('.').writeByte('\r').writeByte('\n')).asReadOnly());
40
41 private boolean contentExpected;
42
43 public SmtpRequestEncoder() {
44 super(Object.class);
45 }
46
47 @Override
48 public boolean acceptOutboundMessage(Object msg) throws Exception {
49 return msg instanceof SmtpRequest || msg instanceof SmtpContent;
50 }
51
52 @Override
53 protected void encode(ChannelHandlerContext ctx, Object msg, List<Object> out) throws Exception {
54 if (msg instanceof SmtpRequest) {
55 final SmtpRequest req = (SmtpRequest) msg;
56 if (contentExpected) {
57 if (req.command().equals(SmtpCommand.RSET)) {
58 contentExpected = false;
59 } else {
60 throw new IllegalStateException("SmtpContent expected");
61 }
62 }
63 boolean release = true;
64 final ByteBuf buffer = ctx.alloc().buffer();
65 try {
66 req.command().encode(buffer);
67 boolean notEmpty = req.command() != SmtpCommand.EMPTY;
68 writeParameters(req.parameters(), buffer, notEmpty);
69 ByteBufUtil.writeShortBE(buffer, CRLF_SHORT);
70 out.add(buffer);
71 release = false;
72 if (req.command().isContentExpected()) {
73 contentExpected = true;
74 }
75 } finally {
76 if (release) {
77 buffer.release();
78 }
79 }
80 }
81
82 if (msg instanceof SmtpContent) {
83 if (!contentExpected) {
84 throw new IllegalStateException("No SmtpContent expected");
85 }
86 final ByteBuf content = ((SmtpContent) msg).content();
87 out.add(content.retain());
88 if (msg instanceof LastSmtpContent) {
89 out.add(DOT_CRLF_BUFFER.retainedDuplicate());
90 contentExpected = false;
91 }
92 }
93 }
94
95 private static void writeParameters(List<CharSequence> parameters, ByteBuf out, boolean commandNotEmpty) {
96 if (parameters.isEmpty()) {
97 return;
98 }
99 if (commandNotEmpty) {
100 out.writeByte(SP);
101 }
102 if (parameters instanceof RandomAccess) {
103 final int sizeMinusOne = parameters.size() - 1;
104 for (int i = 0; i < sizeMinusOne; i++) {
105 ByteBufUtil.writeAscii(out, parameters.get(i));
106 out.writeByte(SP);
107 }
108 ByteBufUtil.writeAscii(out, parameters.get(sizeMinusOne));
109 } else {
110 final Iterator<CharSequence> params = parameters.iterator();
111 for (;;) {
112 ByteBufUtil.writeAscii(out, params.next());
113 if (params.hasNext()) {
114 out.writeByte(SP);
115 } else {
116 break;
117 }
118 }
119 }
120 }
121 }