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