1 #ifndef SMTP_CLIENT_COMMAND
2 #define SMTP_CLIENT_COMMAND
3 
4 struct smtp_reply;
5 struct smtp_params_mail;
6 struct smtp_params_rcpt;
7 struct smtp_client_command;
8 struct smtp_client_connection;
9 
10 enum smtp_client_command_state {
11 	SMTP_CLIENT_COMMAND_STATE_NEW = 0,
12 	SMTP_CLIENT_COMMAND_STATE_SUBMITTED,
13 	SMTP_CLIENT_COMMAND_STATE_SENDING,
14 	SMTP_CLIENT_COMMAND_STATE_WAITING,
15 	SMTP_CLIENT_COMMAND_STATE_FINISHED,
16 	SMTP_CLIENT_COMMAND_STATE_ABORTED
17 };
18 
19 enum smtp_client_command_flags {
20 	/* The command is sent to server before login (or is the login
21 	   command itself). Non-prelogin commands will be queued until login
22 	   is successful. */
23 	SMTP_CLIENT_COMMAND_FLAG_PRELOGIN = 0x01,
24 	/* This command may be positioned anywhere in a PIPELINING group. */
25 	SMTP_CLIENT_COMMAND_FLAG_PIPELINE = 0x02,
26 	/* This command has priority and needs to be inserted before anything
27 	   else. This is e.g. used to make sure that the initial handshake
28 	   commands are sent before any other command that may already be
29 	   submitted to the connection. */
30 	SMTP_CLIENT_COMMAND_FLAG_PRIORITY = 0x04
31 };
32 
33 /* Called when reply is received for command. */
34 typedef void smtp_client_command_callback_t(const struct smtp_reply *reply,
35 					    void *context);
36 
37 struct smtp_client_command *
38 smtp_client_command_new(struct smtp_client_connection *conn,
39 			enum smtp_client_command_flags flags,
40 			smtp_client_command_callback_t *callback,
41 			void *context);
42 #define smtp_client_command_new(conn, flags, callback, context) \
43 	smtp_client_command_new(conn, flags - \
44 		CALLBACK_TYPECHECK(callback, void (*)( \
45 			const struct smtp_reply *reply, typeof(context))), \
46 		(smtp_client_command_callback_t *)callback, context)
47 
48 /* Create a plug command, which is a dummy command that blocks the send queue.
49    This is used by transactions to prevent subsequently submitted
50    transactions from messing up the command sequence while the present
51    transaction is still submitting commands. The plug command is aborted once
52    the send queue is to be released. */
53 struct smtp_client_command *
54 smtp_client_command_plug(struct smtp_client_connection *conn,
55 			 struct smtp_client_command *after);
56 
57 void smtp_client_command_ref(struct smtp_client_command *cmd);
58 bool smtp_client_command_unref(struct smtp_client_command **_cmd)
59 			       ATTR_NOWARN_UNUSED_RESULT;
60 
61 bool smtp_client_command_name_equals(struct smtp_client_command *cmd,
62 				     const char *name);
63 
64 /* Lock the command; no commands after this one will be sent until this one
65    finishes */
66 void smtp_client_command_lock(struct smtp_client_command *cmd);
67 void smtp_client_command_unlock(struct smtp_client_command *cmd);
68 
69 void smtp_client_command_set_flags(struct smtp_client_command *cmd,
70 				   enum smtp_client_command_flags flags);
71 void smtp_client_command_set_stream(struct smtp_client_command *cmd,
72 				    struct istream *input, bool dot);
73 
74 void smtp_client_command_write(struct smtp_client_command *cmd,
75 			       const char *cmd_str);
76 void smtp_client_command_printf(struct smtp_client_command *cmd,
77 				const char *cmd_fmt, ...) ATTR_FORMAT(2, 3);
78 void smtp_client_command_vprintf(struct smtp_client_command *cmd,
79 				 const char *cmd_fmt, va_list args)
80 				 ATTR_FORMAT(2, 0);
81 
82 void smtp_client_command_submit_after(struct smtp_client_command *cmd,
83 				      struct smtp_client_command *after);
84 void smtp_client_command_submit(struct smtp_client_command *cmd);
85 
86 void smtp_client_command_abort(struct smtp_client_command **_cmd);
87 void smtp_client_command_set_abort_callback(struct smtp_client_command *cmd,
88 					    void (*callback)(void *context),
89 					    void *context);
90 
91 void smtp_client_command_set_sent_callback(struct smtp_client_command *cmd,
92 					   void (*callback)(void *context),
93 					   void *context);
94 
95 void smtp_client_command_set_replies(struct smtp_client_command *cmd,
96 				     unsigned int replies);
97 
98 enum smtp_client_command_state
99 smtp_client_command_get_state(struct smtp_client_command *cmd) ATTR_PURE;
100 
101 
102 /*
103  * Standard commands
104  */
105 
106 /* Send NOOP */
107 struct smtp_client_command *
108 smtp_client_command_noop_submit_after(struct smtp_client_connection *conn,
109 				      enum smtp_client_command_flags flags,
110 				      struct smtp_client_command *after,
111 				      smtp_client_command_callback_t *callback,
112 				      void *context);
113 #define smtp_client_command_noop_submit_after(conn, flags, after, \
114 					      callback, context) \
115 	smtp_client_command_noop_submit_after(conn, flags - \
116 		CALLBACK_TYPECHECK(callback, void (*)( \
117 			const struct smtp_reply *reply, typeof(context))), \
118 		after, (smtp_client_command_callback_t *)callback, context)
119 struct smtp_client_command *
120 smtp_client_command_noop_submit(struct smtp_client_connection *conn,
121 				enum smtp_client_command_flags flags,
122 				smtp_client_command_callback_t *callback,
123 				void *context);
124 #define smtp_client_command_noop_submit(conn, flags, callback, context) \
125 	smtp_client_command_noop_submit(conn, flags - \
126 		CALLBACK_TYPECHECK(callback, void (*)( \
127 			const struct smtp_reply *reply, typeof(context))), \
128 		(smtp_client_command_callback_t *)callback, context)
129 
130 /* Send VRFY <param> */
131 struct smtp_client_command *
132 smtp_client_command_vrfy_submit_after(struct smtp_client_connection *conn,
133 				      enum smtp_client_command_flags flags,
134 				      struct smtp_client_command *after,
135 				      const char *param,
136 				      smtp_client_command_callback_t *callback,
137 				      void *context);
138 #define smtp_client_command_vrfy_submit_after(conn, flags, after, param, \
139 					      callback, context) \
140 	smtp_client_command_vrfy_submit_after(conn, flags - \
141 		CALLBACK_TYPECHECK(callback, void (*)( \
142 			const struct smtp_reply *reply, typeof(context))), \
143 		after, param, \
144 		(smtp_client_command_callback_t *)callback, context)
145 struct smtp_client_command *
146 smtp_client_command_vrfy_submit(struct smtp_client_connection *conn,
147 				enum smtp_client_command_flags flags,
148 				const char *param,
149 				smtp_client_command_callback_t *callback,
150 				void *context);
151 #define smtp_client_command_vrfy_submit(conn, flags, param, callback, context) \
152 	smtp_client_command_vrfy_submit(conn, flags - \
153 		CALLBACK_TYPECHECK(callback, void (*)( \
154 			const struct smtp_reply *reply, typeof(context))), \
155 		param, (smtp_client_command_callback_t *)callback, context)
156 
157 /* Send RSET */
158 struct smtp_client_command *
159 smtp_client_command_rset_submit_after(struct smtp_client_connection *conn,
160 				      enum smtp_client_command_flags flags,
161 				      struct smtp_client_command *after,
162 				      smtp_client_command_callback_t *callback,
163 				      void *context);
164 #define smtp_client_command_rset_submit_after(conn, flags, after, \
165 					      callback, context) \
166 	smtp_client_command_rset_submit_after(conn, flags - \
167 		CALLBACK_TYPECHECK(callback, void (*)( \
168 			const struct smtp_reply *reply, typeof(context))), \
169 		after, (smtp_client_command_callback_t *)callback, context)
170 struct smtp_client_command *
171 smtp_client_command_rset_submit(struct smtp_client_connection *conn,
172 				enum smtp_client_command_flags flags,
173 				smtp_client_command_callback_t *callback,
174 				void *context);
175 #define smtp_client_command_rset_submit(conn, flags, callback, context) \
176 	smtp_client_command_rset_submit(conn, flags - \
177 		CALLBACK_TYPECHECK(callback, void (*)( \
178 			const struct smtp_reply *reply, typeof(context))), \
179 		(smtp_client_command_callback_t *)callback, context)
180 
181 /* Send MAIL FROM:<address> <params...> */
182 struct smtp_client_command *
183 smtp_client_command_mail_submit(struct smtp_client_connection *conn,
184 				enum smtp_client_command_flags flags,
185 				const struct smtp_address *from,
186 				const struct smtp_params_mail *params,
187 				smtp_client_command_callback_t *callback,
188 				void *context);
189 #define smtp_client_command_mail_submit(conn, flags, address, params, \
190 					callback, context) \
191 	smtp_client_command_mail_submit(conn, flags - \
192 		CALLBACK_TYPECHECK(callback, void (*)( \
193 			const struct smtp_reply *reply, typeof(context))), \
194 		address, params, \
195 		(smtp_client_command_callback_t *)callback, context)
196 
197 /* send RCPT TO:<address> parameters */
198 struct smtp_client_command *
199 smtp_client_command_rcpt_submit_after(struct smtp_client_connection *conn,
200 				      enum smtp_client_command_flags flags,
201 				      struct smtp_client_command *after,
202 				      const struct smtp_address *to,
203 				      const struct smtp_params_rcpt *params,
204 				      smtp_client_command_callback_t *callback,
205 				      void *context);
206 #define smtp_client_command_rcpt_submit_after(conn, flags, after, to, params, \
207 					      callback, context) \
208 	smtp_client_command_rcpt_submit_after(conn, flags - \
209 		CALLBACK_TYPECHECK(callback, void (*)( \
210 			const struct smtp_reply *reply, typeof(context))), \
211 		after, to, params, \
212 		(smtp_client_command_callback_t *)callback, context)
213 struct smtp_client_command *
214 smtp_client_command_rcpt_submit(struct smtp_client_connection *conn,
215 				enum smtp_client_command_flags flags,
216 				const struct smtp_address *to,
217 				const struct smtp_params_rcpt *params,
218 				smtp_client_command_callback_t *callback,
219 				void *context);
220 #define smtp_client_command_rcpt_submit(conn, flags, to, params, \
221 					callback, context) \
222 	smtp_client_command_rcpt_submit(conn, flags - \
223 		CALLBACK_TYPECHECK(callback, void (*)( \
224 			const struct smtp_reply *reply, typeof(context))), \
225 		to, params, \
226 		(smtp_client_command_callback_t *)callback, context)
227 
228 /* Send message data using DATA or BDAT (preferred if supported).
229    This handles the DATA 354 response implicitly. Making sure that the data has
230    CRLF line endings consistently is the responsibility of the caller.
231  */
232 struct smtp_client_command *
233 smtp_client_command_data_submit_after(struct smtp_client_connection *conn,
234 				      enum smtp_client_command_flags flags,
235 				      struct smtp_client_command *after,
236 				      struct istream *data,
237 				      smtp_client_command_callback_t *callback,
238 				      void *context);
239 #define smtp_client_command_data_submit_after(conn, flags, after, data, \
240 					      callback, context) \
241 	smtp_client_command_data_submit_after(conn, flags - \
242 		CALLBACK_TYPECHECK(callback, void (*)( \
243 			const struct smtp_reply *reply, typeof(context))), \
244 		after, data, \
245 		(smtp_client_command_callback_t *)callback, context)
246 struct smtp_client_command *
247 smtp_client_command_data_submit(struct smtp_client_connection *conn,
248 				enum smtp_client_command_flags flags,
249 				struct istream *data,
250 				smtp_client_command_callback_t *callback,
251 				void *context);
252 #define smtp_client_command_data_submit(conn, flags, data, callback, context) \
253 	smtp_client_command_data_submit(conn, flags - \
254 		CALLBACK_TYPECHECK(callback, void (*)( \
255 			const struct smtp_reply *reply, typeof(context))), \
256 		data, (smtp_client_command_callback_t *)callback, context)
257 
258 #endif
259