void QxtSmtpPrivate::authenticate() { if (!extensions.contains("AUTH") || username.isEmpty() || password.isEmpty()) { state = Authenticated; emit qxt_p().authenticated(); } else { QStringList auth = extensions["AUTH"].toUpper().split(' ', QString::SkipEmptyParts); if (auth.contains("CRAM-MD5")) { authCramMD5(); } else if (auth.contains("PLAIN")) { authPlain(); } else if (auth.contains("LOGIN")) { authLogin(); } else { state = Authenticated; emit qxt_p().authenticated(); } } }
void QxtSmtpPrivate::socketRead() { buffer += socket->readAll(); while (true) { int pos = buffer.indexOf("\r\n"); if (pos < 0) return; QByteArray line = buffer.left(pos); buffer = buffer.mid(pos + 2); QByteArray code = line.left(3); switch (state) { case StartState: if (code[0] != '2') { socket->disconnectFromHost(); } else { ehlo(); } break; case HeloSent: case EhloSent: case EhloGreetReceived: parseEhlo(code, (line[3] != ' '), line.mid(4)); break; #ifndef QT_NO_OPENSSL case StartTLSSent: if (code == "220") { socket->startClientEncryption(); ehlo(); } else { authenticate(); } break; #endif case AuthRequestSent: case AuthUsernameSent: if (authType == AuthPlain) authPlain(); else if (authType == AuthLogin) authLogin(); else authCramMD5(line.mid(4)); break; case AuthSent: if (code[0] == '2') { state = Authenticated; emit qxt_p().authenticated(); } else { state = Disconnected; emit qxt_p().authenticationFailed(); emit qxt_p().authenticationFailed( line ); emit socket->disconnectFromHost(); } break; case MailToSent: case RcptAckPending: if (code[0] != '2') { emit qxt_p().mailFailed( pending.first().first, code.toInt() ); emit qxt_p().mailFailed(pending.first().first, code.toInt(), line); // pending.removeFirst(); // DO NOT remove it, the body sent state needs this message to assigned the next mail failed message that will // the sendNext // a reset will be sent to clear things out sendNext(); state = BodySent; } else sendNextRcpt(code, line); break; case SendingBody: sendBody(code, line); break; case BodySent: if ( pending.count() ) { // if you removeFirst in RcpActpending/MailToSent on an error, and the queue is now empty, // you will get into this state and then crash because no check is done. CHeck added but shouldnt // be necessary since I commented out the removeFirst if (code[0] != '2') { emit qxt_p().mailFailed(pending.first().first, code.toInt() ); emit qxt_p().mailFailed(pending.first().first, code.toInt(), line); } else emit qxt_p().mailSent(pending.first().first); pending.removeFirst(); } sendNext(); break; case Resetting: if (code[0] != '2') { emit qxt_p().connectionFailed(); emit qxt_p().connectionFailed( line ); } else { state = Waiting; sendNext(); } break; } } }
void Smtp::readyRead() { qDebug() << Q_FUNC_INFO; // SMTP is line-oriented buffer += socket->readAll(); while (true) { int pos = buffer.indexOf("\r\n"); if (pos < 0) return; // Loop exit condition QByteArray line = buffer.left(pos); buffer = buffer.mid(pos + 2); qDebug() << "Response line:" << line; // Extract reponse code QByteArray code = line.left(3); switch(state) { case Init: { if (code[0] == '2') { // Connection was successful ehlo(); } else { logError("Connection failed, unrecognized reply: "+line); state = Close; } break; } case EhloSent: case HeloSent: case EhloGreetReceived: parseEhloResponse(code, line[3] != ' ', line.mid(4)); break; #ifndef QT_NO_OPENSSL case StartTLSSent: if (code == "220") { socket->startClientEncryption(); ehlo(); } else { authenticate(); } break; #endif case AuthRequestSent: case AuthUsernameSent: if (authType == AuthPlain) authPlain(); else if (authType == AuthLogin) authLogin(); else authCramMD5(line.mid(4)); break; case AuthSent: case Authenticated: if (code[0] == '2') { qDebug() << "Sending <mail from>..."; socket->write("mail from:<" + from.toLatin1() + ">\r\n"); socket->flush(); state = Rcpt; } else { // Authentication failed! logError("Authentication failed, msg: "+line); state = Close; } break; case Rcpt: if (code[0] == '2') { socket->write("rcpt to:<" + rcpt.toLatin1() + ">\r\n"); socket->flush(); state = Data; } else { logError("<mail from> was rejected by server, msg: "+line); state = Close; } break; case Data: if (code[0] == '2') { socket->write("data\r\n"); socket->flush(); state = Body; } else { logError("<Rcpt to> was rejected by server, msg: "+line); state = Close; } break; case Body: if (code[0] == '3') { socket->write(message + "\r\n.\r\n"); socket->flush(); state = Quit; } else { logError("<data> was rejected by server, msg: "+line); state = Close; } break; case Quit: if (code[0] == '2') { socket->write("QUIT\r\n"); socket->flush(); // here, we just close. state = Close; } else { logError("Message was rejected by the server, error: "+line); state = Close; } break; default: qDebug() << "Disconnecting from host"; socket->disconnectFromHost(); return; } } }