author | jgf <jgf> | 2003-12-18 02:43:07 (UTC) |
---|---|---|
committer | jgf <jgf> | 2003-12-18 02:43:07 (UTC) |
commit | d7fed5a555f51008db8b96e8b978c3830c59be77 (patch) (side-by-side diff) | |
tree | 9f3a8aa82909ef80cf1c42431abc20d3ac585436 | |
parent | 77e353da0c33bbfabf1b919e25008d62581bf164 (diff) | |
download | opie-d7fed5a555f51008db8b96e8b978c3830c59be77.zip opie-d7fed5a555f51008db8b96e8b978c3830c59be77.tar.gz opie-d7fed5a555f51008db8b96e8b978c3830c59be77.tar.bz2 |
decoding of imap folder names
-rw-r--r-- | noncore/net/mail/defines.h | 11 | ||||
-rw-r--r-- | noncore/net/mail/libmailwrapper/mailwrapper.cpp | 107 | ||||
-rw-r--r-- | noncore/net/mail/libmailwrapper/mailwrapper.h | 2 | ||||
-rw-r--r-- | noncore/net/mail/mailwrapper.cpp | 107 | ||||
-rw-r--r-- | noncore/net/mail/mailwrapper.h | 2 |
5 files changed, 201 insertions, 28 deletions
diff --git a/noncore/net/mail/defines.h b/noncore/net/mail/defines.h index 9036658..d9cdab0 100644 --- a/noncore/net/mail/defines.h +++ b/noncore/net/mail/defines.h @@ -1,40 +1,51 @@ #ifndef DEFINE_CONSTANTS_H #define DEFINE_CONSTANTS_H #include <qpe/resource.h> #define USER_AGENT "OpieMail v0.1" #define PIC_COMPOSEMAIL "mail/composemail" #define PIC_SENDQUEUED "mail/sendqueued" #define PIC_SHOWFOLDERS "mail/showfolders" #define PIC_SEARCHMAILS "mail/searchmails" #define PIC_EDITSETTINGS "mail/editsettings" #define PIC_EDITACCOUNTS "mail/editaccounts" #define PIC_SYNC "mail/sync" #define PIC_IMAPFOLDER "mail/imapfolder" #define PIC_POP3FOLDER "mail/pop3folder" #define PIC_INBOXFOLDER "mail/inbox" #define ICON_COMPOSEMAIL QIconSet( Resource::loadPixmap( PIC_COMPOSEMAIL ) ) #define ICON_SENDQUEUED QIconSet( Resource::loadPixmap( PIC_SENDQUEUED ) ) #define ICON_SHOWFOLDERS QIconSet( Resource::loadPixmap( PIC_SHOWFOLDERS ) ) #define ICON_SEARCHMAILS QIconSet( Resource::loadPixmap( PIC_SEARCHMAILS ) ) #define ICON_EDITSETTINGS QIconSet( Resource::loadPixmap( PIC_EDITSETTINGS ) ) #define ICON_EDITACCOUNTS QIconSet( Resource::loadPixmap( PIC_EDITACCOUNTS ) ) #define ICON_SYNC QIconSet( Resource::loadPixmap( PIC_SYNC ) ) #define PIXMAP_IMAPFOLDER QPixmap( Resource::loadPixmap( PIC_IMAPFOLDER ) ) #define PIXMAP_POP3FOLDER QPixmap( Resource::loadPixmap( PIC_POP3FOLDER ) ) #define PIXMAP_INBOXFOLDER QPixmap( Resource::loadPixmap( PIC_INBOXFOLDER) ) #define IMAP_PORT "143" #define IMAP_SSL_PORT "993" #define SMTP_PORT "25" #define SMTP_SSL_PORT "465" #define POP3_PORT "110" #define POP3_SSL_PORT "995" #define NNTP_PORT "119" #define NNTP_SSL_PORT "563" +/* used for decoding imapfoldername */ +#define UNDEFINED 64 +#define MAXLINE 76 +#define UTF16MASK 0x03FFUL +#define UTF16SHIFT 10 +#define UTF16BASE 0x10000UL +#define UTF16HIGHSTART 0xD800UL +#define UTF16HIGHEND 0xDBFFUL +#define UTF16LOSTART 0xDC00UL +#define UTF16LOEND 0xDFFFUL + #endif diff --git a/noncore/net/mail/libmailwrapper/mailwrapper.cpp b/noncore/net/mail/libmailwrapper/mailwrapper.cpp index 858283f..75c06f9 100644 --- a/noncore/net/mail/libmailwrapper/mailwrapper.cpp +++ b/noncore/net/mail/libmailwrapper/mailwrapper.cpp @@ -1,439 +1,518 @@ #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; - - for ( int pos = nameDisplay.find( '&' ); pos != -1; - pos = nameDisplay.find( '&' ) ) { - int end = nameDisplay.find( '-' ); - if ( end == -1 || end <= pos ) break; - QString str64 = nameDisplay.mid( pos + 1, end - pos - 1 ); - // TODO: do real base64 decoding here ! - if ( str64.compare( "APw" ) == 0 ) { - nameDisplay = nameDisplay.replace( pos, end - pos + 1, "ue" ); - } else if ( str64.compare( "APY" ) == 0 ) { - nameDisplay = nameDisplay.replace( pos, end - pos + 1, "oe" ); - } - } - qDebug( "folder " + name + " - displayed as " + nameDisplay ); 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 ); } diff --git a/noncore/net/mail/libmailwrapper/mailwrapper.h b/noncore/net/mail/libmailwrapper/mailwrapper.h index d78f8e9..02fe4b7 100644 --- a/noncore/net/mail/libmailwrapper/mailwrapper.h +++ b/noncore/net/mail/libmailwrapper/mailwrapper.h @@ -1,124 +1,126 @@ #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/mailwrapper.cpp b/noncore/net/mail/mailwrapper.cpp index 858283f..75c06f9 100644 --- a/noncore/net/mail/mailwrapper.cpp +++ b/noncore/net/mail/mailwrapper.cpp @@ -1,439 +1,518 @@ #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; - - for ( int pos = nameDisplay.find( '&' ); pos != -1; - pos = nameDisplay.find( '&' ) ) { - int end = nameDisplay.find( '-' ); - if ( end == -1 || end <= pos ) break; - QString str64 = nameDisplay.mid( pos + 1, end - pos - 1 ); - // TODO: do real base64 decoding here ! - if ( str64.compare( "APw" ) == 0 ) { - nameDisplay = nameDisplay.replace( pos, end - pos + 1, "ue" ); - } else if ( str64.compare( "APY" ) == 0 ) { - nameDisplay = nameDisplay.replace( pos, end - pos + 1, "oe" ); - } - } - qDebug( "folder " + name + " - displayed as " + nameDisplay ); 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 ); } diff --git a/noncore/net/mail/mailwrapper.h b/noncore/net/mail/mailwrapper.h index d78f8e9..02fe4b7 100644 --- a/noncore/net/mail/mailwrapper.h +++ b/noncore/net/mail/mailwrapper.h @@ -1,124 +1,126 @@ #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 |