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
00216 if(n < 0)
00217 return;
00218
00219 readBuffer[n] = '\0';
00220 lineBuffer += readBuffer;
00221 nl = lineBuffer.find('\n');
00222 if(nl == -1)
00223 return;
00224 lastLine = lineBuffer.left(nl);
00225 lineBuffer = lineBuffer.right(lineBuffer.length() - nl - 1);
00226 processLine(&lastLine);
00227 if(connected)
00228 interactTimer.start(timeOut, true);
00229 }
00230
00231 void SMTP::socketClose(KSocket *socket)
00232 {
00233 timeOutTimer.stop();
00234 disconnect(sock, SIGNAL(readEvent(KSocket *)), this, SLOT(socketRead(KSocket *)));
00235 disconnect(sock, SIGNAL(closeEvent(KSocket *)), this, SLOT(socketClose(KSocket *)));
00236 socket->enableRead(false);
00237 kdDebug() << "connection terminated" << endl;
00238 connected = false;
00239 if(socket){
00240 delete socket;
00241 socket = 0L;
00242 sock = 0L;
00243 }
00244 emit connectionClosed();
00245 }
00246
00247 void SMTP::processLine(QString *line)
00248 {
00249 int i, stat;
00250 QString tmpstr;
00251
00252 i = line->find(' ');
00253 tmpstr = line->left(i);
00254 if(i > 3)
00255 kdDebug() << "warning: SMTP status code longer then 3 digits: " << tmpstr << endl;
00256 stat = tmpstr.toInt();
00257 serverState = (SMTPServerStatus)stat;
00258 lastState = state;
00259
00260 kdDebug() << "smtp state: [" << stat << "][" << *line << "]" << endl;
00261
00262 switch(stat){
00263 case GREET:
00264 state = IN;
00265 writeString = QString::fromLatin1("helo %1\r\n").arg(domainName);
00266 kdDebug() << "out: " << writeString << endl;
00267 write(sock->socket(), writeString.ascii(), writeString.length());
00268 break;
00269 case GOODBYE:
00270 state = QUIT;
00271 break;
00272 case SUCCESSFUL:
00273 switch(state){
00274 case IN:
00275 state = READY;
00276 writeString = QString::fromLatin1("mail from: %1\r\n").arg(senderAddress);
00277 kdDebug() << "out: " << writeString << endl;
00278 write(sock->socket(), writeString.ascii(), writeString.length());
00279 break;
00280 case READY:
00281 state = SENTFROM;
00282 writeString = QString::fromLatin1("rcpt to: %1\r\n").arg(recipientAddress);
00283 kdDebug() << "out: " << writeString << endl;
00284 write(sock->socket(), writeString.ascii(), writeString.length());
00285 break;
00286 case SENTFROM:
00287 state = SENTTO;
00288 writeString = QString::fromLatin1("data\r\n");
00289 kdDebug() << "out: " << writeString << endl;
00290 write(sock->socket(), writeString.ascii(), writeString.length());
00291 break;
00292 case DATA:
00293 state = FINISHED;
00294 finished = true;
00295 sock->enableRead(false);
00296 emit messageSent();
00297 break;
00298 default:
00299 state = CERROR;
00300 kdDebug() << "smtp error (state error): [" << lastState << "]:[" << stat << "][" << *line << "]" << endl;
00301 socketClose(sock);
00302 emit error(COMMAND);
00303 break;
00304 }
00305 break;
00306 case READYDATA:
00307 state = DATA;
00308 writeString = QString::fromLatin1("Subject: %1\r\n").arg(messageSubject);
00309 writeString += messageHeader;
00310 writeString += "\r\n";
00311 writeString += messageBody;
00312 writeString += QString::fromLatin1(".\r\n");
00313 kdDebug() << "out: " << writeString;
00314 write(sock->socket(), writeString.ascii(), writeString.length());
00315 break;
00316 case ERROR:
00317 state = CERROR;
00318 kdDebug() << "smtp error (command error): [" << lastState << "]:[" << stat << "][" << *line << "]\n" << endl;
00319 socketClose(sock);
00320 emit error(COMMAND);
00321 break;
00322 case UNKNOWN:
00323 state = CERROR;
00324 kdDebug() << "smtp error (unknown user): [" << lastState << "]:[" << stat << "][" << *line << "]" << endl;
00325 socketClose(sock);
00326 emit error(UNKNOWNUSER);
00327 break;
00328 default:
00329 state = CERROR;
00330 kdDebug() << "unknown response: [" << lastState << "]:[" << stat << "][" << *line << "]" << endl;
00331 socketClose(sock);
00332 emit error(UNKNOWNRESPONSE);
00333 }
00334 }
00335
00336 #include "smtp.moc"