/**************************************************************************** ** $Id: qt/smtp.h 3.3.6 edited Aug 31 2005 $ ** ** Copyright (C) 1992-2005 Trolltech AS. All rights reserved. ** ** This file is part of an example program for Qt. This example ** program may be used, distributed and modified without limitation. ** *****************************************************************************/ #include "smtp.h" #include "preferences.h" #include #include #include #include #include #include Smtp::Smtp(const QString &from, const QString &to, const QString &subject, const QString &body) { socket = new QTcpSocket(this); connect( socket, SIGNAL( readyRead() ), this, SLOT( readyRead() ) ); QTextCodec* latin1 = QTextCodec::codecForName("latin1"); message = ""; message += encode_mime_header("Date", QDateTime::currentDateTime().toUTC().toString("ddd, d MMM yyyy hh:mm:ss UT"), latin1); message += encode_mime_header("From", from, latin1); message += encode_mime_header("Subject", subject, latin1); message += encode_mime_header("To", to, latin1); message += "MIME-Version: 1.0\r\n"; message += "Content-Type: text/plain; charset=UTF-8\r\n"; message += "Content-Transfer-Encoding: base64\r\n"; message += "\r\n"; // Encode the body in base64 QString crlf_body = body; QByteArray b = crlf_body.replace("\n","\r\n").toUtf8().toBase64(); int ct = b.length(); for (int i = 0; i < ct; i += 78) { message += b.mid(i, 78); } this->from = from; rcpt = to; state = Init; socket->connectToHost(Preferences().getMailNotificationSMTP(), 25); if(socket->waitForConnected ( 30000 )) { qDebug("connected"); } else { t = 0; deleteLater(); } t = new QTextStream(socket); } QByteArray Smtp::encode_mime_header(const QString& key, const QString& value, QTextCodec* latin1, const QByteArray& prefix) { QByteArray rv = ""; QByteArray line = key.toAscii() + ": "; if (!prefix.isEmpty()) line += prefix; if (!value.contains("=?") && latin1->canEncode(value)) { bool firstWord = true; foreach(const QByteArray& word, value.toAscii().split(' ')) { if (line.size() > 78) { rv = rv + line + "\r\n"; line.clear(); } if (firstWord) line += word; else line += " " + word; firstWord = false; } } else { // The text cannot be losslessly encoded as Latin-1. Therefore, we // must use base64 encoding. QByteArray utf8 = value.toUtf8(); int ct = utf8.length(); // Use base64 encoding QByteArray base64 = utf8.toBase64(); ct = base64.length(); line += "=?utf-8?b?"; for (int i = 0; i < ct; i += 4) { /*if (line.length() > 72) { rv += line + "?\n\r"; line = " =?utf-8?b?"; }*/ line = line + base64.mid(i, 4); } line += "?="; // end encoded-word atom } return rv + line + "\r\n"; } Smtp::~Smtp() { if(t) delete t; delete socket; } void Smtp::readyRead() { qDebug() << "readyRead"; // SMTP is line-oriented QString responseLine; do { responseLine = socket->readLine(); response += responseLine; } while ( socket->canReadLine() && responseLine[3] != ' ' ); qDebug("Response line: %s", qPrintable(response)); responseLine.truncate( 3 ); if ( state == Init && responseLine[0] == '2' ) { // banner was okay, let's go on QByteArray address = "127.0.0.1"; foreach(const QHostAddress& addr, QNetworkInterface::allAddresses()) { if (addr == QHostAddress::LocalHost || addr == QHostAddress::LocalHostIPv6) continue; address = addr.toString().toAscii(); break; } *t << "ehlo "+ address + "\r\n"; t->flush(); state = Mail; } else if ( state == Mail || state == Mail2 ) { if(responseLine[0] == '2') { // EHLO response was okay (well, it has to be) *t << "mail from:<" << from << ">\r\n"; t->flush(); state = Rcpt; } else { if(state == Mail) { // ehlo did not work, try helo instead *t << "helo\r\n"; t->flush(); state = Mail2; } } } else if ( state == Rcpt && responseLine[0] == '2' ) { *t << "rcpt to:<" << rcpt << ">\r\n"; //r t->flush(); state = Data; } else if ( state == Data && responseLine[0] == '2' ) { *t << "data\r\n"; t->flush(); state = Body; } else if ( state == Body && responseLine[0] == '3' ) { *t << message << "\r\n.\r\n"; t->flush(); state = Quit; } else if(state == Quit && responseLine[0] == '2') { *t << "QUIT\r\n"; t->flush(); // here, we just close. state = Close; } else if ( state == Close ) { deleteLater(); return; } else { // something broke. state = Close; } response = ""; }