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