Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

smtpwrapper.cpp

Go to the documentation of this file.
00001 #include "smtpwrapper.h"
00002 #include "mailwrapper.h"
00003 #include "abstractmail.h"
00004 #include "logindialog.h"
00005 #include "mailtypes.h"
00006 #include "sendmailprogress.h"
00007 
00008 #include <opie2/odebug.h>
00009 #include <qt.h>
00010 
00011 #include <qpe/config.h>
00012 #include <qpe/qcopenvelope_qws.h>
00013 
00014 #include <libetpan/libetpan.h>
00015 
00016 
00017 using namespace Opie::Core;
00018 progressMailSend*SMTPwrapper::sendProgress = 0;
00019 
00020 SMTPwrapper::SMTPwrapper(SMTPaccount * aSmtp )
00021     : Generatemail()
00022 {
00023     m_SmtpAccount = aSmtp;
00024     Config cfg( "mail" );
00025     cfg.setGroup( "Status" );
00026     m_queuedMail =  cfg.readNumEntry( "outgoing", 0 );
00027     emit queuedMails( m_queuedMail );
00028     connect( this, SIGNAL( queuedMails(int) ), this, SLOT( emitQCop(int) )  );
00029     m_smtp = 0;
00030 }
00031 
00032 SMTPwrapper::~SMTPwrapper()
00033 {
00034     disc_server();
00035 }
00036 
00037 void SMTPwrapper::emitQCop( int queued ) {
00038     QCopEnvelope env( "QPE/Pim", "outgoingMails(int)" );
00039     env << queued;
00040 }
00041 
00042 QString SMTPwrapper::mailsmtpError( int errnum ) {
00043     switch ( errnum ) {
00044     case MAILSMTP_NO_ERROR:
00045         return tr( "No error" );
00046     case MAILSMTP_ERROR_UNEXPECTED_CODE:
00047         return tr( "Unexpected error code" );
00048     case MAILSMTP_ERROR_SERVICE_NOT_AVAILABLE:
00049         return tr( "Service not available" );
00050     case MAILSMTP_ERROR_STREAM:
00051         return tr( "Stream error" );
00052     case MAILSMTP_ERROR_HOSTNAME:
00053         return tr( "gethostname() failed" );
00054     case MAILSMTP_ERROR_NOT_IMPLEMENTED:
00055         return tr( "Not implemented" );
00056     case MAILSMTP_ERROR_ACTION_NOT_TAKEN:
00057         return tr( "Error, action not taken" );
00058     case MAILSMTP_ERROR_EXCEED_STORAGE_ALLOCATION:
00059         return tr( "Data exceeds storage allocation" );
00060     case MAILSMTP_ERROR_IN_PROCESSING:
00061         return tr( "Error in processing" );
00062     case MAILSMTP_ERROR_STARTTLS_NOT_SUPPORTED:
00063         return tr( "Starttls not supported" );
00064         //      case MAILSMTP_ERROR_INSUFFISANT_SYSTEM_STORAGE:
00065         //        return tr( "Insufficient system storage" );
00066     case MAILSMTP_ERROR_MAILBOX_UNAVAILABLE:
00067         return tr( "Mailbox unavailable" );
00068     case MAILSMTP_ERROR_MAILBOX_NAME_NOT_ALLOWED:
00069         return tr( "Mailbox name not allowed" );
00070     case MAILSMTP_ERROR_BAD_SEQUENCE_OF_COMMAND:
00071         return tr( "Bad command sequence" );
00072     case MAILSMTP_ERROR_USER_NOT_LOCAL:
00073         return tr( "User not local" );
00074     case MAILSMTP_ERROR_TRANSACTION_FAILED:
00075         return tr( "Transaction failed" );
00076     case MAILSMTP_ERROR_MEMORY:
00077         return tr( "Memory error" );
00078     case MAILSMTP_ERROR_CONNECTION_REFUSED:
00079         return tr( "Connection refused" );
00080     default:
00081         return tr( "Unknown error code" );
00082     }
00083 }
00084 
00085 
00086 void SMTPwrapper::progress( size_t current, size_t maximum ) {
00087     if (SMTPwrapper::sendProgress) {
00088         SMTPwrapper::sendProgress->setSingleMail(current, maximum );
00089         qApp->processEvents();
00090     }
00091 }
00092 
00093 void SMTPwrapper::storeMail(const char*mail, size_t length, const QString&box) {
00094     if (!mail)
00095         return;
00096     QString localfolders = AbstractMail::defaultLocalfolder();
00097     AbstractMail*wrap = AbstractMail::getWrapper(localfolders);
00098     wrap->createMbox(box);
00099     wrap->storeMessage(mail,length,box);
00100     delete wrap;
00101 }
00102 
00103 void SMTPwrapper::smtpSend( mailmime *mail,bool later) {
00104     clist *rcpts = 0;
00105     char *from, *data;
00106     size_t size;
00107 
00108     from = data = 0;
00109 
00110     mailmessage * msg = 0;
00111     msg = mime_message_init(mail);
00112     mime_message_set_tmpdir(msg,getenv( "HOME" ));
00113     int r = mailmessage_fetch(msg,&data,&size);
00114     mime_message_detach_mime(msg);
00115     mailmessage_free(msg);
00116     if (r != MAIL_NO_ERROR || !data) {
00117         if (data)
00118             free(data);
00119         odebug << "Error fetching mime..." << oendl; 
00120         return;
00121     }
00122     msg = 0;
00123     if (later) {
00124         storeMail(data,size,"Outgoing");
00125         if (data)
00126             free( data );
00127         Config cfg( "mail" );
00128         cfg.setGroup( "Status" );
00129         cfg.writeEntry( "outgoing", ++m_queuedMail );
00130         emit queuedMails( m_queuedMail );
00131         return;
00132     }
00133     from = getFrom( mail );
00134     rcpts = createRcptList( mail->mm_data.mm_message.mm_fields );
00135     smtpSend(from,rcpts,data,size);
00136     if (data) {
00137         free(data);
00138     }
00139     if (from) {
00140         free(from);
00141     }
00142     if (rcpts)
00143         smtp_address_list_free( rcpts );
00144 }
00145 
00146 void SMTPwrapper::storeFailedMail(const char*data,unsigned int size, const char*failuremessage)
00147 {
00148     if (data) {
00149         storeMail(data,size,"Sendfailed");
00150     }
00151     if (failuremessage) {
00152         QMessageBox::critical(0,tr("Error sending mail"),
00153             tr("<center>%1</center>").arg(failuremessage));
00154     }
00155 }
00156 
00157 int SMTPwrapper::start_smtp_tls()
00158 {
00159     if (!m_smtp) {
00160         return MAILSMTP_ERROR_IN_PROCESSING;
00161     }
00162     int err = mailesmtp_starttls(m_smtp);
00163     if (err != MAILSMTP_NO_ERROR) return err;
00164     mailstream_low * low;
00165     mailstream_low * new_low;
00166     low = mailstream_get_low(m_smtp->stream);
00167     if (!low) {
00168         return MAILSMTP_ERROR_IN_PROCESSING;
00169     }
00170     int fd = mailstream_low_get_fd(low);
00171     if (fd > -1 && (new_low = mailstream_low_ssl_open(fd))!=0) {
00172         mailstream_low_free(low);
00173         mailstream_set_low(m_smtp->stream, new_low);
00174     } else {
00175         return MAILSMTP_ERROR_IN_PROCESSING;
00176     }
00177     return err;
00178 }
00179 
00180 void SMTPwrapper::connect_server()
00181 {
00182     const char *server, *user, *pass;
00183     bool ssl;
00184     uint16_t port;
00185     ssl = false;
00186     bool try_tls = true;
00187     bool force_tls=false;
00188     server = user = pass = 0;
00189     QString failuretext = "";
00190 
00191     if (m_smtp || !m_SmtpAccount) {
00192         return;
00193     }
00194     server = m_SmtpAccount->getServer().latin1();
00195     if  ( m_SmtpAccount->ConnectionType() == 2 ) {
00196         ssl = true;
00197         try_tls = false;
00198     } else if (m_SmtpAccount->ConnectionType() == 1) {
00199         force_tls = true;
00200     }
00201     int result = 1;
00202     port = m_SmtpAccount->getPort().toUInt();
00203 
00204     m_smtp = mailsmtp_new( 20, &progress );
00205     if ( m_smtp == NULL ) {
00206         /* no failure message cause this happens when problems with memory - than we
00207            we can not display any messagebox */
00208         return;
00209     }
00210 
00211     int err = MAILSMTP_NO_ERROR;
00212     odebug << "Servername " << server << " at port " << port << "" << oendl; 
00213     if ( ssl ) {
00214         odebug << "SSL session" << oendl; 
00215         err = mailsmtp_ssl_connect( m_smtp, server, port );
00216     } else {
00217         odebug << "No SSL session" << oendl; 
00218         err = mailsmtp_socket_connect( m_smtp, server, port );
00219     }
00220     if ( err != MAILSMTP_NO_ERROR ) {
00221         odebug << "Error init connection" << oendl; 
00222         failuretext = tr("Error init SMTP connection: %1").arg(mailsmtpError(err));
00223         result = 0;
00224     }
00225 
00226     /* switch to tls after init 'cause there it will send the ehlo */
00227     if (result) {
00228         err = mailsmtp_init( m_smtp );
00229         if (err != MAILSMTP_NO_ERROR) {
00230             result = 0;
00231             failuretext = tr("Error init SMTP connection: %1").arg(mailsmtpError(err));
00232         }
00233     }
00234 
00235     if (try_tls) {
00236         err = start_smtp_tls();
00237         if (err != MAILSMTP_NO_ERROR) {
00238             try_tls = false;
00239         } else {
00240             err = mailesmtp_ehlo(m_smtp);
00241         }
00242     }
00243 
00244     if (!try_tls && force_tls) {
00245         result = 0;
00246         failuretext = tr("Error init SMTP tls: %1").arg(mailsmtpError(err));
00247     }
00248 
00249     if (result==1 && m_SmtpAccount->getLogin() ) {
00250         odebug << "smtp with auth" << oendl; 
00251         if ( m_SmtpAccount->getUser().isEmpty() || m_SmtpAccount->getPassword().isEmpty() ) {
00252             // get'em
00253             LoginDialog login( m_SmtpAccount->getUser(),
00254                 m_SmtpAccount->getPassword(), NULL, 0, true );
00255             login.show();
00256             if ( QDialog::Accepted == login.exec() ) {
00257                 // ok
00258                 user = login.getUser().latin1();
00259                 pass = login.getPassword().latin1();
00260             } else {
00261                 result = 0;
00262                 failuretext=tr("Login aborted - storing mail to localfolder");
00263             }
00264         } else {
00265             user = m_SmtpAccount->getUser().latin1();
00266             pass = m_SmtpAccount->getPassword().latin1();
00267         }
00268         odebug << "session->auth: " << m_smtp->auth << "" << oendl; 
00269         if (result) {
00270             err = mailsmtp_auth( m_smtp, (char*)user, (char*)pass );
00271             if ( err == MAILSMTP_NO_ERROR ) {
00272                 odebug << "auth ok" << oendl; 
00273             } else {
00274                 failuretext = tr("Authentification failed");
00275                 result = 0;
00276             }
00277         }
00278     }
00279 }
00280 
00281 void SMTPwrapper::disc_server()
00282 {
00283     if (m_smtp) {
00284         mailsmtp_quit( m_smtp );
00285         mailsmtp_free( m_smtp );
00286         m_smtp = 0;
00287     }
00288 }
00289 
00290 int SMTPwrapper::smtpSend(char*from,clist*rcpts,const char*data,size_t size )
00291 {
00292     int err,result;
00293     QString failuretext = "";
00294 
00295     connect_server();
00296 
00297     result = 1;
00298     if (m_smtp) {
00299         err = mailsmtp_send( m_smtp, from, rcpts, data, size );
00300         if ( err != MAILSMTP_NO_ERROR ) {
00301             failuretext=tr("Error sending mail: %1").arg(mailsmtpError(err));
00302             result = 0;
00303         }
00304     } else {
00305         result = 0;
00306     }
00307 
00308     if (!result) {
00309         storeFailedMail(data,size,failuretext);
00310     } else {
00311         odebug << "Mail sent." << oendl; 
00312         storeMail(data,size,"Sent");
00313     }
00314     return result;
00315 }
00316 
00317 void SMTPwrapper::sendMail(const Opie::Core::OSmartPointer<Mail>&mail,bool later )
00318 {
00319     mailmime * mimeMail;
00320 
00321     mimeMail = createMimeMail(mail );
00322     if ( mimeMail == NULL ) {
00323         odebug << "sendMail: error creating mime mail" << oendl; 
00324     } else {
00325         sendProgress = new progressMailSend();
00326         sendProgress->show();
00327         sendProgress->setMaxMails(1);
00328         smtpSend( mimeMail,later);
00329         odebug << "Clean up done" << oendl; 
00330         sendProgress->hide();
00331         delete sendProgress;
00332         sendProgress = 0;
00333         mailmime_free( mimeMail );
00334     }
00335 }
00336 
00337 int SMTPwrapper::sendQueuedMail(AbstractMail*wrap,const RecMailP&which) {
00338     size_t curTok = 0;
00339     mailimf_fields *fields = 0;
00340     mailimf_field*ffrom = 0;
00341     clist *rcpts = 0;
00342     char*from = 0;
00343     int res = 0;
00344 
00345     encodedString * data = wrap->fetchRawBody(which);
00346     if (!data)
00347         return 0;
00348     int err = mailimf_fields_parse( data->Content(), data->Length(), &curTok, &fields );
00349     if (err != MAILIMF_NO_ERROR) {
00350         delete data;
00351         delete wrap;
00352         return 0;
00353     }
00354 
00355     rcpts = createRcptList( fields );
00356     ffrom = getField(fields, MAILIMF_FIELD_FROM );
00357     from = getFrom(ffrom);
00358 
00359     if (rcpts && from) {
00360         res = smtpSend(from,rcpts,data->Content(),data->Length());
00361     }
00362     if (fields) {
00363         mailimf_fields_free(fields);
00364         fields = 0;
00365     }
00366     if (data) {
00367         delete data;
00368     }
00369     if (from) {
00370         free(from);
00371     }
00372     if (rcpts) {
00373         smtp_address_list_free( rcpts );
00374     }
00375     return res;
00376 }
00377 
00378 /* this is a special fun */
00379 bool SMTPwrapper::flushOutbox() {
00380     bool returnValue = true;
00381 
00382     odebug << "Sending the queue" << oendl; 
00383     if (!m_SmtpAccount) {
00384         odebug << "No smtp account given" << oendl; 
00385         return false;
00386     }
00387 
00388     bool reset_user_value = false;
00389     QString localfolders = AbstractMail::defaultLocalfolder();
00390     AbstractMail*wrap = AbstractMail::getWrapper(localfolders);
00391     if (!wrap) {
00392         odebug << "memory error" << oendl; 
00393         return false;
00394     }
00395     QString oldPw, oldUser;
00396     QValueList<RecMailP> mailsToSend;
00397     QValueList<RecMailP> mailsToRemove;
00398     QString mbox("Outgoing");
00399     wrap->listMessages(mbox,mailsToSend);
00400     if (mailsToSend.count()==0) {
00401         delete wrap;
00402         odebug << "No mails to send" << oendl; 
00403         return false;
00404     }
00405 
00406     oldPw = m_SmtpAccount->getPassword();
00407     oldUser = m_SmtpAccount->getUser();
00408     if (m_SmtpAccount->getLogin() && (m_SmtpAccount->getUser().isEmpty() || m_SmtpAccount->getPassword().isEmpty()) ) {
00409         // get'em
00410         QString user,pass;
00411         LoginDialog login( m_SmtpAccount->getUser(), m_SmtpAccount->getPassword(), NULL, 0, true );
00412         login.show();
00413         if ( QDialog::Accepted == login.exec() ) {
00414             // ok
00415             user = login.getUser().latin1();
00416             pass = login.getPassword().latin1();
00417             reset_user_value = true;
00418             m_SmtpAccount->setUser(user);
00419             m_SmtpAccount->setPassword(pass);
00420         } else {
00421             return true;
00422         }
00423     }
00424 
00425 
00426     sendProgress = new progressMailSend();
00427     sendProgress->show();
00428     sendProgress->setMaxMails(mailsToSend.count());
00429 
00430     while (mailsToSend.count()>0) {
00431         if (sendQueuedMail(wrap, (*mailsToSend.begin()))==0) {
00432             QMessageBox::critical(0,tr("Error sending mail"),
00433                                   tr("Error sending queued mail - breaking"));
00434             returnValue = false;
00435             break;
00436         }
00437         mailsToRemove.append((*mailsToSend.begin()));
00438         mailsToSend.remove(mailsToSend.begin());
00439         sendProgress->setCurrentMails(mailsToRemove.count());
00440     }
00441     if (reset_user_value) {
00442         m_SmtpAccount->setUser(oldUser);
00443         m_SmtpAccount->setPassword(oldPw);
00444     }
00445     Config cfg( "mail" );
00446     cfg.setGroup( "Status" );
00447     m_queuedMail = 0;
00448     cfg.writeEntry( "outgoing", m_queuedMail );
00449     emit queuedMails( m_queuedMail );
00450     sendProgress->hide();
00451     delete sendProgress;
00452     sendProgress = 0;
00453     wrap->deleteMails(mbox,mailsToRemove);
00454     delete wrap;
00455     return returnValue;
00456 }

Generated on Sat Nov 5 16:17:38 2005 for OPIE by  doxygen 1.4.2