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 #if 0
00181
00182 if (!sock->connect()) {
00183 timeOutTimer.stop();
00184 kDebug() << "connection failed!";
00185 socketClosed();
00186 emit error(ConnectError);
00187 connected = false;
00188 return;
00189 }
00190 #endif
00191 connected = true;
00192 finished = false;
00193 state = Init;
00194 serverState = None;
00195
00196 connect(sock, SIGNAL(readyRead()), this, SLOT(socketReadyToRead()));
00197 connect(sock, SIGNAL(error()), this, SLOT(socketClosed()));
00198 connect(sock, SIGNAL(disconnected()), this, SLOT(socketClosed()));
00199 timeOutTimer.stop();
00200 kDebug() << "connected";
00201 }
00202
00203 void SMTP::connectTimedOut(void)
00204 {
00205 timeOutTimer.stop();
00206
00207 kDebug() << "socket connection timed out";
00208 socketClosed();
00209 emit error(ConnectTimeout);
00210 }
00211
00212 void SMTP::interactTimedOut(void)
00213 {
00214 interactTimer.stop();
00215
00216 kDebug() << "time out waiting for server interaction";
00217 socketClosed();
00218 emit error(InteractTimeout);
00219 }
00220
00221 void SMTP::socketReadyToRead()
00222 {
00223 int n, nl;
00224
00225 kDebug() << "socketRead() called...";
00226 interactTimer.stop();
00227
00228 if (!sock)
00229 return;
00230
00231 n = sock->read(readBuffer, SMTP_READ_BUFFER_SIZE-1);
00232 if (n < 0)
00233 return;
00234 readBuffer[n] = 0;
00235 lineBuffer += readBuffer;
00236 nl = lineBuffer.indexOf('\n');
00237 if(nl == -1)
00238 return;
00239 lastLine = lineBuffer.left(nl);
00240 lineBuffer = lineBuffer.right(lineBuffer.length() - nl - 1);
00241 processLine(&lastLine);
00242 if(connected) {
00243 interactTimer.setSingleShot(true);
00244 interactTimer.start(timeOut);
00245 }
00246 }
00247
00248 void SMTP::socketClosed()
00249 {
00250 timeOutTimer.stop();
00251 kDebug() << "connection terminated";
00252 connected = false;
00253 delete sock;
00254 sock = 0L;
00255 emit connectionClosed();
00256 }
00257
00258 void SMTP::processLine(QString *line)
00259 {
00260 int i, stat;
00261 QString tmpstr;
00262
00263 i = line->indexOf(' ');
00264 tmpstr = line->left(i);
00265 if(i > 3)
00266 kDebug() << "warning: SMTP status code longer then 3 digits: " << tmpstr;
00267 stat = tmpstr.toInt();
00268 serverState = (SMTPServerStatus)stat;
00269 lastState = state;
00270
00271 kDebug() << "smtp state: [" << stat << "][" << *line << "]";
00272
00273 switch(stat){
00274 case Greet:
00275 state = In;
00276 writeString = QString::fromLatin1("helo %1\r\n").arg(domainName);
00277 kDebug() << "out: " << writeString;
00278 sock->write(writeString.toAscii().constData(), writeString.length());
00279 break;
00280 case Goodbye:
00281 state = Quit;
00282 break;
00283 case Successful:
00284 switch(state){
00285 case In:
00286 state = Ready;
00287 writeString = QString::fromLatin1("mail from: %1\r\n").arg(senderAddress);
00288 kDebug() << "out: " << writeString;
00289 sock->write(writeString.toAscii().constData(), writeString.length());
00290 break;
00291 case Ready:
00292 state = SentFrom;
00293 writeString = QString::fromLatin1("rcpt to: %1\r\n").arg(recipientAddress);
00294 kDebug() << "out: " << writeString;
00295 sock->write(writeString.toAscii().constData(), writeString.length());
00296 break;
00297 case SentFrom:
00298 state = SentTo;
00299 writeString = QLatin1String("data\r\n");
00300 kDebug() << "out: " << writeString;
00301 sock->write(writeString.toAscii().constData(), writeString.length());
00302 break;
00303 case Data:
00304 state = Finished;
00305 finished = true;
00306 emit messageSent();
00307 break;
00308 default:
00309 state = CError;
00310 kDebug() << "smtp error (state error): [" << lastState << "]:[" << stat << "][" << *line << "]";
00311 socketClosed();
00312 emit error(Command);
00313 break;
00314 }
00315 break;
00316 case ReadyData:
00317 state = Data;
00318 writeString = QString::fromLatin1("Subject: %1\r\n").arg(messageSubject);
00319 writeString += messageHeader;
00320 writeString += "\r\n";
00321 writeString += messageBody;
00322 writeString += QLatin1String(".\r\n");
00323 kDebug() << "out: " << writeString;
00324 sock->write(writeString.toAscii().constData(), writeString.length());
00325 break;
00326 case Error:
00327 state = CError;
00328 kDebug() << "smtp error (command error): [" << lastState << "]:[" << stat << "][" << *line << "]\n";
00329 socketClosed();
00330 emit error(Command);
00331 break;
00332 case Unknown:
00333 state = CError;
00334 kDebug() << "smtp error (unknown user): [" << lastState << "]:[" << stat << "][" << *line << "]";
00335 socketClosed();
00336 emit error(UnknownUser);
00337 break;
00338 default:
00339 state = CError;
00340 kDebug() << "unknown response: [" << lastState << "]:[" << stat << "][" << *line << "]";
00341 socketClosed();
00342 emit error(UnknownResponse);
00343 }
00344 }
00345
00346 #include "smtp.moc"