smtp_helo (CamelSmtpTransport *transport,
	   CamelStreamBuffer *istream,
	   CamelStream *ostream,
	   gboolean ignore_8bitmime,
           GCancellable *cancellable,
           GError **error)
{
	gchar *name = NULL, *cmdbuf = NULL, *respbuf = NULL;
	gboolean first_line = TRUE;
	const gchar *token;
	GResolver *resolver;
	GInetAddress *address;
	GError *local_error = NULL;

	/* these are flags that we set, so unset them in case we
	 * are being called a second time (ie, after a STARTTLS) */
	transport->flags &= ~(CAMEL_SMTP_TRANSPORT_8BITMIME |
			      CAMEL_SMTP_TRANSPORT_ENHANCEDSTATUSCODES |
			      CAMEL_SMTP_TRANSPORT_STARTTLS);

	if (transport->authtypes) {
		g_hash_table_foreach (transport->authtypes, authtypes_free, NULL);
		g_hash_table_destroy (transport->authtypes);
		transport->authtypes = NULL;
	}

	resolver = g_resolver_get_default ();
	address = g_inet_socket_address_get_address (
		G_INET_SOCKET_ADDRESS (transport->local_address));

	name = g_resolver_lookup_by_address (
		resolver, address, cancellable, &local_error);

	/* Sanity check. */
	g_return_val_if_fail (
		((name != NULL) && (local_error == NULL)) ||
		((name == NULL) && (local_error != NULL)), FALSE);

	if (g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_CANCELLED))
		return FALSE;

	g_clear_error (&local_error);

	if (name == NULL) {
		GSocketFamily family;
		gchar *string;

		string = g_inet_address_to_string (address);
		family = g_inet_address_get_family (address);
		if (family == G_SOCKET_FAMILY_IPV6)
			name = g_strdup_printf ("[IPv6:%s]", string);
		else
			name = g_strdup_printf ("[%s]", string);
		g_free (string);
	}

	camel_operation_push_message (cancellable, _("SMTP Greeting"));

	token = (transport->flags & CAMEL_SMTP_TRANSPORT_IS_ESMTP) ? "EHLO" : "HELO";
	cmdbuf = g_strdup_printf ("%s %s\r\n", token, name);
	g_free (name);

	d (fprintf (stderr, "[SMTP] sending: %s", cmdbuf));
	if (camel_stream_write_string (ostream, cmdbuf, cancellable, error) == -1) {
		g_free (cmdbuf);
		g_prefix_error (error, _("HELO command failed: "));
		camel_operation_pop_message (cancellable);

		return FALSE;
	}
	g_free (cmdbuf);

	do {
		/* Check for "250" */
		g_free (respbuf);
		respbuf = camel_stream_buffer_read_line (istream, cancellable, error);
		d (fprintf (stderr, "[SMTP] received: %s\n", respbuf ? respbuf : "(null)"));
		if (respbuf == NULL) {
			g_prefix_error (error, _("HELO command failed: "));
			transport->connected = FALSE;
			camel_operation_pop_message (cancellable);
			return FALSE;
		}
		if (strncmp (respbuf, "250", 3)) {
			smtp_set_error (transport, istream, respbuf, cancellable, error);
			g_prefix_error (error, _("HELO command failed: "));
			camel_operation_pop_message (cancellable);
			g_free (respbuf);
			return FALSE;
		}

		token = respbuf + 4;

		if (first_line) {
			ignore_8bitmime = ignore_8bitmime || camel_strstrcase (token, "yahoo.com") != NULL;
			first_line = FALSE;
		}

		if (transport->flags & CAMEL_SMTP_TRANSPORT_IS_ESMTP) {
			if (!g_ascii_strncasecmp (token, "8BITMIME", 8)) {
				if (ignore_8bitmime)
					d (fprintf (stderr, "[SMTP] Ignoring 8BITMIME extension\n"));
				else
					transport->flags |= CAMEL_SMTP_TRANSPORT_8BITMIME;
			} else if (!g_ascii_strncasecmp (token, "ENHANCEDSTATUSCODES", 19)) {
				transport->flags |= CAMEL_SMTP_TRANSPORT_ENHANCEDSTATUSCODES;
			} else if (!g_ascii_strncasecmp (token, "STARTTLS", 8)) {
				transport->flags |= CAMEL_SMTP_TRANSPORT_STARTTLS;
			} else if (!g_ascii_strncasecmp (token, "AUTH", 4)) {
				if (!transport->authtypes || transport->flags & CAMEL_SMTP_TRANSPORT_AUTH_EQUAL) {
					/* Don't bother parsing any authtypes if we already have a list.
					 * Some servers will list AUTH twice, once the standard way and
					 * once the way Microsoft Outlook requires them to be:
					 *
					 * 250-AUTH LOGIN PLAIN DIGEST-MD5 CRAM-MD5
					 * 250-AUTH=LOGIN PLAIN DIGEST-MD5 CRAM-MD5
					 *
					 * Since they can come in any order, parse each list that we get
					 * until we parse an authtype list that does not use the AUTH=
					 * format. We want to let the standard way have priority over the
					 * broken way.
					 **/

					if (token[4] == '=')
						transport->flags |= CAMEL_SMTP_TRANSPORT_AUTH_EQUAL;
					else
						transport->flags &= ~CAMEL_SMTP_TRANSPORT_AUTH_EQUAL;

					/* parse for supported AUTH types */
					token += 4;

					if (transport->authtypes) {
						g_hash_table_foreach (transport->authtypes, authtypes_free, NULL);
						g_hash_table_destroy (transport->authtypes);
					}

					transport->authtypes = esmtp_get_authtypes ((const guchar *) token);
				}
			}
		}
	} while (*(respbuf+3) == '-'); /* if we got "250-" then loop again */
	g_free (respbuf);

	camel_operation_pop_message (cancellable);

	return TRUE;
}