author | alwin <alwin> | 2003-12-21 10:36:22 (UTC) |
---|---|---|
committer | alwin <alwin> | 2003-12-21 10:36:22 (UTC) |
commit | af0b88049e0c77cb90ef1aca608accc32a2e2828 (patch) (side-by-side diff) | |
tree | ad8a2ce76ae1ab3cf535f4d1d7addbc240ff4209 | |
parent | 8e884631cc002011a9abab37be9223d4a1421ff2 (diff) | |
download | opie-af0b88049e0c77cb90ef1aca608accc32a2e2828.zip opie-af0b88049e0c77cb90ef1aca608accc32a2e2828.tar.gz opie-af0b88049e0c77cb90ef1aca608accc32a2e2828.tar.bz2 |
- MailWrapper -> SMTPwrapper
- made dependies from libetpan includes somewhat cleaner
- removed standalone static funs and moved to class based static methods
- arguements in SMTPwrapper now always const references and not deep copies
TODO: clean up GOTO statements, change QList to QValueList for a better
handling of "const" arguments, store mails in queue and/or a local "Sent"
folder.
-rw-r--r-- | noncore/net/mail/abstractmail.cpp | 1 | ||||
-rw-r--r-- | noncore/net/mail/composemail.cpp | 3 | ||||
-rw-r--r-- | noncore/net/mail/imapwrapper.cpp | 3 | ||||
-rw-r--r-- | noncore/net/mail/imapwrapper.h | 1 | ||||
-rw-r--r-- | noncore/net/mail/libmailwrapper/abstractmail.cpp | 1 | ||||
-rw-r--r-- | noncore/net/mail/libmailwrapper/imapwrapper.cpp | 3 | ||||
-rw-r--r-- | noncore/net/mail/libmailwrapper/imapwrapper.h | 1 | ||||
-rw-r--r-- | noncore/net/mail/libmailwrapper/mailwrapper.cpp | 585 | ||||
-rw-r--r-- | noncore/net/mail/libmailwrapper/mailwrapper.h | 35 | ||||
-rw-r--r-- | noncore/net/mail/libmailwrapper/pop3wrapper.h | 6 | ||||
-rw-r--r-- | noncore/net/mail/libmailwrapper/smtpwrapper.cpp | 604 | ||||
-rw-r--r-- | noncore/net/mail/libmailwrapper/smtpwrapper.h | 53 | ||||
-rw-r--r-- | noncore/net/mail/mail.pro | 6 | ||||
-rw-r--r-- | noncore/net/mail/mailwrapper.cpp | 585 | ||||
-rw-r--r-- | noncore/net/mail/mailwrapper.h | 35 | ||||
-rw-r--r-- | noncore/net/mail/pop3wrapper.h | 6 | ||||
-rw-r--r-- | noncore/net/mail/smtpwrapper.cpp | 604 | ||||
-rw-r--r-- | noncore/net/mail/smtpwrapper.h | 53 |
18 files changed, 1340 insertions, 1245 deletions
diff --git a/noncore/net/mail/abstractmail.cpp b/noncore/net/mail/abstractmail.cpp index 626b9aa..3cb8f7d 100644 --- a/noncore/net/mail/abstractmail.cpp +++ b/noncore/net/mail/abstractmail.cpp @@ -1,83 +1,84 @@ #include "abstractmail.h" #include "imapwrapper.h" #include "pop3wrapper.h" #include "mailtypes.h" #include <qstring.h> #include <qfile.h> #include <qtextstream.h> #include <stdlib.h> #include <libetpan/mailmime_content.h> +#include <libetpan/mailmime.h> AbstractMail* AbstractMail::getWrapper(IMAPaccount *a) { return new IMAPwrapper(a); } AbstractMail* AbstractMail::getWrapper(POP3account *a) { return new POP3wrapper(a); } encodedString* AbstractMail::decode_String(const encodedString*text,const QString&enc) { qDebug("Decode string start"); char*result_text; size_t index = 0; /* reset for recursive use! */ size_t target_length = 0; result_text = 0; int mimetype = MAILMIME_MECHANISM_7BIT; if (enc.lower()=="quoted-printable") { mimetype = MAILMIME_MECHANISM_QUOTED_PRINTABLE; } else if (enc.lower()=="base64") { mimetype = MAILMIME_MECHANISM_BASE64; } else if (enc.lower()=="8bit") { mimetype = MAILMIME_MECHANISM_8BIT; } else if (enc.lower()=="binary") { mimetype = MAILMIME_MECHANISM_BINARY; } int err = mailmime_part_parse(text->Content(),text->Length(),&index,mimetype, &result_text,&target_length); encodedString* result = new encodedString(); if (err == MAILIMF_NO_ERROR) { result->setContent(result_text,target_length); } qDebug("Decode string finished"); return result; } QString AbstractMail::convert_String(const char*text) { size_t index = 0; char*res = 0; /* attention - doesn't work with arm systems! */ int err = mailmime_encoded_phrase_parse("iso-8859-1", text, strlen(text),&index, "iso-8859-1",&res); if (err != MAILIMF_NO_ERROR) { if (res) free(res); return QString(text); } if (res) { QString result(res); free(res); return result; } return QString(text); } /* cp & paste from launcher */ QString AbstractMail::gen_attachment_id() { QFile file( "/proc/sys/kernel/random/uuid" ); if (!file.open(IO_ReadOnly ) ) return QString::null; QTextStream stream(&file); return "{" + stream.read().stripWhiteSpace() + "}"; } diff --git a/noncore/net/mail/composemail.cpp b/noncore/net/mail/composemail.cpp index cfccdbb..048fa85 100644 --- a/noncore/net/mail/composemail.cpp +++ b/noncore/net/mail/composemail.cpp @@ -1,202 +1,203 @@ #include <qt.h> #include <opie/ofiledialog.h> #include <qpe/resource.h> #include "composemail.h" +#include "smtpwrapper.h" ComposeMail::ComposeMail( Settings *s, QWidget *parent, const char *name, bool modal, WFlags flags ) : ComposeMailUI( parent, name, modal, flags ) { settings = s; attList->addColumn( tr( "Name" ) ); attList->addColumn( tr( "Size" ) ); QList<Account> accounts = settings->getAccounts(); Account *it; for ( it = accounts.first(); it; it = accounts.next() ) { if ( it->getType().compare( "SMTP" ) == 0 ) { SMTPaccount *smtp = static_cast<SMTPaccount *>(it); fromBox->insertItem( smtp->getMail() ); smtpAccounts.append( smtp ); } } if ( smtpAccounts.count() > 0 ) { fillValues( fromBox->currentItem() ); } else { QMessageBox::information( this, tr( "Problem" ), tr( "<p>Please create an SMTP account first.</p>" ), tr( "Ok" ) ); } connect( fromBox, SIGNAL( activated( int ) ), SLOT( fillValues( int ) ) ); connect( toButton, SIGNAL( clicked() ), SLOT( pickAddressTo() ) ); connect( ccButton, SIGNAL( clicked() ), SLOT( pickAddressCC() ) ); connect( bccButton, SIGNAL( clicked() ), SLOT( pickAddressBCC() ) ); connect( replyButton, SIGNAL( clicked() ), SLOT( pickAddressReply() ) ); connect( addButton, SIGNAL( clicked() ), SLOT( addAttachment() ) ); connect( deleteButton, SIGNAL( clicked() ), SLOT( removeAttachment() ) ); } void ComposeMail::pickAddress( QLineEdit *line ) { QString names = AddressPicker::getNames(); if ( line->text().isEmpty() ) { line->setText( names ); } else if ( !names.isEmpty() ) { line->setText( line->text() + ", " + names ); } } void ComposeMail::setTo( const QString & to ) { /* QString toline; QStringList toEntry = to; for ( QStringList::Iterator it = toEntry.begin(); it != toEntry.end(); ++it ) { toline += (*it); } toLine->setText( toline ); */ toLine->setText( to ); } void ComposeMail::setSubject( const QString & subject ) { subjectLine->setText( subject ); } void ComposeMail::setInReplyTo( const QString & messageId ) { } void ComposeMail::setMessage( const QString & text ) { message->setText( text ); } void ComposeMail::pickAddressTo() { pickAddress( toLine ); } void ComposeMail::pickAddressCC() { pickAddress( ccLine ); } void ComposeMail::pickAddressBCC() { pickAddress( bccLine ); } void ComposeMail::pickAddressReply() { pickAddress( replyLine ); } void ComposeMail::fillValues( int current ) { SMTPaccount *smtp = smtpAccounts.at( current ); ccLine->clear(); if ( smtp->getUseCC() ) { ccLine->setText( smtp->getCC() ); } bccLine->clear(); if ( smtp->getUseBCC() ) { bccLine->setText( smtp->getBCC() ); } replyLine->clear(); if ( smtp->getUseReply() ) { replyLine->setText( smtp->getReply() ); } sigMultiLine->setText( smtp->getSignature() ); } void ComposeMail::slotAdjustColumns() { int currPage = tabWidget->currentPageIndex(); tabWidget->showPage( attachTab ); attList->setColumnWidth( 0, attList->visibleWidth() - 80 ); attList->setColumnWidth( 1, 80 ); tabWidget->setCurrentPage( currPage ); } void ComposeMail::addAttachment() { DocLnk lnk = OFileDialog::getOpenFileName( 1, "/" ); if ( !lnk.name().isEmpty() ) { Attachment *att = new Attachment( lnk ); (void) new AttachViewItem( attList, att ); } } void ComposeMail::removeAttachment() { if ( !attList->currentItem() ) { QMessageBox::information( this, tr( "Error" ), tr( "<p>Please select a File.</p>" ), tr( "Ok" ) ); } else { attList->takeItem( attList->currentItem() ); } } void ComposeMail::accept() { qDebug( "Sending Mail with " + smtpAccounts.at( fromBox->currentItem() )->getAccountName() ); Mail *mail = new Mail(); SMTPaccount *smtp = smtpAccounts.at( fromBox->currentItem() ); mail->setMail( smtp->getMail() ); mail->setName( smtp->getName() ); if ( !toLine->text().isEmpty() ) { mail->setTo( toLine->text() ); } else { qDebug( "No Reciever spezified -> returning" ); return; } mail->setCC( ccLine->text() ); mail->setBCC( bccLine->text() ); mail->setReply( replyLine->text() ); mail->setSubject( subjectLine->text() ); QString txt = message->text(); if ( !sigMultiLine->text().isEmpty() ) { txt.append( "\n--\n" ); txt.append( sigMultiLine->text() ); } mail->setMessage( txt ); AttachViewItem *it = (AttachViewItem *) attList->firstChild(); while ( it != NULL ) { mail->addAttachment( it->getAttachment() ); it = (AttachViewItem *) it->itemBelow(); } - MailWrapper wrapper( settings ); + SMTPwrapper wrapper( settings ); wrapper.sendMail( *mail ); QDialog::accept(); } AttachViewItem::AttachViewItem( QListView *parent, Attachment *att ) : QListViewItem( parent ) { attachment = att; qDebug( att->getMimeType() ); setPixmap( 0, attachment->getDocLnk().pixmap().isNull() ? Resource::loadPixmap( "UnknownDocument-14" ) : attachment->getDocLnk().pixmap() ); setText( 0, att->getName().isEmpty() ? att->getFileName() : att->getName() ); setText( 1, QString::number( att->getSize() ) ); } diff --git a/noncore/net/mail/imapwrapper.cpp b/noncore/net/mail/imapwrapper.cpp index cce3d34..30eb678 100644 --- a/noncore/net/mail/imapwrapper.cpp +++ b/noncore/net/mail/imapwrapper.cpp @@ -1,519 +1,520 @@ #include <stdlib.h> +#include <libetpan/mailimap.h> + #include "imapwrapper.h" #include "mailtypes.h" #include "logindialog.h" -#include <libetpan/mailimap.h> IMAPwrapper::IMAPwrapper( IMAPaccount *a ) : AbstractMail() { account = a; m_imap = 0; } IMAPwrapper::~IMAPwrapper() { logout(); } void IMAPwrapper::imap_progress( size_t current, size_t maximum ) { qDebug( "IMAP: %i of %i", current, maximum ); } void IMAPwrapper::login() { const char *server, *user, *pass; uint16_t port; int err = MAILIMAP_NO_ERROR; /* we are connected this moment */ /* TODO: setup a timer holding the line or if connection closed - delete the value */ if (m_imap) { mailstream_flush(m_imap->imap_stream); return; } server = account->getServer().latin1(); port = account->getPort().toUInt(); if ( account->getUser().isEmpty() || account->getPassword().isEmpty() ) { LoginDialog login( account->getUser(), account->getPassword(), NULL, 0, true ); login.show(); if ( QDialog::Accepted == login.exec() ) { // ok user = strdup( login.getUser().latin1() ); pass = strdup( login.getPassword().latin1() ); } else { // cancel qDebug( "IMAP: Login canceled" ); return; } } else { user = account->getUser().latin1(); pass = account->getPassword().latin1(); } m_imap = mailimap_new( 20, &imap_progress ); /* connect */ if (account->getSSL()) { err = mailimap_ssl_connect( m_imap, (char*)server, port ); } else { err = mailimap_socket_connect( m_imap, (char*)server, port ); } if ( err != MAILIMAP_NO_ERROR && err != MAILIMAP_NO_ERROR_AUTHENTICATED && err != MAILIMAP_NO_ERROR_NON_AUTHENTICATED ) { qDebug("error connecting server: %s",m_imap->imap_response); mailimap_free( m_imap ); m_imap = 0; return; } /* login */ err = mailimap_login_simple( m_imap, (char*)user, (char*)pass ); if ( err != MAILIMAP_NO_ERROR ) { qDebug("error logging in imap: %s",m_imap->imap_response); err = mailimap_close( m_imap ); mailimap_free( m_imap ); m_imap = 0; } } void IMAPwrapper::logout() { int err = MAILIMAP_NO_ERROR; if (!m_imap) return; err = mailimap_logout( m_imap ); err = mailimap_close( m_imap ); mailimap_free( m_imap ); m_imap = 0; } void IMAPwrapper::listMessages(const QString&mailbox,QList<RecMail> &target ) { const char *mb; int err = MAILIMAP_NO_ERROR; clist *result; clistcell *current; // mailimap_fetch_att *fetchAtt,*fetchAttFlags,*fetchAttDate,*fetchAttSize; mailimap_fetch_type *fetchType; mailimap_set *set; mb = mailbox.latin1(); login(); if (!m_imap) { return; } /* select mailbox READONLY for operations */ err = mailimap_examine( m_imap, (char*)mb); if ( err != MAILIMAP_NO_ERROR ) { qDebug("error selecting mailbox: %s",m_imap->imap_response); return; } int last = m_imap->imap_selection_info->sel_exists; if (last == 0) { qDebug("mailbox has no mails"); return; } result = clist_new(); /* the range has to start at 1!!! not with 0!!!! */ set = mailimap_set_new_interval( 1, last ); fetchType = mailimap_fetch_type_new_fetch_att_list_empty(); mailimap_fetch_type_new_fetch_att_list_add(fetchType,mailimap_fetch_att_new_envelope()); mailimap_fetch_type_new_fetch_att_list_add(fetchType,mailimap_fetch_att_new_flags()); mailimap_fetch_type_new_fetch_att_list_add(fetchType,mailimap_fetch_att_new_internaldate()); mailimap_fetch_type_new_fetch_att_list_add(fetchType,mailimap_fetch_att_new_rfc822_size()); err = mailimap_fetch( m_imap, set, fetchType, &result ); mailimap_set_free( set ); mailimap_fetch_type_free( fetchType ); QString date,subject,from; if ( err == MAILIMAP_NO_ERROR ) { mailimap_msg_att * msg_att; int i = 0; for (current = clist_begin(result); current != 0; current=clist_next(current)) { ++i; msg_att = (mailimap_msg_att*)current->data; RecMail*m = parse_list_result(msg_att); if (m) { m->setNumber(i); m->setMbox(mailbox); m->setWrapper(this); target.append(m); } } } else { qDebug("Error fetching headers: %s",m_imap->imap_response); } mailimap_fetch_list_free(result); } QList<Folder>* IMAPwrapper::listFolders() { const char *path, *mask; int err = MAILIMAP_NO_ERROR; clist *result; clistcell *current; QList<Folder> * folders = new QList<Folder>(); folders->setAutoDelete( false ); login(); if (!m_imap) { return folders; } /* * First we have to check for INBOX 'cause it sometimes it's not inside the path. * We must not forget to filter them out in next loop! * it seems like ugly code. and yes - it is ugly code. but the best way. */ QString temp; mask = "INBOX" ; result = clist_new(); mailimap_mailbox_list *list; err = mailimap_list( m_imap, (char*)"", (char*)mask, &result ); QString del; if ( err == MAILIMAP_NO_ERROR ) { current = result->first; for ( int i = result->count; i > 0; i-- ) { list = (mailimap_mailbox_list *) current->data; // it is better use the deep copy mechanism of qt itself // instead of using strdup! temp = list->mb_name; del = list->mb_delimiter; folders->append( new IMAPFolder(temp,del,true,account->getPrefix())); current = current->next; } } else { qDebug("error fetching folders: %s",m_imap->imap_response); } mailimap_list_result_free( result ); /* * second stage - get the other then inbox folders */ mask = "*" ; path = account->getPrefix().latin1(); if (!path) path = ""; result = clist_new(); qDebug(path); bool selectable = true; mailimap_mbx_list_flags*bflags; err = mailimap_list( m_imap, (char*)path, (char*)mask, &result ); if ( err == MAILIMAP_NO_ERROR ) { current = result->first; for ( current=clist_begin(result);current!=NULL;current=clist_next(current)) { list = (mailimap_mailbox_list *) current->data; // it is better use the deep copy mechanism of qt itself // instead of using strdup! temp = list->mb_name; if (temp.lower()=="inbox") continue; if (temp.lower()==account->getPrefix().lower()) continue; if ( (bflags = list->mb_flag) ) { selectable = !(bflags->mbf_type==MAILIMAP_MBX_LIST_FLAGS_SFLAG&& bflags->mbf_sflag==MAILIMAP_MBX_LIST_SFLAG_NOSELECT); } del = list->mb_delimiter; folders->append(new IMAPFolder(temp,del,selectable,account->getPrefix())); } } else { qDebug("error fetching folders %s",m_imap->imap_response); } mailimap_list_result_free( result ); return folders; } RecMail*IMAPwrapper::parse_list_result(mailimap_msg_att* m_att) { RecMail * m = 0; mailimap_msg_att_item *item=0; clistcell *current,*c,*cf; mailimap_msg_att_dynamic*flist; mailimap_flag_fetch*cflag; int size; QBitArray mFlags(7); QStringList addresslist; if (!m_att) { return m; } m = new RecMail(); for (c = clist_begin(m_att->att_list); c!=NULL;c=clist_next(c) ) { current = c; size = 0; item = (mailimap_msg_att_item*)current->data; if (item->att_type!=MAILIMAP_MSG_ATT_ITEM_STATIC) { flist = (mailimap_msg_att_dynamic*)item->att_data.att_dyn; if (!flist->att_list) { continue; } cf = flist->att_list->first; for (cf = clist_begin(flist->att_list); cf!=NULL; cf = clist_next(cf)) { cflag = (mailimap_flag_fetch*)cf->data; if (cflag->fl_type==MAILIMAP_FLAG_FETCH_OTHER && cflag->fl_flag!=0) { switch (cflag->fl_flag->fl_type) { case MAILIMAP_FLAG_ANSWERED: /* \Answered flag */ mFlags.setBit(FLAG_ANSWERED); break; case MAILIMAP_FLAG_FLAGGED: /* \Flagged flag */ mFlags.setBit(FLAG_FLAGGED); break; case MAILIMAP_FLAG_DELETED: /* \Deleted flag */ mFlags.setBit(FLAG_DELETED); break; case MAILIMAP_FLAG_SEEN: /* \Seen flag */ mFlags.setBit(FLAG_SEEN); break; case MAILIMAP_FLAG_DRAFT: /* \Draft flag */ mFlags.setBit(FLAG_DRAFT); break; case MAILIMAP_FLAG_KEYWORD: /* keyword flag */ break; case MAILIMAP_FLAG_EXTENSION: /* \extension flag */ break; default: break; } } else if (cflag->fl_type==MAILIMAP_FLAG_FETCH_RECENT) { mFlags.setBit(FLAG_RECENT); } } continue; } if (item->att_data.att_static->att_type==MAILIMAP_MSG_ATT_ENVELOPE) { mailimap_envelope * head = item->att_data.att_static->att_data.att_env; m->setDate(head->env_date); m->setSubject(convert_String((const char*)head->env_subject)); //m->setSubject(head->env_subject); if (head->env_from!=NULL) { addresslist = address_list_to_stringlist(head->env_from->frm_list); if (addresslist.count()) { m->setFrom(addresslist.first()); } } if (head->env_to!=NULL) { addresslist = address_list_to_stringlist(head->env_to->to_list); m->setTo(addresslist); } if (head->env_cc!=NULL) { addresslist = address_list_to_stringlist(head->env_cc->cc_list); m->setCC(addresslist); } if (head->env_bcc!=NULL) { addresslist = address_list_to_stringlist(head->env_bcc->bcc_list); m->setBcc(addresslist); } if (head->env_reply_to!=NULL) { addresslist = address_list_to_stringlist(head->env_reply_to->rt_list); if (addresslist.count()) { m->setReplyto(addresslist.first()); } } m->setMsgid(QString(head->env_message_id)); } else if (item->att_data.att_static->att_type==MAILIMAP_MSG_ATT_INTERNALDATE) { #if 0 mailimap_date_time*d = item->att_data.att_static->att_data.att_internal_date; QDateTime da(QDate(d->dt_year,d->dt_month,d->dt_day),QTime(d->dt_hour,d->dt_min,d->dt_sec)); qDebug("%i %i %i - %i %i %i",d->dt_year,d->dt_month,d->dt_day,d->dt_hour,d->dt_min,d->dt_sec); qDebug(da.toString()); #endif } else if (item->att_data.att_static->att_type==MAILIMAP_MSG_ATT_RFC822_SIZE) { size = item->att_data.att_static->att_data.att_rfc822_size; } } /* msg is already deleted */ if (mFlags.testBit(FLAG_DELETED) && m) { delete m; m = 0; } if (m) { m->setFlags(mFlags); m->setMsgsize(size); } return m; } RecBody IMAPwrapper::fetchBody(const RecMail&mail) { RecBody body; const char *mb; int err = MAILIMAP_NO_ERROR; clist *result; clistcell *current; mailimap_fetch_att *fetchAtt; mailimap_fetch_type *fetchType; mailimap_set *set; mailimap_body*body_desc; mb = mail.getMbox().latin1(); login(); if (!m_imap) { return body; } err = mailimap_select( m_imap, (char*)mb); if ( err != MAILIMAP_NO_ERROR ) { qDebug("error selecting mailbox: %s",m_imap->imap_response); return body; } result = clist_new(); /* the range has to start at 1!!! not with 0!!!! */ set = mailimap_set_new_interval( mail.getNumber(),mail.getNumber() ); fetchAtt = mailimap_fetch_att_new_bodystructure(); fetchType = mailimap_fetch_type_new_fetch_att(fetchAtt); err = mailimap_fetch( m_imap, set, fetchType, &result ); mailimap_set_free( set ); mailimap_fetch_type_free( fetchType ); if (err == MAILIMAP_NO_ERROR && (current=clist_begin(result)) ) { mailimap_msg_att * msg_att; msg_att = (mailimap_msg_att*)current->data; mailimap_msg_att_item*item = (mailimap_msg_att_item*)msg_att->att_list->first->data; body_desc = item->att_data.att_static->att_data.att_body; if (body_desc->bd_type==MAILIMAP_BODY_1PART) { searchBodyText(mail,body_desc->bd_data.bd_body_1part,body); } else if (body_desc->bd_type==MAILIMAP_BODY_MPART) { qDebug("Mulitpart mail"); searchBodyText(mail,body_desc->bd_data.bd_body_mpart,body); } } else { qDebug("error fetching body: %s",m_imap->imap_response); } mailimap_fetch_list_free(result); return body; } /* this routine is just called when the mail has only ONE part. for filling the parts of a multi-part-message there are other routines 'cause we can not simply fetch the whole body. */ void IMAPwrapper::searchBodyText(const RecMail&mail,mailimap_body_type_1part*mailDescription,RecBody&target_body) { if (!mailDescription) { return; } QString sub,body_text; RecPart singlePart; QValueList<int> path; fillSinglePart(singlePart,mailDescription); switch (mailDescription->bd_type) { case MAILIMAP_BODY_TYPE_1PART_MSG: path.append(1); body_text = fetchTextPart(mail,path,true,singlePart.Encoding()); target_body.setBodytext(body_text); target_body.setDescription(singlePart); break; case MAILIMAP_BODY_TYPE_1PART_TEXT: qDebug("Mediatype single: %s",mailDescription->bd_data.bd_type_text->bd_media_text); path.append(1); body_text = fetchTextPart(mail,path,true,singlePart.Encoding()); target_body.setBodytext(body_text); target_body.setDescription(singlePart); break; case MAILIMAP_BODY_TYPE_1PART_BASIC: qDebug("Single attachment"); target_body.setBodytext(""); target_body.addPart(singlePart); break; default: break; } return; } QStringList IMAPwrapper::address_list_to_stringlist(clist*list) { QStringList l; QString from; bool named_from; clistcell *current = NULL; mailimap_address * current_address=NULL; if (!list) { return l; } unsigned int count = 0; for (current=clist_begin(list);current!= NULL;current=clist_next(current)) { from = ""; named_from = false; current_address=(mailimap_address*)current->data; if (current_address->ad_personal_name){ from+=convert_String((const char*)current_address->ad_personal_name); //from+=QString(current_address->ad_personal_name); from+=" "; named_from = true; } if (named_from && (current_address->ad_mailbox_name || current_address->ad_host_name)) { from+="<"; } if (current_address->ad_mailbox_name) { from+=QString(current_address->ad_mailbox_name); from+="@"; } if (current_address->ad_host_name) { from+=QString(current_address->ad_host_name); } if (named_from && (current_address->ad_mailbox_name || current_address->ad_host_name)) { from+=">"; } l.append(QString(from)); if (++count > 99) { break; } } return l; } encodedString*IMAPwrapper::fetchRawPart(const RecMail&mail,const QValueList<int>&path,bool internal_call) { encodedString*res=new encodedString; const char*mb; int err; mailimap_fetch_type *fetchType; mailimap_set *set; clistcell*current,*cur; login(); if (!m_imap) { return res; } if (!internal_call) { mb = mail.getMbox().latin1(); err = mailimap_select( m_imap, (char*)mb); if ( err != MAILIMAP_NO_ERROR ) { qDebug("error selecting mailbox: %s",m_imap->imap_response); return res; } } set = mailimap_set_new_single(mail.getNumber()); clist*id_list=clist_new(); for (unsigned j=0; j < path.count();++j) { uint32_t * p_id = (uint32_t *)malloc(sizeof(*p_id)); *p_id = path[j]; clist_append(id_list,p_id); } mailimap_section_part * section_part = mailimap_section_part_new(id_list); mailimap_section_spec * section_spec = mailimap_section_spec_new(MAILIMAP_SECTION_SPEC_SECTION_PART, NULL, section_part, NULL); mailimap_section * section = mailimap_section_new(section_spec); mailimap_fetch_att * fetch_att = mailimap_fetch_att_new_body_section(section); fetchType = mailimap_fetch_type_new_fetch_att(fetch_att); clist*result = clist_new(); err = mailimap_fetch( m_imap, set, fetchType, &result ); mailimap_set_free( set ); mailimap_fetch_type_free( fetchType ); diff --git a/noncore/net/mail/imapwrapper.h b/noncore/net/mail/imapwrapper.h index aeebda8..f046297 100644 --- a/noncore/net/mail/imapwrapper.h +++ b/noncore/net/mail/imapwrapper.h @@ -1,62 +1,63 @@ #ifndef __IMAPWRAPPER #define __IMAPWRAPPER #include <qlist.h> #include "mailwrapper.h" #include "abstractmail.h" +#include <libetpan/clist.h> struct mailimap; struct mailimap_body_type_1part; struct mailimap_body_type_text; struct mailimap_body_type_basic; struct mailimap_body_type_msg; struct mailimap_body_type_mpart; struct mailimap_body_fields; struct mailimap_msg_att; class encodedString; class IMAPwrapper : public AbstractMail { Q_OBJECT public: IMAPwrapper( IMAPaccount *a ); virtual ~IMAPwrapper(); virtual QList<Folder>* listFolders(); virtual void listMessages(const QString & mailbox,QList<RecMail>&target ); virtual void deleteMail(const RecMail&mail); virtual void answeredMail(const RecMail&mail); virtual RecBody fetchBody(const RecMail&mail); virtual QString fetchTextPart(const RecMail&mail,const RecPart&part); virtual encodedString* fetchDecodedPart(const RecMail&mail,const RecPart&part); virtual encodedString* fetchRawPart(const RecMail&mail,const RecPart&part); static void imap_progress( size_t current, size_t maximum ); protected: RecMail*parse_list_result(mailimap_msg_att*); void login(); void logout(); virtual QString fetchTextPart(const RecMail&mail,const QValueList<int>&path,bool internal_call=false,const QString&enc=""); virtual encodedString*fetchRawPart(const RecMail&mail,const QValueList<int>&path,bool internal_call); void searchBodyText(const RecMail&mail,mailimap_body_type_1part*mailDescription,RecBody&target_body); void searchBodyText(const RecMail&mail,mailimap_body_type_mpart*mailDescription,RecBody&target_body,int current_recursion=0,QValueList<int>recList=QValueList<int>()); void fillSinglePart(RecPart&target_part,mailimap_body_type_1part*Description); void fillSingleTextPart(RecPart&target_part,mailimap_body_type_text*which); void fillSingleBasicPart(RecPart&target_part,mailimap_body_type_basic*which); void fillSingleMsgPart(RecPart&target_part,mailimap_body_type_msg*which); /* just helpers */ static void fillBodyFields(RecPart&target_part,mailimap_body_fields*which); static QStringList address_list_to_stringlist(clist*list); IMAPaccount *account; mailimap *m_imap; }; #endif diff --git a/noncore/net/mail/libmailwrapper/abstractmail.cpp b/noncore/net/mail/libmailwrapper/abstractmail.cpp index 626b9aa..3cb8f7d 100644 --- a/noncore/net/mail/libmailwrapper/abstractmail.cpp +++ b/noncore/net/mail/libmailwrapper/abstractmail.cpp @@ -1,83 +1,84 @@ #include "abstractmail.h" #include "imapwrapper.h" #include "pop3wrapper.h" #include "mailtypes.h" #include <qstring.h> #include <qfile.h> #include <qtextstream.h> #include <stdlib.h> #include <libetpan/mailmime_content.h> +#include <libetpan/mailmime.h> AbstractMail* AbstractMail::getWrapper(IMAPaccount *a) { return new IMAPwrapper(a); } AbstractMail* AbstractMail::getWrapper(POP3account *a) { return new POP3wrapper(a); } encodedString* AbstractMail::decode_String(const encodedString*text,const QString&enc) { qDebug("Decode string start"); char*result_text; size_t index = 0; /* reset for recursive use! */ size_t target_length = 0; result_text = 0; int mimetype = MAILMIME_MECHANISM_7BIT; if (enc.lower()=="quoted-printable") { mimetype = MAILMIME_MECHANISM_QUOTED_PRINTABLE; } else if (enc.lower()=="base64") { mimetype = MAILMIME_MECHANISM_BASE64; } else if (enc.lower()=="8bit") { mimetype = MAILMIME_MECHANISM_8BIT; } else if (enc.lower()=="binary") { mimetype = MAILMIME_MECHANISM_BINARY; } int err = mailmime_part_parse(text->Content(),text->Length(),&index,mimetype, &result_text,&target_length); encodedString* result = new encodedString(); if (err == MAILIMF_NO_ERROR) { result->setContent(result_text,target_length); } qDebug("Decode string finished"); return result; } QString AbstractMail::convert_String(const char*text) { size_t index = 0; char*res = 0; /* attention - doesn't work with arm systems! */ int err = mailmime_encoded_phrase_parse("iso-8859-1", text, strlen(text),&index, "iso-8859-1",&res); if (err != MAILIMF_NO_ERROR) { if (res) free(res); return QString(text); } if (res) { QString result(res); free(res); return result; } return QString(text); } /* cp & paste from launcher */ QString AbstractMail::gen_attachment_id() { QFile file( "/proc/sys/kernel/random/uuid" ); if (!file.open(IO_ReadOnly ) ) return QString::null; QTextStream stream(&file); return "{" + stream.read().stripWhiteSpace() + "}"; } diff --git a/noncore/net/mail/libmailwrapper/imapwrapper.cpp b/noncore/net/mail/libmailwrapper/imapwrapper.cpp index cce3d34..30eb678 100644 --- a/noncore/net/mail/libmailwrapper/imapwrapper.cpp +++ b/noncore/net/mail/libmailwrapper/imapwrapper.cpp @@ -1,519 +1,520 @@ #include <stdlib.h> +#include <libetpan/mailimap.h> + #include "imapwrapper.h" #include "mailtypes.h" #include "logindialog.h" -#include <libetpan/mailimap.h> IMAPwrapper::IMAPwrapper( IMAPaccount *a ) : AbstractMail() { account = a; m_imap = 0; } IMAPwrapper::~IMAPwrapper() { logout(); } void IMAPwrapper::imap_progress( size_t current, size_t maximum ) { qDebug( "IMAP: %i of %i", current, maximum ); } void IMAPwrapper::login() { const char *server, *user, *pass; uint16_t port; int err = MAILIMAP_NO_ERROR; /* we are connected this moment */ /* TODO: setup a timer holding the line or if connection closed - delete the value */ if (m_imap) { mailstream_flush(m_imap->imap_stream); return; } server = account->getServer().latin1(); port = account->getPort().toUInt(); if ( account->getUser().isEmpty() || account->getPassword().isEmpty() ) { LoginDialog login( account->getUser(), account->getPassword(), NULL, 0, true ); login.show(); if ( QDialog::Accepted == login.exec() ) { // ok user = strdup( login.getUser().latin1() ); pass = strdup( login.getPassword().latin1() ); } else { // cancel qDebug( "IMAP: Login canceled" ); return; } } else { user = account->getUser().latin1(); pass = account->getPassword().latin1(); } m_imap = mailimap_new( 20, &imap_progress ); /* connect */ if (account->getSSL()) { err = mailimap_ssl_connect( m_imap, (char*)server, port ); } else { err = mailimap_socket_connect( m_imap, (char*)server, port ); } if ( err != MAILIMAP_NO_ERROR && err != MAILIMAP_NO_ERROR_AUTHENTICATED && err != MAILIMAP_NO_ERROR_NON_AUTHENTICATED ) { qDebug("error connecting server: %s",m_imap->imap_response); mailimap_free( m_imap ); m_imap = 0; return; } /* login */ err = mailimap_login_simple( m_imap, (char*)user, (char*)pass ); if ( err != MAILIMAP_NO_ERROR ) { qDebug("error logging in imap: %s",m_imap->imap_response); err = mailimap_close( m_imap ); mailimap_free( m_imap ); m_imap = 0; } } void IMAPwrapper::logout() { int err = MAILIMAP_NO_ERROR; if (!m_imap) return; err = mailimap_logout( m_imap ); err = mailimap_close( m_imap ); mailimap_free( m_imap ); m_imap = 0; } void IMAPwrapper::listMessages(const QString&mailbox,QList<RecMail> &target ) { const char *mb; int err = MAILIMAP_NO_ERROR; clist *result; clistcell *current; // mailimap_fetch_att *fetchAtt,*fetchAttFlags,*fetchAttDate,*fetchAttSize; mailimap_fetch_type *fetchType; mailimap_set *set; mb = mailbox.latin1(); login(); if (!m_imap) { return; } /* select mailbox READONLY for operations */ err = mailimap_examine( m_imap, (char*)mb); if ( err != MAILIMAP_NO_ERROR ) { qDebug("error selecting mailbox: %s",m_imap->imap_response); return; } int last = m_imap->imap_selection_info->sel_exists; if (last == 0) { qDebug("mailbox has no mails"); return; } result = clist_new(); /* the range has to start at 1!!! not with 0!!!! */ set = mailimap_set_new_interval( 1, last ); fetchType = mailimap_fetch_type_new_fetch_att_list_empty(); mailimap_fetch_type_new_fetch_att_list_add(fetchType,mailimap_fetch_att_new_envelope()); mailimap_fetch_type_new_fetch_att_list_add(fetchType,mailimap_fetch_att_new_flags()); mailimap_fetch_type_new_fetch_att_list_add(fetchType,mailimap_fetch_att_new_internaldate()); mailimap_fetch_type_new_fetch_att_list_add(fetchType,mailimap_fetch_att_new_rfc822_size()); err = mailimap_fetch( m_imap, set, fetchType, &result ); mailimap_set_free( set ); mailimap_fetch_type_free( fetchType ); QString date,subject,from; if ( err == MAILIMAP_NO_ERROR ) { mailimap_msg_att * msg_att; int i = 0; for (current = clist_begin(result); current != 0; current=clist_next(current)) { ++i; msg_att = (mailimap_msg_att*)current->data; RecMail*m = parse_list_result(msg_att); if (m) { m->setNumber(i); m->setMbox(mailbox); m->setWrapper(this); target.append(m); } } } else { qDebug("Error fetching headers: %s",m_imap->imap_response); } mailimap_fetch_list_free(result); } QList<Folder>* IMAPwrapper::listFolders() { const char *path, *mask; int err = MAILIMAP_NO_ERROR; clist *result; clistcell *current; QList<Folder> * folders = new QList<Folder>(); folders->setAutoDelete( false ); login(); if (!m_imap) { return folders; } /* * First we have to check for INBOX 'cause it sometimes it's not inside the path. * We must not forget to filter them out in next loop! * it seems like ugly code. and yes - it is ugly code. but the best way. */ QString temp; mask = "INBOX" ; result = clist_new(); mailimap_mailbox_list *list; err = mailimap_list( m_imap, (char*)"", (char*)mask, &result ); QString del; if ( err == MAILIMAP_NO_ERROR ) { current = result->first; for ( int i = result->count; i > 0; i-- ) { list = (mailimap_mailbox_list *) current->data; // it is better use the deep copy mechanism of qt itself // instead of using strdup! temp = list->mb_name; del = list->mb_delimiter; folders->append( new IMAPFolder(temp,del,true,account->getPrefix())); current = current->next; } } else { qDebug("error fetching folders: %s",m_imap->imap_response); } mailimap_list_result_free( result ); /* * second stage - get the other then inbox folders */ mask = "*" ; path = account->getPrefix().latin1(); if (!path) path = ""; result = clist_new(); qDebug(path); bool selectable = true; mailimap_mbx_list_flags*bflags; err = mailimap_list( m_imap, (char*)path, (char*)mask, &result ); if ( err == MAILIMAP_NO_ERROR ) { current = result->first; for ( current=clist_begin(result);current!=NULL;current=clist_next(current)) { list = (mailimap_mailbox_list *) current->data; // it is better use the deep copy mechanism of qt itself // instead of using strdup! temp = list->mb_name; if (temp.lower()=="inbox") continue; if (temp.lower()==account->getPrefix().lower()) continue; if ( (bflags = list->mb_flag) ) { selectable = !(bflags->mbf_type==MAILIMAP_MBX_LIST_FLAGS_SFLAG&& bflags->mbf_sflag==MAILIMAP_MBX_LIST_SFLAG_NOSELECT); } del = list->mb_delimiter; folders->append(new IMAPFolder(temp,del,selectable,account->getPrefix())); } } else { qDebug("error fetching folders %s",m_imap->imap_response); } mailimap_list_result_free( result ); return folders; } RecMail*IMAPwrapper::parse_list_result(mailimap_msg_att* m_att) { RecMail * m = 0; mailimap_msg_att_item *item=0; clistcell *current,*c,*cf; mailimap_msg_att_dynamic*flist; mailimap_flag_fetch*cflag; int size; QBitArray mFlags(7); QStringList addresslist; if (!m_att) { return m; } m = new RecMail(); for (c = clist_begin(m_att->att_list); c!=NULL;c=clist_next(c) ) { current = c; size = 0; item = (mailimap_msg_att_item*)current->data; if (item->att_type!=MAILIMAP_MSG_ATT_ITEM_STATIC) { flist = (mailimap_msg_att_dynamic*)item->att_data.att_dyn; if (!flist->att_list) { continue; } cf = flist->att_list->first; for (cf = clist_begin(flist->att_list); cf!=NULL; cf = clist_next(cf)) { cflag = (mailimap_flag_fetch*)cf->data; if (cflag->fl_type==MAILIMAP_FLAG_FETCH_OTHER && cflag->fl_flag!=0) { switch (cflag->fl_flag->fl_type) { case MAILIMAP_FLAG_ANSWERED: /* \Answered flag */ mFlags.setBit(FLAG_ANSWERED); break; case MAILIMAP_FLAG_FLAGGED: /* \Flagged flag */ mFlags.setBit(FLAG_FLAGGED); break; case MAILIMAP_FLAG_DELETED: /* \Deleted flag */ mFlags.setBit(FLAG_DELETED); break; case MAILIMAP_FLAG_SEEN: /* \Seen flag */ mFlags.setBit(FLAG_SEEN); break; case MAILIMAP_FLAG_DRAFT: /* \Draft flag */ mFlags.setBit(FLAG_DRAFT); break; case MAILIMAP_FLAG_KEYWORD: /* keyword flag */ break; case MAILIMAP_FLAG_EXTENSION: /* \extension flag */ break; default: break; } } else if (cflag->fl_type==MAILIMAP_FLAG_FETCH_RECENT) { mFlags.setBit(FLAG_RECENT); } } continue; } if (item->att_data.att_static->att_type==MAILIMAP_MSG_ATT_ENVELOPE) { mailimap_envelope * head = item->att_data.att_static->att_data.att_env; m->setDate(head->env_date); m->setSubject(convert_String((const char*)head->env_subject)); //m->setSubject(head->env_subject); if (head->env_from!=NULL) { addresslist = address_list_to_stringlist(head->env_from->frm_list); if (addresslist.count()) { m->setFrom(addresslist.first()); } } if (head->env_to!=NULL) { addresslist = address_list_to_stringlist(head->env_to->to_list); m->setTo(addresslist); } if (head->env_cc!=NULL) { addresslist = address_list_to_stringlist(head->env_cc->cc_list); m->setCC(addresslist); } if (head->env_bcc!=NULL) { addresslist = address_list_to_stringlist(head->env_bcc->bcc_list); m->setBcc(addresslist); } if (head->env_reply_to!=NULL) { addresslist = address_list_to_stringlist(head->env_reply_to->rt_list); if (addresslist.count()) { m->setReplyto(addresslist.first()); } } m->setMsgid(QString(head->env_message_id)); } else if (item->att_data.att_static->att_type==MAILIMAP_MSG_ATT_INTERNALDATE) { #if 0 mailimap_date_time*d = item->att_data.att_static->att_data.att_internal_date; QDateTime da(QDate(d->dt_year,d->dt_month,d->dt_day),QTime(d->dt_hour,d->dt_min,d->dt_sec)); qDebug("%i %i %i - %i %i %i",d->dt_year,d->dt_month,d->dt_day,d->dt_hour,d->dt_min,d->dt_sec); qDebug(da.toString()); #endif } else if (item->att_data.att_static->att_type==MAILIMAP_MSG_ATT_RFC822_SIZE) { size = item->att_data.att_static->att_data.att_rfc822_size; } } /* msg is already deleted */ if (mFlags.testBit(FLAG_DELETED) && m) { delete m; m = 0; } if (m) { m->setFlags(mFlags); m->setMsgsize(size); } return m; } RecBody IMAPwrapper::fetchBody(const RecMail&mail) { RecBody body; const char *mb; int err = MAILIMAP_NO_ERROR; clist *result; clistcell *current; mailimap_fetch_att *fetchAtt; mailimap_fetch_type *fetchType; mailimap_set *set; mailimap_body*body_desc; mb = mail.getMbox().latin1(); login(); if (!m_imap) { return body; } err = mailimap_select( m_imap, (char*)mb); if ( err != MAILIMAP_NO_ERROR ) { qDebug("error selecting mailbox: %s",m_imap->imap_response); return body; } result = clist_new(); /* the range has to start at 1!!! not with 0!!!! */ set = mailimap_set_new_interval( mail.getNumber(),mail.getNumber() ); fetchAtt = mailimap_fetch_att_new_bodystructure(); fetchType = mailimap_fetch_type_new_fetch_att(fetchAtt); err = mailimap_fetch( m_imap, set, fetchType, &result ); mailimap_set_free( set ); mailimap_fetch_type_free( fetchType ); if (err == MAILIMAP_NO_ERROR && (current=clist_begin(result)) ) { mailimap_msg_att * msg_att; msg_att = (mailimap_msg_att*)current->data; mailimap_msg_att_item*item = (mailimap_msg_att_item*)msg_att->att_list->first->data; body_desc = item->att_data.att_static->att_data.att_body; if (body_desc->bd_type==MAILIMAP_BODY_1PART) { searchBodyText(mail,body_desc->bd_data.bd_body_1part,body); } else if (body_desc->bd_type==MAILIMAP_BODY_MPART) { qDebug("Mulitpart mail"); searchBodyText(mail,body_desc->bd_data.bd_body_mpart,body); } } else { qDebug("error fetching body: %s",m_imap->imap_response); } mailimap_fetch_list_free(result); return body; } /* this routine is just called when the mail has only ONE part. for filling the parts of a multi-part-message there are other routines 'cause we can not simply fetch the whole body. */ void IMAPwrapper::searchBodyText(const RecMail&mail,mailimap_body_type_1part*mailDescription,RecBody&target_body) { if (!mailDescription) { return; } QString sub,body_text; RecPart singlePart; QValueList<int> path; fillSinglePart(singlePart,mailDescription); switch (mailDescription->bd_type) { case MAILIMAP_BODY_TYPE_1PART_MSG: path.append(1); body_text = fetchTextPart(mail,path,true,singlePart.Encoding()); target_body.setBodytext(body_text); target_body.setDescription(singlePart); break; case MAILIMAP_BODY_TYPE_1PART_TEXT: qDebug("Mediatype single: %s",mailDescription->bd_data.bd_type_text->bd_media_text); path.append(1); body_text = fetchTextPart(mail,path,true,singlePart.Encoding()); target_body.setBodytext(body_text); target_body.setDescription(singlePart); break; case MAILIMAP_BODY_TYPE_1PART_BASIC: qDebug("Single attachment"); target_body.setBodytext(""); target_body.addPart(singlePart); break; default: break; } return; } QStringList IMAPwrapper::address_list_to_stringlist(clist*list) { QStringList l; QString from; bool named_from; clistcell *current = NULL; mailimap_address * current_address=NULL; if (!list) { return l; } unsigned int count = 0; for (current=clist_begin(list);current!= NULL;current=clist_next(current)) { from = ""; named_from = false; current_address=(mailimap_address*)current->data; if (current_address->ad_personal_name){ from+=convert_String((const char*)current_address->ad_personal_name); //from+=QString(current_address->ad_personal_name); from+=" "; named_from = true; } if (named_from && (current_address->ad_mailbox_name || current_address->ad_host_name)) { from+="<"; } if (current_address->ad_mailbox_name) { from+=QString(current_address->ad_mailbox_name); from+="@"; } if (current_address->ad_host_name) { from+=QString(current_address->ad_host_name); } if (named_from && (current_address->ad_mailbox_name || current_address->ad_host_name)) { from+=">"; } l.append(QString(from)); if (++count > 99) { break; } } return l; } encodedString*IMAPwrapper::fetchRawPart(const RecMail&mail,const QValueList<int>&path,bool internal_call) { encodedString*res=new encodedString; const char*mb; int err; mailimap_fetch_type *fetchType; mailimap_set *set; clistcell*current,*cur; login(); if (!m_imap) { return res; } if (!internal_call) { mb = mail.getMbox().latin1(); err = mailimap_select( m_imap, (char*)mb); if ( err != MAILIMAP_NO_ERROR ) { qDebug("error selecting mailbox: %s",m_imap->imap_response); return res; } } set = mailimap_set_new_single(mail.getNumber()); clist*id_list=clist_new(); for (unsigned j=0; j < path.count();++j) { uint32_t * p_id = (uint32_t *)malloc(sizeof(*p_id)); *p_id = path[j]; clist_append(id_list,p_id); } mailimap_section_part * section_part = mailimap_section_part_new(id_list); mailimap_section_spec * section_spec = mailimap_section_spec_new(MAILIMAP_SECTION_SPEC_SECTION_PART, NULL, section_part, NULL); mailimap_section * section = mailimap_section_new(section_spec); mailimap_fetch_att * fetch_att = mailimap_fetch_att_new_body_section(section); fetchType = mailimap_fetch_type_new_fetch_att(fetch_att); clist*result = clist_new(); err = mailimap_fetch( m_imap, set, fetchType, &result ); mailimap_set_free( set ); mailimap_fetch_type_free( fetchType ); diff --git a/noncore/net/mail/libmailwrapper/imapwrapper.h b/noncore/net/mail/libmailwrapper/imapwrapper.h index aeebda8..f046297 100644 --- a/noncore/net/mail/libmailwrapper/imapwrapper.h +++ b/noncore/net/mail/libmailwrapper/imapwrapper.h @@ -1,62 +1,63 @@ #ifndef __IMAPWRAPPER #define __IMAPWRAPPER #include <qlist.h> #include "mailwrapper.h" #include "abstractmail.h" +#include <libetpan/clist.h> struct mailimap; struct mailimap_body_type_1part; struct mailimap_body_type_text; struct mailimap_body_type_basic; struct mailimap_body_type_msg; struct mailimap_body_type_mpart; struct mailimap_body_fields; struct mailimap_msg_att; class encodedString; class IMAPwrapper : public AbstractMail { Q_OBJECT public: IMAPwrapper( IMAPaccount *a ); virtual ~IMAPwrapper(); virtual QList<Folder>* listFolders(); virtual void listMessages(const QString & mailbox,QList<RecMail>&target ); virtual void deleteMail(const RecMail&mail); virtual void answeredMail(const RecMail&mail); virtual RecBody fetchBody(const RecMail&mail); virtual QString fetchTextPart(const RecMail&mail,const RecPart&part); virtual encodedString* fetchDecodedPart(const RecMail&mail,const RecPart&part); virtual encodedString* fetchRawPart(const RecMail&mail,const RecPart&part); static void imap_progress( size_t current, size_t maximum ); protected: RecMail*parse_list_result(mailimap_msg_att*); void login(); void logout(); virtual QString fetchTextPart(const RecMail&mail,const QValueList<int>&path,bool internal_call=false,const QString&enc=""); virtual encodedString*fetchRawPart(const RecMail&mail,const QValueList<int>&path,bool internal_call); void searchBodyText(const RecMail&mail,mailimap_body_type_1part*mailDescription,RecBody&target_body); void searchBodyText(const RecMail&mail,mailimap_body_type_mpart*mailDescription,RecBody&target_body,int current_recursion=0,QValueList<int>recList=QValueList<int>()); void fillSinglePart(RecPart&target_part,mailimap_body_type_1part*Description); void fillSingleTextPart(RecPart&target_part,mailimap_body_type_text*which); void fillSingleBasicPart(RecPart&target_part,mailimap_body_type_basic*which); void fillSingleMsgPart(RecPart&target_part,mailimap_body_type_msg*which); /* just helpers */ static void fillBodyFields(RecPart&target_part,mailimap_body_fields*which); static QStringList address_list_to_stringlist(clist*list); IMAPaccount *account; mailimap *m_imap; }; #endif diff --git a/noncore/net/mail/libmailwrapper/mailwrapper.cpp b/noncore/net/mail/libmailwrapper/mailwrapper.cpp index 75c06f9..c5d4265 100644 --- a/noncore/net/mail/libmailwrapper/mailwrapper.cpp +++ b/noncore/net/mail/libmailwrapper/mailwrapper.cpp @@ -1,723 +1,138 @@ #include <stdlib.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> #include <fcntl.h> #include <string.h> #include <qdir.h> #include "mailwrapper.h" #include "logindialog.h" //#include "mail.h" #include "defines.h" Attachment::Attachment( DocLnk lnk ) { doc = lnk; size = QFileInfo( doc.file() ).size(); } Folder::Folder(const QString&tmp_name, const QString&sep ) { name = tmp_name; nameDisplay = name; separator = sep; } const QString& Folder::Separator()const { return separator; } IMAPFolder::IMAPFolder(const QString&name,const QString&sep, bool select,const QString&prefix ) : Folder( name,sep ),m_MaySelect(select) { // Decode IMAP foldername nameDisplay = IMAPFolder::decodeFolderName( name ); qDebug( "folder " + name + " - displayed as " + nameDisplay ); if (prefix.length()>0) { if (nameDisplay.startsWith(prefix) && nameDisplay.length()>prefix.length()) { nameDisplay=nameDisplay.right(nameDisplay.length()-prefix.length()); } } } static unsigned char base64chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,"; /** * Decodes base64 encoded parts of the imapfolder name * Code taken from kde cvs: kdebase/kioslave/imap4/rfcdecoder.cc */ QString IMAPFolder::decodeFolderName( const QString &name ) { unsigned char c, i, bitcount; unsigned long ucs4, utf16, bitbuf; unsigned char base64[256], utf8[6]; unsigned long srcPtr = 0; QCString dst; QCString src = name.ascii(); /* initialize modified base64 decoding table */ memset(base64, UNDEFINED, sizeof(base64)); for (i = 0; i < sizeof(base64chars); ++i) { base64[(int)base64chars[i]] = i; } /* loop until end of string */ while (srcPtr < src.length ()) { c = src[srcPtr++]; /* deal with literal characters and &- */ if (c != '&' || src[srcPtr] == '-') { /* encode literally */ dst += c; /* skip over the '-' if this is an &- sequence */ if (c == '&') srcPtr++; } else { /* convert modified UTF-7 -> UTF-16 -> UCS-4 -> UTF-8 -> HEX */ bitbuf = 0; bitcount = 0; ucs4 = 0; while ((c = base64[(unsigned char) src[srcPtr]]) != UNDEFINED) { ++srcPtr; bitbuf = (bitbuf << 6) | c; bitcount += 6; /* enough bits for a UTF-16 character? */ if (bitcount >= 16) { bitcount -= 16; utf16 = (bitcount ? bitbuf >> bitcount : bitbuf) & 0xffff; /* convert UTF16 to UCS4 */ if (utf16 >= UTF16HIGHSTART && utf16 <= UTF16HIGHEND) { ucs4 = (utf16 - UTF16HIGHSTART) << UTF16SHIFT; continue; } else if (utf16 >= UTF16LOSTART && utf16 <= UTF16LOEND) { ucs4 += utf16 - UTF16LOSTART + UTF16BASE; } else { ucs4 = utf16; } /* convert UTF-16 range of UCS4 to UTF-8 */ if (ucs4 <= 0x7fUL) { utf8[0] = ucs4; i = 1; } else if (ucs4 <= 0x7ffUL) { utf8[0] = 0xc0 | (ucs4 >> 6); utf8[1] = 0x80 | (ucs4 & 0x3f); i = 2; } else if (ucs4 <= 0xffffUL) { utf8[0] = 0xe0 | (ucs4 >> 12); utf8[1] = 0x80 | ((ucs4 >> 6) & 0x3f); utf8[2] = 0x80 | (ucs4 & 0x3f); i = 3; } else { utf8[0] = 0xf0 | (ucs4 >> 18); utf8[1] = 0x80 | ((ucs4 >> 12) & 0x3f); utf8[2] = 0x80 | ((ucs4 >> 6) & 0x3f); utf8[3] = 0x80 | (ucs4 & 0x3f); i = 4; } /* copy it */ for (c = 0; c < i; ++c) { dst += utf8[c]; } } } /* skip over trailing '-' in modified UTF-7 encoding */ if (src[srcPtr] == '-') ++srcPtr; } } return QString::fromUtf8( dst.data() ); } -MailWrapper::MailWrapper( Settings *s ) - : QObject() -{ - settings = s; -} - -QString MailWrapper::mailsmtpError( int errnum ) -{ - switch ( errnum ) { - case MAILSMTP_NO_ERROR: - return tr( "No error" ); - case MAILSMTP_ERROR_UNEXPECTED_CODE: - return tr( "Unexpected error code" ); - case MAILSMTP_ERROR_SERVICE_NOT_AVAILABLE: - return tr( "Service not available" ); - case MAILSMTP_ERROR_STREAM: - return tr( "Stream error" ); - case MAILSMTP_ERROR_HOSTNAME: - return tr( "gethostname() failed" ); - case MAILSMTP_ERROR_NOT_IMPLEMENTED: - return tr( "Not implemented" ); - case MAILSMTP_ERROR_ACTION_NOT_TAKEN: - return tr( "Error, action not taken" ); - case MAILSMTP_ERROR_EXCEED_STORAGE_ALLOCATION: - return tr( "Data exceeds storage allocation" ); - case MAILSMTP_ERROR_IN_PROCESSING: - return tr( "Error in processing" ); - // case MAILSMTP_ERROR_INSUFFISANT_SYSTEM_STORAGE: - // return tr( "Insufficient system storage" ); - case MAILSMTP_ERROR_MAILBOX_UNAVAILABLE: - return tr( "Mailbox unavailable" ); - case MAILSMTP_ERROR_MAILBOX_NAME_NOT_ALLOWED: - return tr( "Mailbox name not allowed" ); - case MAILSMTP_ERROR_BAD_SEQUENCE_OF_COMMAND: - return tr( "Bad command sequence" ); - case MAILSMTP_ERROR_USER_NOT_LOCAL: - return tr( "User not local" ); - case MAILSMTP_ERROR_TRANSACTION_FAILED: - return tr( "Transaction failed" ); - case MAILSMTP_ERROR_MEMORY: - return tr( "Memory error" ); - case MAILSMTP_ERROR_CONNECTION_REFUSED: - return tr( "Connection refused" ); - default: - return tr( "Unknown error code" ); - } -} - -mailimf_mailbox *MailWrapper::newMailbox(const QString&name, const QString&mail ) -{ - return mailimf_mailbox_new( strdup( name.latin1() ), - strdup( mail.latin1() ) ); -} - -mailimf_address_list *MailWrapper::parseAddresses(const QString&addr ) -{ - mailimf_address_list *addresses; - - if ( addr.isEmpty() ) return NULL; - - addresses = mailimf_address_list_new_empty(); - - QStringList list = QStringList::split( ',', addr ); - QStringList::Iterator it; - for ( it = list.begin(); it != list.end(); it++ ) { - char *str = strdup( (*it).latin1() ); - int err = mailimf_address_list_add_parse( addresses, str ); - if ( err != MAILIMF_NO_ERROR ) { - qDebug( "Error parsing" ); - qDebug( *it ); - free( str ); - } else { - qDebug( "Parse success! :)" ); - } - } - - return addresses; -} - -mailimf_fields *MailWrapper::createImfFields( Mail *mail ) -{ - mailimf_fields *fields; - mailimf_field *xmailer; - mailimf_mailbox *sender, *fromBox; - mailimf_mailbox_list *from; - mailimf_address_list *to, *cc, *bcc, *reply; - char *subject = strdup( mail->getSubject().latin1() ); - int err; - - sender = newMailbox( mail->getName(), mail->getMail() ); - if ( sender == NULL ) goto err_free; - - fromBox = newMailbox( mail->getName(), mail->getMail() ); - if ( fromBox == NULL ) goto err_free_sender; - - from = mailimf_mailbox_list_new_empty(); - if ( from == NULL ) goto err_free_fromBox; - - err = mailimf_mailbox_list_add( from, fromBox ); - if ( err != MAILIMF_NO_ERROR ) goto err_free_from; - - to = parseAddresses( mail->getTo() ); - if ( to == NULL ) goto err_free_from; - - cc = parseAddresses( mail->getCC() ); - bcc = parseAddresses( mail->getBCC() ); - reply = parseAddresses( mail->getReply() ); - - fields = mailimf_fields_new_with_data( from, sender, reply, to, cc, bcc, - NULL, NULL, subject ); - if ( fields == NULL ) goto err_free_reply; - - xmailer = mailimf_field_new_custom( strdup( "User-Agent" ), - strdup( USER_AGENT ) ); - if ( xmailer == NULL ) goto err_free_fields; - - err = mailimf_fields_add( fields, xmailer ); - if ( err != MAILIMF_NO_ERROR ) goto err_free_xmailer; - - return fields; // Success :) - -err_free_xmailer: - mailimf_field_free( xmailer ); -err_free_fields: - mailimf_fields_free( fields ); -err_free_reply: - mailimf_address_list_free( reply ); - mailimf_address_list_free( bcc ); - mailimf_address_list_free( cc ); - mailimf_address_list_free( to ); -err_free_from: - mailimf_mailbox_list_free( from ); -err_free_fromBox: - mailimf_mailbox_free( fromBox ); -err_free_sender: - mailimf_mailbox_free( sender ); -err_free: - free( subject ); - qDebug( "createImfFields - error" ); - - return NULL; // Error :( -} - -mailmime *MailWrapper::buildTxtPart( QString str ) -{ - mailmime *txtPart; - mailmime_fields *fields; - mailmime_content *content; - mailmime_parameter *param; - char *txt = strdup( str.latin1() ); - int err; - - param = mailmime_parameter_new( strdup( "charset" ), - strdup( "iso-8859-1" ) ); - if ( param == NULL ) goto err_free; - - content = mailmime_content_new_with_str( "text/plain" ); - if ( content == NULL ) goto err_free_param; - - err = clist_append( content->ct_parameters, param ); - if ( err != MAILIMF_NO_ERROR ) goto err_free_content; - - fields = mailmime_fields_new_encoding( MAILMIME_MECHANISM_8BIT ); - if ( fields == NULL ) goto err_free_content; - - txtPart = mailmime_new_empty( content, fields ); - if ( txtPart == NULL ) goto err_free_fields; - - err = mailmime_set_body_text( txtPart, txt, strlen( txt ) ); - if ( err != MAILIMF_NO_ERROR ) goto err_free_txtPart; - - return txtPart; // Success :) - -err_free_txtPart: - mailmime_free( txtPart ); -err_free_fields: - mailmime_fields_free( fields ); -err_free_content: - mailmime_content_free( content ); -err_free_param: - mailmime_parameter_free( param ); -err_free: - free( txt ); - qDebug( "buildTxtPart - error" ); - - return NULL; // Error :( -} - -mailmime *MailWrapper::buildFilePart( QString filename, QString mimetype ) -{ - mailmime * filePart; - mailmime_fields * fields; - mailmime_content * content; - mailmime_parameter * param = NULL; - int err; - - int pos = filename.findRev( '/' ); - QString tmp = filename.right( filename.length() - ( pos + 1 ) ); - char *name = strdup( tmp.latin1() ); // just filename - char *file = strdup( filename.latin1() ); // full name with path - char *mime = strdup( mimetype.latin1() ); // mimetype -e.g. text/plain - - fields = mailmime_fields_new_filename( - MAILMIME_DISPOSITION_TYPE_ATTACHMENT, name, - MAILMIME_MECHANISM_BASE64 ); - if ( fields == NULL ) goto err_free; - - content = mailmime_content_new_with_str( mime ); - if ( content == NULL ) goto err_free_fields; - - if ( mimetype.compare( "text/plain" ) == 0 ) { - param = mailmime_parameter_new( strdup( "charset" ), - strdup( "iso-8859-1" ) ); - if ( param == NULL ) goto err_free_content; - - err = clist_append( content->ct_parameters, param ); - if ( err != MAILIMF_NO_ERROR ) goto err_free_param; - } - - filePart = mailmime_new_empty( content, fields ); - if ( filePart == NULL ) goto err_free_param; - - err = mailmime_set_body_file( filePart, file ); - if ( err != MAILIMF_NO_ERROR ) goto err_free_filePart; - - return filePart; // Success :) - -err_free_filePart: - mailmime_free( filePart ); -err_free_param: - if ( param != NULL ) mailmime_parameter_free( param ); -err_free_content: - mailmime_content_free( content ); -err_free_fields: - mailmime_fields_free( fields ); -err_free: - free( name ); - free( mime ); - free( file ); - qDebug( "buildFilePart - error" ); - - return NULL; // Error :( -} - -void MailWrapper::addFileParts( mailmime *message, QList<Attachment> files ) -{ - Attachment *it; - for ( it = files.first(); it; it = files.next() ) { - qDebug( "Adding file" ); - mailmime *filePart; - int err; - - filePart = buildFilePart( it->getFileName(), it->getMimeType() ); - if ( filePart == NULL ) goto err_free; - - err = mailmime_smart_add_part( message, filePart ); - if ( err != MAILIMF_NO_ERROR ) goto err_free_filePart; - - continue; // Success :) - - err_free_filePart: - mailmime_free( filePart ); - err_free: - qDebug( "addFileParts: error adding file:" ); - qDebug( it->getFileName() ); - } -} - -mailmime *MailWrapper::createMimeMail( Mail *mail ) -{ - mailmime *message, *txtPart; - mailimf_fields *fields; - int err; - - fields = createImfFields( mail ); - if ( fields == NULL ) goto err_free; - - message = mailmime_new_message_data( NULL ); - if ( message == NULL ) goto err_free_fields; - - mailmime_set_imf_fields( message, fields ); - - txtPart = buildTxtPart( mail->getMessage() ); - if ( txtPart == NULL ) goto err_free_message; - - err = mailmime_smart_add_part( message, txtPart ); - if ( err != MAILIMF_NO_ERROR ) goto err_free_txtPart; - - addFileParts( message, mail->getAttachments() ); - - return message; // Success :) - -err_free_txtPart: - mailmime_free( txtPart ); -err_free_message: - mailmime_free( message ); -err_free_fields: - mailimf_fields_free( fields ); -err_free: - qDebug( "createMimeMail: error" ); - - return NULL; // Error :( -} - -mailimf_field *MailWrapper::getField( mailimf_fields *fields, int type ) -{ - mailimf_field *field; - clistiter *it; - - it = clist_begin( fields->fld_list ); - while ( it ) { - field = (mailimf_field *) it->data; - if ( field->fld_type == type ) { - return field; - } - it = it->next; - } - - return NULL; -} - -static void addRcpts( clist *list, mailimf_address_list *addr_list ) -{ - clistiter *it, *it2; - - for ( it = clist_begin( addr_list->ad_list ); it; it = it->next ) { - mailimf_address *addr; - addr = (mailimf_address *) it->data; - - if ( addr->ad_type == MAILIMF_ADDRESS_MAILBOX ) { - esmtp_address_list_add( list, addr->ad_data.ad_mailbox->mb_addr_spec, 0, NULL ); - } else if ( addr->ad_type == MAILIMF_ADDRESS_GROUP ) { - clist *l = addr->ad_data.ad_group->grp_mb_list->mb_list; - for ( it2 = clist_begin( l ); it2; it2 = it2->next ) { - mailimf_mailbox *mbox; - mbox = (mailimf_mailbox *) it2->data; - esmtp_address_list_add( list, mbox->mb_addr_spec, 0, NULL ); - } - } - } -} - -clist *MailWrapper::createRcptList( mailimf_fields *fields ) -{ - clist *rcptList; - mailimf_field *field; - - rcptList = esmtp_address_list_new(); - - field = getField( fields, MAILIMF_FIELD_TO ); - if ( field && (field->fld_type == MAILIMF_FIELD_TO) - && field->fld_data.fld_to->to_addr_list ) { - addRcpts( rcptList, field->fld_data.fld_to->to_addr_list ); - } - - field = getField( fields, MAILIMF_FIELD_CC ); - if ( field && (field->fld_type == MAILIMF_FIELD_CC) - && field->fld_data.fld_cc->cc_addr_list ) { - addRcpts( rcptList, field->fld_data.fld_cc->cc_addr_list ); - } - - field = getField( fields, MAILIMF_FIELD_BCC ); - if ( field && (field->fld_type == MAILIMF_FIELD_BCC) - && field->fld_data.fld_bcc->bcc_addr_list ) { - addRcpts( rcptList, field->fld_data.fld_bcc->bcc_addr_list ); - } - - return rcptList; -} - -char *MailWrapper::getFrom( mailmime *mail ) -{ - char *from = NULL; - - mailimf_field *ffrom; - ffrom = getField( mail->mm_data.mm_message.mm_fields, MAILIMF_FIELD_FROM ); - if ( ffrom && (ffrom->fld_type == MAILIMF_FIELD_FROM) - && ffrom->fld_data.fld_from->frm_mb_list && ffrom->fld_data.fld_from->frm_mb_list->mb_list ) { - clist *cl = ffrom->fld_data.fld_from->frm_mb_list->mb_list; - clistiter *it; - for ( it = clist_begin( cl ); it; it = it->next ) { - mailimf_mailbox *mb = (mailimf_mailbox *) it->data; - from = strdup( mb->mb_addr_spec ); - } - } - - return from; -} - -SMTPaccount *MailWrapper::getAccount( QString from ) -{ - SMTPaccount *smtp; - - QList<Account> list = settings->getAccounts(); - Account *it; - for ( it = list.first(); it; it = list.next() ) { - if ( it->getType().compare( "SMTP" ) == 0 ) { - smtp = static_cast<SMTPaccount *>(it); - if ( smtp->getMail().compare( from ) == 0 ) { - qDebug( "SMTPaccount found for" ); - qDebug( from ); - return smtp; - } - } - } - - return NULL; -} - -QString MailWrapper::getTmpFile() { - int num = 0; - QString unique; - - QDir dir( "/tmp" ); - QStringList::Iterator it; - - QStringList list = dir.entryList( "opiemail-tmp-*" ); - do { - unique.setNum( num++ ); - } while ( list.contains( "opiemail-tmp-" + unique ) > 0 ); - - return "/tmp/opiemail-tmp-" + unique; -} - -void MailWrapper::writeToFile( QString file, mailmime *mail ) -{ - FILE *f; - int err, col = 0; - - f = fopen( file.latin1(), "w" ); - if ( f == NULL ) { - qDebug( "writeToFile: error opening file" ); - return; - } - - err = mailmime_write( f, &col, mail ); - if ( err != MAILIMF_NO_ERROR ) { - fclose( f ); - qDebug( "writeToFile: error writing mailmime" ); - return; - } - - fclose( f ); -} - -void MailWrapper::readFromFile( QString file, char **data, size_t *size ) -{ - char *buf; - struct stat st; - int fd, count = 0, total = 0; - - fd = open( file.latin1(), O_RDONLY, 0 ); - if ( fd == -1 ) return; - - if ( fstat( fd, &st ) != 0 ) goto err_close; - if ( !st.st_size ) goto err_close; - - buf = (char *) malloc( st.st_size ); - if ( !buf ) goto err_close; - - while ( ( total < st.st_size ) && ( count >= 0 ) ) { - count = read( fd, buf + total, st.st_size - total ); - total += count; - } - if ( count < 0 ) goto err_free; - - *data = buf; - *size = st.st_size; - - close( fd ); - - return; // Success :) - -err_free: - free( buf ); -err_close: - close( fd ); -} - -void progress( size_t current, size_t maximum ) -{ - qDebug( "Current: %i of %i", current, maximum ); -} - -void MailWrapper::smtpSend( mailmime *mail ) -{ - mailsmtp *session; - clist *rcpts; - char *from, *data, *server, *user = NULL, *pass = NULL; - size_t size; - int err; - bool ssl; - uint16_t port; - - - from = getFrom( mail ); - SMTPaccount *smtp = getAccount( from ); - if ( smtp == NULL ) { - free(from); - return; - } - server = strdup( smtp->getServer().latin1() ); - ssl = smtp->getSSL(); - port = smtp->getPort().toUInt(); - rcpts = createRcptList( mail->mm_data.mm_message.mm_fields ); - - QString file = getTmpFile(); - writeToFile( file, mail ); - readFromFile( file, &data, &size ); - QFile f( file ); - f.remove(); - - session = mailsmtp_new( 20, &progress ); - if ( session == NULL ) goto free_mem; - - qDebug( "Servername %s at port %i", server, port ); - if ( ssl ) { - qDebug( "SSL session" ); - err = mailsmtp_ssl_connect( session, server, port ); - } else { - qDebug( "No SSL session" ); - err = mailsmtp_socket_connect( session, server, port ); - } - if ( err != MAILSMTP_NO_ERROR ) goto free_mem_session; - - err = mailsmtp_init( session ); - if ( err != MAILSMTP_NO_ERROR ) goto free_con_session; - - qDebug( "INIT OK" ); - - if ( smtp->getLogin() ) { - if ( smtp->getUser().isEmpty() || smtp->getPassword().isEmpty() ) { - // get'em - LoginDialog login( smtp->getUser(), smtp->getPassword(), NULL, 0, true ); - login.show(); - if ( QDialog::Accepted == login.exec() ) { - // ok - user = strdup( login.getUser().latin1() ); - pass = strdup( login.getPassword().latin1() ); - } else { - goto free_con_session; - } - } else { - user = strdup( smtp->getUser().latin1() ); - pass = strdup( smtp->getPassword().latin1() ); - } - qDebug( "session->auth: %i", session->auth); - err = mailsmtp_auth( session, user, pass ); - if ( err == MAILSMTP_NO_ERROR ) qDebug("auth ok"); - qDebug( "Done auth!" ); - } - - err = mailsmtp_send( session, from, rcpts, data, size ); - if ( err != MAILSMTP_NO_ERROR ) goto free_con_session; - - qDebug( "Mail sent." ); - -free_con_session: - mailsmtp_quit( session ); -free_mem_session: - mailsmtp_free( session ); -free_mem: - smtp_address_list_free( rcpts ); - free( data ); - free( server ); - if ( smtp->getLogin() ) { - free( user ); - free( pass ); - } - free( from ); -} - -void MailWrapper::sendMail( Mail mail ) -{ - mailmime *mimeMail; - - mimeMail = createMimeMail( &mail ); - if ( mimeMail == NULL ) { - qDebug( "sendMail: error creating mime mail" ); - } else { - smtpSend( mimeMail ); - mailmime_free( mimeMail ); - } -} - Mail::Mail() :name(""), mail(""), to(""), cc(""), bcc(""), reply(""), subject(""), message("") { } diff --git a/noncore/net/mail/libmailwrapper/mailwrapper.h b/noncore/net/mail/libmailwrapper/mailwrapper.h index 02fe4b7..8fd886f 100644 --- a/noncore/net/mail/libmailwrapper/mailwrapper.h +++ b/noncore/net/mail/libmailwrapper/mailwrapper.h @@ -1,126 +1,91 @@ #ifndef MAILWRAPPER_H #define MAILWRAPPER_H #include <qpe/applnk.h> -#include <libetpan/mailmime.h> -#include <libetpan/mailimf.h> -#include <libetpan/mailsmtp.h> -#include <libetpan/mailstorage.h> -#include <libetpan/maildriver.h> #include <qbitarray.h> #include <qdatetime.h> #include "settings.h" class Attachment { public: Attachment( DocLnk lnk ); virtual ~Attachment(){} const QString getFileName()const{ return doc.file(); } const QString getName()const{ return doc.name(); } const QString getMimeType()const{ return doc.type(); } const QPixmap getPixmap()const{ return doc.pixmap(); } const int getSize()const { return size; } DocLnk getDocLnk() { return doc; } protected: DocLnk doc; int size; }; class Mail { public: Mail(); /* Possible that this destructor must not be declared virtual * 'cause it seems that it will never have some child classes. * in this case this object will not get a virtual table -> memory and * speed will be a little bit better? */ virtual ~Mail(){} void addAttachment( Attachment *att ) { attList.append( att ); } const QList<Attachment>& getAttachments()const { return attList; } void removeAttachment( Attachment *att ) { attList.remove( att ); } const QString&getName()const { return name; } void setName( QString s ) { name = s; } const QString&getMail()const{ return mail; } void setMail( const QString&s ) { mail = s; } const QString&getTo()const{ return to; } void setTo( const QString&s ) { to = s; } const QString&getCC()const{ return cc; } void setCC( const QString&s ) { cc = s; } const QString&getBCC()const { return bcc; } void setBCC( const QString&s ) { bcc = s; } const QString&getMessage()const { return message; } void setMessage( const QString&s ) { message = s; } const QString&getSubject()const { return subject; } void setSubject( const QString&s ) { subject = s; } const QString&getReply()const{ return reply; } void setReply( const QString&a ) { reply = a; } private: QList<Attachment> attList; QString name, mail, to, cc, bcc, reply, subject, message; }; class Folder : public QObject { Q_OBJECT public: Folder( const QString&init_name,const QString&sep ); const QString&getDisplayName()const { return nameDisplay; } const QString&getName()const { return name; } virtual bool may_select()const{return true;}; const QString&Separator()const; protected: QString nameDisplay, name, separator; }; class IMAPFolder : public Folder { public: IMAPFolder(const QString&name, const QString&sep, bool select=true,const QString&prefix="" ); virtual bool may_select()const{return m_MaySelect;} private: static QString decodeFolderName( const QString &name ); bool m_MaySelect; }; -class MailWrapper : public QObject -{ - Q_OBJECT - -public: - MailWrapper( Settings *s ); - void sendMail( Mail mail ); - -private: - mailimf_mailbox *newMailbox(const QString&name,const QString&mail ); - mailimf_address_list *parseAddresses(const QString&addr ); - mailimf_fields *createImfFields( Mail *mail ); - mailmime *buildTxtPart( QString str ); - mailmime *buildFilePart( QString filename, QString mimetype ); - void addFileParts( mailmime *message, QList<Attachment> files ); - mailmime *createMimeMail( Mail *mail ); - void smtpSend( mailmime *mail ); - mailimf_field *getField( mailimf_fields *fields, int type ); - clist *createRcptList( mailimf_fields *fields ); - char *getFrom( mailmime *mail ); - SMTPaccount *getAccount( QString from ); - void writeToFile( QString file, mailmime *mail ); - void readFromFile( QString file, char **data, size_t *size ); - static QString mailsmtpError( int err ); - static QString getTmpFile(); - - Settings *settings; - -}; - #endif diff --git a/noncore/net/mail/libmailwrapper/pop3wrapper.h b/noncore/net/mail/libmailwrapper/pop3wrapper.h index a31a145..75d70f8 100644 --- a/noncore/net/mail/libmailwrapper/pop3wrapper.h +++ b/noncore/net/mail/libmailwrapper/pop3wrapper.h @@ -1,63 +1,69 @@ #ifndef __POP3WRAPPER #define __POP3WRAPPER +#include <libetpan/clist.h> #include "mailwrapper.h" #include "abstractmail.h" #include <qmap.h> #include <qstring.h> class RecMail; class RecBody; class encodedString; struct mailpop3; struct mailmessage; struct mailmime; struct mailmime_mechanism; +struct mailimf_mailbox_list; +struct mailimf_mailbox; +struct mailimf_date_time; +struct mailimf_group; +struct mailimf_address_list; class POP3wrapper : public AbstractMail { Q_OBJECT public: POP3wrapper( POP3account *a ); virtual ~POP3wrapper(); /* mailbox will be ignored */ virtual void listMessages(const QString & mailbox, QList<RecMail> &target ); virtual QList<Folder>* listFolders(); virtual QString fetchTextPart(const RecMail&mail,const RecPart&part); virtual encodedString* fetchDecodedPart(const RecMail&mail,const RecPart&part); virtual encodedString* fetchRawPart(const RecMail&mail,const RecPart&part); virtual void deleteMail(const RecMail&mail); virtual void answeredMail(const RecMail&mail); RecBody fetchBody( const RecMail &mail ); static void pop3_progress( size_t current, size_t maximum ); protected: void login(); void logout(); RecMail *parseHeader( const char *header ); RecBody parseMail( char *message ); QString parseMailboxList( mailimf_mailbox_list *list ); QString parseMailbox( mailimf_mailbox *box ); QString parseGroup( mailimf_group *group ); QString parseAddressList( mailimf_address_list *list ); QString parseDateTime( mailimf_date_time *date ); void cleanUpCache(); void traverseBody(RecBody&target,mailmessage*message,mailmime*mime,unsigned int current_rek=0); static void fillSingleBody(RecPart&target,mailmessage*message,mailmime*mime); static void fillParameters(RecPart&target,clist*parameters); static QString POP3wrapper::getencoding(mailmime_mechanism*aEnc); POP3account *account; mailpop3 *m_pop3; QString msgTempName; unsigned int last_msg_id; QMap<QString,encodedString*> bodyCache; }; #endif diff --git a/noncore/net/mail/libmailwrapper/smtpwrapper.cpp b/noncore/net/mail/libmailwrapper/smtpwrapper.cpp new file mode 100644 index 0000000..162b1b9 --- a/dev/null +++ b/noncore/net/mail/libmailwrapper/smtpwrapper.cpp @@ -0,0 +1,604 @@ +#include <stdlib.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <qdir.h> + +#include <libetpan/mailmime.h> +#include <libetpan/mailimf.h> +#include <libetpan/mailsmtp.h> +#include <libetpan/mailstorage.h> +#include <libetpan/maildriver.h> + +#include "smtpwrapper.h" +#include "mailwrapper.h" +#include "logindialog.h" +#include "defines.h" + +SMTPwrapper::SMTPwrapper( Settings *s ) + : QObject() +{ + settings = s; +} + +QString SMTPwrapper::mailsmtpError( int errnum ) +{ + switch ( errnum ) { + case MAILSMTP_NO_ERROR: + return tr( "No error" ); + case MAILSMTP_ERROR_UNEXPECTED_CODE: + return tr( "Unexpected error code" ); + case MAILSMTP_ERROR_SERVICE_NOT_AVAILABLE: + return tr( "Service not available" ); + case MAILSMTP_ERROR_STREAM: + return tr( "Stream error" ); + case MAILSMTP_ERROR_HOSTNAME: + return tr( "gethostname() failed" ); + case MAILSMTP_ERROR_NOT_IMPLEMENTED: + return tr( "Not implemented" ); + case MAILSMTP_ERROR_ACTION_NOT_TAKEN: + return tr( "Error, action not taken" ); + case MAILSMTP_ERROR_EXCEED_STORAGE_ALLOCATION: + return tr( "Data exceeds storage allocation" ); + case MAILSMTP_ERROR_IN_PROCESSING: + return tr( "Error in processing" ); + // case MAILSMTP_ERROR_INSUFFISANT_SYSTEM_STORAGE: + // return tr( "Insufficient system storage" ); + case MAILSMTP_ERROR_MAILBOX_UNAVAILABLE: + return tr( "Mailbox unavailable" ); + case MAILSMTP_ERROR_MAILBOX_NAME_NOT_ALLOWED: + return tr( "Mailbox name not allowed" ); + case MAILSMTP_ERROR_BAD_SEQUENCE_OF_COMMAND: + return tr( "Bad command sequence" ); + case MAILSMTP_ERROR_USER_NOT_LOCAL: + return tr( "User not local" ); + case MAILSMTP_ERROR_TRANSACTION_FAILED: + return tr( "Transaction failed" ); + case MAILSMTP_ERROR_MEMORY: + return tr( "Memory error" ); + case MAILSMTP_ERROR_CONNECTION_REFUSED: + return tr( "Connection refused" ); + default: + return tr( "Unknown error code" ); + } +} + +mailimf_mailbox *SMTPwrapper::newMailbox(const QString&name, const QString&mail ) +{ + return mailimf_mailbox_new( strdup( name.latin1() ), + strdup( mail.latin1() ) ); +} + +mailimf_address_list *SMTPwrapper::parseAddresses(const QString&addr ) +{ + mailimf_address_list *addresses; + + if ( addr.isEmpty() ) return NULL; + + addresses = mailimf_address_list_new_empty(); + + QStringList list = QStringList::split( ',', addr ); + QStringList::Iterator it; + for ( it = list.begin(); it != list.end(); it++ ) { + char *str = strdup( (*it).latin1() ); + int err = mailimf_address_list_add_parse( addresses, str ); + if ( err != MAILIMF_NO_ERROR ) { + qDebug( "Error parsing" ); + qDebug( *it ); + free( str ); + } else { + qDebug( "Parse success! :)" ); + } + } + + return addresses; +} + +mailimf_fields *SMTPwrapper::createImfFields(const Mail&mail ) +{ + mailimf_fields *fields; + mailimf_field *xmailer; + mailimf_mailbox *sender, *fromBox; + mailimf_mailbox_list *from; + mailimf_address_list *to, *cc, *bcc, *reply; + char *subject = strdup( mail.getSubject().latin1() ); + int err; + + sender = newMailbox( mail.getName(), mail.getMail() ); + if ( sender == NULL ) goto err_free; + + fromBox = newMailbox( mail.getName(), mail.getMail() ); + if ( fromBox == NULL ) goto err_free_sender; + + from = mailimf_mailbox_list_new_empty(); + if ( from == NULL ) goto err_free_fromBox; + + err = mailimf_mailbox_list_add( from, fromBox ); + if ( err != MAILIMF_NO_ERROR ) goto err_free_from; + + to = parseAddresses( mail.getTo() ); + if ( to == NULL ) goto err_free_from; + + cc = parseAddresses( mail.getCC() ); + bcc = parseAddresses( mail.getBCC() ); + reply = parseAddresses( mail.getReply() ); + + fields = mailimf_fields_new_with_data( from, sender, reply, to, cc, bcc, + NULL, NULL, subject ); + if ( fields == NULL ) goto err_free_reply; + + xmailer = mailimf_field_new_custom( strdup( "User-Agent" ), + strdup( USER_AGENT ) ); + if ( xmailer == NULL ) goto err_free_fields; + + err = mailimf_fields_add( fields, xmailer ); + if ( err != MAILIMF_NO_ERROR ) goto err_free_xmailer; + + return fields; // Success :) + +err_free_xmailer: + mailimf_field_free( xmailer ); +err_free_fields: + mailimf_fields_free( fields ); +err_free_reply: + mailimf_address_list_free( reply ); + mailimf_address_list_free( bcc ); + mailimf_address_list_free( cc ); + mailimf_address_list_free( to ); +err_free_from: + mailimf_mailbox_list_free( from ); +err_free_fromBox: + mailimf_mailbox_free( fromBox ); +err_free_sender: + mailimf_mailbox_free( sender ); +err_free: + free( subject ); + qDebug( "createImfFields - error" ); + + return NULL; // Error :( +} + +mailmime *SMTPwrapper::buildTxtPart(const QString&str ) +{ + mailmime *txtPart; + mailmime_fields *fields; + mailmime_content *content; + mailmime_parameter *param; + char *txt = strdup( str.latin1() ); + int err; + + param = mailmime_parameter_new( strdup( "charset" ), + strdup( "iso-8859-1" ) ); + if ( param == NULL ) goto err_free; + + content = mailmime_content_new_with_str( "text/plain" ); + if ( content == NULL ) goto err_free_param; + + err = clist_append( content->ct_parameters, param ); + if ( err != MAILIMF_NO_ERROR ) goto err_free_content; + + fields = mailmime_fields_new_encoding( MAILMIME_MECHANISM_8BIT ); + if ( fields == NULL ) goto err_free_content; + + txtPart = mailmime_new_empty( content, fields ); + if ( txtPart == NULL ) goto err_free_fields; + + err = mailmime_set_body_text( txtPart, txt, strlen( txt ) ); + if ( err != MAILIMF_NO_ERROR ) goto err_free_txtPart; + + return txtPart; // Success :) + +err_free_txtPart: + mailmime_free( txtPart ); +err_free_fields: + mailmime_fields_free( fields ); +err_free_content: + mailmime_content_free( content ); +err_free_param: + mailmime_parameter_free( param ); +err_free: + free( txt ); + qDebug( "buildTxtPart - error" ); + + return NULL; // Error :( +} + +mailmime *SMTPwrapper::buildFilePart(const QString&filename,const QString&mimetype ) +{ + mailmime * filePart; + mailmime_fields * fields; + mailmime_content * content; + mailmime_parameter * param = NULL; + int err; + + int pos = filename.findRev( '/' ); + QString tmp = filename.right( filename.length() - ( pos + 1 ) ); + char *name = strdup( tmp.latin1() ); // just filename + char *file = strdup( filename.latin1() ); // full name with path + char *mime = strdup( mimetype.latin1() ); // mimetype -e.g. text/plain + + fields = mailmime_fields_new_filename( + MAILMIME_DISPOSITION_TYPE_ATTACHMENT, name, + MAILMIME_MECHANISM_BASE64 ); + if ( fields == NULL ) goto err_free; + + content = mailmime_content_new_with_str( mime ); + if ( content == NULL ) goto err_free_fields; + + if ( mimetype.compare( "text/plain" ) == 0 ) { + param = mailmime_parameter_new( strdup( "charset" ), + strdup( "iso-8859-1" ) ); + if ( param == NULL ) goto err_free_content; + + err = clist_append( content->ct_parameters, param ); + if ( err != MAILIMF_NO_ERROR ) goto err_free_param; + } + + filePart = mailmime_new_empty( content, fields ); + if ( filePart == NULL ) goto err_free_param; + + err = mailmime_set_body_file( filePart, file ); + if ( err != MAILIMF_NO_ERROR ) goto err_free_filePart; + + return filePart; // Success :) + +err_free_filePart: + mailmime_free( filePart ); +err_free_param: + if ( param != NULL ) mailmime_parameter_free( param ); +err_free_content: + mailmime_content_free( content ); +err_free_fields: + mailmime_fields_free( fields ); +err_free: + free( name ); + free( mime ); + free( file ); + qDebug( "buildFilePart - error" ); + + return NULL; // Error :( +} + +void SMTPwrapper::addFileParts( mailmime *message,const QList<Attachment>&files ) +{ + const Attachment *it; + /* work around for the brainfucked qlist which can not act with const values */ + for ( it = ((QList<Attachment>)files).first(); it; it = ((QList<Attachment>)files).next() ) { + qDebug( "Adding file" ); + mailmime *filePart; + int err; + + filePart = buildFilePart( it->getFileName(), it->getMimeType() ); + if ( filePart == NULL ) goto err_free; + + err = mailmime_smart_add_part( message, filePart ); + if ( err != MAILIMF_NO_ERROR ) goto err_free_filePart; + + continue; // Success :) + + err_free_filePart: + mailmime_free( filePart ); + err_free: + qDebug( "addFileParts: error adding file:" ); + qDebug( it->getFileName() ); + } +} + +mailmime *SMTPwrapper::createMimeMail(const Mail &mail ) +{ + mailmime *message, *txtPart; + mailimf_fields *fields; + int err; + + fields = createImfFields( mail ); + if ( fields == NULL ) goto err_free; + + message = mailmime_new_message_data( NULL ); + if ( message == NULL ) goto err_free_fields; + + mailmime_set_imf_fields( message, fields ); + + txtPart = buildTxtPart( mail.getMessage() ); + if ( txtPart == NULL ) goto err_free_message; + + err = mailmime_smart_add_part( message, txtPart ); + if ( err != MAILIMF_NO_ERROR ) goto err_free_txtPart; + + addFileParts( message, mail.getAttachments() ); + + return message; // Success :) + +err_free_txtPart: + mailmime_free( txtPart ); +err_free_message: + mailmime_free( message ); +err_free_fields: + mailimf_fields_free( fields ); +err_free: + qDebug( "createMimeMail: error" ); + + return NULL; // Error :( +} + +mailimf_field *SMTPwrapper::getField( mailimf_fields *fields, int type ) +{ + mailimf_field *field; + clistiter *it; + + it = clist_begin( fields->fld_list ); + while ( it ) { + field = (mailimf_field *) it->data; + if ( field->fld_type == type ) { + return field; + } + it = it->next; + } + + return NULL; +} + +void SMTPwrapper::addRcpts( clist *list, mailimf_address_list *addr_list ) +{ + clistiter *it, *it2; + + for ( it = clist_begin( addr_list->ad_list ); it; it = it->next ) { + mailimf_address *addr; + addr = (mailimf_address *) it->data; + + if ( addr->ad_type == MAILIMF_ADDRESS_MAILBOX ) { + esmtp_address_list_add( list, addr->ad_data.ad_mailbox->mb_addr_spec, 0, NULL ); + } else if ( addr->ad_type == MAILIMF_ADDRESS_GROUP ) { + clist *l = addr->ad_data.ad_group->grp_mb_list->mb_list; + for ( it2 = clist_begin( l ); it2; it2 = it2->next ) { + mailimf_mailbox *mbox; + mbox = (mailimf_mailbox *) it2->data; + esmtp_address_list_add( list, mbox->mb_addr_spec, 0, NULL ); + } + } + } +} + +clist *SMTPwrapper::createRcptList( mailimf_fields *fields ) +{ + clist *rcptList; + mailimf_field *field; + + rcptList = esmtp_address_list_new(); + + field = getField( fields, MAILIMF_FIELD_TO ); + if ( field && (field->fld_type == MAILIMF_FIELD_TO) + && field->fld_data.fld_to->to_addr_list ) { + addRcpts( rcptList, field->fld_data.fld_to->to_addr_list ); + } + + field = getField( fields, MAILIMF_FIELD_CC ); + if ( field && (field->fld_type == MAILIMF_FIELD_CC) + && field->fld_data.fld_cc->cc_addr_list ) { + addRcpts( rcptList, field->fld_data.fld_cc->cc_addr_list ); + } + + field = getField( fields, MAILIMF_FIELD_BCC ); + if ( field && (field->fld_type == MAILIMF_FIELD_BCC) + && field->fld_data.fld_bcc->bcc_addr_list ) { + addRcpts( rcptList, field->fld_data.fld_bcc->bcc_addr_list ); + } + + return rcptList; +} + +char *SMTPwrapper::getFrom( mailmime *mail ) +{ + char *from = NULL; + + mailimf_field *ffrom; + ffrom = getField( mail->mm_data.mm_message.mm_fields, MAILIMF_FIELD_FROM ); + if ( ffrom && (ffrom->fld_type == MAILIMF_FIELD_FROM) + && ffrom->fld_data.fld_from->frm_mb_list && ffrom->fld_data.fld_from->frm_mb_list->mb_list ) { + clist *cl = ffrom->fld_data.fld_from->frm_mb_list->mb_list; + clistiter *it; + for ( it = clist_begin( cl ); it; it = it->next ) { + mailimf_mailbox *mb = (mailimf_mailbox *) it->data; + from = strdup( mb->mb_addr_spec ); + } + } + + return from; +} + +SMTPaccount *SMTPwrapper::getAccount(const QString&from ) +{ + SMTPaccount *smtp; + + QList<Account> list = settings->getAccounts(); + Account *it; + for ( it = list.first(); it; it = list.next() ) { + if ( it->getType().compare( "SMTP" ) == 0 ) { + smtp = static_cast<SMTPaccount *>(it); + if ( smtp->getMail().compare( from ) == 0 ) { + qDebug( "SMTPaccount found for" ); + qDebug( from ); + return smtp; + } + } + } + + return NULL; +} + +QString SMTPwrapper::getTmpFile() { + int num = 0; + QString unique; + + QDir dir( "/tmp" ); + QStringList::Iterator it; + + QStringList list = dir.entryList( "opiemail-tmp-*" ); + do { + unique.setNum( num++ ); + } while ( list.contains( "opiemail-tmp-" + unique ) > 0 ); + + return "/tmp/opiemail-tmp-" + unique; +} + +void SMTPwrapper::writeToFile(const QString&file, mailmime *mail ) +{ + FILE *f; + int err, col = 0; + + f = fopen( file.latin1(), "w" ); + if ( f == NULL ) { + qDebug( "writeToFile: error opening file" ); + return; + } + + err = mailmime_write( f, &col, mail ); + if ( err != MAILIMF_NO_ERROR ) { + fclose( f ); + qDebug( "writeToFile: error writing mailmime" ); + return; + } + + fclose( f ); +} + +void SMTPwrapper::readFromFile(const QString&file, char **data, size_t *size ) +{ + char *buf; + struct stat st; + int fd, count = 0, total = 0; + + fd = open( file.latin1(), O_RDONLY, 0 ); + if ( fd == -1 ) return; + + if ( fstat( fd, &st ) != 0 ) goto err_close; + if ( !st.st_size ) goto err_close; + + buf = (char *) malloc( st.st_size ); + if ( !buf ) goto err_close; + + while ( ( total < st.st_size ) && ( count >= 0 ) ) { + count = read( fd, buf + total, st.st_size - total ); + total += count; + } + if ( count < 0 ) goto err_free; + + *data = buf; + *size = st.st_size; + + close( fd ); + + return; // Success :) + +err_free: + free( buf ); +err_close: + close( fd ); +} + +void SMTPwrapper::progress( size_t current, size_t maximum ) +{ + qDebug( "Current: %i of %i", current, maximum ); +} + +void SMTPwrapper::smtpSend( mailmime *mail ) +{ + mailsmtp *session; + clist *rcpts; + char *from, *data, *server, *user = NULL, *pass = NULL; + size_t size; + int err; + bool ssl; + uint16_t port; + + + from = getFrom( mail ); + SMTPaccount *smtp = getAccount( from ); + if ( smtp == NULL ) { + free(from); + return; + } + server = strdup( smtp->getServer().latin1() ); + ssl = smtp->getSSL(); + port = smtp->getPort().toUInt(); + rcpts = createRcptList( mail->mm_data.mm_message.mm_fields ); + + QString file = getTmpFile(); + writeToFile( file, mail ); + readFromFile( file, &data, &size ); + QFile f( file ); + f.remove(); + + session = mailsmtp_new( 20, &progress ); + if ( session == NULL ) goto free_mem; + + qDebug( "Servername %s at port %i", server, port ); + if ( ssl ) { + qDebug( "SSL session" ); + err = mailsmtp_ssl_connect( session, server, port ); + } else { + qDebug( "No SSL session" ); + err = mailsmtp_socket_connect( session, server, port ); + } + if ( err != MAILSMTP_NO_ERROR ) goto free_mem_session; + + err = mailsmtp_init( session ); + if ( err != MAILSMTP_NO_ERROR ) goto free_con_session; + + qDebug( "INIT OK" ); + + if ( smtp->getLogin() ) { + if ( smtp->getUser().isEmpty() || smtp->getPassword().isEmpty() ) { + // get'em + LoginDialog login( smtp->getUser(), smtp->getPassword(), NULL, 0, true ); + login.show(); + if ( QDialog::Accepted == login.exec() ) { + // ok + user = strdup( login.getUser().latin1() ); + pass = strdup( login.getPassword().latin1() ); + } else { + goto free_con_session; + } + } else { + user = strdup( smtp->getUser().latin1() ); + pass = strdup( smtp->getPassword().latin1() ); + } + qDebug( "session->auth: %i", session->auth); + err = mailsmtp_auth( session, user, pass ); + if ( err == MAILSMTP_NO_ERROR ) qDebug("auth ok"); + qDebug( "Done auth!" ); + } + + err = mailsmtp_send( session, from, rcpts, data, size ); + if ( err != MAILSMTP_NO_ERROR ) goto free_con_session; + + qDebug( "Mail sent." ); + +free_con_session: + mailsmtp_quit( session ); +free_mem_session: + mailsmtp_free( session ); +free_mem: + smtp_address_list_free( rcpts ); + free( data ); + free( server ); + if ( smtp->getLogin() ) { + free( user ); + free( pass ); + } + free( from ); +} + +void SMTPwrapper::sendMail(const Mail&mail ) +{ + mailmime *mimeMail; + + mimeMail = createMimeMail(mail ); + if ( mimeMail == NULL ) { + qDebug( "sendMail: error creating mime mail" ); + } else { + smtpSend( mimeMail ); + mailmime_free( mimeMail ); + } +} diff --git a/noncore/net/mail/libmailwrapper/smtpwrapper.h b/noncore/net/mail/libmailwrapper/smtpwrapper.h new file mode 100644 index 0000000..8fdb07d --- a/dev/null +++ b/noncore/net/mail/libmailwrapper/smtpwrapper.h @@ -0,0 +1,53 @@ +#ifndef SMTPwrapper_H +#define SMTPwrapper_H + +#include <qpe/applnk.h> + +#include <qbitarray.h> +#include <qdatetime.h> +#include <libetpan/clist.h> + +#include "settings.h" + +class Mail; +class Attachment; +struct mailimf_fields; +struct mailimf_field; +struct mailimf_mailbox; +struct mailmime; +struct mailimf_address_list; + +class SMTPwrapper : public QObject +{ + Q_OBJECT + +public: + SMTPwrapper( Settings *s ); + virtual ~SMTPwrapper(){} + void sendMail(const Mail& mail ); + +protected: + mailimf_mailbox *newMailbox(const QString&name,const QString&mail ); + mailimf_fields *createImfFields(const Mail &mail ); + mailmime *createMimeMail(const Mail&mail ); + + mailimf_address_list *parseAddresses(const QString&addr ); + void addFileParts( mailmime *message,const QList<Attachment>&files ); + mailmime *buildTxtPart(const QString&str ); + mailmime *buildFilePart(const QString&filename,const QString&mimetype ); + void smtpSend( mailmime *mail ); + mailimf_field *getField( mailimf_fields *fields, int type ); + clist *createRcptList( mailimf_fields *fields ); + char *getFrom( mailmime *mail ); + SMTPaccount *getAccount(const QString&from ); + void writeToFile(const QString&file, mailmime *mail ); + void readFromFile(const QString&file, char **data, size_t *size ); + + static QString mailsmtpError( int err ); + static QString getTmpFile(); + static void progress( size_t current, size_t maximum ); + static void addRcpts( clist *list, mailimf_address_list *addr_list ); + Settings *settings; +}; + +#endif diff --git a/noncore/net/mail/mail.pro b/noncore/net/mail/mail.pro index 49be889..2542344 100644 --- a/noncore/net/mail/mail.pro +++ b/noncore/net/mail/mail.pro @@ -1,64 +1,66 @@ CONFIG += qt warn_on debug quick-app HEADERS = defines.h \ logindialog.h \ settings.h \ editaccounts.h \ mailwrapper.h \ composemail.h \ accountview.h \ mainwindow.h \ viewmail.h \ viewmailbase.h \ opiemail.h \ imapwrapper.h \ mailtypes.h \ mailistviewitem.h \ pop3wrapper.h \ abstractmail.h \ settingsdialog.h \ - statuswidget.h + statuswidget.h \ + smtpwrapper.h SOURCES = main.cpp \ opiemail.cpp \ mainwindow.cpp \ accountview.cpp \ composemail.cpp \ mailwrapper.cpp \ imapwrapper.cpp \ addresspicker.cpp \ editaccounts.cpp \ logindialog.cpp \ viewmail.cpp \ viewmailbase.cpp \ settings.cpp \ mailtypes.cpp \ pop3wrapper.cpp \ abstractmail.cpp \ settingsdialog.cpp \ - statuswidget.cpp + statuswidget.cpp \ + smtpwrapper.cpp INTERFACES = editaccountsui.ui \ selectmailtypeui.ui \ imapconfigui.ui \ pop3configui.ui \ nntpconfigui.ui \ smtpconfigui.ui \ addresspickerui.ui \ logindialogui.ui \ composemailui.ui \ settingsdialogui.ui \ statuswidgetui.ui INCLUDEPATH += $(OPIEDIR)/include CONFTEST = $$system( echo $CONFIG_TARGET_MACOSX ) contains( CONFTEST, y ){ LIBS += -lqpe -letpan -lssl -lcrypto -lopie -liconv }else{ LIBS += -lqpe -letpan -lssl -lcrypto -lopie } TARGET = opiemail include ( $(OPIEDIR)/include.pro ) diff --git a/noncore/net/mail/mailwrapper.cpp b/noncore/net/mail/mailwrapper.cpp index 75c06f9..c5d4265 100644 --- a/noncore/net/mail/mailwrapper.cpp +++ b/noncore/net/mail/mailwrapper.cpp @@ -1,723 +1,138 @@ #include <stdlib.h> #include <sys/stat.h> #include <sys/types.h> #include <unistd.h> #include <fcntl.h> #include <string.h> #include <qdir.h> #include "mailwrapper.h" #include "logindialog.h" //#include "mail.h" #include "defines.h" Attachment::Attachment( DocLnk lnk ) { doc = lnk; size = QFileInfo( doc.file() ).size(); } Folder::Folder(const QString&tmp_name, const QString&sep ) { name = tmp_name; nameDisplay = name; separator = sep; } const QString& Folder::Separator()const { return separator; } IMAPFolder::IMAPFolder(const QString&name,const QString&sep, bool select,const QString&prefix ) : Folder( name,sep ),m_MaySelect(select) { // Decode IMAP foldername nameDisplay = IMAPFolder::decodeFolderName( name ); qDebug( "folder " + name + " - displayed as " + nameDisplay ); if (prefix.length()>0) { if (nameDisplay.startsWith(prefix) && nameDisplay.length()>prefix.length()) { nameDisplay=nameDisplay.right(nameDisplay.length()-prefix.length()); } } } static unsigned char base64chars[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,"; /** * Decodes base64 encoded parts of the imapfolder name * Code taken from kde cvs: kdebase/kioslave/imap4/rfcdecoder.cc */ QString IMAPFolder::decodeFolderName( const QString &name ) { unsigned char c, i, bitcount; unsigned long ucs4, utf16, bitbuf; unsigned char base64[256], utf8[6]; unsigned long srcPtr = 0; QCString dst; QCString src = name.ascii(); /* initialize modified base64 decoding table */ memset(base64, UNDEFINED, sizeof(base64)); for (i = 0; i < sizeof(base64chars); ++i) { base64[(int)base64chars[i]] = i; } /* loop until end of string */ while (srcPtr < src.length ()) { c = src[srcPtr++]; /* deal with literal characters and &- */ if (c != '&' || src[srcPtr] == '-') { /* encode literally */ dst += c; /* skip over the '-' if this is an &- sequence */ if (c == '&') srcPtr++; } else { /* convert modified UTF-7 -> UTF-16 -> UCS-4 -> UTF-8 -> HEX */ bitbuf = 0; bitcount = 0; ucs4 = 0; while ((c = base64[(unsigned char) src[srcPtr]]) != UNDEFINED) { ++srcPtr; bitbuf = (bitbuf << 6) | c; bitcount += 6; /* enough bits for a UTF-16 character? */ if (bitcount >= 16) { bitcount -= 16; utf16 = (bitcount ? bitbuf >> bitcount : bitbuf) & 0xffff; /* convert UTF16 to UCS4 */ if (utf16 >= UTF16HIGHSTART && utf16 <= UTF16HIGHEND) { ucs4 = (utf16 - UTF16HIGHSTART) << UTF16SHIFT; continue; } else if (utf16 >= UTF16LOSTART && utf16 <= UTF16LOEND) { ucs4 += utf16 - UTF16LOSTART + UTF16BASE; } else { ucs4 = utf16; } /* convert UTF-16 range of UCS4 to UTF-8 */ if (ucs4 <= 0x7fUL) { utf8[0] = ucs4; i = 1; } else if (ucs4 <= 0x7ffUL) { utf8[0] = 0xc0 | (ucs4 >> 6); utf8[1] = 0x80 | (ucs4 & 0x3f); i = 2; } else if (ucs4 <= 0xffffUL) { utf8[0] = 0xe0 | (ucs4 >> 12); utf8[1] = 0x80 | ((ucs4 >> 6) & 0x3f); utf8[2] = 0x80 | (ucs4 & 0x3f); i = 3; } else { utf8[0] = 0xf0 | (ucs4 >> 18); utf8[1] = 0x80 | ((ucs4 >> 12) & 0x3f); utf8[2] = 0x80 | ((ucs4 >> 6) & 0x3f); utf8[3] = 0x80 | (ucs4 & 0x3f); i = 4; } /* copy it */ for (c = 0; c < i; ++c) { dst += utf8[c]; } } } /* skip over trailing '-' in modified UTF-7 encoding */ if (src[srcPtr] == '-') ++srcPtr; } } return QString::fromUtf8( dst.data() ); } -MailWrapper::MailWrapper( Settings *s ) - : QObject() -{ - settings = s; -} - -QString MailWrapper::mailsmtpError( int errnum ) -{ - switch ( errnum ) { - case MAILSMTP_NO_ERROR: - return tr( "No error" ); - case MAILSMTP_ERROR_UNEXPECTED_CODE: - return tr( "Unexpected error code" ); - case MAILSMTP_ERROR_SERVICE_NOT_AVAILABLE: - return tr( "Service not available" ); - case MAILSMTP_ERROR_STREAM: - return tr( "Stream error" ); - case MAILSMTP_ERROR_HOSTNAME: - return tr( "gethostname() failed" ); - case MAILSMTP_ERROR_NOT_IMPLEMENTED: - return tr( "Not implemented" ); - case MAILSMTP_ERROR_ACTION_NOT_TAKEN: - return tr( "Error, action not taken" ); - case MAILSMTP_ERROR_EXCEED_STORAGE_ALLOCATION: - return tr( "Data exceeds storage allocation" ); - case MAILSMTP_ERROR_IN_PROCESSING: - return tr( "Error in processing" ); - // case MAILSMTP_ERROR_INSUFFISANT_SYSTEM_STORAGE: - // return tr( "Insufficient system storage" ); - case MAILSMTP_ERROR_MAILBOX_UNAVAILABLE: - return tr( "Mailbox unavailable" ); - case MAILSMTP_ERROR_MAILBOX_NAME_NOT_ALLOWED: - return tr( "Mailbox name not allowed" ); - case MAILSMTP_ERROR_BAD_SEQUENCE_OF_COMMAND: - return tr( "Bad command sequence" ); - case MAILSMTP_ERROR_USER_NOT_LOCAL: - return tr( "User not local" ); - case MAILSMTP_ERROR_TRANSACTION_FAILED: - return tr( "Transaction failed" ); - case MAILSMTP_ERROR_MEMORY: - return tr( "Memory error" ); - case MAILSMTP_ERROR_CONNECTION_REFUSED: - return tr( "Connection refused" ); - default: - return tr( "Unknown error code" ); - } -} - -mailimf_mailbox *MailWrapper::newMailbox(const QString&name, const QString&mail ) -{ - return mailimf_mailbox_new( strdup( name.latin1() ), - strdup( mail.latin1() ) ); -} - -mailimf_address_list *MailWrapper::parseAddresses(const QString&addr ) -{ - mailimf_address_list *addresses; - - if ( addr.isEmpty() ) return NULL; - - addresses = mailimf_address_list_new_empty(); - - QStringList list = QStringList::split( ',', addr ); - QStringList::Iterator it; - for ( it = list.begin(); it != list.end(); it++ ) { - char *str = strdup( (*it).latin1() ); - int err = mailimf_address_list_add_parse( addresses, str ); - if ( err != MAILIMF_NO_ERROR ) { - qDebug( "Error parsing" ); - qDebug( *it ); - free( str ); - } else { - qDebug( "Parse success! :)" ); - } - } - - return addresses; -} - -mailimf_fields *MailWrapper::createImfFields( Mail *mail ) -{ - mailimf_fields *fields; - mailimf_field *xmailer; - mailimf_mailbox *sender, *fromBox; - mailimf_mailbox_list *from; - mailimf_address_list *to, *cc, *bcc, *reply; - char *subject = strdup( mail->getSubject().latin1() ); - int err; - - sender = newMailbox( mail->getName(), mail->getMail() ); - if ( sender == NULL ) goto err_free; - - fromBox = newMailbox( mail->getName(), mail->getMail() ); - if ( fromBox == NULL ) goto err_free_sender; - - from = mailimf_mailbox_list_new_empty(); - if ( from == NULL ) goto err_free_fromBox; - - err = mailimf_mailbox_list_add( from, fromBox ); - if ( err != MAILIMF_NO_ERROR ) goto err_free_from; - - to = parseAddresses( mail->getTo() ); - if ( to == NULL ) goto err_free_from; - - cc = parseAddresses( mail->getCC() ); - bcc = parseAddresses( mail->getBCC() ); - reply = parseAddresses( mail->getReply() ); - - fields = mailimf_fields_new_with_data( from, sender, reply, to, cc, bcc, - NULL, NULL, subject ); - if ( fields == NULL ) goto err_free_reply; - - xmailer = mailimf_field_new_custom( strdup( "User-Agent" ), - strdup( USER_AGENT ) ); - if ( xmailer == NULL ) goto err_free_fields; - - err = mailimf_fields_add( fields, xmailer ); - if ( err != MAILIMF_NO_ERROR ) goto err_free_xmailer; - - return fields; // Success :) - -err_free_xmailer: - mailimf_field_free( xmailer ); -err_free_fields: - mailimf_fields_free( fields ); -err_free_reply: - mailimf_address_list_free( reply ); - mailimf_address_list_free( bcc ); - mailimf_address_list_free( cc ); - mailimf_address_list_free( to ); -err_free_from: - mailimf_mailbox_list_free( from ); -err_free_fromBox: - mailimf_mailbox_free( fromBox ); -err_free_sender: - mailimf_mailbox_free( sender ); -err_free: - free( subject ); - qDebug( "createImfFields - error" ); - - return NULL; // Error :( -} - -mailmime *MailWrapper::buildTxtPart( QString str ) -{ - mailmime *txtPart; - mailmime_fields *fields; - mailmime_content *content; - mailmime_parameter *param; - char *txt = strdup( str.latin1() ); - int err; - - param = mailmime_parameter_new( strdup( "charset" ), - strdup( "iso-8859-1" ) ); - if ( param == NULL ) goto err_free; - - content = mailmime_content_new_with_str( "text/plain" ); - if ( content == NULL ) goto err_free_param; - - err = clist_append( content->ct_parameters, param ); - if ( err != MAILIMF_NO_ERROR ) goto err_free_content; - - fields = mailmime_fields_new_encoding( MAILMIME_MECHANISM_8BIT ); - if ( fields == NULL ) goto err_free_content; - - txtPart = mailmime_new_empty( content, fields ); - if ( txtPart == NULL ) goto err_free_fields; - - err = mailmime_set_body_text( txtPart, txt, strlen( txt ) ); - if ( err != MAILIMF_NO_ERROR ) goto err_free_txtPart; - - return txtPart; // Success :) - -err_free_txtPart: - mailmime_free( txtPart ); -err_free_fields: - mailmime_fields_free( fields ); -err_free_content: - mailmime_content_free( content ); -err_free_param: - mailmime_parameter_free( param ); -err_free: - free( txt ); - qDebug( "buildTxtPart - error" ); - - return NULL; // Error :( -} - -mailmime *MailWrapper::buildFilePart( QString filename, QString mimetype ) -{ - mailmime * filePart; - mailmime_fields * fields; - mailmime_content * content; - mailmime_parameter * param = NULL; - int err; - - int pos = filename.findRev( '/' ); - QString tmp = filename.right( filename.length() - ( pos + 1 ) ); - char *name = strdup( tmp.latin1() ); // just filename - char *file = strdup( filename.latin1() ); // full name with path - char *mime = strdup( mimetype.latin1() ); // mimetype -e.g. text/plain - - fields = mailmime_fields_new_filename( - MAILMIME_DISPOSITION_TYPE_ATTACHMENT, name, - MAILMIME_MECHANISM_BASE64 ); - if ( fields == NULL ) goto err_free; - - content = mailmime_content_new_with_str( mime ); - if ( content == NULL ) goto err_free_fields; - - if ( mimetype.compare( "text/plain" ) == 0 ) { - param = mailmime_parameter_new( strdup( "charset" ), - strdup( "iso-8859-1" ) ); - if ( param == NULL ) goto err_free_content; - - err = clist_append( content->ct_parameters, param ); - if ( err != MAILIMF_NO_ERROR ) goto err_free_param; - } - - filePart = mailmime_new_empty( content, fields ); - if ( filePart == NULL ) goto err_free_param; - - err = mailmime_set_body_file( filePart, file ); - if ( err != MAILIMF_NO_ERROR ) goto err_free_filePart; - - return filePart; // Success :) - -err_free_filePart: - mailmime_free( filePart ); -err_free_param: - if ( param != NULL ) mailmime_parameter_free( param ); -err_free_content: - mailmime_content_free( content ); -err_free_fields: - mailmime_fields_free( fields ); -err_free: - free( name ); - free( mime ); - free( file ); - qDebug( "buildFilePart - error" ); - - return NULL; // Error :( -} - -void MailWrapper::addFileParts( mailmime *message, QList<Attachment> files ) -{ - Attachment *it; - for ( it = files.first(); it; it = files.next() ) { - qDebug( "Adding file" ); - mailmime *filePart; - int err; - - filePart = buildFilePart( it->getFileName(), it->getMimeType() ); - if ( filePart == NULL ) goto err_free; - - err = mailmime_smart_add_part( message, filePart ); - if ( err != MAILIMF_NO_ERROR ) goto err_free_filePart; - - continue; // Success :) - - err_free_filePart: - mailmime_free( filePart ); - err_free: - qDebug( "addFileParts: error adding file:" ); - qDebug( it->getFileName() ); - } -} - -mailmime *MailWrapper::createMimeMail( Mail *mail ) -{ - mailmime *message, *txtPart; - mailimf_fields *fields; - int err; - - fields = createImfFields( mail ); - if ( fields == NULL ) goto err_free; - - message = mailmime_new_message_data( NULL ); - if ( message == NULL ) goto err_free_fields; - - mailmime_set_imf_fields( message, fields ); - - txtPart = buildTxtPart( mail->getMessage() ); - if ( txtPart == NULL ) goto err_free_message; - - err = mailmime_smart_add_part( message, txtPart ); - if ( err != MAILIMF_NO_ERROR ) goto err_free_txtPart; - - addFileParts( message, mail->getAttachments() ); - - return message; // Success :) - -err_free_txtPart: - mailmime_free( txtPart ); -err_free_message: - mailmime_free( message ); -err_free_fields: - mailimf_fields_free( fields ); -err_free: - qDebug( "createMimeMail: error" ); - - return NULL; // Error :( -} - -mailimf_field *MailWrapper::getField( mailimf_fields *fields, int type ) -{ - mailimf_field *field; - clistiter *it; - - it = clist_begin( fields->fld_list ); - while ( it ) { - field = (mailimf_field *) it->data; - if ( field->fld_type == type ) { - return field; - } - it = it->next; - } - - return NULL; -} - -static void addRcpts( clist *list, mailimf_address_list *addr_list ) -{ - clistiter *it, *it2; - - for ( it = clist_begin( addr_list->ad_list ); it; it = it->next ) { - mailimf_address *addr; - addr = (mailimf_address *) it->data; - - if ( addr->ad_type == MAILIMF_ADDRESS_MAILBOX ) { - esmtp_address_list_add( list, addr->ad_data.ad_mailbox->mb_addr_spec, 0, NULL ); - } else if ( addr->ad_type == MAILIMF_ADDRESS_GROUP ) { - clist *l = addr->ad_data.ad_group->grp_mb_list->mb_list; - for ( it2 = clist_begin( l ); it2; it2 = it2->next ) { - mailimf_mailbox *mbox; - mbox = (mailimf_mailbox *) it2->data; - esmtp_address_list_add( list, mbox->mb_addr_spec, 0, NULL ); - } - } - } -} - -clist *MailWrapper::createRcptList( mailimf_fields *fields ) -{ - clist *rcptList; - mailimf_field *field; - - rcptList = esmtp_address_list_new(); - - field = getField( fields, MAILIMF_FIELD_TO ); - if ( field && (field->fld_type == MAILIMF_FIELD_TO) - && field->fld_data.fld_to->to_addr_list ) { - addRcpts( rcptList, field->fld_data.fld_to->to_addr_list ); - } - - field = getField( fields, MAILIMF_FIELD_CC ); - if ( field && (field->fld_type == MAILIMF_FIELD_CC) - && field->fld_data.fld_cc->cc_addr_list ) { - addRcpts( rcptList, field->fld_data.fld_cc->cc_addr_list ); - } - - field = getField( fields, MAILIMF_FIELD_BCC ); - if ( field && (field->fld_type == MAILIMF_FIELD_BCC) - && field->fld_data.fld_bcc->bcc_addr_list ) { - addRcpts( rcptList, field->fld_data.fld_bcc->bcc_addr_list ); - } - - return rcptList; -} - -char *MailWrapper::getFrom( mailmime *mail ) -{ - char *from = NULL; - - mailimf_field *ffrom; - ffrom = getField( mail->mm_data.mm_message.mm_fields, MAILIMF_FIELD_FROM ); - if ( ffrom && (ffrom->fld_type == MAILIMF_FIELD_FROM) - && ffrom->fld_data.fld_from->frm_mb_list && ffrom->fld_data.fld_from->frm_mb_list->mb_list ) { - clist *cl = ffrom->fld_data.fld_from->frm_mb_list->mb_list; - clistiter *it; - for ( it = clist_begin( cl ); it; it = it->next ) { - mailimf_mailbox *mb = (mailimf_mailbox *) it->data; - from = strdup( mb->mb_addr_spec ); - } - } - - return from; -} - -SMTPaccount *MailWrapper::getAccount( QString from ) -{ - SMTPaccount *smtp; - - QList<Account> list = settings->getAccounts(); - Account *it; - for ( it = list.first(); it; it = list.next() ) { - if ( it->getType().compare( "SMTP" ) == 0 ) { - smtp = static_cast<SMTPaccount *>(it); - if ( smtp->getMail().compare( from ) == 0 ) { - qDebug( "SMTPaccount found for" ); - qDebug( from ); - return smtp; - } - } - } - - return NULL; -} - -QString MailWrapper::getTmpFile() { - int num = 0; - QString unique; - - QDir dir( "/tmp" ); - QStringList::Iterator it; - - QStringList list = dir.entryList( "opiemail-tmp-*" ); - do { - unique.setNum( num++ ); - } while ( list.contains( "opiemail-tmp-" + unique ) > 0 ); - - return "/tmp/opiemail-tmp-" + unique; -} - -void MailWrapper::writeToFile( QString file, mailmime *mail ) -{ - FILE *f; - int err, col = 0; - - f = fopen( file.latin1(), "w" ); - if ( f == NULL ) { - qDebug( "writeToFile: error opening file" ); - return; - } - - err = mailmime_write( f, &col, mail ); - if ( err != MAILIMF_NO_ERROR ) { - fclose( f ); - qDebug( "writeToFile: error writing mailmime" ); - return; - } - - fclose( f ); -} - -void MailWrapper::readFromFile( QString file, char **data, size_t *size ) -{ - char *buf; - struct stat st; - int fd, count = 0, total = 0; - - fd = open( file.latin1(), O_RDONLY, 0 ); - if ( fd == -1 ) return; - - if ( fstat( fd, &st ) != 0 ) goto err_close; - if ( !st.st_size ) goto err_close; - - buf = (char *) malloc( st.st_size ); - if ( !buf ) goto err_close; - - while ( ( total < st.st_size ) && ( count >= 0 ) ) { - count = read( fd, buf + total, st.st_size - total ); - total += count; - } - if ( count < 0 ) goto err_free; - - *data = buf; - *size = st.st_size; - - close( fd ); - - return; // Success :) - -err_free: - free( buf ); -err_close: - close( fd ); -} - -void progress( size_t current, size_t maximum ) -{ - qDebug( "Current: %i of %i", current, maximum ); -} - -void MailWrapper::smtpSend( mailmime *mail ) -{ - mailsmtp *session; - clist *rcpts; - char *from, *data, *server, *user = NULL, *pass = NULL; - size_t size; - int err; - bool ssl; - uint16_t port; - - - from = getFrom( mail ); - SMTPaccount *smtp = getAccount( from ); - if ( smtp == NULL ) { - free(from); - return; - } - server = strdup( smtp->getServer().latin1() ); - ssl = smtp->getSSL(); - port = smtp->getPort().toUInt(); - rcpts = createRcptList( mail->mm_data.mm_message.mm_fields ); - - QString file = getTmpFile(); - writeToFile( file, mail ); - readFromFile( file, &data, &size ); - QFile f( file ); - f.remove(); - - session = mailsmtp_new( 20, &progress ); - if ( session == NULL ) goto free_mem; - - qDebug( "Servername %s at port %i", server, port ); - if ( ssl ) { - qDebug( "SSL session" ); - err = mailsmtp_ssl_connect( session, server, port ); - } else { - qDebug( "No SSL session" ); - err = mailsmtp_socket_connect( session, server, port ); - } - if ( err != MAILSMTP_NO_ERROR ) goto free_mem_session; - - err = mailsmtp_init( session ); - if ( err != MAILSMTP_NO_ERROR ) goto free_con_session; - - qDebug( "INIT OK" ); - - if ( smtp->getLogin() ) { - if ( smtp->getUser().isEmpty() || smtp->getPassword().isEmpty() ) { - // get'em - LoginDialog login( smtp->getUser(), smtp->getPassword(), NULL, 0, true ); - login.show(); - if ( QDialog::Accepted == login.exec() ) { - // ok - user = strdup( login.getUser().latin1() ); - pass = strdup( login.getPassword().latin1() ); - } else { - goto free_con_session; - } - } else { - user = strdup( smtp->getUser().latin1() ); - pass = strdup( smtp->getPassword().latin1() ); - } - qDebug( "session->auth: %i", session->auth); - err = mailsmtp_auth( session, user, pass ); - if ( err == MAILSMTP_NO_ERROR ) qDebug("auth ok"); - qDebug( "Done auth!" ); - } - - err = mailsmtp_send( session, from, rcpts, data, size ); - if ( err != MAILSMTP_NO_ERROR ) goto free_con_session; - - qDebug( "Mail sent." ); - -free_con_session: - mailsmtp_quit( session ); -free_mem_session: - mailsmtp_free( session ); -free_mem: - smtp_address_list_free( rcpts ); - free( data ); - free( server ); - if ( smtp->getLogin() ) { - free( user ); - free( pass ); - } - free( from ); -} - -void MailWrapper::sendMail( Mail mail ) -{ - mailmime *mimeMail; - - mimeMail = createMimeMail( &mail ); - if ( mimeMail == NULL ) { - qDebug( "sendMail: error creating mime mail" ); - } else { - smtpSend( mimeMail ); - mailmime_free( mimeMail ); - } -} - Mail::Mail() :name(""), mail(""), to(""), cc(""), bcc(""), reply(""), subject(""), message("") { } diff --git a/noncore/net/mail/mailwrapper.h b/noncore/net/mail/mailwrapper.h index 02fe4b7..8fd886f 100644 --- a/noncore/net/mail/mailwrapper.h +++ b/noncore/net/mail/mailwrapper.h @@ -1,126 +1,91 @@ #ifndef MAILWRAPPER_H #define MAILWRAPPER_H #include <qpe/applnk.h> -#include <libetpan/mailmime.h> -#include <libetpan/mailimf.h> -#include <libetpan/mailsmtp.h> -#include <libetpan/mailstorage.h> -#include <libetpan/maildriver.h> #include <qbitarray.h> #include <qdatetime.h> #include "settings.h" class Attachment { public: Attachment( DocLnk lnk ); virtual ~Attachment(){} const QString getFileName()const{ return doc.file(); } const QString getName()const{ return doc.name(); } const QString getMimeType()const{ return doc.type(); } const QPixmap getPixmap()const{ return doc.pixmap(); } const int getSize()const { return size; } DocLnk getDocLnk() { return doc; } protected: DocLnk doc; int size; }; class Mail { public: Mail(); /* Possible that this destructor must not be declared virtual * 'cause it seems that it will never have some child classes. * in this case this object will not get a virtual table -> memory and * speed will be a little bit better? */ virtual ~Mail(){} void addAttachment( Attachment *att ) { attList.append( att ); } const QList<Attachment>& getAttachments()const { return attList; } void removeAttachment( Attachment *att ) { attList.remove( att ); } const QString&getName()const { return name; } void setName( QString s ) { name = s; } const QString&getMail()const{ return mail; } void setMail( const QString&s ) { mail = s; } const QString&getTo()const{ return to; } void setTo( const QString&s ) { to = s; } const QString&getCC()const{ return cc; } void setCC( const QString&s ) { cc = s; } const QString&getBCC()const { return bcc; } void setBCC( const QString&s ) { bcc = s; } const QString&getMessage()const { return message; } void setMessage( const QString&s ) { message = s; } const QString&getSubject()const { return subject; } void setSubject( const QString&s ) { subject = s; } const QString&getReply()const{ return reply; } void setReply( const QString&a ) { reply = a; } private: QList<Attachment> attList; QString name, mail, to, cc, bcc, reply, subject, message; }; class Folder : public QObject { Q_OBJECT public: Folder( const QString&init_name,const QString&sep ); const QString&getDisplayName()const { return nameDisplay; } const QString&getName()const { return name; } virtual bool may_select()const{return true;}; const QString&Separator()const; protected: QString nameDisplay, name, separator; }; class IMAPFolder : public Folder { public: IMAPFolder(const QString&name, const QString&sep, bool select=true,const QString&prefix="" ); virtual bool may_select()const{return m_MaySelect;} private: static QString decodeFolderName( const QString &name ); bool m_MaySelect; }; -class MailWrapper : public QObject -{ - Q_OBJECT - -public: - MailWrapper( Settings *s ); - void sendMail( Mail mail ); - -private: - mailimf_mailbox *newMailbox(const QString&name,const QString&mail ); - mailimf_address_list *parseAddresses(const QString&addr ); - mailimf_fields *createImfFields( Mail *mail ); - mailmime *buildTxtPart( QString str ); - mailmime *buildFilePart( QString filename, QString mimetype ); - void addFileParts( mailmime *message, QList<Attachment> files ); - mailmime *createMimeMail( Mail *mail ); - void smtpSend( mailmime *mail ); - mailimf_field *getField( mailimf_fields *fields, int type ); - clist *createRcptList( mailimf_fields *fields ); - char *getFrom( mailmime *mail ); - SMTPaccount *getAccount( QString from ); - void writeToFile( QString file, mailmime *mail ); - void readFromFile( QString file, char **data, size_t *size ); - static QString mailsmtpError( int err ); - static QString getTmpFile(); - - Settings *settings; - -}; - #endif diff --git a/noncore/net/mail/pop3wrapper.h b/noncore/net/mail/pop3wrapper.h index a31a145..75d70f8 100644 --- a/noncore/net/mail/pop3wrapper.h +++ b/noncore/net/mail/pop3wrapper.h @@ -1,63 +1,69 @@ #ifndef __POP3WRAPPER #define __POP3WRAPPER +#include <libetpan/clist.h> #include "mailwrapper.h" #include "abstractmail.h" #include <qmap.h> #include <qstring.h> class RecMail; class RecBody; class encodedString; struct mailpop3; struct mailmessage; struct mailmime; struct mailmime_mechanism; +struct mailimf_mailbox_list; +struct mailimf_mailbox; +struct mailimf_date_time; +struct mailimf_group; +struct mailimf_address_list; class POP3wrapper : public AbstractMail { Q_OBJECT public: POP3wrapper( POP3account *a ); virtual ~POP3wrapper(); /* mailbox will be ignored */ virtual void listMessages(const QString & mailbox, QList<RecMail> &target ); virtual QList<Folder>* listFolders(); virtual QString fetchTextPart(const RecMail&mail,const RecPart&part); virtual encodedString* fetchDecodedPart(const RecMail&mail,const RecPart&part); virtual encodedString* fetchRawPart(const RecMail&mail,const RecPart&part); virtual void deleteMail(const RecMail&mail); virtual void answeredMail(const RecMail&mail); RecBody fetchBody( const RecMail &mail ); static void pop3_progress( size_t current, size_t maximum ); protected: void login(); void logout(); RecMail *parseHeader( const char *header ); RecBody parseMail( char *message ); QString parseMailboxList( mailimf_mailbox_list *list ); QString parseMailbox( mailimf_mailbox *box ); QString parseGroup( mailimf_group *group ); QString parseAddressList( mailimf_address_list *list ); QString parseDateTime( mailimf_date_time *date ); void cleanUpCache(); void traverseBody(RecBody&target,mailmessage*message,mailmime*mime,unsigned int current_rek=0); static void fillSingleBody(RecPart&target,mailmessage*message,mailmime*mime); static void fillParameters(RecPart&target,clist*parameters); static QString POP3wrapper::getencoding(mailmime_mechanism*aEnc); POP3account *account; mailpop3 *m_pop3; QString msgTempName; unsigned int last_msg_id; QMap<QString,encodedString*> bodyCache; }; #endif diff --git a/noncore/net/mail/smtpwrapper.cpp b/noncore/net/mail/smtpwrapper.cpp new file mode 100644 index 0000000..162b1b9 --- a/dev/null +++ b/noncore/net/mail/smtpwrapper.cpp @@ -0,0 +1,604 @@ +#include <stdlib.h> +#include <sys/stat.h> +#include <sys/types.h> +#include <unistd.h> +#include <fcntl.h> +#include <string.h> +#include <qdir.h> + +#include <libetpan/mailmime.h> +#include <libetpan/mailimf.h> +#include <libetpan/mailsmtp.h> +#include <libetpan/mailstorage.h> +#include <libetpan/maildriver.h> + +#include "smtpwrapper.h" +#include "mailwrapper.h" +#include "logindialog.h" +#include "defines.h" + +SMTPwrapper::SMTPwrapper( Settings *s ) + : QObject() +{ + settings = s; +} + +QString SMTPwrapper::mailsmtpError( int errnum ) +{ + switch ( errnum ) { + case MAILSMTP_NO_ERROR: + return tr( "No error" ); + case MAILSMTP_ERROR_UNEXPECTED_CODE: + return tr( "Unexpected error code" ); + case MAILSMTP_ERROR_SERVICE_NOT_AVAILABLE: + return tr( "Service not available" ); + case MAILSMTP_ERROR_STREAM: + return tr( "Stream error" ); + case MAILSMTP_ERROR_HOSTNAME: + return tr( "gethostname() failed" ); + case MAILSMTP_ERROR_NOT_IMPLEMENTED: + return tr( "Not implemented" ); + case MAILSMTP_ERROR_ACTION_NOT_TAKEN: + return tr( "Error, action not taken" ); + case MAILSMTP_ERROR_EXCEED_STORAGE_ALLOCATION: + return tr( "Data exceeds storage allocation" ); + case MAILSMTP_ERROR_IN_PROCESSING: + return tr( "Error in processing" ); + // case MAILSMTP_ERROR_INSUFFISANT_SYSTEM_STORAGE: + // return tr( "Insufficient system storage" ); + case MAILSMTP_ERROR_MAILBOX_UNAVAILABLE: + return tr( "Mailbox unavailable" ); + case MAILSMTP_ERROR_MAILBOX_NAME_NOT_ALLOWED: + return tr( "Mailbox name not allowed" ); + case MAILSMTP_ERROR_BAD_SEQUENCE_OF_COMMAND: + return tr( "Bad command sequence" ); + case MAILSMTP_ERROR_USER_NOT_LOCAL: + return tr( "User not local" ); + case MAILSMTP_ERROR_TRANSACTION_FAILED: + return tr( "Transaction failed" ); + case MAILSMTP_ERROR_MEMORY: + return tr( "Memory error" ); + case MAILSMTP_ERROR_CONNECTION_REFUSED: + return tr( "Connection refused" ); + default: + return tr( "Unknown error code" ); + } +} + +mailimf_mailbox *SMTPwrapper::newMailbox(const QString&name, const QString&mail ) +{ + return mailimf_mailbox_new( strdup( name.latin1() ), + strdup( mail.latin1() ) ); +} + +mailimf_address_list *SMTPwrapper::parseAddresses(const QString&addr ) +{ + mailimf_address_list *addresses; + + if ( addr.isEmpty() ) return NULL; + + addresses = mailimf_address_list_new_empty(); + + QStringList list = QStringList::split( ',', addr ); + QStringList::Iterator it; + for ( it = list.begin(); it != list.end(); it++ ) { + char *str = strdup( (*it).latin1() ); + int err = mailimf_address_list_add_parse( addresses, str ); + if ( err != MAILIMF_NO_ERROR ) { + qDebug( "Error parsing" ); + qDebug( *it ); + free( str ); + } else { + qDebug( "Parse success! :)" ); + } + } + + return addresses; +} + +mailimf_fields *SMTPwrapper::createImfFields(const Mail&mail ) +{ + mailimf_fields *fields; + mailimf_field *xmailer; + mailimf_mailbox *sender, *fromBox; + mailimf_mailbox_list *from; + mailimf_address_list *to, *cc, *bcc, *reply; + char *subject = strdup( mail.getSubject().latin1() ); + int err; + + sender = newMailbox( mail.getName(), mail.getMail() ); + if ( sender == NULL ) goto err_free; + + fromBox = newMailbox( mail.getName(), mail.getMail() ); + if ( fromBox == NULL ) goto err_free_sender; + + from = mailimf_mailbox_list_new_empty(); + if ( from == NULL ) goto err_free_fromBox; + + err = mailimf_mailbox_list_add( from, fromBox ); + if ( err != MAILIMF_NO_ERROR ) goto err_free_from; + + to = parseAddresses( mail.getTo() ); + if ( to == NULL ) goto err_free_from; + + cc = parseAddresses( mail.getCC() ); + bcc = parseAddresses( mail.getBCC() ); + reply = parseAddresses( mail.getReply() ); + + fields = mailimf_fields_new_with_data( from, sender, reply, to, cc, bcc, + NULL, NULL, subject ); + if ( fields == NULL ) goto err_free_reply; + + xmailer = mailimf_field_new_custom( strdup( "User-Agent" ), + strdup( USER_AGENT ) ); + if ( xmailer == NULL ) goto err_free_fields; + + err = mailimf_fields_add( fields, xmailer ); + if ( err != MAILIMF_NO_ERROR ) goto err_free_xmailer; + + return fields; // Success :) + +err_free_xmailer: + mailimf_field_free( xmailer ); +err_free_fields: + mailimf_fields_free( fields ); +err_free_reply: + mailimf_address_list_free( reply ); + mailimf_address_list_free( bcc ); + mailimf_address_list_free( cc ); + mailimf_address_list_free( to ); +err_free_from: + mailimf_mailbox_list_free( from ); +err_free_fromBox: + mailimf_mailbox_free( fromBox ); +err_free_sender: + mailimf_mailbox_free( sender ); +err_free: + free( subject ); + qDebug( "createImfFields - error" ); + + return NULL; // Error :( +} + +mailmime *SMTPwrapper::buildTxtPart(const QString&str ) +{ + mailmime *txtPart; + mailmime_fields *fields; + mailmime_content *content; + mailmime_parameter *param; + char *txt = strdup( str.latin1() ); + int err; + + param = mailmime_parameter_new( strdup( "charset" ), + strdup( "iso-8859-1" ) ); + if ( param == NULL ) goto err_free; + + content = mailmime_content_new_with_str( "text/plain" ); + if ( content == NULL ) goto err_free_param; + + err = clist_append( content->ct_parameters, param ); + if ( err != MAILIMF_NO_ERROR ) goto err_free_content; + + fields = mailmime_fields_new_encoding( MAILMIME_MECHANISM_8BIT ); + if ( fields == NULL ) goto err_free_content; + + txtPart = mailmime_new_empty( content, fields ); + if ( txtPart == NULL ) goto err_free_fields; + + err = mailmime_set_body_text( txtPart, txt, strlen( txt ) ); + if ( err != MAILIMF_NO_ERROR ) goto err_free_txtPart; + + return txtPart; // Success :) + +err_free_txtPart: + mailmime_free( txtPart ); +err_free_fields: + mailmime_fields_free( fields ); +err_free_content: + mailmime_content_free( content ); +err_free_param: + mailmime_parameter_free( param ); +err_free: + free( txt ); + qDebug( "buildTxtPart - error" ); + + return NULL; // Error :( +} + +mailmime *SMTPwrapper::buildFilePart(const QString&filename,const QString&mimetype ) +{ + mailmime * filePart; + mailmime_fields * fields; + mailmime_content * content; + mailmime_parameter * param = NULL; + int err; + + int pos = filename.findRev( '/' ); + QString tmp = filename.right( filename.length() - ( pos + 1 ) ); + char *name = strdup( tmp.latin1() ); // just filename + char *file = strdup( filename.latin1() ); // full name with path + char *mime = strdup( mimetype.latin1() ); // mimetype -e.g. text/plain + + fields = mailmime_fields_new_filename( + MAILMIME_DISPOSITION_TYPE_ATTACHMENT, name, + MAILMIME_MECHANISM_BASE64 ); + if ( fields == NULL ) goto err_free; + + content = mailmime_content_new_with_str( mime ); + if ( content == NULL ) goto err_free_fields; + + if ( mimetype.compare( "text/plain" ) == 0 ) { + param = mailmime_parameter_new( strdup( "charset" ), + strdup( "iso-8859-1" ) ); + if ( param == NULL ) goto err_free_content; + + err = clist_append( content->ct_parameters, param ); + if ( err != MAILIMF_NO_ERROR ) goto err_free_param; + } + + filePart = mailmime_new_empty( content, fields ); + if ( filePart == NULL ) goto err_free_param; + + err = mailmime_set_body_file( filePart, file ); + if ( err != MAILIMF_NO_ERROR ) goto err_free_filePart; + + return filePart; // Success :) + +err_free_filePart: + mailmime_free( filePart ); +err_free_param: + if ( param != NULL ) mailmime_parameter_free( param ); +err_free_content: + mailmime_content_free( content ); +err_free_fields: + mailmime_fields_free( fields ); +err_free: + free( name ); + free( mime ); + free( file ); + qDebug( "buildFilePart - error" ); + + return NULL; // Error :( +} + +void SMTPwrapper::addFileParts( mailmime *message,const QList<Attachment>&files ) +{ + const Attachment *it; + /* work around for the brainfucked qlist which can not act with const values */ + for ( it = ((QList<Attachment>)files).first(); it; it = ((QList<Attachment>)files).next() ) { + qDebug( "Adding file" ); + mailmime *filePart; + int err; + + filePart = buildFilePart( it->getFileName(), it->getMimeType() ); + if ( filePart == NULL ) goto err_free; + + err = mailmime_smart_add_part( message, filePart ); + if ( err != MAILIMF_NO_ERROR ) goto err_free_filePart; + + continue; // Success :) + + err_free_filePart: + mailmime_free( filePart ); + err_free: + qDebug( "addFileParts: error adding file:" ); + qDebug( it->getFileName() ); + } +} + +mailmime *SMTPwrapper::createMimeMail(const Mail &mail ) +{ + mailmime *message, *txtPart; + mailimf_fields *fields; + int err; + + fields = createImfFields( mail ); + if ( fields == NULL ) goto err_free; + + message = mailmime_new_message_data( NULL ); + if ( message == NULL ) goto err_free_fields; + + mailmime_set_imf_fields( message, fields ); + + txtPart = buildTxtPart( mail.getMessage() ); + if ( txtPart == NULL ) goto err_free_message; + + err = mailmime_smart_add_part( message, txtPart ); + if ( err != MAILIMF_NO_ERROR ) goto err_free_txtPart; + + addFileParts( message, mail.getAttachments() ); + + return message; // Success :) + +err_free_txtPart: + mailmime_free( txtPart ); +err_free_message: + mailmime_free( message ); +err_free_fields: + mailimf_fields_free( fields ); +err_free: + qDebug( "createMimeMail: error" ); + + return NULL; // Error :( +} + +mailimf_field *SMTPwrapper::getField( mailimf_fields *fields, int type ) +{ + mailimf_field *field; + clistiter *it; + + it = clist_begin( fields->fld_list ); + while ( it ) { + field = (mailimf_field *) it->data; + if ( field->fld_type == type ) { + return field; + } + it = it->next; + } + + return NULL; +} + +void SMTPwrapper::addRcpts( clist *list, mailimf_address_list *addr_list ) +{ + clistiter *it, *it2; + + for ( it = clist_begin( addr_list->ad_list ); it; it = it->next ) { + mailimf_address *addr; + addr = (mailimf_address *) it->data; + + if ( addr->ad_type == MAILIMF_ADDRESS_MAILBOX ) { + esmtp_address_list_add( list, addr->ad_data.ad_mailbox->mb_addr_spec, 0, NULL ); + } else if ( addr->ad_type == MAILIMF_ADDRESS_GROUP ) { + clist *l = addr->ad_data.ad_group->grp_mb_list->mb_list; + for ( it2 = clist_begin( l ); it2; it2 = it2->next ) { + mailimf_mailbox *mbox; + mbox = (mailimf_mailbox *) it2->data; + esmtp_address_list_add( list, mbox->mb_addr_spec, 0, NULL ); + } + } + } +} + +clist *SMTPwrapper::createRcptList( mailimf_fields *fields ) +{ + clist *rcptList; + mailimf_field *field; + + rcptList = esmtp_address_list_new(); + + field = getField( fields, MAILIMF_FIELD_TO ); + if ( field && (field->fld_type == MAILIMF_FIELD_TO) + && field->fld_data.fld_to->to_addr_list ) { + addRcpts( rcptList, field->fld_data.fld_to->to_addr_list ); + } + + field = getField( fields, MAILIMF_FIELD_CC ); + if ( field && (field->fld_type == MAILIMF_FIELD_CC) + && field->fld_data.fld_cc->cc_addr_list ) { + addRcpts( rcptList, field->fld_data.fld_cc->cc_addr_list ); + } + + field = getField( fields, MAILIMF_FIELD_BCC ); + if ( field && (field->fld_type == MAILIMF_FIELD_BCC) + && field->fld_data.fld_bcc->bcc_addr_list ) { + addRcpts( rcptList, field->fld_data.fld_bcc->bcc_addr_list ); + } + + return rcptList; +} + +char *SMTPwrapper::getFrom( mailmime *mail ) +{ + char *from = NULL; + + mailimf_field *ffrom; + ffrom = getField( mail->mm_data.mm_message.mm_fields, MAILIMF_FIELD_FROM ); + if ( ffrom && (ffrom->fld_type == MAILIMF_FIELD_FROM) + && ffrom->fld_data.fld_from->frm_mb_list && ffrom->fld_data.fld_from->frm_mb_list->mb_list ) { + clist *cl = ffrom->fld_data.fld_from->frm_mb_list->mb_list; + clistiter *it; + for ( it = clist_begin( cl ); it; it = it->next ) { + mailimf_mailbox *mb = (mailimf_mailbox *) it->data; + from = strdup( mb->mb_addr_spec ); + } + } + + return from; +} + +SMTPaccount *SMTPwrapper::getAccount(const QString&from ) +{ + SMTPaccount *smtp; + + QList<Account> list = settings->getAccounts(); + Account *it; + for ( it = list.first(); it; it = list.next() ) { + if ( it->getType().compare( "SMTP" ) == 0 ) { + smtp = static_cast<SMTPaccount *>(it); + if ( smtp->getMail().compare( from ) == 0 ) { + qDebug( "SMTPaccount found for" ); + qDebug( from ); + return smtp; + } + } + } + + return NULL; +} + +QString SMTPwrapper::getTmpFile() { + int num = 0; + QString unique; + + QDir dir( "/tmp" ); + QStringList::Iterator it; + + QStringList list = dir.entryList( "opiemail-tmp-*" ); + do { + unique.setNum( num++ ); + } while ( list.contains( "opiemail-tmp-" + unique ) > 0 ); + + return "/tmp/opiemail-tmp-" + unique; +} + +void SMTPwrapper::writeToFile(const QString&file, mailmime *mail ) +{ + FILE *f; + int err, col = 0; + + f = fopen( file.latin1(), "w" ); + if ( f == NULL ) { + qDebug( "writeToFile: error opening file" ); + return; + } + + err = mailmime_write( f, &col, mail ); + if ( err != MAILIMF_NO_ERROR ) { + fclose( f ); + qDebug( "writeToFile: error writing mailmime" ); + return; + } + + fclose( f ); +} + +void SMTPwrapper::readFromFile(const QString&file, char **data, size_t *size ) +{ + char *buf; + struct stat st; + int fd, count = 0, total = 0; + + fd = open( file.latin1(), O_RDONLY, 0 ); + if ( fd == -1 ) return; + + if ( fstat( fd, &st ) != 0 ) goto err_close; + if ( !st.st_size ) goto err_close; + + buf = (char *) malloc( st.st_size ); + if ( !buf ) goto err_close; + + while ( ( total < st.st_size ) && ( count >= 0 ) ) { + count = read( fd, buf + total, st.st_size - total ); + total += count; + } + if ( count < 0 ) goto err_free; + + *data = buf; + *size = st.st_size; + + close( fd ); + + return; // Success :) + +err_free: + free( buf ); +err_close: + close( fd ); +} + +void SMTPwrapper::progress( size_t current, size_t maximum ) +{ + qDebug( "Current: %i of %i", current, maximum ); +} + +void SMTPwrapper::smtpSend( mailmime *mail ) +{ + mailsmtp *session; + clist *rcpts; + char *from, *data, *server, *user = NULL, *pass = NULL; + size_t size; + int err; + bool ssl; + uint16_t port; + + + from = getFrom( mail ); + SMTPaccount *smtp = getAccount( from ); + if ( smtp == NULL ) { + free(from); + return; + } + server = strdup( smtp->getServer().latin1() ); + ssl = smtp->getSSL(); + port = smtp->getPort().toUInt(); + rcpts = createRcptList( mail->mm_data.mm_message.mm_fields ); + + QString file = getTmpFile(); + writeToFile( file, mail ); + readFromFile( file, &data, &size ); + QFile f( file ); + f.remove(); + + session = mailsmtp_new( 20, &progress ); + if ( session == NULL ) goto free_mem; + + qDebug( "Servername %s at port %i", server, port ); + if ( ssl ) { + qDebug( "SSL session" ); + err = mailsmtp_ssl_connect( session, server, port ); + } else { + qDebug( "No SSL session" ); + err = mailsmtp_socket_connect( session, server, port ); + } + if ( err != MAILSMTP_NO_ERROR ) goto free_mem_session; + + err = mailsmtp_init( session ); + if ( err != MAILSMTP_NO_ERROR ) goto free_con_session; + + qDebug( "INIT OK" ); + + if ( smtp->getLogin() ) { + if ( smtp->getUser().isEmpty() || smtp->getPassword().isEmpty() ) { + // get'em + LoginDialog login( smtp->getUser(), smtp->getPassword(), NULL, 0, true ); + login.show(); + if ( QDialog::Accepted == login.exec() ) { + // ok + user = strdup( login.getUser().latin1() ); + pass = strdup( login.getPassword().latin1() ); + } else { + goto free_con_session; + } + } else { + user = strdup( smtp->getUser().latin1() ); + pass = strdup( smtp->getPassword().latin1() ); + } + qDebug( "session->auth: %i", session->auth); + err = mailsmtp_auth( session, user, pass ); + if ( err == MAILSMTP_NO_ERROR ) qDebug("auth ok"); + qDebug( "Done auth!" ); + } + + err = mailsmtp_send( session, from, rcpts, data, size ); + if ( err != MAILSMTP_NO_ERROR ) goto free_con_session; + + qDebug( "Mail sent." ); + +free_con_session: + mailsmtp_quit( session ); +free_mem_session: + mailsmtp_free( session ); +free_mem: + smtp_address_list_free( rcpts ); + free( data ); + free( server ); + if ( smtp->getLogin() ) { + free( user ); + free( pass ); + } + free( from ); +} + +void SMTPwrapper::sendMail(const Mail&mail ) +{ + mailmime *mimeMail; + + mimeMail = createMimeMail(mail ); + if ( mimeMail == NULL ) { + qDebug( "sendMail: error creating mime mail" ); + } else { + smtpSend( mimeMail ); + mailmime_free( mimeMail ); + } +} diff --git a/noncore/net/mail/smtpwrapper.h b/noncore/net/mail/smtpwrapper.h new file mode 100644 index 0000000..8fdb07d --- a/dev/null +++ b/noncore/net/mail/smtpwrapper.h @@ -0,0 +1,53 @@ +#ifndef SMTPwrapper_H +#define SMTPwrapper_H + +#include <qpe/applnk.h> + +#include <qbitarray.h> +#include <qdatetime.h> +#include <libetpan/clist.h> + +#include "settings.h" + +class Mail; +class Attachment; +struct mailimf_fields; +struct mailimf_field; +struct mailimf_mailbox; +struct mailmime; +struct mailimf_address_list; + +class SMTPwrapper : public QObject +{ + Q_OBJECT + +public: + SMTPwrapper( Settings *s ); + virtual ~SMTPwrapper(){} + void sendMail(const Mail& mail ); + +protected: + mailimf_mailbox *newMailbox(const QString&name,const QString&mail ); + mailimf_fields *createImfFields(const Mail &mail ); + mailmime *createMimeMail(const Mail&mail ); + + mailimf_address_list *parseAddresses(const QString&addr ); + void addFileParts( mailmime *message,const QList<Attachment>&files ); + mailmime *buildTxtPart(const QString&str ); + mailmime *buildFilePart(const QString&filename,const QString&mimetype ); + void smtpSend( mailmime *mail ); + mailimf_field *getField( mailimf_fields *fields, int type ); + clist *createRcptList( mailimf_fields *fields ); + char *getFrom( mailmime *mail ); + SMTPaccount *getAccount(const QString&from ); + void writeToFile(const QString&file, mailmime *mail ); + void readFromFile(const QString&file, char **data, size_t *size ); + + static QString mailsmtpError( int err ); + static QString getTmpFile(); + static void progress( size_t current, size_t maximum ); + static void addRcpts( clist *list, mailimf_address_list *addr_list ); + Settings *settings; +}; + +#endif |