KIO
smtp.cpp
Go to the documentation of this file.
00001 /* 00002 Copyright (c) 2000 Bernd Johannes Wuebben <wuebben@math.cornell.edu> 00003 Copyright (c) 2000 Stephan Kulow <coolo@kde.org> 00004 00005 This program is free software; you can redistribute it and/or modify 00006 it under the terms of the GNU General Public License as published by 00007 the Free Software Foundation; either version 2, or (at your option) 00008 any later version. 00009 00010 This program is distributed in the hope that it will be useful, 00011 but WITHOUT ANY WARRANTY; without even the implied warranty of 00012 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00013 GNU General Public License for more details. 00014 00015 You should have received a copy of the GNU General Public License 00016 along with this program; if not, write to the Free Software 00017 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 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 // some sendmail will give 'duplicate helo' error, quick fix for now 00063 connect(this, SIGNAL(messageSent()), SLOT(closeConnection())); 00064 } 00065 00066 SMTP::~SMTP() 00067 { 00068 delete sock; 00069 sock = 0L; 00070 connectTimer.stop(); 00071 timeOutTimer.stop(); 00072 } 00073 00074 void SMTP::setServerHost(const QString& serverhost) 00075 { 00076 serverHost = serverhost; 00077 } 00078 00079 void SMTP::setPort(unsigned short int port) 00080 { 00081 hostPort = port; 00082 } 00083 00084 void SMTP::setTimeOut(int timeout) 00085 { 00086 timeOut = timeout; 00087 } 00088 00089 void SMTP::setSenderAddress(const QString& sender) 00090 { 00091 senderAddress = sender; 00092 int index = senderAddress.indexOf('<'); 00093 if (index == -1) 00094 return; 00095 senderAddress = senderAddress.mid(index + 1); 00096 index = senderAddress.indexOf('>'); 00097 if (index != -1) 00098 senderAddress = senderAddress.left(index); 00099 senderAddress = senderAddress.simplified(); 00100 while (1) { 00101 index = senderAddress.indexOf(' '); 00102 if (index != -1) 00103 senderAddress = senderAddress.mid(index + 1); // take one side 00104 else 00105 break; 00106 } 00107 index = senderAddress.indexOf('@'); 00108 if (index == -1) 00109 senderAddress.append("@localhost"); // won't go through without a local mail system 00110 00111 } 00112 00113 void SMTP::setRecipientAddress(const QString& recipient) 00114 { 00115 recipientAddress = recipient; 00116 } 00117 00118 void SMTP::setMessageSubject(const QString& subject) 00119 { 00120 messageSubject = subject; 00121 } 00122 00123 void SMTP::setMessageBody(const QString& message) 00124 { 00125 messageBody = message; 00126 } 00127 00128 void SMTP::setMessageHeader(const QString &header) 00129 { 00130 messageHeader = header; 00131 } 00132 00133 void SMTP::openConnection(void) 00134 { 00135 kDebug() << "started connect timer"; 00136 connectTimer.setSingleShot(true); 00137 connectTimer.start(100); 00138 } 00139 00140 void SMTP::closeConnection(void) 00141 { 00142 socketClosed(); 00143 } 00144 00145 void SMTP::sendMessage(void) 00146 { 00147 if(!connected) 00148 connectTimerTick(); 00149 if(state == Finished && connected){ 00150 kDebug() << "state was == Finished\n"; 00151 finished = false; 00152 state = In; 00153 writeString = QString::fromLatin1("helo %1\r\n").arg(domainName); 00154 sock->write(writeString.toAscii().constData(), writeString.length()); 00155 } 00156 if(connected){ 00157 kDebug() << "enabling read on sock...\n"; 00158 interactTimer.setSingleShot(true); 00159 interactTimer.start(timeOut); 00160 } 00161 } 00162 00163 void SMTP::connectTimerTick(void) 00164 { 00165 connectTimer.stop(); 00166 // timeOutTimer.start(timeOut, true); 00167 00168 kDebug() << "connectTimerTick called..."; 00169 00170 delete sock; 00171 sock = 0L; 00172 00173 kDebug() << "connecting to " << serverHost << ":" << hostPort << " ..... "; 00174 sock = KSocketFactory::connectToHost("smtp", serverHost, hostPort, this); 00175 00176 connected = true; 00177 finished = false; 00178 state = Init; 00179 serverState = None; 00180 00181 connect(sock, SIGNAL(readyRead()), this, SLOT(socketReadyToRead())); 00182 connect(sock, SIGNAL(error(QAbstractSocket::SocketError)), this, 00183 SLOT(socketError(QAbstractSocket::SocketError))); 00184 connect(sock, SIGNAL(disconnected()), this, SLOT(socketClosed())); 00185 timeOutTimer.stop(); 00186 kDebug() << "connected"; 00187 } 00188 00189 void SMTP::connectTimedOut(void) 00190 { 00191 timeOutTimer.stop(); 00192 00193 kDebug() << "socket connection timed out"; 00194 socketClosed(); 00195 emit error(ConnectTimeout); 00196 } 00197 00198 void SMTP::interactTimedOut(void) 00199 { 00200 interactTimer.stop(); 00201 00202 kDebug() << "time out waiting for server interaction"; 00203 socketClosed(); 00204 emit error(InteractTimeout); 00205 } 00206 00207 void SMTP::socketReadyToRead() 00208 { 00209 int n, nl; 00210 00211 kDebug() << "socketRead() called..."; 00212 interactTimer.stop(); 00213 00214 if (!sock) 00215 return; 00216 00217 n = sock->read(readBuffer, SMTP_READ_BUFFER_SIZE-1); 00218 if (n < 0) 00219 return; 00220 readBuffer[n] = 0; 00221 lineBuffer += readBuffer; 00222 nl = lineBuffer.indexOf('\n'); 00223 if(nl == -1) 00224 return; 00225 lastLine = lineBuffer.left(nl); 00226 lineBuffer = lineBuffer.right(lineBuffer.length() - nl - 1); 00227 processLine(&lastLine); 00228 if(connected) { 00229 interactTimer.setSingleShot(true); 00230 interactTimer.start(timeOut); 00231 } 00232 } 00233 00234 void SMTP::socketError(QAbstractSocket::SocketError socketError) 00235 { 00236 kDebug() << socketError << sock->errorString(); 00237 Q_UNUSED(socketError); 00238 emit error(ConnectError); 00239 socketClosed(); 00240 } 00241 00242 void SMTP::socketClosed() 00243 { 00244 timeOutTimer.stop(); 00245 kDebug() << "connection terminated"; 00246 connected = false; 00247 if (sock) 00248 sock->deleteLater(); 00249 sock = 0; 00250 emit connectionClosed(); 00251 } 00252 00253 void SMTP::processLine(QString *line) 00254 { 00255 int i, stat; 00256 QString tmpstr; 00257 00258 i = line->indexOf(' '); 00259 tmpstr = line->left(i); 00260 if(i > 3) 00261 kDebug() << "warning: SMTP status code longer than 3 digits: " << tmpstr; 00262 stat = tmpstr.toInt(); 00263 serverState = (SMTPServerStatus)stat; 00264 lastState = state; 00265 00266 kDebug() << "smtp state: [" << stat << "][" << *line << "]"; 00267 00268 switch(stat){ 00269 case Greet: //220 00270 state = In; 00271 writeString = QString::fromLatin1("helo %1\r\n").arg(domainName); 00272 kDebug() << "out: " << writeString; 00273 sock->write(writeString.toAscii().constData(), writeString.length()); 00274 break; 00275 case Goodbye: //221 00276 state = Quit; 00277 break; 00278 case Successful://250 00279 switch(state){ 00280 case In: 00281 state = Ready; 00282 writeString = QString::fromLatin1("mail from: %1\r\n").arg(senderAddress); 00283 kDebug() << "out: " << writeString; 00284 sock->write(writeString.toAscii().constData(), writeString.length()); 00285 break; 00286 case Ready: 00287 state = SentFrom; 00288 writeString = QString::fromLatin1("rcpt to: %1\r\n").arg(recipientAddress); 00289 kDebug() << "out: " << writeString; 00290 sock->write(writeString.toAscii().constData(), writeString.length()); 00291 break; 00292 case SentFrom: 00293 state = SentTo; 00294 writeString = QLatin1String("data\r\n"); 00295 kDebug() << "out: " << writeString; 00296 sock->write(writeString.toAscii().constData(), writeString.length()); 00297 break; 00298 case Data: 00299 state = Finished; 00300 finished = true; 00301 emit messageSent(); 00302 break; 00303 default: 00304 state = CError; 00305 kDebug() << "smtp error (state error): [" << lastState << "]:[" << stat << "][" << *line << "]"; 00306 socketClosed(); 00307 emit error(Command); 00308 break; 00309 } 00310 break; 00311 case ReadyData: //354 00312 state = Data; 00313 writeString = QString::fromLatin1("Subject: %1\r\n").arg(messageSubject); 00314 writeString += messageHeader; 00315 writeString += "\r\n"; 00316 writeString += messageBody; 00317 writeString += QLatin1String(".\r\n"); 00318 kDebug() << "out: " << writeString; 00319 sock->write(writeString.toAscii().constData(), writeString.length()); 00320 break; 00321 case Error: //501 00322 state = CError; 00323 kDebug() << "smtp error (command error): [" << lastState << "]:[" << stat << "][" << *line << "]\n"; 00324 socketClosed(); 00325 emit error(Command); 00326 break; 00327 case Unknown: //550 00328 state = CError; 00329 kDebug() << "smtp error (unknown user): [" << lastState << "]:[" << stat << "][" << *line << "]"; 00330 socketClosed(); 00331 emit error(UnknownUser); 00332 break; 00333 default: 00334 state = CError; 00335 kDebug() << "unknown response: [" << lastState << "]:[" << stat << "][" << *line << "]"; 00336 socketClosed(); 00337 emit error(UnknownResponse); 00338 } 00339 } 00340 00341 #include "smtp.moc"
KDE 4.6 API Reference