KIO
smtp.cpp
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #include "smtp.h"
00021
00022 #include <sys/utsname.h>
00023 #include <unistd.h>
00024 #include <stdio.h>
00025
00026 #include <kdebug.h>
00027
00028 SMTP::SMTP(char *serverhost, unsigned short int port, int timeout)
00029 {
00030 struct utsname uts;
00031
00032 serverHost = serverhost;
00033 hostPort = port;
00034 timeOut = timeout * 1000;
00035
00036 senderAddress = "user@example.net";
00037 recipientAddress = "user@example.net";
00038 messageSubject = "(no subject)";
00039 messageBody = "empty";
00040 messageHeader = "";
00041
00042 connected = false;
00043 finished = false;
00044
00045 sock = 0L;
00046 state = Init;
00047 serverState = None;
00048
00049 uname(&uts);
00050 domainName = uts.nodename;
00051
00052
00053 if(domainName.isEmpty())
00054 domainName = "somemachine.example.net";
00055
00056 kDebug() << "SMTP object created";
00057
00058 connect(&connectTimer, SIGNAL(timeout()), this, SLOT(connectTimerTick()));
00059 connect(&timeOutTimer, SIGNAL(timeout()), this, SLOT(connectTimedOut()));
00060 connect(&interactTimer, SIGNAL(timeout()), this, SLOT(interactTimedOut()));
00061
00062
00063 connect(this, SIGNAL(messageSent()), SLOT(closeConnection()));
00064 }
00065
00066 SMTP::~SMTP()
00067 {
00068 if(sock){
00069 delete sock;
00070 sock = 0L;
00071 }
00072 connectTimer.stop();
00073 timeOutTimer.stop();
00074 }
00075
00076 void SMTP::setServerHost(const QString& serverhost)
00077 {
00078 serverHost = serverhost;
00079 }
00080
00081 void SMTP::setPort(unsigned short int port)
00082 {
00083 hostPort = port;
00084 }
00085
00086 void SMTP::setTimeOut(int timeout)
00087 {
00088 timeOut = timeout;
00089 }
00090
00091 void SMTP::setSenderAddress(const QString& sender)
00092 {
00093 senderAddress = sender;
00094 int index = senderAddress.indexOf('<');
00095 if (index == -1)
00096 return;
00097 senderAddress = senderAddress.mid(index + 1);
00098 index = senderAddress.indexOf('>');
00099 if (index != -1)
00100 senderAddress = senderAddress.left(index);
00101 senderAddress = senderAddress.simplified();
00102 while (1) {
00103 index = senderAddress.indexOf(' ');
00104 if (index != -1)
00105 senderAddress = senderAddress.mid(index + 1);
00106 else
00107 break;
00108 }
00109 index = senderAddress.indexOf('@');
00110 if (index == -1)
00111 senderAddress.append("@localhost");
00112
00113 }
00114
00115 void SMTP::setRecipientAddress(const QString& recipient)
00116 {
00117 recipientAddress = recipient;
00118 }
00119
00120 void SMTP::setMessageSubject(const QString& subject)
00121 {
00122 messageSubject = subject;
00123 }
00124
00125 void SMTP::setMessageBody(const QString& message)
00126 {
00127 messageBody = message;
00128 }
00129
00130 void SMTP::setMessageHeader(const QString &header)
00131 {
00132 messageHeader = header;
00133 }
00134
00135 void SMTP::openConnection(void)
00136 {
00137 kDebug() << "started connect timer";
00138 connectTimer.setSingleShot(true);
00139 connectTimer.start(100);
00140 }
00141
00142 void SMTP::closeConnection(void)
00143 {
00144 socketClosed();
00145 }
00146
00147 void SMTP::sendMessage(void)
00148 {
00149 if(!connected)
00150 connectTimerTick();
00151 if(state == Finished && connected){
00152 kDebug() << "state was == Finished\n";
00153 finished = false;
00154 state = In;
00155 writeString = QString::fromLatin1("helo %1\r\n").arg(domainName);
00156 sock->write(writeString.toAscii().constData(), writeString.length());
00157 }
00158 if(connected){
00159 kDebug() << "enabling read on sock...\n";
00160 interactTimer.setSingleShot(true);
00161 interactTimer.start(timeOut);
00162 }
00163 }
00164
00165 void SMTP::connectTimerTick(void)
00166 {
00167 connectTimer.stop();
00168
00169
00170 kDebug() << "connectTimerTick called...";
00171
00172 if(sock){
00173 delete sock;
00174 sock = 0L;
00175 }
00176
00177 kDebug() << "connecting to " << serverHost << ":" << hostPort << " ..... ";
00178 sock = KSocketFactory::connectToHost("smtp", serverHost, hostPort, this);
00179
00180 connected = true;
00181 finished = false;
00182 state = Init;
00183 serverState = None;
00184
00185 connect(sock, SIGNAL(readyRead()), this, SLOT(socketReadyToRead()));
00186 connect(sock, SIGNAL(error(QAbstractSocket::SocketError)), this,
00187 SLOT(socketError(QAbstractSocket::SocketError)));
00188 connect(sock, SIGNAL(disconnected()), this, SLOT(socketClosed()));
00189 timeOutTimer.stop();
00190 kDebug() << "connected";
00191 }
00192
00193 void SMTP::connectTimedOut(void)
00194 {
00195 timeOutTimer.stop();
00196
00197 kDebug() << "socket connection timed out";
00198 socketClosed();
00199 emit error(ConnectTimeout);
00200 }
00201
00202 void SMTP::interactTimedOut(void)
00203 {
00204 interactTimer.stop();
00205
00206 kDebug() << "time out waiting for server interaction";
00207 socketClosed();
00208 emit error(InteractTimeout);
00209 }
00210
00211 void SMTP::socketReadyToRead()
00212 {
00213 int n, nl;
00214
00215 kDebug() << "socketRead() called...";
00216 interactTimer.stop();
00217
00218 if (!sock)
00219 return;
00220
00221 n = sock->read(readBuffer, SMTP_READ_BUFFER_SIZE-1);
00222 if (n < 0)
00223 return;
00224 readBuffer[n] = 0;
00225 lineBuffer += readBuffer;
00226 nl = lineBuffer.indexOf('\n');
00227 if(nl == -1)
00228 return;
00229 lastLine = lineBuffer.left(nl);
00230 lineBuffer = lineBuffer.right(lineBuffer.length() - nl - 1);
00231 processLine(&lastLine);
00232 if(connected) {
00233 interactTimer.setSingleShot(true);
00234 interactTimer.start(timeOut);
00235 }
00236 }
00237
00238 void SMTP::socketError(QAbstractSocket::SocketError socketError)
00239 {
00240 kDebug() << socketError << sock->errorString();
00241 Q_UNUSED(socketError);
00242 emit error(ConnectError);
00243 socketClosed();
00244 }
00245
00246 void SMTP::socketClosed()
00247 {
00248 timeOutTimer.stop();
00249 kDebug() << "connection terminated";
00250 connected = false;
00251 if (sock)
00252 sock->deleteLater();
00253 sock = 0;
00254 emit connectionClosed();
00255 }
00256
00257 void SMTP::processLine(QString *line)
00258 {
00259 int i, stat;
00260 QString tmpstr;
00261
00262 i = line->indexOf(' ');
00263 tmpstr = line->left(i);
00264 if(i > 3)
00265 kDebug() << "warning: SMTP status code longer than 3 digits: " << tmpstr;
00266 stat = tmpstr.toInt();
00267 serverState = (SMTPServerStatus)stat;
00268 lastState = state;
00269
00270 kDebug() << "smtp state: [" << stat << "][" << *line << "]";
00271
00272 switch(stat){
00273 case Greet:
00274 state = In;
00275 writeString = QString::fromLatin1("helo %1\r\n").arg(domainName);
00276 kDebug() << "out: " << writeString;
00277 sock->write(writeString.toAscii().constData(), writeString.length());
00278 break;
00279 case Goodbye:
00280 state = Quit;
00281 break;
00282 case Successful:
00283 switch(state){
00284 case In:
00285 state = Ready;
00286 writeString = QString::fromLatin1("mail from: %1\r\n").arg(senderAddress);
00287 kDebug() << "out: " << writeString;
00288 sock->write(writeString.toAscii().constData(), writeString.length());
00289 break;
00290 case Ready:
00291 state = SentFrom;
00292 writeString = QString::fromLatin1("rcpt to: %1\r\n").arg(recipientAddress);
00293 kDebug() << "out: " << writeString;
00294 sock->write(writeString.toAscii().constData(), writeString.length());
00295 break;
00296 case SentFrom:
00297 state = SentTo;
00298 writeString = QLatin1String("data\r\n");
00299 kDebug() << "out: " << writeString;
00300 sock->write(writeString.toAscii().constData(), writeString.length());
00301 break;
00302 case Data:
00303 state = Finished;
00304 finished = true;
00305 emit messageSent();
00306 break;
00307 default:
00308 state = CError;
00309 kDebug() << "smtp error (state error): [" << lastState << "]:[" << stat << "][" << *line << "]";
00310 socketClosed();
00311 emit error(Command);
00312 break;
00313 }
00314 break;
00315 case ReadyData:
00316 state = Data;
00317 writeString = QString::fromLatin1("Subject: %1\r\n").arg(messageSubject);
00318 writeString += messageHeader;
00319 writeString += "\r\n";
00320 writeString += messageBody;
00321 writeString += QLatin1String(".\r\n");
00322 kDebug() << "out: " << writeString;
00323 sock->write(writeString.toAscii().constData(), writeString.length());
00324 break;
00325 case Error:
00326 state = CError;
00327 kDebug() << "smtp error (command error): [" << lastState << "]:[" << stat << "][" << *line << "]\n";
00328 socketClosed();
00329 emit error(Command);
00330 break;
00331 case Unknown:
00332 state = CError;
00333 kDebug() << "smtp error (unknown user): [" << lastState << "]:[" << stat << "][" << *line << "]";
00334 socketClosed();
00335 emit error(UnknownUser);
00336 break;
00337 default:
00338 state = CError;
00339 kDebug() << "unknown response: [" << lastState << "]:[" << stat << "][" << *line << "]";
00340 socketClosed();
00341 emit error(UnknownResponse);
00342 }
00343 }
00344
00345 #include "smtp.moc"