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