++ CONNECTION *conn = nserv->conn;
++ char buf[LONG_STRING];
++ char authenticators[LONG_STRING] = "USER";
++ char *method, *a, *p;
++ unsigned char flags = conn->account.flags;
++
++ while (1)
++ {
++ /* get login and password */
++ if (mutt_account_getuser (&conn->account) || !conn->account.user[0] ||
++ mutt_account_getpass (&conn->account) || !conn->account.pass[0])
++ break;
++
++ /* get list of authenticators */
++ if (NntpAuthenticators && *NntpAuthenticators)
++ strfcpy (authenticators, NntpAuthenticators, sizeof (authenticators));
++ else if (nserv->hasCAPABILITIES)
++ {
++ strfcpy (authenticators, NONULL (nserv->authenticators),
++ sizeof (authenticators));
++ p = authenticators;
++ while (*p)
++ {
++ if (*p == ' ')
++ *p = ':';
++ p++;
++ }
++ }
++ p = authenticators;
++ while (*p)
++ {
++ *p = ascii_toupper (*p);
++ p++;
++ }
++
++ dprint (1, (debugfile,
++ "nntp_auth: available methods: %s\n", nserv->authenticators));
++ a = authenticators;
++ while (1)
++ {
++ if (!a)
++ {
++ mutt_error _("No authenticators available");
++ mutt_sleep (2);
++ break;
++ }
++
++ method = a;
++ a = strchr (a, ':');
++ if (a)
++ *a++ = '\0';
++
++ /* check authenticator */
++ if (nserv->hasCAPABILITIES)
++ {
++ char *m;
++
++ if (!nserv->authenticators)
++ continue;
++ m = strcasestr (nserv->authenticators, method);
++ if (!m)
++ continue;
++ if (m > nserv->authenticators && *(m - 1) != ' ')
++ continue;
++ m += strlen (method);
++ if (*m != '\0' && *m != ' ')
++ continue;
++ }
++ dprint (1, (debugfile, "nntp_auth: trying method %s\n", method));
++
++ /* AUTHINFO USER authentication */
++ if (!strcmp (method, "USER"))
++ {
++ mutt_message (_("Authenticating (%s)..."), method);
++ snprintf (buf, sizeof (buf), "AUTHINFO USER %s\r\n", conn->account.user);
++ if (mutt_socket_write (conn, buf) < 0 ||
++ mutt_socket_readln (buf, sizeof (buf), conn) < 0)
++ break;
++
++ /* authenticated, password is not required */
++ if (!mutt_strncmp ("281", buf, 3))
++ return 0;
++
++ /* username accepted, sending password */
++ if (!mutt_strncmp ("381", buf, 3))
++ {
++#ifdef DEBUG
++ if (debuglevel < MUTT_SOCK_LOG_FULL)
++ dprint (MUTT_SOCK_LOG_CMD, (debugfile,
++ "%d> AUTHINFO PASS *\n", conn->fd));
++#endif
++ snprintf (buf, sizeof (buf), "AUTHINFO PASS %s\r\n",
++ conn->account.pass);
++ if (mutt_socket_write_d (conn, buf, -1, MUTT_SOCK_LOG_FULL) < 0 ||
++ mutt_socket_readln (buf, sizeof (buf), conn) < 0)
++ break;
++
++ /* authenticated */
++ if (!mutt_strncmp ("281", buf, 3))
++ return 0;
++ }
++
++ /* server doesn't support AUTHINFO USER, trying next method */
++ if (*buf == '5')
++ continue;
++ }
++
++ else
++ {
++#ifdef USE_SASL
++ sasl_conn_t *saslconn;
++ sasl_interact_t *interaction = NULL;
++ int rc;
++ char inbuf[LONG_STRING] = "";
++ const char *mech;
++ const char *client_out = NULL;
++ unsigned int client_len, len;
++
++ if (mutt_sasl_client_new (conn, &saslconn) < 0)
++ {
++ dprint (1, (debugfile,
++ "nntp_auth: error allocating SASL connection.\n"));
++ continue;
++ }
++
++ while (1)
++ {
++ rc = sasl_client_start (saslconn, method, &interaction,
++ &client_out, &client_len, &mech);
++ if (rc != SASL_INTERACT)
++ break;
++ mutt_sasl_interact (interaction);
++ }
++ if (rc != SASL_OK && rc != SASL_CONTINUE)
++ {
++ sasl_dispose (&saslconn);
++ dprint (1, (debugfile,
++ "nntp_auth: error starting SASL authentication exchange.\n"));
++ continue;
++ }
++
++ mutt_message (_("Authenticating (%s)..."), method);
++ snprintf (buf, sizeof (buf), "AUTHINFO SASL %s", method);
++
++ /* looping protocol */
++ while (rc == SASL_CONTINUE || (rc == SASL_OK && client_len))
++ {
++ /* send out client response */
++ if (client_len)
++ {
++#ifdef DEBUG
++ if (debuglevel >= MUTT_SOCK_LOG_FULL)
++ {
++ char tmp[LONG_STRING];
++ memcpy (tmp, client_out, client_len);
++ for (p = tmp; p < tmp + client_len; p++)
++ {
++ if (*p == '\0')
++ *p = '.';
++ }
++ *p = '\0';
++ dprint (1, (debugfile, "SASL> %s\n", tmp));
++ }
++#endif
++
++ if (*buf)
++ safe_strcat (buf, sizeof (buf), " ");
++ len = strlen (buf);
++ if (sasl_encode64 (client_out, client_len,
++ buf + len, sizeof (buf) - len, &len) != SASL_OK)
++ {
++ dprint (1, (debugfile,
++ "nntp_auth: error base64-encoding client response.\n"));
++ break;
++ }
++ }
++
++ safe_strcat (buf, sizeof (buf), "\r\n");
++#ifdef DEBUG
++ if (debuglevel < MUTT_SOCK_LOG_FULL)
++ {
++ if (strchr (buf, ' '))
++ dprint (MUTT_SOCK_LOG_CMD, (debugfile, "%d> AUTHINFO SASL %s%s\n",
++ conn->fd, method, client_len ? " sasl_data" : ""));
++ else
++ dprint (MUTT_SOCK_LOG_CMD, (debugfile, "%d> sasl_data\n", conn->fd));
++ }
++#endif
++ client_len = 0;
++ if (mutt_socket_write_d (conn, buf, -1, MUTT_SOCK_LOG_FULL) < 0 ||
++ mutt_socket_readln_d (inbuf, sizeof (inbuf), conn, MUTT_SOCK_LOG_FULL) < 0)
++ break;
++ if (mutt_strncmp (inbuf, "283 ", 4) &&
++ mutt_strncmp (inbuf, "383 ", 4))
++ {
++#ifdef DEBUG
++ if (debuglevel < MUTT_SOCK_LOG_FULL)
++ dprint (MUTT_SOCK_LOG_CMD, (debugfile, "%d< %s\n", conn->fd, inbuf));
++#endif
++ break;
++ }
++#ifdef DEBUG
++ if (debuglevel < MUTT_SOCK_LOG_FULL)
++ {
++ inbuf[3] = '\0';
++ dprint (MUTT_SOCK_LOG_CMD, (debugfile,
++ "%d< %s sasl_data\n", conn->fd, inbuf));
++ }
++#endif
++
++ if (!strcmp ("=", inbuf + 4))
++ len = 0;
++ else if (sasl_decode64 (inbuf + 4, strlen (inbuf + 4),
++ buf, sizeof (buf) - 1, &len) != SASL_OK)
++ {
++ dprint (1, (debugfile,
++ "nntp_auth: error base64-decoding server response.\n"));
++ break;
++ }
++#ifdef DEBUG
++ else if (debuglevel >= MUTT_SOCK_LOG_FULL)
++ {
++ char tmp[LONG_STRING];
++ memcpy (tmp, buf, len);
++ for (p = tmp; p < tmp + len; p++)
++ {
++ if (*p == '\0')
++ *p = '.';
++ }
++ *p = '\0';
++ dprint (1, (debugfile, "SASL< %s\n", tmp));
++ }
++#endif
++
++ while (1)
++ {
++ rc = sasl_client_step (saslconn, buf, len,
++ &interaction, &client_out, &client_len);
++ if (rc != SASL_INTERACT)
++ break;
++ mutt_sasl_interact (interaction);
++ }
++ if (*inbuf != '3')
++ break;
++
++ *buf = '\0';
++ } /* looping protocol */
++
++ if (rc == SASL_OK && client_len == 0 && *inbuf == '2')
++ {
++ mutt_sasl_setup_conn (conn, saslconn);
++ return 0;
++ }
++
++ /* terminate SASL sessoin */
++ sasl_dispose (&saslconn);
++ if (conn->fd < 0)
++ break;
++ if (!mutt_strncmp (inbuf, "383 ", 4))
++ {
++ if (mutt_socket_write (conn, "*\r\n") < 0 ||
++ mutt_socket_readln (inbuf, sizeof (inbuf), conn) < 0)
++ break;
++ }
++
++ /* server doesn't support AUTHINFO SASL, trying next method */
++ if (*inbuf == '5')
++ continue;
++#else
++ continue;
++#endif /* USE_SASL */
++ }
++
++ mutt_error (_("%s authentication failed."), method);
++ mutt_sleep (2);
++ break;
++ }
++ break;
++ }
++
++ /* error */
++ nserv->status = NNTP_BYE;
++ conn->account.flags = flags;
++ if (conn->fd < 0)
++ {
++ mutt_error _("Server closed connection!");
++ mutt_sleep (2);
++ }
++ else
++ mutt_socket_close (conn);