comparison src/smtp_out.c @ 246:4cff8638dd9b

SMTP client: tries EHLO now always first Changed the behavior of the SMTP client. Now always an EHLO greeting is sent, no matter what kind of greeting text the server had sent. If the EHLO failed, an HELO greeting is tried as fall back. This is the behavior RFC 2821 requires (section 3.2). This change will fix setups that were not possible to sent to a server because that requires AUTH but hadn't said ``ESMTP'' in its greeting message. See also: Debian bug #349211 Thanks to Steffen (inne)
author markus schnalke <meillo@marmaro.de>
date Thu, 28 Oct 2010 16:40:02 -0300
parents 589c365d90b1
children c74adb7c4f50
comparison
equal deleted inserted replaced
245:2f5e2b6a3a39 246:4cff8638dd9b
119 119
120 smtp_base *psb = (smtp_base *) g_malloc(sizeof(smtp_base)); 120 smtp_base *psb = (smtp_base *) g_malloc(sizeof(smtp_base));
121 121
122 psb->sock = sock; 122 psb->sock = sock;
123 123
124 psb->use_esmtp = FALSE;
125 psb->use_size = FALSE; 124 psb->use_size = FALSE;
126 psb->use_pipelining = FALSE; 125 psb->use_pipelining = FALSE;
127 psb->use_auth = FALSE; 126 psb->use_auth = FALSE;
128 127
129 psb->max_size = 0; 128 psb->max_size = 0;
197 DEBUG(6) debugf("response failure:'%s' after_data = %d\n", psb->buffer, (int) after_data); 196 DEBUG(6) debugf("response failure:'%s' after_data = %d\n", psb->buffer, (int) after_data);
198 return FALSE; 197 return FALSE;
199 } 198 }
200 } 199 }
201 200
202 static gboolean
203 check_init_response(smtp_base * psb)
204 {
205 if (check_response(psb, FALSE)) {
206 psb->use_esmtp = (strstr(psb->buffer, "ESMTP") != NULL);
207
208 DEBUG(4) debugf(psb->use_esmtp ? "uses esmtp\n" : "no esmtp\n");
209
210 return TRUE;
211 }
212 return FALSE;
213 }
214
215 static gchar* 201 static gchar*
216 get_response_arg(gchar * response) 202 get_response_arg(gchar * response)
217 { 203 {
218 gchar buf[SMTP_BUF_LEN]; 204 gchar buf[SMTP_BUF_LEN];
219 gchar *p = response, *q = buf; 205 gchar *p = response, *q = buf;
295 } 281 }
296 282
297 return TRUE; 283 return TRUE;
298 } 284 }
299 285
286 /*
287 We first try EHLO, but if it fails HELO in a second fall back try.
288 This is what is requested by RFC 2821 (sec 3.2):
289
290 Once the server has sent the welcoming message and
291 the client has received it, the client normally sends
292 the EHLO command to the server, [...]
293 For a particular connection attempt, if the server
294 returns a "command not recognized" response to EHLO,
295 the client SHOULD be able to fall back and send HELO.
296
297 Up to and including version 0.3.0 masqmail used ESMTP only if the
298 string ``ESMTP'' appeared within the server's greeting message. This
299 made it impossible to use AUTH with servers that would send odd
300 greeting messages.
301 */
300 static gboolean 302 static gboolean
301 smtp_helo(smtp_base * psb, gchar * helo) 303 smtp_helo(smtp_base * psb, gchar * helo)
302 { 304 {
303 while (TRUE) { 305 fprintf(psb->out, "EHLO %s\r\n", helo);
304 if (psb->use_esmtp) { 306 fflush(psb->out);
305 fprintf(psb->out, "EHLO %s\r\n", helo); 307 DEBUG(4) debugf("C: EHLO %s\r\n", helo);
306 fflush(psb->out); 308
307 309 if (!read_response(psb, SMTP_CMD_TIMEOUT)) {
308 DEBUG(4) debugf("C: EHLO %s\r\n", helo); 310 return FALSE;
309 311 }
310 } else { 312 if (check_helo_response(psb)) {
311 fprintf(psb->out, "HELO %s\r\n", helo); 313 DEBUG(4) debugf("uses esmtp\n");
312 fflush(psb->out); 314 return TRUE;
313 315 }
314 DEBUG(4) debugf("C: HELO %s\r\n", helo); 316
315 317 if (psb->error != smtp_fail) {
316 } 318 return FALSE;
317 319 }
318 if (!read_response(psb, SMTP_CMD_TIMEOUT)) 320
319 return FALSE; 321 /* our guess that server understands EHLO could have been wrong,
320 322 try again with HELO */
321 if (check_helo_response(psb)) 323
322 return TRUE; 324 fprintf(psb->out, "HELO %s\r\n", helo);
323 else { 325 fflush(psb->out);
324 if (psb->error == smtp_fail) { 326 DEBUG(4) debugf("C: HELO %s\r\n", helo);
325 if (psb->use_esmtp) { 327
326 /* our guess that server understands EHLO was wrong, try again with HELO */ 328 if (!read_response(psb, SMTP_CMD_TIMEOUT)) {
327 psb->use_esmtp = FALSE; 329 return FALSE;
328 } else { 330 }
329 /* what sort of server ist THAT ?! give up... */ 331 if (check_helo_response(psb)) {
330 return FALSE; 332 DEBUG(4) debugf("uses smtp\n");
331 } 333 return TRUE;
332 } else 334 }
333 return FALSE; 335
334 } 336 /* what sort of server ist THAT ?! give up... */
335 } 337 return FALSE;
336 } 338 }
337 339
338 static void 340 static void
339 smtp_cmd_mailfrom(smtp_base * psb, address * return_path, guint size) 341 smtp_cmd_mailfrom(smtp_base * psb, address * return_path, guint size)
340 { 342 {
689 { 691 {
690 gboolean ok; 692 gboolean ok;
691 693
692 logwrite(LOG_INFO, "smtp_out_init(): instant_helo:%d\n", instant_helo); 694 logwrite(LOG_INFO, "smtp_out_init(): instant_helo:%d\n", instant_helo);
693 695
694 if (instant_helo) { 696 if (!instant_helo) {
695 /* we say hello right away, hence we don't know if
696 ESMTP is supported; we just assume it */
697 psb->use_esmtp = 1;
698 } else {
699 if ((ok = read_response(psb, SMTP_INITIAL_TIMEOUT))) { 697 if ((ok = read_response(psb, SMTP_INITIAL_TIMEOUT))) {
700 ok = check_init_response(psb); 698 ok = check_response(psb, FALSE);
701 } 699 }
702 if (!ok) { 700 if (!ok) {
703 smtp_out_log_failure(psb, NULL); 701 smtp_out_log_failure(psb, NULL);
704 return ok; 702 return ok;
705 } 703 }
883 if (psb->error == smtp_ok) { 881 if (psb->error == smtp_ok) {
884 GList *rcpt_node; 882 GList *rcpt_node;
885 for (rcpt_node = g_list_first(rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) { 883 for (rcpt_node = g_list_first(rcpt_list); rcpt_node; rcpt_node = g_list_next(rcpt_node)) {
886 address *rcpt = (address *) (rcpt_node->data); 884 address *rcpt = (address *) (rcpt_node->data);
887 if (addr_is_delivered(rcpt)) 885 if (addr_is_delivered(rcpt))
888 logwrite(LOG_NOTICE, "%s => %s host=%s with %s\n", msg->uid, addr_string(rcpt), 886 logwrite(LOG_NOTICE, "%s => %s host=%s\n",
889 psb->remote_host, psb->use_esmtp ? "esmtp" : "smtp"); 887 msg->uid, addr_string(rcpt), psb->remote_host);
890 } 888 }
891 } else { 889 } else {
892 /* if something went wrong, 890 /* if something went wrong,
893 we have to unmark the rcpts prematurely marked as delivered 891 we have to unmark the rcpts prematurely marked as delivered
894 and mark the status */ 892 and mark the status */