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