aboutsummaryrefslogtreecommitdiff
path: root/vmime-master
diff options
context:
space:
mode:
Diffstat (limited to 'vmime-master')
-rw-r--r--vmime-master/.gitignore41
-rw-r--r--vmime-master/.travis.yml37
-rw-r--r--vmime-master/AUTHORS38
-rw-r--r--vmime-master/CMakeLists.txt1038
-rw-r--r--vmime-master/COPYING674
-rw-r--r--vmime-master/COPYING.OpenSSL26
-rw-r--r--vmime-master/Doxyfile.in1043
-rw-r--r--vmime-master/HACKING360
-rw-r--r--vmime-master/NEWS0
-rw-r--r--vmime-master/README30
-rw-r--r--vmime-master/README.autotools13
-rwxr-xr-xvmime-master/build_for_losedows.sh23
-rw-r--r--vmime-master/cmake/FindCppUnit.cmake34
-rw-r--r--vmime-master/cmake/FindGSasl.cmake51
-rw-r--r--vmime-master/cmake/FindICU.cmake314
-rw-r--r--vmime-master/cmake/FindIconv.cmake61
-rw-r--r--vmime-master/cmake/Utils.cmake13
-rw-r--r--vmime-master/cmake/config.hpp.cmake97
-rw-r--r--vmime-master/config_header/config.hpp97
-rw-r--r--vmime-master/contrib/punycode/punycode.c264
-rw-r--r--vmime-master/contrib/punycode/punycode.h84
-rw-r--r--vmime-master/contrib/utf8/utf8.h34
-rw-r--r--vmime-master/contrib/utf8/utf8/checked.h327
-rw-r--r--vmime-master/contrib/utf8/utf8/core.h326
-rw-r--r--vmime-master/contrib/utf8/utf8/unchecked.h228
-rw-r--r--vmime-master/doc/book/.gitignore17
-rw-r--r--vmime-master/doc/book/basics.tex823
-rw-r--r--vmime-master/doc/book/book.tex118
-rw-r--r--vmime-master/doc/book/building.tex175
-rw-r--r--vmime-master/doc/book/images/address-mailbox-mailboxgroup.svg355
-rw-r--r--vmime-master/doc/book/images/message-body-header.svg716
-rw-r--r--vmime-master/doc/book/images/messaging-services.svg617
-rw-r--r--vmime-master/doc/book/intro.tex90
-rw-r--r--vmime-master/doc/book/msg.tex430
-rw-r--r--vmime-master/doc/book/net.tex1203
-rw-r--r--vmime-master/doc/book/start.tex111
-rw-r--r--vmime-master/examples/CMakeLists.txt38
-rw-r--r--vmime-master/examples/example1.cpp107
-rw-r--r--vmime-master/examples/example2.cpp121
-rw-r--r--vmime-master/examples/example3.cpp153
-rw-r--r--vmime-master/examples/example4.cpp108
-rw-r--r--vmime-master/examples/example5.cpp85
-rw-r--r--vmime-master/examples/example6.cpp938
-rw-r--r--vmime-master/examples/example6_authenticator.hpp112
-rw-r--r--vmime-master/examples/example6_certificateVerifier.hpp64
-rw-r--r--vmime-master/examples/example6_timeoutHandler.hpp60
-rw-r--r--vmime-master/examples/example6_tracer.hpp59
-rw-r--r--vmime-master/examples/example7.cpp118
-rw-r--r--vmime-master/examples/viewer/CMakeLists.txt31
-rw-r--r--vmime-master/examples/viewer/viewer.cpp294
-rw-r--r--vmime-master/mingw_cross_toolchain.cmake14
-rw-r--r--vmime-master/src/vmime/address.cpp236
-rw-r--r--vmime-master/src/vmime/address.hpp89
-rw-r--r--vmime-master/src/vmime/addressList.cpp328
-rw-r--r--vmime-master/src/vmime/addressList.hpp198
-rw-r--r--vmime-master/src/vmime/attachment.hpp116
-rw-r--r--vmime-master/src/vmime/attachmentHelper.cpp339
-rw-r--r--vmime-master/src/vmime/attachmentHelper.hpp137
-rw-r--r--vmime-master/src/vmime/base.cpp158
-rw-r--r--vmime-master/src/vmime/base.hpp258
-rw-r--r--vmime-master/src/vmime/body.cpp1111
-rw-r--r--vmime-master/src/vmime/body.hpp365
-rw-r--r--vmime-master/src/vmime/bodyPart.cpp198
-rw-r--r--vmime-master/src/vmime/bodyPart.hpp155
-rw-r--r--vmime-master/src/vmime/bodyPartAttachment.cpp147
-rw-r--r--vmime-master/src/vmime/bodyPartAttachment.hpp76
-rw-r--r--vmime-master/src/vmime/charset.cpp268
-rw-r--r--vmime-master/src/vmime/charset.hpp176
-rw-r--r--vmime-master/src/vmime/charsetConverter.cpp53
-rw-r--r--vmime-master/src/vmime/charsetConverter.hpp162
-rw-r--r--vmime-master/src/vmime/charsetConverterOptions.cpp37
-rw-r--r--vmime-master/src/vmime/charsetConverterOptions.hpp59
-rw-r--r--vmime-master/src/vmime/charsetConverter_iconv.cpp537
-rw-r--r--vmime-master/src/vmime/charsetConverter_iconv.hpp145
-rw-r--r--vmime-master/src/vmime/charsetConverter_icu.cpp572
-rw-r--r--vmime-master/src/vmime/charsetConverter_icu.hpp137
-rw-r--r--vmime-master/src/vmime/charsetConverter_idna.cpp208
-rw-r--r--vmime-master/src/vmime/charsetConverter_idna.hpp74
-rw-r--r--vmime-master/src/vmime/charsetConverter_win.cpp227
-rw-r--r--vmime-master/src/vmime/charsetConverter_win.hpp91
-rw-r--r--vmime-master/src/vmime/component.cpp275
-rw-r--r--vmime-master/src/vmime/component.hpp265
-rw-r--r--vmime-master/src/vmime/constants.cpp251
-rw-r--r--vmime-master/src/vmime/constants.hpp272
-rw-r--r--vmime-master/src/vmime/contentDisposition.cpp144
-rw-r--r--vmime-master/src/vmime/contentDisposition.hpp99
-rw-r--r--vmime-master/src/vmime/contentDispositionField.cpp162
-rw-r--r--vmime-master/src/vmime/contentDispositionField.hpp146
-rw-r--r--vmime-master/src/vmime/contentHandler.cpp39
-rw-r--r--vmime-master/src/vmime/contentHandler.hpp147
-rw-r--r--vmime-master/src/vmime/contentTypeField.cpp114
-rw-r--r--vmime-master/src/vmime/contentTypeField.hpp113
-rw-r--r--vmime-master/src/vmime/context.cpp86
-rw-r--r--vmime-master/src/vmime/context.hpp120
-rw-r--r--vmime-master/src/vmime/dateTime.cpp925
-rw-r--r--vmime-master/src/vmime/dateTime.hpp275
-rw-r--r--vmime-master/src/vmime/defaultAttachment.cpp164
-rw-r--r--vmime-master/src/vmime/defaultAttachment.hpp99
-rw-r--r--vmime-master/src/vmime/disposition.cpp351
-rw-r--r--vmime-master/src/vmime/disposition.hpp163
-rw-r--r--vmime-master/src/vmime/emailAddress.cpp708
-rw-r--r--vmime-master/src/vmime/emailAddress.hpp135
-rw-r--r--vmime-master/src/vmime/emptyContentHandler.cpp126
-rw-r--r--vmime-master/src/vmime/emptyContentHandler.hpp80
-rw-r--r--vmime-master/src/vmime/encoding.cpp331
-rw-r--r--vmime-master/src/vmime/encoding.hpp180
-rw-r--r--vmime-master/src/vmime/exception.cpp735
-rw-r--r--vmime-master/src/vmime/exception.hpp865
-rw-r--r--vmime-master/src/vmime/export.hpp36
-rw-r--r--vmime-master/src/vmime/fileAttachment.cpp253
-rw-r--r--vmime-master/src/vmime/fileAttachment.hpp226
-rw-r--r--vmime-master/src/vmime/fileContentHandler.cpp94
-rw-r--r--vmime-master/src/vmime/fileContentHandler.hpp102
-rw-r--r--vmime-master/src/vmime/generatedMessageAttachment.cpp108
-rw-r--r--vmime-master/src/vmime/generatedMessageAttachment.hpp77
-rw-r--r--vmime-master/src/vmime/generationContext.cpp139
-rw-r--r--vmime-master/src/vmime/generationContext.hpp171
-rw-r--r--vmime-master/src/vmime/header.cpp417
-rw-r--r--vmime-master/src/vmime/header.hpp362
-rw-r--r--vmime-master/src/vmime/headerField.cpp374
-rw-r--r--vmime-master/src/vmime/headerField.hpp191
-rw-r--r--vmime-master/src/vmime/headerFieldFactory.cpp158
-rw-r--r--vmime-master/src/vmime/headerFieldFactory.hpp159
-rw-r--r--vmime-master/src/vmime/headerFieldValue.cpp43
-rw-r--r--vmime-master/src/vmime/headerFieldValue.hpp49
-rw-r--r--vmime-master/src/vmime/htmlTextPart.cpp568
-rw-r--r--vmime-master/src/vmime/htmlTextPart.hpp268
-rw-r--r--vmime-master/src/vmime/mailbox.cpp476
-rw-r--r--vmime-master/src/vmime/mailbox.hpp123
-rw-r--r--vmime-master/src/vmime/mailboxField.cpp96
-rw-r--r--vmime-master/src/vmime/mailboxField.hpp69
-rw-r--r--vmime-master/src/vmime/mailboxGroup.cpp406
-rw-r--r--vmime-master/src/vmime/mailboxGroup.hpp206
-rw-r--r--vmime-master/src/vmime/mailboxList.cpp252
-rw-r--r--vmime-master/src/vmime/mailboxList.hpp184
-rw-r--r--vmime-master/src/vmime/mdn/MDNHelper.cpp362
-rw-r--r--vmime-master/src/vmime/mdn/MDNHelper.hpp142
-rw-r--r--vmime-master/src/vmime/mdn/MDNInfos.cpp38
-rw-r--r--vmime-master/src/vmime/mdn/MDNInfos.hpp57
-rw-r--r--vmime-master/src/vmime/mdn/receivedMDNInfos.cpp140
-rw-r--r--vmime-master/src/vmime/mdn/receivedMDNInfos.hpp93
-rw-r--r--vmime-master/src/vmime/mdn/sendableMDNInfos.cpp72
-rw-r--r--vmime-master/src/vmime/mdn/sendableMDNInfos.hpp72
-rw-r--r--vmime-master/src/vmime/mediaType.cpp207
-rw-r--r--vmime-master/src/vmime/mediaType.hpp119
-rw-r--r--vmime-master/src/vmime/message.cpp49
-rw-r--r--vmime-master/src/vmime/message.hpp60
-rw-r--r--vmime-master/src/vmime/messageAttachment.hpp52
-rw-r--r--vmime-master/src/vmime/messageBuilder.cpp333
-rw-r--r--vmime-master/src/vmime/messageBuilder.hpp221
-rw-r--r--vmime-master/src/vmime/messageId.cpp329
-rw-r--r--vmime-master/src/vmime/messageId.hpp144
-rw-r--r--vmime-master/src/vmime/messageIdSequence.cpp277
-rw-r--r--vmime-master/src/vmime/messageIdSequence.hpp175
-rw-r--r--vmime-master/src/vmime/messageParser.cpp328
-rw-r--r--vmime-master/src/vmime/messageParser.hpp164
-rw-r--r--vmime-master/src/vmime/misc/importanceHelper.cpp163
-rw-r--r--vmime-master/src/vmime/misc/importanceHelper.hpp103
-rw-r--r--vmime-master/src/vmime/net/builtinServices.inl76
-rw-r--r--vmime-master/src/vmime/net/connectionInfos.hpp68
-rw-r--r--vmime-master/src/vmime/net/defaultConnectionInfos.cpp60
-rw-r--r--vmime-master/src/vmime/net/defaultConnectionInfos.hpp66
-rw-r--r--vmime-master/src/vmime/net/defaultTimeoutHandler.cpp78
-rw-r--r--vmime-master/src/vmime/net/defaultTimeoutHandler.hpp80
-rw-r--r--vmime-master/src/vmime/net/dsnAttributes.cpp71
-rw-r--r--vmime-master/src/vmime/net/dsnAttributes.hpp114
-rw-r--r--vmime-master/src/vmime/net/events.cpp180
-rw-r--r--vmime-master/src/vmime/net/events.hpp276
-rw-r--r--vmime-master/src/vmime/net/fetchAttributes.cpp98
-rw-r--r--vmime-master/src/vmime/net/fetchAttributes.hpp140
-rw-r--r--vmime-master/src/vmime/net/folder.cpp134
-rw-r--r--vmime-master/src/vmime/net/folder.hpp440
-rw-r--r--vmime-master/src/vmime/net/folderAttributes.cpp122
-rw-r--r--vmime-master/src/vmime/net/folderAttributes.hpp177
-rw-r--r--vmime-master/src/vmime/net/folderStatus.hpp73
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPCommand.cpp437
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPCommand.hpp124
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPConnection.cpp886
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPConnection.hpp172
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPFolder.cpp1622
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPFolder.hpp230
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPFolderStatus.cpp292
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPFolderStatus.hpp123
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPMessage.cpp760
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPMessage.hpp200
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPMessagePart.cpp225
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPMessagePart.hpp108
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPMessagePartContentHandler.cpp227
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPMessagePartContentHandler.hpp95
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPMessageStructure.cpp94
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPMessageStructure.hpp75
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPParser.hpp4986
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPSStore.cpp82
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPSStore.hpp70
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPServiceInfos.cpp135
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPServiceInfos.hpp89
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPStore.cpp287
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPStore.hpp124
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPTag.cpp148
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPTag.hpp85
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPUtils.cpp854
-rw-r--r--vmime-master/src/vmime/net/imap/IMAPUtils.hpp144
-rw-r--r--vmime-master/src/vmime/net/imap/imap.hpp35
-rw-r--r--vmime-master/src/vmime/net/maildir/format/courierMaildirFormat.cpp569
-rw-r--r--vmime-master/src/vmime/net/maildir/format/courierMaildirFormat.hpp127
-rw-r--r--vmime-master/src/vmime/net/maildir/format/kmailMaildirFormat.cpp337
-rw-r--r--vmime-master/src/vmime/net/maildir/format/kmailMaildirFormat.hpp115
-rw-r--r--vmime-master/src/vmime/net/maildir/maildir.hpp34
-rw-r--r--vmime-master/src/vmime/net/maildir/maildirFolder.cpp1365
-rw-r--r--vmime-master/src/vmime/net/maildir/maildirFolder.hpp211
-rw-r--r--vmime-master/src/vmime/net/maildir/maildirFolderStatus.cpp88
-rw-r--r--vmime-master/src/vmime/net/maildir/maildirFolderStatus.hpp75
-rw-r--r--vmime-master/src/vmime/net/maildir/maildirFormat.cpp104
-rw-r--r--vmime-master/src/vmime/net/maildir/maildirFormat.hpp192
-rw-r--r--vmime-master/src/vmime/net/maildir/maildirMessage.cpp410
-rw-r--r--vmime-master/src/vmime/net/maildir/maildirMessage.hpp137
-rw-r--r--vmime-master/src/vmime/net/maildir/maildirMessagePart.cpp178
-rw-r--r--vmime-master/src/vmime/net/maildir/maildirMessagePart.hpp106
-rw-r--r--vmime-master/src/vmime/net/maildir/maildirMessageStructure.cpp104
-rw-r--r--vmime-master/src/vmime/net/maildir/maildirMessageStructure.hpp82
-rw-r--r--vmime-master/src/vmime/net/maildir/maildirServiceInfos.cpp76
-rw-r--r--vmime-master/src/vmime/net/maildir/maildirServiceInfos.hpp69
-rw-r--r--vmime-master/src/vmime/net/maildir/maildirStore.cpp294
-rw-r--r--vmime-master/src/vmime/net/maildir/maildirStore.hpp123
-rw-r--r--vmime-master/src/vmime/net/maildir/maildirUtils.cpp288
-rw-r--r--vmime-master/src/vmime/net/maildir/maildirUtils.hpp160
-rw-r--r--vmime-master/src/vmime/net/message.cpp155
-rw-r--r--vmime-master/src/vmime/net/message.hpp369
-rw-r--r--vmime-master/src/vmime/net/messageSet.cpp430
-rw-r--r--vmime-master/src/vmime/net/messageSet.hpp358
-rw-r--r--vmime-master/src/vmime/net/pop3/POP3Command.cpp267
-rw-r--r--vmime-master/src/vmime/net/pop3/POP3Command.hpp123
-rw-r--r--vmime-master/src/vmime/net/pop3/POP3Connection.cpp737
-rw-r--r--vmime-master/src/vmime/net/pop3/POP3Connection.hpp132
-rw-r--r--vmime-master/src/vmime/net/pop3/POP3Folder.cpp822
-rw-r--r--vmime-master/src/vmime/net/pop3/POP3Folder.hpp179
-rw-r--r--vmime-master/src/vmime/net/pop3/POP3FolderStatus.cpp88
-rw-r--r--vmime-master/src/vmime/net/pop3/POP3FolderStatus.hpp75
-rw-r--r--vmime-master/src/vmime/net/pop3/POP3Message.cpp283
-rw-r--r--vmime-master/src/vmime/net/pop3/POP3Message.hpp124
-rw-r--r--vmime-master/src/vmime/net/pop3/POP3Response.cpp504
-rw-r--r--vmime-master/src/vmime/net/pop3/POP3Response.hpp194
-rw-r--r--vmime-master/src/vmime/net/pop3/POP3SStore.cpp82
-rw-r--r--vmime-master/src/vmime/net/pop3/POP3SStore.hpp74
-rw-r--r--vmime-master/src/vmime/net/pop3/POP3ServiceInfos.cpp142
-rw-r--r--vmime-master/src/vmime/net/pop3/POP3ServiceInfos.hpp91
-rw-r--r--vmime-master/src/vmime/net/pop3/POP3Store.cpp262
-rw-r--r--vmime-master/src/vmime/net/pop3/POP3Store.hpp120
-rw-r--r--vmime-master/src/vmime/net/pop3/POP3Utils.cpp135
-rw-r--r--vmime-master/src/vmime/net/pop3/POP3Utils.hpp92
-rw-r--r--vmime-master/src/vmime/net/pop3/pop3.hpp35
-rw-r--r--vmime-master/src/vmime/net/securedConnectionInfos.hpp55
-rw-r--r--vmime-master/src/vmime/net/sendmail/sendmail.hpp31
-rw-r--r--vmime-master/src/vmime/net/sendmail/sendmailServiceInfos.cpp77
-rw-r--r--vmime-master/src/vmime/net/sendmail/sendmailServiceInfos.hpp69
-rw-r--r--vmime-master/src/vmime/net/sendmail/sendmailTransport.cpp244
-rw-r--r--vmime-master/src/vmime/net/sendmail/sendmailTransport.hpp112
-rw-r--r--vmime-master/src/vmime/net/service.cpp170
-rw-r--r--vmime-master/src/vmime/net/service.hpp239
-rw-r--r--vmime-master/src/vmime/net/serviceFactory.cpp157
-rw-r--r--vmime-master/src/vmime/net/serviceFactory.hpp168
-rw-r--r--vmime-master/src/vmime/net/serviceInfos.cpp198
-rw-r--r--vmime-master/src/vmime/net/serviceInfos.hpp263
-rw-r--r--vmime-master/src/vmime/net/serviceRegistration.inl105
-rw-r--r--vmime-master/src/vmime/net/session.cpp188
-rw-r--r--vmime-master/src/vmime/net/session.hpp206
-rw-r--r--vmime-master/src/vmime/net/smtp/SMTPChunkingOutputStreamAdapter.cpp180
-rw-r--r--vmime-master/src/vmime/net/smtp/SMTPChunkingOutputStreamAdapter.hpp94
-rw-r--r--vmime-master/src/vmime/net/smtp/SMTPCommand.cpp258
-rw-r--r--vmime-master/src/vmime/net/smtp/SMTPCommand.hpp125
-rw-r--r--vmime-master/src/vmime/net/smtp/SMTPCommandSet.cpp160
-rw-r--r--vmime-master/src/vmime/net/smtp/SMTPCommandSet.hpp106
-rw-r--r--vmime-master/src/vmime/net/smtp/SMTPConnection.cpp714
-rw-r--r--vmime-master/src/vmime/net/smtp/SMTPConnection.hpp136
-rw-r--r--vmime-master/src/vmime/net/smtp/SMTPExceptions.cpp212
-rw-r--r--vmime-master/src/vmime/net/smtp/SMTPExceptions.hpp159
-rw-r--r--vmime-master/src/vmime/net/smtp/SMTPResponse.cpp366
-rw-r--r--vmime-master/src/vmime/net/smtp/SMTPResponse.hpp200
-rw-r--r--vmime-master/src/vmime/net/smtp/SMTPSTransport.cpp82
-rw-r--r--vmime-master/src/vmime/net/smtp/SMTPSTransport.hpp74
-rw-r--r--vmime-master/src/vmime/net/smtp/SMTPServiceInfos.cpp144
-rw-r--r--vmime-master/src/vmime/net/smtp/SMTPServiceInfos.hpp93
-rw-r--r--vmime-master/src/vmime/net/smtp/SMTPTransport.cpp502
-rw-r--r--vmime-master/src/vmime/net/smtp/SMTPTransport.hpp144
-rw-r--r--vmime-master/src/vmime/net/smtp/smtp.hpp33
-rw-r--r--vmime-master/src/vmime/net/socket.hpp223
-rw-r--r--vmime-master/src/vmime/net/store.cpp57
-rw-r--r--vmime-master/src/vmime/net/store.hpp115
-rw-r--r--vmime-master/src/vmime/net/timeoutHandler.hpp89
-rw-r--r--vmime-master/src/vmime/net/tls/TLSProperties.cpp44
-rw-r--r--vmime-master/src/vmime/net/tls/TLSProperties.hpp105
-rw-r--r--vmime-master/src/vmime/net/tls/TLSSecuredConnectionInfos.cpp77
-rw-r--r--vmime-master/src/vmime/net/tls/TLSSecuredConnectionInfos.hpp88
-rw-r--r--vmime-master/src/vmime/net/tls/TLSSession.cpp48
-rw-r--r--vmime-master/src/vmime/net/tls/TLSSession.hpp96
-rw-r--r--vmime-master/src/vmime/net/tls/TLSSocket.cpp44
-rw-r--r--vmime-master/src/vmime/net/tls/TLSSocket.hpp88
-rw-r--r--vmime-master/src/vmime/net/tls/gnutls/TLSProperties_GnuTLS.cpp113
-rw-r--r--vmime-master/src/vmime/net/tls/gnutls/TLSProperties_GnuTLS.hpp68
-rw-r--r--vmime-master/src/vmime/net/tls/gnutls/TLSSession_GnuTLS.cpp313
-rw-r--r--vmime-master/src/vmime/net/tls/gnutls/TLSSession_GnuTLS.hpp95
-rw-r--r--vmime-master/src/vmime/net/tls/gnutls/TLSSocket_GnuTLS.cpp548
-rw-r--r--vmime-master/src/vmime/net/tls/gnutls/TLSSocket_GnuTLS.hpp129
-rw-r--r--vmime-master/src/vmime/net/tls/openssl/OpenSSLInitializer.cpp169
-rw-r--r--vmime-master/src/vmime/net/tls/openssl/OpenSSLInitializer.hpp90
-rw-r--r--vmime-master/src/vmime/net/tls/openssl/TLSProperties_OpenSSL.cpp112
-rw-r--r--vmime-master/src/vmime/net/tls/openssl/TLSProperties_OpenSSL.hpp68
-rw-r--r--vmime-master/src/vmime/net/tls/openssl/TLSSession_OpenSSL.cpp147
-rw-r--r--vmime-master/src/vmime/net/tls/openssl/TLSSession_OpenSSL.hpp109
-rw-r--r--vmime-master/src/vmime/net/tls/openssl/TLSSocket_OpenSSL.cpp761
-rw-r--r--vmime-master/src/vmime/net/tls/openssl/TLSSocket_OpenSSL.hpp142
-rw-r--r--vmime-master/src/vmime/net/tracer.cpp74
-rw-r--r--vmime-master/src/vmime/net/tracer.hpp110
-rw-r--r--vmime-master/src/vmime/net/transport.cpp265
-rw-r--r--vmime-master/src/vmime/net/transport.hpp152
-rw-r--r--vmime-master/src/vmime/object.cpp52
-rw-r--r--vmime-master/src/vmime/object.hpp52
-rw-r--r--vmime-master/src/vmime/parameter.cpp665
-rw-r--r--vmime-master/src/vmime/parameter.hpp176
-rw-r--r--vmime-master/src/vmime/parameterizedHeaderField.cpp634
-rw-r--r--vmime-master/src/vmime/parameterizedHeaderField.hpp222
-rw-r--r--vmime-master/src/vmime/parsedMessageAttachment.cpp114
-rw-r--r--vmime-master/src/vmime/parsedMessageAttachment.hpp76
-rw-r--r--vmime-master/src/vmime/parserHelpers.hpp140
-rw-r--r--vmime-master/src/vmime/parsingContext.cpp64
-rw-r--r--vmime-master/src/vmime/parsingContext.hpp82
-rw-r--r--vmime-master/src/vmime/path.cpp206
-rw-r--r--vmime-master/src/vmime/path.hpp106
-rw-r--r--vmime-master/src/vmime/plainTextPart.cpp121
-rw-r--r--vmime-master/src/vmime/plainTextPart.hpp74
-rw-r--r--vmime-master/src/vmime/platform.cpp77
-rw-r--r--vmime-master/src/vmime/platform.hpp158
-rw-r--r--vmime-master/src/vmime/platforms/posix/posixChildProcess.cpp410
-rw-r--r--vmime-master/src/vmime/platforms/posix/posixChildProcess.hpp92
-rw-r--r--vmime-master/src/vmime/platforms/posix/posixCriticalSection.cpp67
-rw-r--r--vmime-master/src/vmime/platforms/posix/posixCriticalSection.hpp69
-rw-r--r--vmime-master/src/vmime/platforms/posix/posixFile.cpp715
-rw-r--r--vmime-master/src/vmime/platforms/posix/posixFile.hpp224
-rw-r--r--vmime-master/src/vmime/platforms/posix/posixHandler.cpp292
-rw-r--r--vmime-master/src/vmime/platforms/posix/posixHandler.hpp103
-rw-r--r--vmime-master/src/vmime/platforms/posix/posixSocket.cpp969
-rw-r--r--vmime-master/src/vmime/platforms/posix/posixSocket.hpp118
-rw-r--r--vmime-master/src/vmime/platforms/windows/windowsCodepages.hpp197
-rw-r--r--vmime-master/src/vmime/platforms/windows/windowsCriticalSection.cpp67
-rw-r--r--vmime-master/src/vmime/platforms/windows/windowsCriticalSection.hpp68
-rw-r--r--vmime-master/src/vmime/platforms/windows/windowsFile.cpp712
-rw-r--r--vmime-master/src/vmime/platforms/windows/windowsFile.hpp225
-rw-r--r--vmime-master/src/vmime/platforms/windows/windowsHandler.cpp315
-rw-r--r--vmime-master/src/vmime/platforms/windows/windowsHandler.hpp101
-rw-r--r--vmime-master/src/vmime/platforms/windows/windowsSocket.cpp547
-rw-r--r--vmime-master/src/vmime/platforms/windows/windowsSocket.hpp117
-rw-r--r--vmime-master/src/vmime/propertySet.cpp399
-rw-r--r--vmime-master/src/vmime/propertySet.hpp461
-rw-r--r--vmime-master/src/vmime/relay.cpp363
-rw-r--r--vmime-master/src/vmime/relay.hpp108
-rw-r--r--vmime-master/src/vmime/security/authenticator.hpp136
-rw-r--r--vmime-master/src/vmime/security/cert/X509Certificate.cpp72
-rw-r--r--vmime-master/src/vmime/security/cert/X509Certificate.hpp197
-rw-r--r--vmime-master/src/vmime/security/cert/certificate.hpp84
-rw-r--r--vmime-master/src/vmime/security/cert/certificateChain.cpp53
-rw-r--r--vmime-master/src/vmime/security/cert/certificateChain.hpp79
-rw-r--r--vmime-master/src/vmime/security/cert/certificateException.cpp84
-rw-r--r--vmime-master/src/vmime/security/cert/certificateException.hpp95
-rw-r--r--vmime-master/src/vmime/security/cert/certificateExpiredException.cpp55
-rw-r--r--vmime-master/src/vmime/security/cert/certificateExpiredException.hpp65
-rw-r--r--vmime-master/src/vmime/security/cert/certificateIssuerVerificationException.cpp55
-rw-r--r--vmime-master/src/vmime/security/cert/certificateIssuerVerificationException.hpp65
-rw-r--r--vmime-master/src/vmime/security/cert/certificateNotTrustedException.cpp55
-rw-r--r--vmime-master/src/vmime/security/cert/certificateNotTrustedException.hpp65
-rw-r--r--vmime-master/src/vmime/security/cert/certificateNotYetValidException.cpp55
-rw-r--r--vmime-master/src/vmime/security/cert/certificateNotYetValidException.hpp65
-rw-r--r--vmime-master/src/vmime/security/cert/certificateVerifier.hpp76
-rw-r--r--vmime-master/src/vmime/security/cert/defaultCertificateVerifier.cpp191
-rw-r--r--vmime-master/src/vmime/security/cert/defaultCertificateVerifier.hpp98
-rw-r--r--vmime-master/src/vmime/security/cert/gnutls/X509Certificate_GnuTLS.cpp395
-rw-r--r--vmime-master/src/vmime/security/cert/gnutls/X509Certificate_GnuTLS.hpp96
-rw-r--r--vmime-master/src/vmime/security/cert/openssl/X509Certificate_OpenSSL.cpp655
-rw-r--r--vmime-master/src/vmime/security/cert/openssl/X509Certificate_OpenSSL.hpp119
-rw-r--r--vmime-master/src/vmime/security/cert/serverIdentityException.cpp55
-rw-r--r--vmime-master/src/vmime/security/cert/serverIdentityException.hpp65
-rw-r--r--vmime-master/src/vmime/security/cert/unsupportedCertificateTypeException.cpp61
-rw-r--r--vmime-master/src/vmime/security/cert/unsupportedCertificateTypeException.hpp72
-rw-r--r--vmime-master/src/vmime/security/defaultAuthenticator.cpp130
-rw-r--r--vmime-master/src/vmime/security/defaultAuthenticator.hpp73
-rw-r--r--vmime-master/src/vmime/security/digest/md5/md5MessageDigest.cpp349
-rw-r--r--vmime-master/src/vmime/security/digest/md5/md5MessageDigest.hpp85
-rw-r--r--vmime-master/src/vmime/security/digest/messageDigest.cpp56
-rw-r--r--vmime-master/src/vmime/security/digest/messageDigest.hpp142
-rw-r--r--vmime-master/src/vmime/security/digest/messageDigestFactory.cpp81
-rw-r--r--vmime-master/src/vmime/security/digest/messageDigestFactory.hpp110
-rw-r--r--vmime-master/src/vmime/security/digest/sha1/sha1MessageDigest.cpp276
-rw-r--r--vmime-master/src/vmime/security/digest/sha1/sha1MessageDigest.hpp79
-rw-r--r--vmime-master/src/vmime/security/sasl/SASLAuthenticator.hpp96
-rw-r--r--vmime-master/src/vmime/security/sasl/SASLContext.cpp221
-rw-r--r--vmime-master/src/vmime/security/sasl/SASLContext.hpp136
-rw-r--r--vmime-master/src/vmime/security/sasl/SASLMechanism.hpp153
-rw-r--r--vmime-master/src/vmime/security/sasl/SASLMechanismFactory.cpp149
-rw-r--r--vmime-master/src/vmime/security/sasl/SASLMechanismFactory.hpp155
-rw-r--r--vmime-master/src/vmime/security/sasl/SASLSession.cpp221
-rw-r--r--vmime-master/src/vmime/security/sasl/SASLSession.hpp180
-rw-r--r--vmime-master/src/vmime/security/sasl/SASLSocket.cpp273
-rw-r--r--vmime-master/src/vmime/security/sasl/SASLSocket.hpp108
-rw-r--r--vmime-master/src/vmime/security/sasl/XOAuth2SASLAuthenticator.cpp99
-rw-r--r--vmime-master/src/vmime/security/sasl/XOAuth2SASLAuthenticator.hpp77
-rw-r--r--vmime-master/src/vmime/security/sasl/XOAuth2SASLMechanism.cpp155
-rw-r--r--vmime-master/src/vmime/security/sasl/XOAuth2SASLMechanism.hpp102
-rw-r--r--vmime-master/src/vmime/security/sasl/builtinSASLMechanism.cpp221
-rw-r--r--vmime-master/src/vmime/security/sasl/builtinSASLMechanism.hpp105
-rw-r--r--vmime-master/src/vmime/security/sasl/defaultSASLAuthenticator.cpp159
-rw-r--r--vmime-master/src/vmime/security/sasl/defaultSASLAuthenticator.hpp91
-rw-r--r--vmime-master/src/vmime/streamContentHandler.cpp257
-rw-r--r--vmime-master/src/vmime/streamContentHandler.hpp126
-rw-r--r--vmime-master/src/vmime/stringContentHandler.cpp228
-rw-r--r--vmime-master/src/vmime/stringContentHandler.hpp107
-rw-r--r--vmime-master/src/vmime/text.cpp536
-rw-r--r--vmime-master/src/vmime/text.hpp291
-rw-r--r--vmime-master/src/vmime/textPart.hpp117
-rw-r--r--vmime-master/src/vmime/textPartFactory.cpp68
-rw-r--r--vmime-master/src/vmime/textPartFactory.hpp77
-rw-r--r--vmime-master/src/vmime/types.hpp87
-rw-r--r--vmime-master/src/vmime/utility/childProcess.hpp103
-rw-r--r--vmime-master/src/vmime/utility/datetimeUtils.cpp317
-rw-r--r--vmime-master/src/vmime/utility/datetimeUtils.hpp98
-rw-r--r--vmime-master/src/vmime/utility/encoder/b64Encoder.cpp350
-rw-r--r--vmime-master/src/vmime/utility/encoder/b64Encoder.hpp73
-rw-r--r--vmime-master/src/vmime/utility/encoder/binaryEncoder.cpp39
-rw-r--r--vmime-master/src/vmime/utility/encoder/binaryEncoder.hpp51
-rw-r--r--vmime-master/src/vmime/utility/encoder/eightBitEncoder.cpp39
-rw-r--r--vmime-master/src/vmime/utility/encoder/eightBitEncoder.hpp51
-rw-r--r--vmime-master/src/vmime/utility/encoder/encoder.cpp76
-rw-r--r--vmime-master/src/vmime/utility/encoder/encoder.hpp135
-rw-r--r--vmime-master/src/vmime/utility/encoder/encoderFactory.cpp149
-rw-r--r--vmime-master/src/vmime/utility/encoder/encoderFactory.hpp164
-rw-r--r--vmime-master/src/vmime/utility/encoder/noopEncoder.cpp94
-rw-r--r--vmime-master/src/vmime/utility/encoder/noopEncoder.hpp66
-rw-r--r--vmime-master/src/vmime/utility/encoder/qpEncoder.cpp568
-rw-r--r--vmime-master/src/vmime/utility/encoder/qpEncoder.hpp77
-rw-r--r--vmime-master/src/vmime/utility/encoder/sevenBitEncoder.cpp39
-rw-r--r--vmime-master/src/vmime/utility/encoder/sevenBitEncoder.hpp51
-rw-r--r--vmime-master/src/vmime/utility/encoder/uuEncoder.cpp358
-rw-r--r--vmime-master/src/vmime/utility/encoder/uuEncoder.hpp68
-rw-r--r--vmime-master/src/vmime/utility/file.hpp264
-rw-r--r--vmime-master/src/vmime/utility/filteredStream.cpp402
-rw-r--r--vmime-master/src/vmime/utility/filteredStream.hpp405
-rw-r--r--vmime-master/src/vmime/utility/inputStream.cpp33
-rw-r--r--vmime-master/src/vmime/utility/inputStream.hpp75
-rw-r--r--vmime-master/src/vmime/utility/inputStreamAdapter.cpp84
-rw-r--r--vmime-master/src/vmime/utility/inputStreamAdapter.hpp65
-rw-r--r--vmime-master/src/vmime/utility/inputStreamByteBufferAdapter.cpp104
-rw-r--r--vmime-master/src/vmime/utility/inputStreamByteBufferAdapter.hpp63
-rw-r--r--vmime-master/src/vmime/utility/inputStreamPointerAdapter.cpp48
-rw-r--r--vmime-master/src/vmime/utility/inputStreamPointerAdapter.hpp61
-rw-r--r--vmime-master/src/vmime/utility/inputStreamSocketAdapter.cpp79
-rw-r--r--vmime-master/src/vmime/utility/inputStreamSocketAdapter.hpp75
-rw-r--r--vmime-master/src/vmime/utility/inputStreamStringAdapter.cpp119
-rw-r--r--vmime-master/src/vmime/utility/inputStreamStringAdapter.hpp66
-rw-r--r--vmime-master/src/vmime/utility/outputStream.cpp44
-rw-r--r--vmime-master/src/vmime/utility/outputStream.hpp133
-rw-r--r--vmime-master/src/vmime/utility/outputStreamAdapter.cpp52
-rw-r--r--vmime-master/src/vmime/utility/outputStreamAdapter.hpp63
-rw-r--r--vmime-master/src/vmime/utility/outputStreamByteArrayAdapter.cpp50
-rw-r--r--vmime-master/src/vmime/utility/outputStreamByteArrayAdapter.hpp59
-rw-r--r--vmime-master/src/vmime/utility/outputStreamSocketAdapter.cpp65
-rw-r--r--vmime-master/src/vmime/utility/outputStreamSocketAdapter.hpp76
-rw-r--r--vmime-master/src/vmime/utility/outputStreamStringAdapter.cpp52
-rw-r--r--vmime-master/src/vmime/utility/outputStreamStringAdapter.hpp59
-rw-r--r--vmime-master/src/vmime/utility/parserInputStreamAdapter.cpp175
-rw-r--r--vmime-master/src/vmime/utility/parserInputStreamAdapter.hpp172
-rw-r--r--vmime-master/src/vmime/utility/path.cpp324
-rw-r--r--vmime-master/src/vmime/utility/path.hpp189
-rw-r--r--vmime-master/src/vmime/utility/progressListener.cpp78
-rw-r--r--vmime-master/src/vmime/utility/progressListener.hpp99
-rw-r--r--vmime-master/src/vmime/utility/random.cpp90
-rw-r--r--vmime-master/src/vmime/utility/random.hpp78
-rw-r--r--vmime-master/src/vmime/utility/seekableInputStream.hpp62
-rw-r--r--vmime-master/src/vmime/utility/seekableInputStreamRegionAdapter.cpp111
-rw-r--r--vmime-master/src/vmime/utility/seekableInputStreamRegionAdapter.hpp73
-rw-r--r--vmime-master/src/vmime/utility/stream.cpp39
-rw-r--r--vmime-master/src/vmime/utility/stream.hpp60
-rw-r--r--vmime-master/src/vmime/utility/streamUtils.cpp130
-rw-r--r--vmime-master/src/vmime/utility/streamUtils.hpp83
-rw-r--r--vmime-master/src/vmime/utility/stringUtils.cpp337
-rw-r--r--vmime-master/src/vmime/utility/stringUtils.hpp271
-rw-r--r--vmime-master/src/vmime/utility/sync/autoLock.hpp65
-rw-r--r--vmime-master/src/vmime/utility/sync/criticalSection.cpp44
-rw-r--r--vmime-master/src/vmime/utility/sync/criticalSection.hpp64
-rw-r--r--vmime-master/src/vmime/utility/url.cpp431
-rw-r--r--vmime-master/src/vmime/utility/url.hpp213
-rw-r--r--vmime-master/src/vmime/utility/urlUtils.cpp133
-rw-r--r--vmime-master/src/vmime/utility/urlUtils.hpp57
-rw-r--r--vmime-master/src/vmime/vmime.hpp160
-rw-r--r--vmime-master/src/vmime/word.cpp939
-rw-r--r--vmime-master/src/vmime/word.hpp272
-rw-r--r--vmime-master/src/vmime/wordEncoder.cpp320
-rw-r--r--vmime-master/src/vmime/wordEncoder.hpp118
-rwxr-xr-xvmime-master/test-outsourced-build.sh12
-rw-r--r--vmime-master/tests/misc/importanceHelperTest.cpp191
-rw-r--r--vmime-master/tests/net/folderAttributesTest.cpp137
-rw-r--r--vmime-master/tests/net/imap/IMAPCommandTest.cpp495
-rw-r--r--vmime-master/tests/net/imap/IMAPParserTest.cpp374
-rw-r--r--vmime-master/tests/net/imap/IMAPTagTest.cpp90
-rw-r--r--vmime-master/tests/net/imap/IMAPUtilsTest.cpp283
-rw-r--r--vmime-master/tests/net/maildir/maildirStoreTest.cpp584
-rw-r--r--vmime-master/tests/net/maildir/maildirUtilsTest.cpp54
-rw-r--r--vmime-master/tests/net/messageSetTest.cpp229
-rw-r--r--vmime-master/tests/net/pop3/POP3CommandTest.cpp241
-rw-r--r--vmime-master/tests/net/pop3/POP3ResponseTest.cpp244
-rw-r--r--vmime-master/tests/net/pop3/POP3StoreTest.cpp67
-rw-r--r--vmime-master/tests/net/pop3/POP3TestUtils.hpp69
-rw-r--r--vmime-master/tests/net/pop3/POP3UtilsTest.cpp88
-rw-r--r--vmime-master/tests/net/smtp/SMTPCommandSetTest.cpp181
-rw-r--r--vmime-master/tests/net/smtp/SMTPCommandTest.cpp252
-rw-r--r--vmime-master/tests/net/smtp/SMTPResponseTest.cpp238
-rw-r--r--vmime-master/tests/net/smtp/SMTPTransportTest.cpp324
-rw-r--r--vmime-master/tests/net/smtp/SMTPTransportTestUtils.hpp792
-rw-r--r--vmime-master/tests/parser/attachmentHelperTest.cpp335
-rw-r--r--vmime-master/tests/parser/bodyPartTest.cpp414
-rw-r--r--vmime-master/tests/parser/bodyTest.cpp79
-rw-r--r--vmime-master/tests/parser/charsetFilteredOutputStreamTest.cpp213
-rw-r--r--vmime-master/tests/parser/charsetTest.cpp252
-rw-r--r--vmime-master/tests/parser/charsetTestSuites.hpp102
-rw-r--r--vmime-master/tests/parser/datetimeTest.cpp123
-rw-r--r--vmime-master/tests/parser/dispositionTest.cpp150
-rw-r--r--vmime-master/tests/parser/emailAddressTest.cpp281
-rw-r--r--vmime-master/tests/parser/emptyContentHandlerTest.cpp99
-rw-r--r--vmime-master/tests/parser/fileContentHandlerTest.cpp134
-rw-r--r--vmime-master/tests/parser/headerFieldTest.cpp112
-rw-r--r--vmime-master/tests/parser/headerTest.cpp375
-rw-r--r--vmime-master/tests/parser/htmlTextPartTest.cpp241
-rw-r--r--vmime-master/tests/parser/mailboxGroupTest.cpp107
-rw-r--r--vmime-master/tests/parser/mailboxListTest.cpp47
-rw-r--r--vmime-master/tests/parser/mailboxTest.cpp187
-rw-r--r--vmime-master/tests/parser/mediaTypeTest.cpp100
-rw-r--r--vmime-master/tests/parser/messageIdSequenceTest.cpp78
-rw-r--r--vmime-master/tests/parser/messageIdTest.cpp77
-rw-r--r--vmime-master/tests/parser/messageTest.cpp64
-rw-r--r--vmime-master/tests/parser/parameterTest.cpp722
-rw-r--r--vmime-master/tests/parser/pathTest.cpp102
-rw-r--r--vmime-master/tests/parser/streamContentHandlerTest.cpp194
-rw-r--r--vmime-master/tests/parser/stringContentHandlerTest.cpp165
-rw-r--r--vmime-master/tests/parser/textTest.cpp918
-rw-r--r--vmime-master/tests/parser/wordEncoderTest.cpp174
-rw-r--r--vmime-master/tests/security/digest/md5Test.cpp228
-rw-r--r--vmime-master/tests/security/digest/sha1Test.cpp119
-rw-r--r--vmime-master/tests/testRunner.cpp305
-rw-r--r--vmime-master/tests/testUtils.cpp404
-rw-r--r--vmime-master/tests/testUtils.hpp407
-rw-r--r--vmime-master/tests/utility/datetimeUtilsTest.cpp157
-rw-r--r--vmime-master/tests/utility/encoder/b64EncoderTest.cpp168
-rw-r--r--vmime-master/tests/utility/encoder/encoderFactoryTest.cpp63
-rw-r--r--vmime-master/tests/utility/encoder/encoderTestUtils.hpp82
-rw-r--r--vmime-master/tests/utility/encoder/qpEncoderTest.cpp275
-rw-r--r--vmime-master/tests/utility/filteredStreamTest.cpp341
-rw-r--r--vmime-master/tests/utility/outputStreamByteArrayAdapterTest.cpp82
-rw-r--r--vmime-master/tests/utility/outputStreamSocketAdapterTest.cpp87
-rw-r--r--vmime-master/tests/utility/outputStreamStringAdapterTest.cpp84
-rw-r--r--vmime-master/tests/utility/parserInputStreamAdapterTest.cpp51
-rw-r--r--vmime-master/tests/utility/pathTest.cpp356
-rw-r--r--vmime-master/tests/utility/seekableInputStreamRegionAdapterTest.cpp176
-rw-r--r--vmime-master/tests/utility/stringUtilsTest.cpp214
-rw-r--r--vmime-master/tests/utility/urlTest.cpp312
-rw-r--r--vmime-master/vmime.pc.in13
562 files changed, 116586 insertions, 0 deletions
diff --git a/vmime-master/.gitignore b/vmime-master/.gitignore
new file mode 100644
index 0000000..2262aac
--- /dev/null
+++ b/vmime-master/.gitignore
@@ -0,0 +1,41 @@
+*.o
+*.sw?
+*.a
+*.dSYM
+*.vim
+
+# Doxygen-generated
+doc/html/*
+
+# CMake-generated / Build files
+CMakeFiles/
+CMakeCache.txt
+/_CPack_Packages/
+cmake_install.cmake
+/CPackConfig.cmake
+/CPackSourceConfig.cmake
+/Doxyfile
+/Makefile
+/install_manifest*
+/libvmime.a
+/vmime.pc
+/src/vmime/config.hpp
+/src/vmime/export-static.hpp
+/src/vmime/export-shared.hpp
+/COPYING.txt
+build/
+Makefile
+export-shared.hpp
+export-static.hpp
+
+# Outsourced build test
+/_build/
+/_install/
+
+# CTest-generated files
+/CTestTestfile.cmake
+/Testing/
+
+# Mac
+._DS_Store
+
diff --git a/vmime-master/.travis.yml b/vmime-master/.travis.yml
new file mode 100644
index 0000000..eb3ada8
--- /dev/null
+++ b/vmime-master/.travis.yml
@@ -0,0 +1,37 @@
+# Travis-CI build file for VMime
+# See http://travis-ci.org for details
+
+language: cpp
+
+compiler:
+ - gcc
+ - clang
+
+# Settings
+env:
+ # -- default configuration (iconv + GnuTLS)
+ - CTEST_OUTPUT_ON_FAILURE=1 OPTIONS="-DVMIME_SENDMAIL_PATH=/path/to/sendmail -DCMAKE_BUILD_TYPE=Debug -DVMIME_BUILD_TESTS=ON -DVMIME_BUILD_SAMPLES=ON"
+ # -- ICU
+ - CTEST_OUTPUT_ON_FAILURE=1 OPTIONS="-DVMIME_SENDMAIL_PATH=/path/to/sendmail -DCMAKE_BUILD_TYPE=Debug -DVMIME_BUILD_TESTS=ON -DVMIME_BUILD_SAMPLES=ON -DVMIME_CHARSETCONV_LIB_IS_ICONV=OFF -DVMIME_CHARSETCONV_LIB_IS_ICU=ON"
+ # -- OpenSSL
+ - CTEST_OUTPUT_ON_FAILURE=1 OPTIONS="-DVMIME_SENDMAIL_PATH=/path/to/sendmail -DCMAKE_BUILD_TYPE=Debug -DVMIME_BUILD_TESTS=ON -DVMIME_BUILD_SAMPLES=ON -DVMIME_TLS_SUPPORT_LIB_IS_GNUTLS=OFF -DVMIME_TLS_SUPPORT_LIB_IS_OPENSSL=ON"
+
+# Make sure some required tools/libraries are installed
+install:
+ - sudo apt-get update >/dev/null
+ - sudo apt-get -q install cmake libcppunit-dev valgrind
+ - sudo apt-get -q install libgsasl7-dev libgnutls-dev libssl-dev libicu-dev libboost-dev
+ # -- for the samples
+ - sudo apt-get -q install libgtk-3-dev
+
+# Run the build script
+script:
+ - mkdir _build
+ - cd _build
+ - cmake .. -DCMAKE_INSTALL_PREFIX=../_install $OPTIONS
+ - cmake .. -L
+ - cat ./src/vmime/config.hpp
+ - cat ./src/vmime/export-shared.hpp
+ - cat ./src/vmime/export-static.hpp
+ - cmake --build . --target install
+ - ctest
diff --git a/vmime-master/AUTHORS b/vmime-master/AUTHORS
new file mode 100644
index 0000000..1ddeb3d
--- /dev/null
+++ b/vmime-master/AUTHORS
@@ -0,0 +1,38 @@
+
+VMIME AUTHOR
+============
+
+Vincent Richard <vincent@vmime.org>
+Project owner and creator. VMime was created in 1998, and publicly released
+under the GNU GPL license in 2003.
+
+
+VMIME CONTRIBUTORS
+==================
+
+VMime is Open Source software, you are free and welcome to contribute!
+
+If you have a patch and you want it to be included into official VMime
+release, you have to release your patch into the public domain or assign
+the copyright to "VMime authors". You will then be credited in this
+AUTHORS file.
+
+ - Stefan Uhrig <stefanuhrig@gmx.net>
+ - Rafael Fernandez <prf@adinet.com.uy>
+ - Xin Li <lixin3@staff.sina.com.cn>
+ - Benjamin Biron <benbiron@gmail.com>
+ - Bertrand Benoit <projettwk@users.sourceforge.net>
+ - Tim Teulings <rael@edge.ping.de>
+ - Georg Sauthoff <gsauthof@techfak.uni-bielefeld.de>
+ - Pierre Thierry <nowhere.man@levallois.eu.org> (patches for STL algorithms)
+ - Zarafa <http://developer.zarafa.com/VmimePatches>
+ - Bartek Szurgot <vempirelord@wp.pl, http://baszerr.org>
+ - Achim Brandt <http://sourceforge.net/users/a-brandt/>
+ - Mehmet Bozkurt <mehmet.bozkurt78@gmail.com> (OpenSSL support, ICU support)
+ - Anthony Dervish <antmd@mac.com>
+
+Please apologize if I have forgotten someone here. ;) Send me an email
+to <vincent@vmime.org> if you want your name to be listed.
+
+See Changelogs for full list.
+
diff --git a/vmime-master/CMakeLists.txt b/vmime-master/CMakeLists.txt
new file mode 100644
index 0000000..6206e6f
--- /dev/null
+++ b/vmime-master/CMakeLists.txt
@@ -0,0 +1,1038 @@
+#
+# CMake configuration file for VMime
+#
+# Usage:
+#
+# . 'cmake -LH' to list build settings variable
+#
+# . 'cmake -G <generator>' to generate makefiles for a build system
+# eg. cmake -G "Unix Makefiles"
+#
+# For more information, please visit:
+# http://www.cmake.org
+#
+
+CMAKE_MINIMUM_REQUIRED(VERSION 3.1 FATAL_ERROR)
+
+INCLUDE(cmake/Utils.cmake)
+
+INCLUDE(CheckIncludeFiles)
+INCLUDE(CheckIncludeFileCXX)
+INCLUDE(CheckFunctionExists)
+INCLUDE(CheckSymbolExists)
+INCLUDE(CheckTypeSize)
+INCLUDE(CheckLibraryExists)
+INCLUDE(CheckCXXSourceCompiles)
+INCLUDE(GNUInstallDirs)
+
+
+# CMake configuration
+SET(CMAKE_RUNTIME_OUTPUT_DIRECTORY build/bin)
+SET(CMAKE_LIBRARY_OUTPUT_DIRECTORY build/lib)
+SET(CMAKE_ARCHIVE_OUTPUT_DIRECTORY build/lib)
+
+SET(CMAKE_VERBOSE_MAKEFILE ON)
+
+
+# Package version number
+SET(VMIME_VERSION_MAJOR 0)
+SET(VMIME_VERSION_MINOR 9)
+SET(VMIME_VERSION_MICRO 2)
+
+# API version number (libtool)
+#
+# Increment this number only immediately before a public release.
+# This is independent from package version number.
+#
+# See: http://semver.org/
+#
+# . Implementation changed (eg. bug/security fix): REVISION++
+# . Interfaces added/removed/changed: CURRENT++, REVISION=0
+# . Interfaces added (upward-compatible changes): AGE++
+# . Interfaces removed: AGE=0
+SET(VMIME_API_VERSION_CURRENT 1)
+SET(VMIME_API_VERSION_REVISION 0)
+SET(VMIME_API_VERSION_AGE 0)
+
+
+SET(VMIME_VERSION ${VMIME_VERSION_MAJOR}.${VMIME_VERSION_MINOR}.${VMIME_VERSION_MICRO})
+SET(VMIME_API_VERSION ${VMIME_API_VERSION_CURRENT}.${VMIME_API_VERSION_REVISION}.${VMIME_API_VERSION_AGE})
+
+
+##############################################################################
+# VMime Library
+
+# Project
+PROJECT(
+ vmime
+ LANGUAGES CXX C
+ VERSION ${VMIME_VERSION}
+)
+
+# Set base name
+SET(VMIME_LIBRARY_NAME vmime)
+SET(VMIME_LIBRARY_VENDOR Kisli)
+
+# Enable C++11
+SET(CMAKE_CXX_STANDARD 11)
+SET(CMAKE_CXX_STANDARD_REQUIRED ON)
+SET(CMAKE_CXX_EXTENSIONS OFF)
+
+# Source files
+FILE(
+ GLOB_RECURSE
+ VMIME_LIBRARY_SRC_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/vmime/*.cpp
+)
+
+FILE(
+ GLOB_RECURSE
+ VMIME_LIBRARY_INCLUDE_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/src/vmime/*.hpp
+)
+
+LIST(APPEND VMIME_LIBRARY_GENERATED_INCLUDE_FILES "${CMAKE_BINARY_DIR}/src/vmime/config.hpp")
+
+INCLUDE_DIRECTORIES(
+ ${CMAKE_CURRENT_SOURCE_DIR} # for "contrib/"
+ ${CMAKE_CURRENT_SOURCE_DIR}/src # for "vmime/
+ ${CMAKE_BINARY_DIR}/src # for "config.hpp"
+ ${CMAKE_BINARY_DIR}/src/vmime # for "config.hpp"
+)
+
+INCLUDE(GenerateExportHeader)
+ADD_COMPILER_EXPORT_FLAGS()
+
+# Shared library
+OPTION(
+ VMIME_BUILD_SHARED_LIBRARY
+ "Build shared library"
+ ON
+)
+
+IF(VMIME_BUILD_SHARED_LIBRARY)
+
+ ADD_LIBRARY(
+ ${VMIME_LIBRARY_NAME}
+ SHARED
+ ${VMIME_LIBRARY_SRC_FILES}
+ ${VMIME_LIBRARY_INCLUDE_FILES}
+ )
+
+ TARGET_INCLUDE_DIRECTORIES(${VMIME_LIBRARY_NAME} PUBLIC
+ $<INSTALL_INTERFACE:include>
+ )
+
+ GENERATE_EXPORT_HEADER(
+ ${VMIME_LIBRARY_NAME}
+ BASE_NAME VMIME
+ STATIC_DEFINE VMIME_STATIC
+ EXPORT_FILE_NAME export-shared.hpp
+ )
+
+ FILE(
+ COPY
+ ${CMAKE_CURRENT_BINARY_DIR}/export-shared.hpp
+ DESTINATION
+ ${CMAKE_BINARY_DIR}/src/vmime
+ )
+
+ LIST(APPEND VMIME_LIBRARY_GENERATED_INCLUDE_FILES "${CMAKE_BINARY_DIR}/src/vmime/export-shared.hpp")
+
+ SET_TARGET_PROPERTIES(
+ ${VMIME_LIBRARY_NAME}
+ PROPERTIES
+ VERSION "${VMIME_API_VERSION}"
+ SOVERSION "${VMIME_API_VERSION_CURRENT}"
+ COMPILE_FLAGS -DVMIME_SHARED
+ )
+
+ENDIF()
+
+# Static library
+#
+# Note: cannot have two targets with the same name so the static version has
+# '-static' appended and then the name of the output file is set separately.
+OPTION(
+ VMIME_BUILD_STATIC_LIBRARY
+ "Build static library"
+ ON
+)
+
+IF(VMIME_BUILD_STATIC_LIBRARY)
+
+ ADD_LIBRARY(
+ ${VMIME_LIBRARY_NAME}-static
+ STATIC
+ ${VMIME_LIBRARY_SRC_FILES}
+ ${VMIME_LIBRARY_INCLUDE_FILES}
+ )
+
+ TARGET_INCLUDE_DIRECTORIES(${VMIME_LIBRARY_NAME}-static PUBLIC
+ $<INSTALL_INTERFACE:include>
+ )
+
+ GENERATE_EXPORT_HEADER(
+ ${VMIME_LIBRARY_NAME}-static
+ BASE_NAME VMIME
+ STATIC_DEFINE VMIME_STATIC
+ EXPORT_FILE_NAME export-static.hpp
+ )
+
+ FILE(
+ COPY
+ ${CMAKE_CURRENT_BINARY_DIR}/export-static.hpp
+ DESTINATION
+ ${CMAKE_BINARY_DIR}/src/vmime
+ )
+
+ LIST(APPEND VMIME_LIBRARY_GENERATED_INCLUDE_FILES "${CMAKE_BINARY_DIR}/src/vmime/export-static.hpp")
+
+ SET_TARGET_PROPERTIES(
+ ${VMIME_LIBRARY_NAME}-static
+ PROPERTIES
+ OUTPUT_NAME ${VMIME_LIBRARY_NAME}
+ COMPILE_FLAGS -DVMIME_STATIC
+ )
+
+ENDIF()
+
+# Ensure at least one type of library (either shared or static) is build
+IF(NOT(VMIME_BUILD_SHARED_LIBRARY OR VMIME_BUILD_STATIC_LIBRARY))
+ MESSAGE(FATAL_ERROR "You should select at least one library to build (either VMIME_BUILD_SHARED_LIBRARY or VMIME_BUILD_STATIC_LIBRARY must be set to YES.")
+ENDIF()
+
+# These next two lines are required but it is unclear exactly what they do.
+# The CMake FAQ mentions they are necessary and it does not work otherwise.
+IF(VMIME_BUILD_SHARED_LIBRARY)
+ SET_TARGET_PROPERTIES(${VMIME_LIBRARY_NAME} PROPERTIES CLEAN_DIRECT_OUTPUT 1)
+ENDIF()
+IF(VMIME_BUILD_STATIC_LIBRARY)
+ SET_TARGET_PROPERTIES(${VMIME_LIBRARY_NAME}-static PROPERTIES CLEAN_DIRECT_OUTPUT 1)
+ENDIF()
+
+SET(CMAKE_INSTALL_LIBDIR lib CACHE PATH "Output directory for libraries")
+
+# Installation of libraries
+IF(VMIME_BUILD_SHARED_LIBRARY)
+ INSTALL(
+ TARGETS ${VMIME_LIBRARY_NAME}
+ EXPORT ${VMIME_LIBRARY_NAME}-config
+ LIBRARY DESTINATION "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}" COMPONENT sharedlibs
+ ARCHIVE DESTINATION "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}" COMPONENT sharedlibs
+ )
+ENDIF()
+
+IF(VMIME_BUILD_STATIC_LIBRARY)
+ INSTALL(
+ TARGETS ${VMIME_LIBRARY_NAME}-static
+ EXPORT ${VMIME_LIBRARY_NAME}-config
+ LIBRARY DESTINATION "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}" COMPONENT staticlibs
+ ARCHIVE DESTINATION "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}" COMPONENT staticlibs
+ )
+ENDIF()
+
+# Installation of header files
+INSTALL_HEADERS_WITH_DIRECTORY(VMIME_LIBRARY_INCLUDE_FILES headers "${CMAKE_CURRENT_SOURCE_DIR}/src/")
+INSTALL_HEADERS_WITH_DIRECTORY(VMIME_LIBRARY_GENERATED_INCLUDE_FILES headers "${CMAKE_BINARY_DIR}/src")
+
+#INSTALL(
+# FILES ${VMIME_LIBRARY_INCLUDE_FILES}
+# DESTINATION include
+# COMPONENT headers
+#)
+
+install(EXPORT ${VMIME_LIBRARY_NAME}-config DESTINATION cmake)
+
+
+##############################################################################
+# Tests
+
+OPTION(
+ VMIME_BUILD_TESTS
+ "Build unit tests (this will create a 'run-tests' binary)"
+ OFF
+)
+
+IF(VMIME_BUILD_TESTS)
+
+ ENABLE_TESTING()
+
+ INCLUDE(cmake/FindCppUnit.cmake)
+ INCLUDE_DIRECTORIES(${CPPUNIT_INCLUDE_DIR})
+
+ FILE(
+ GLOB_RECURSE
+ VMIME_TESTS_SRC_FILES
+ ${CMAKE_CURRENT_SOURCE_DIR}/tests/*Test.cpp
+ )
+
+ ADD_LIBRARY(
+ test-runner
+ ${CMAKE_CURRENT_SOURCE_DIR}/tests/testRunner.cpp ${CMAKE_CURRENT_SOURCE_DIR}/tests/testUtils.cpp
+ )
+
+ # Build one file for each test
+ FOREACH(VMIME_TEST_SRC_FILE ${VMIME_TESTS_SRC_FILES})
+
+ # "/path/to/vmime/tests/module/testFile.cpp" --> "module_testFile"
+ GET_FILENAME_COMPONENT(VMIME_TEST_SRC_PATH "${VMIME_TEST_SRC_FILE}" PATH)
+ STRING(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}" "" VMIME_TEST_SRC_PATH "${VMIME_TEST_SRC_PATH}")
+ GET_FILENAME_COMPONENT(VMIME_TEST_NAME "${VMIME_TEST_SRC_FILE}" NAME_WE)
+ SET(VMIME_TEST_NAME "${VMIME_TEST_SRC_PATH}/${VMIME_TEST_NAME}")
+ STRING(REPLACE "/" "_" VMIME_TEST_NAME "${VMIME_TEST_NAME}")
+ STRING(REPLACE "_tests_" "" VMIME_TEST_NAME "${VMIME_TEST_NAME}")
+
+ ADD_EXECUTABLE(
+ ${VMIME_TEST_NAME}
+ ${VMIME_TEST_SRC_FILE}
+ )
+
+ TARGET_LINK_LIBRARIES(
+ ${VMIME_TEST_NAME}
+ ${VMIME_LIBRARY_NAME}
+ ${CPPUNIT_LIBRARY} test-runner
+ )
+
+ ADD_DEPENDENCIES(
+ ${VMIME_TEST_NAME}
+ ${VMIME_LIBRARY_NAME}
+ )
+
+ ADD_TEST(
+ ${VMIME_TEST_NAME}
+ ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${VMIME_TEST_NAME}
+ )
+
+ ENDFOREACH()
+
+ # Build one file for all tests
+ ADD_EXECUTABLE(
+ "run-tests"
+ ${VMIME_TESTS_SRC_FILES}
+ )
+
+ TARGET_LINK_LIBRARIES(
+ "run-tests"
+ ${VMIME_LIBRARY_NAME}
+ ${CPPUNIT_LIBRARY} test-runner
+ )
+
+ ADD_DEPENDENCIES(
+ "run-tests"
+ ${VMIME_LIBRARY_NAME}
+ )
+
+ENDIF()
+
+
+##############################################################################
+# Examples
+
+OPTION(
+ VMIME_BUILD_SAMPLES
+ "Build samples (in 'examples' directory)"
+ OFF
+)
+
+
+##############################################################################
+# Packaging / Distribution
+
+# Package information
+SET(VMIME_PACKAGE_NAME ${VMIME_LIBRARY_NAME})
+SET(VMIME_PACKAGE_VENDOR ${VMIME_LIBRARY_VENDOR})
+SET(VMIME_PACKAGE_VERSION ${VMIME_VERSION})
+SET(VMIME_PACKAGE_CONTACT "Vincent Richard <vincent@vmime.org>")
+SET(VMIME_PACKAGE_DESCRIPTION "VMime C++ Mail Library (http://www.vmime.org)")
+SET(VMIME_PACKAGE_HOMEPAGE_URL "https://www.vmime.org")
+
+SET(CPACK_PACKAGE_NAME "${VMIME_PACKAGE_NAME}")
+SET(CPACK_PACKAGE_VENDOR "${VMIME_PACKAGE_VENDOR}")
+SET(CPACK_PACKAGE_CONTACT "${VMIME_PACKAGE_CONTACT}")
+SET(CPACK_PACKAGE_DESCRIPTION "${VMIME_PACKAGE_DESCRIPTION}")
+SET(CPACK_PACKAGE_DESCRIPTION_SUMMARY "${CPACK_PACKAGE_DESCRIPTION}")
+SET(CPACK_PACKAGE_HOMEPAGE_URL "${VMIME_PACKAGE_HOMEPAGE_URL}")
+SET(CPACK_PACKAGE_VERSION "${VMIME_PACKAGE_VERSION}")
+
+# Package settings
+IF(APPLE)
+ # CPack/PackageManager won't allow file without recognized extension
+ # to be used as license file.
+ CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/COPYING" "${CMAKE_BINARY_DIR}/COPYING.txt" COPYONLY)
+ SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_BINARY_DIR}/COPYING.txt")
+ CONFIGURE_FILE("${CMAKE_CURRENT_SOURCE_DIR}/README" "${CMAKE_BINARY_DIR}/README.txt" COPYONLY)
+ SET(CPACK_RESOURCE_FILE_README "${CMAKE_BINARY_DIR}/README.txt")
+ELSE()
+ SET(CPACK_RESOURCE_FILE_LICENSE "${CMAKE_CURRENT_SOURCE_DIR}/COPYING")
+ SET(CPACK_RESOURCE_FILE_README "${CMAKE_CURRENT_SOURCE_DIR}/README")
+ENDIF(APPLE)
+
+SET(CPACK_SOURCE_GENERATOR TGZ)
+SET(CPACK_SOURCE_IGNORE_FILES "\\\\.git;~$;build/")
+SET(CPACK_SOURCE_PACKAGE_FILE_NAME ${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION})
+
+# Set components
+SET(CPACK_COMPONENTS_ALL sharedlibs staticlibs headers)
+
+SET(CPACK_COMPONENT_SHAREDLIBS_DISPLAY_NAME "Shared libraries")
+SET(CPACK_COMPONENT_SHAREDLIBS_DESCRIPTION
+ "Shared library for general use.")
+
+SET(CPACK_COMPONENT_STATICLIBS_DISPLAY_NAME "Static libraries")
+SET(CPACK_COMPONENT_STATICLIBS_DESCRIPTION
+ "Static library, good if you want to embed VMime in your application.")
+
+SET(CPACK_COMPONENT_HEADERS_DISPLAY_NAME "C++ Headers")
+SET(CPACK_COMPONENT_HEADERS_DESCRIPTION
+ "C/C++ header files.")
+
+SET(CPACK_COMPONENT_SHAREDLIBS_GROUP "Development")
+SET(CPACK_COMPONENT_STATICLIBS_GROUP "Development")
+SET(CPACK_COMPONENT_HEADERS_GROUP "Development")
+SET(CPACK_COMPONENT_GROUP_DEVELOPMENT_DESCRIPTION "")
+
+# Make a target "dist" to generate tarball
+SET(ARCHIVE_NAME ${CPACK_PACKAGE_NAME}-${CPACK_PACKAGE_VERSION})
+
+ADD_CUSTOM_TARGET(
+ dist
+ COMMAND git archive --prefix=${ARCHIVE_NAME}/ HEAD
+ | bzip2 > ${CMAKE_BINARY_DIR}/${ARCHIVE_NAME}.tar.bz2
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+)
+
+# PkgConfig
+SET(prefix ${CMAKE_INSTALL_PREFIX})
+SET(exec_prefix ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_BINDIR})
+SET(includedir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_INCLUDEDIR}/vmime)
+SET(libdir ${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR})
+
+SET(VMIME_PKGCONFIG_LIBS "")
+SET(VMIME_PKGCONFIG_CFLAGS "")
+SET(VMIME_PKGCONFIG_REQUIRES "")
+
+
+##############################################################################
+# Build type
+
+IF(NOT CMAKE_BUILD_TYPE)
+ SET(
+ CMAKE_BUILD_TYPE
+ "Debug"
+ CACHE STRING
+ "Choose the type of build, options are: None Debug Release RelWithDebInfo MinSizeRel."
+ FORCE
+ )
+ENDIF(NOT CMAKE_BUILD_TYPE)
+
+# Set a default build type for single-configuration
+# CMake generators if no build type is set.
+IF(NOT CMAKE_CONFIGURATION_TYPES AND NOT CMAKE_BUILD_TYPE)
+ SET(CMAKE_BUILD_TYPE Debug)
+ENDIF()
+
+# Debug build
+MESSAGE("-- Build type: ${CMAKE_BUILD_TYPE}")
+IF(${CMAKE_BUILD_TYPE} STREQUAL Debug)
+ ADD_DEFINITIONS(-DDEBUG)
+ENDIF(${CMAKE_BUILD_TYPE} STREQUAL Debug)
+
+
+IF(CMAKE_BUILD_TYPE STREQUAL "Debug")
+ SET(VMIME_DEBUG 1)
+ELSE()
+ SET(VMIME_DEBUG 0)
+ENDIF()
+
+
+##############################################################################
+# Test endianness and basic type sizes
+
+INCLUDE(TestBigEndian)
+TEST_BIG_ENDIAN(BIGENDIAN)
+
+IF(BIGENDIAN EQUAL 0)
+ set(VMIME_BYTE_ORDER_BIG_ENDIAN 0)
+ set(VMIME_BYTE_ORDER_LITTLE_ENDIAN 1)
+ELSE(BIGENDIAN EQUAL 0)
+ SET(VMIME_BYTE_ORDER_BIG_ENDIAN 1)
+ SET(VMIME_BYTE_ORDER_LITTLE_ENDIAN 0)
+ENDIF(BIGENDIAN EQUAL 0)
+
+
+CHECK_INCLUDE_FILE_CXX(cstdint VMIME_HAVE_CSTDINT)
+
+CHECK_TYPE_SIZE("char" SIZEOF_CHAR)
+CHECK_TYPE_SIZE("short" SIZEOF_SHORT)
+CHECK_TYPE_SIZE("int" SIZEOF_INT)
+CHECK_TYPE_SIZE("long" SIZEOF_LONG)
+CHECK_TYPE_SIZE("long long" SIZEOF_LONG_LONG)
+CHECK_TYPE_SIZE("__int64" SIZEOF___INT64)
+
+SET(CMAKE_EXTRA_INCLUDE_FILES cstdint)
+CHECK_TYPE_SIZE("int64_t" SIZEOF_INT64_T)
+SET(CMAKE_EXTRA_INCLUDE_FILES)
+
+
+IF(SIZEOF_CHAR EQUAL 1)
+ SET(VMIME_8BIT_TYPE "char")
+ELSE()
+ MESSAGE(FATAL_ERROR "Cannot determine 8-bit type")
+ENDIF()
+
+IF(SIZEOF_INT EQUAL 2)
+ SET(VMIME_16BIT_TYPE "int")
+ELSE()
+ IF(SIZEOF_SHORT EQUAL 2)
+ SET(VMIME_16BIT_TYPE "short")
+ ELSE()
+ MESSAGE(FATAL_ERROR "Cannot determine 16-bit type")
+ ENDIF()
+ENDIF()
+
+IF(SIZEOF_INT EQUAL 4)
+ SET(VMIME_32BIT_TYPE "int")
+ELSE()
+ IF(SIZEOF_LONG EQUAL 4)
+ SET(VMIME_32BIT_TYPE "long")
+ ELSE()
+ IF(SIZEOF_LONG_LONG EQUAL 4)
+ SET(VMIME_32BIT_TYPE "long long")
+ ELSE()
+ MESSAGE(FATAL_ERROR "Cannot determine 32-bit type")
+ ENDIF()
+ ENDIF()
+ENDIF()
+
+IF(SIZEOF_INT EQUAL 8)
+ SET(VMIME_64BIT_TYPE "int")
+ELSE()
+ IF(SIZEOF_LONG EQUAL 8)
+ SET(VMIME_64BIT_TYPE "long")
+ ELSE()
+ IF(SIZEOF_LONG_LONG EQUAL 8)
+ SET(VMIME_64BIT_TYPE "long long")
+ ELSE()
+ IF(SIZEOF_INT64_T EQUAL 8)
+ SET(VMIME_64BIT_TYPE "int64_t")
+ ELSE()
+ IF(SIZEOF___INT64 EQUAL 8)
+ SET(VMIME_64BIT_TYPE "__int64")
+ ELSE()
+ MESSAGE(FATAL_ERROR "Cannot determine 64-bit type")
+ ENDIF()
+ ENDIF()
+ ENDIF()
+ ENDIF()
+ENDIF()
+
+
+CHECK_TYPE_SIZE(size_t VMIME_HAVE_SIZE_T)
+
+
+##############################################################################
+# Sendmail path
+
+FOREACH (SENDMAIL_PATH /usr/sbin/sendmail /usr/lib/sendmail /usr/bin/sendmail /bin/sendmail /var/qmail/bin/qmail-inject /bin/cgimail)
+ IF(EXISTS ${SENDMAIL_PATH})
+ MESSAGE(STATUS "Sendmail binary found at ${SENDMAIL_PATH}")
+ SET(VMIME_DEFAULT_SENDMAIL_PATH ${SENDMAIL_PATH})
+ ENDIF()
+ENDFOREACH(SENDMAIL_PATH)
+
+SET(
+ VMIME_SENDMAIL_PATH
+ ${VMIME_DEFAULT_SENDMAIL_PATH}
+ CACHE
+ STRING
+ "Specifies the path to sendmail binary"
+)
+
+
+##############################################################################
+# Messaging features
+
+# Module
+OPTION(
+ VMIME_HAVE_MESSAGING_FEATURES
+ "Enable messaging features (connection to IMAP, POP3, SMTP...)"
+ ON
+)
+
+# Protocols
+OPTION(
+ VMIME_HAVE_MESSAGING_PROTO_POP3
+ "Enable POP3 protocol"
+ ON
+)
+
+OPTION(
+ VMIME_HAVE_MESSAGING_PROTO_SMTP
+ "Enable SMTP protocol"
+ ON
+)
+
+OPTION(
+ VMIME_HAVE_MESSAGING_PROTO_IMAP
+ "Enable IMAP protocol"
+ ON
+)
+
+OPTION(
+ VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+ "Enable Maildir protocol"
+ ON
+)
+
+OPTION(
+ VMIME_HAVE_MESSAGING_PROTO_SENDMAIL
+ "Enable Sendmail protocol"
+ ON
+)
+
+
+##############################################################################
+# File-system features
+
+OPTION(
+ VMIME_HAVE_FILESYSTEM_FEATURES
+ "Enable file-system features (required for file attachments and Maildir)"
+ ON
+)
+
+
+##############################################################################
+# SASL support
+
+INCLUDE(cmake/FindGSasl.cmake)
+
+OPTION(
+ VMIME_HAVE_SASL_SUPPORT
+ "Enable SASL support (requires GNU SASL library)"
+ ON
+)
+
+IF(VMIME_HAVE_SASL_SUPPORT)
+
+ INCLUDE_DIRECTORIES(
+ ${INCLUDE_DIRECTORIES}
+ ${GSASL_INCLUDE_DIR}
+ )
+
+ IF(VMIME_BUILD_SHARED_LIBRARY)
+ TARGET_LINK_LIBRARIES(
+ ${VMIME_LIBRARY_NAME}
+ ${TARGET_LINK_LIBRARIES}
+ ${GSASL_LIBRARIES}
+ )
+ ENDIF()
+
+ SET(VMIME_PKGCONFIG_REQUIRES "${VMIME_PKGCONFIG_REQUIRES} libgsasl")
+
+ENDIF()
+
+
+##############################################################################
+# SSL/TLS support
+
+INCLUDE(FindGnuTLS)
+INCLUDE(FindOpenSSL)
+
+SET(CMAKE_REQUIRED_LIBRARIES "${GNUTLS_LIBRARY}")
+CHECK_FUNCTION_EXISTS(gnutls_priority_set_direct VMIME_HAVE_GNUTLS_PRIORITY_FUNCS)
+
+
+OPTION(
+ VMIME_HAVE_TLS_SUPPORT
+ "SSL/TLS support (requires either GNU TLS or OpenSSL library)"
+ ON
+)
+
+SET(
+ VMIME_TLS_SUPPORT_LIB
+ "gnutls"
+ CACHE
+ STRING
+ "Library to use for SSL/TLS conversion"
+)
+SET_PROPERTY(
+ CACHE
+ VMIME_TLS_SUPPORT_LIB
+ PROPERTY STRINGS gnutls openssl
+)
+
+
+IF(VMIME_HAVE_TLS_SUPPORT)
+
+ IF(VMIME_TLS_SUPPORT_LIB STREQUAL "gnutls")
+
+ INCLUDE_DIRECTORIES(
+ ${INCLUDE_DIRECTORIES}
+ ${GNUTLS_INCLUDE_DIR}
+ )
+
+ LINK_DIRECTORIES(
+ ${LINK_DIRECTORIES}
+ ${GNUTLS_LIBRARY_DIRS}
+ )
+
+ IF(VMIME_BUILD_SHARED_LIBRARY)
+ TARGET_LINK_LIBRARIES(
+ ${VMIME_LIBRARY_NAME}
+ ${TARGET_LINK_LIBRARIES}
+ ${GNUTLS_LIBRARY}
+ )
+ ENDIF()
+
+ SET(VMIME_PKGCONFIG_REQUIRES "${VMIME_PKGCONFIG_REQUIRES} gnutls")
+
+ SET(VMIME_TLS_SUPPORT_LIB_IS_GNUTLS "ON")
+ SET(VMIME_TLS_SUPPORT_LIB_IS_OPENSSL "OFF")
+
+ ELSEIF(VMIME_TLS_SUPPORT_LIB STREQUAL "openssl")
+
+ INCLUDE_DIRECTORIES(
+ ${INCLUDE_DIRECTORIES}
+ ${OPENSSL_INCLUDE_DIR}
+ )
+
+ IF(VMIME_BUILD_SHARED_LIBRARY)
+ TARGET_LINK_LIBRARIES(
+ ${VMIME_LIBRARY_NAME}
+ ${TARGET_LINK_LIBRARIES}
+ ${OPENSSL_LIBRARIES}
+ )
+ ENDIF()
+
+ SET(VMIME_PKGCONFIG_REQUIRES "${VMIME_PKGCONFIG_REQUIRES} openssl")
+
+ SET(VMIME_TLS_SUPPORT_LIB_IS_GNUTLS "OFF")
+ SET(VMIME_TLS_SUPPORT_LIB_IS_OPENSSL "ON")
+
+ ELSE()
+
+ MESSAGE(FATAL_ERROR "TLS support is enabled, but no TLS/SSL library was selected/found")
+
+ ENDIF()
+
+ENDIF(VMIME_HAVE_TLS_SUPPORT)
+
+
+##############################################################################
+# Charset conversion library
+
+INCLUDE(cmake/FindIconv.cmake)
+INCLUDE(cmake/FindICU.cmake)
+
+FIND_PACKAGE(ICU QUIET)
+
+IF(ICU_LIBRARIES)
+ SET(VMIME_CHARSETCONV_LIB_DETECTED "icu")
+ELSEIF(ICONV_FOUND)
+ SET(VMIME_CHARSETCONV_LIB_DETECTED "iconv")
+ELSEIF(WIN32)
+ SET(VMIME_CHARSETCONV_LIB_DETECTED "win")
+ENDIF()
+
+SET(
+ VMIME_CHARSETCONV_LIB
+ "${VMIME_CHARSETCONV_LIB_DETECTED}"
+ CACHE
+ STRING
+ "Library to use for charset conversion"
+)
+SET_PROPERTY(
+ CACHE
+ VMIME_CHARSETCONV_LIB
+ PROPERTY STRINGS win iconv icu
+)
+
+
+IF(VMIME_CHARSETCONV_LIB STREQUAL "iconv")
+
+ INCLUDE_DIRECTORIES(
+ ${INCLUDE_DIRECTORIES}
+ ${ICONV_INCLUDE_DIR}
+ )
+
+ IF(VMIME_BUILD_SHARED_LIBRARY)
+ TARGET_LINK_LIBRARIES(
+ ${VMIME_LIBRARY_NAME}
+ ${TARGET_LINK_LIBRARIES}
+ ${ICONV_LIBRARIES}
+ )
+ ENDIF()
+
+ SET(VMIME_PKGCONFIG_LIBS "${VMIME_PKGCONFIG_LIBS} ${ICONV_LIBRARIES}")
+ SET(VMIME_PKGCONFIG_CFLAGS "${VMIME_PKGCONFIG_CFLAGS} -I${ICONV_INCLUDE_DIR}")
+
+ SET(VMIME_CHARSETCONV_LIB_IS_ICONV "ON")
+ SET(VMIME_CHARSETCONV_LIB_IS_ICU "OFF")
+ SET(VMIME_CHARSETCONV_LIB_IS_WIN "OFF")
+
+ELSEIF(VMIME_CHARSETCONV_LIB STREQUAL "icu")
+
+ INCLUDE_DIRECTORIES(
+ ${INCLUDE_DIRECTORIES}
+ ${ICU_INCLUDE_DIRS}
+ )
+
+ IF(VMIME_BUILD_SHARED_LIBRARY)
+ TARGET_LINK_LIBRARIES(
+ ${VMIME_LIBRARY_NAME}
+ ${TARGET_LINK_LIBRARIES}
+ ${ICU_LIBRARIES}
+ )
+ ENDIF()
+
+ SET(VMIME_PKGCONFIG_LIBS "${VMIME_PKGCONFIG_LIBS} ${ICU_LIBRARIES}")
+ SET(VMIME_PKGCONFIG_CFLAGS "${VMIME_PKGCONFIG_CFLAGS} -I${ICU_INCLUDE_DIRS}")
+
+ SET(VMIME_CHARSETCONV_LIB_IS_ICONV "OFF")
+ SET(VMIME_CHARSETCONV_LIB_IS_ICU "ON")
+ SET(VMIME_CHARSETCONV_LIB_IS_WIN "OFF")
+
+ELSEIF(VMIME_CHARSETCONV_LIB STREQUAL "win")
+
+ MESSAGE(WARNING "*** ICU or iconv library should always be preferred"
+ " over MultiByteToWideChar/WideCharToMultiByte on Windows, as"
+ " error handling is very poor, and there is no streaming support.")
+
+ SET(VMIME_CHARSETCONV_LIB_IS_ICONV "OFF")
+ SET(VMIME_CHARSETCONV_LIB_IS_ICU "OFF")
+ SET(VMIME_CHARSETCONV_LIB_IS_WIN "ON")
+
+ELSE()
+
+ MESSAGE(FATAL_ERROR "No charset conversion library was selected/found")
+
+ENDIF()
+
+
+##############################################################################
+# Platform
+
+SET(VMIME_PLATFORM_IS_POSIX OFF)
+SET(VMIME_PLATFORM_IS_WINDOWS OFF)
+
+IF(WIN32)
+ SET(VMIME_PLATFORM_IS_WINDOWS ON)
+ELSE()
+ SET(VMIME_PLATFORM_IS_POSIX ON)
+ENDIF()
+
+
+##############################################################################
+# Platform-specific checks
+
+CHECK_FUNCTION_EXISTS(gmtime_s VMIME_HAVE_GMTIME_S)
+CHECK_FUNCTION_EXISTS(gmtime_r VMIME_HAVE_GMTIME_R)
+CHECK_FUNCTION_EXISTS(localtime_s VMIME_HAVE_LOCALTIME_S)
+CHECK_FUNCTION_EXISTS(localtime_r VMIME_HAVE_LOCALTIME_R)
+CHECK_FUNCTION_EXISTS(strcpy_s VMIME_HAVE_STRCPY_S)
+
+
+##############################################################################
+# Windows-specific checks
+
+IF(WIN32)
+
+ # Winsock
+ CHECK_LIBRARY_EXISTS("ws2_32" getch "${CMAKE_LIBRARY_PATH}" VMIME_HAVE_LIBWS2_32)
+
+ IF(VMIME_HAVE_LIBWS2_32)
+ IF(VMIME_BUILD_SHARED_LIBRARY)
+ TARGET_LINK_LIBRARIES(
+ ${VMIME_LIBRARY_NAME}
+ ${TARGET_LINK_LIBRARIES}
+ "ws2_32"
+ )
+ ELSE()
+ SET(VMIME_PKGCONFIG_LIBS "${VMIME_PKGCONFIG_LIBS} -lws2_32")
+ ENDIF()
+ ENDIF()
+
+ # MLang
+ CHECK_INCLUDE_FILES(Mlang.h VMIME_HAVE_MLANG_H)
+ CHECK_LIBRARY_EXISTS("mlang" ConvertINetString "${CMAKE_LIBRARY_PATH}" VMIME_HAVE_MLANG_LIB)
+
+ IF(VMIME_HAVE_MLANG_H)
+ IF(VMIME_HAVE_MLANG_LIB)
+ SET(VMIME_HAVE_MLANG ON)
+
+ IF(VMIME_BUILD_SHARED_LIBRARY)
+ TARGET_LINK_LIBRARIES(
+ ${VMIME_LIBRARY_NAME}
+ ${TARGET_LINK_LIBRARIES}
+ "mlang"
+ )
+ ENDIF()
+ ENDIF()
+ ENDIF()
+
+ENDIF()
+
+
+##############################################################################
+# POSIX-specific checks
+
+CHECK_FUNCTION_EXISTS(getaddrinfo VMIME_HAVE_GETADDRINFO)
+CHECK_FUNCTION_EXISTS(getnameinfo VMIME_HAVE_GETNAMEINFO)
+
+CHECK_FUNCTION_EXISTS(gettid VMIME_HAVE_GETTID)
+CHECK_FUNCTION_EXISTS(syscall VMIME_HAVE_SYSCALL)
+CHECK_SYMBOL_EXISTS(SYS_gettid sys/syscall.h VMIME_HAVE_SYSCALL_GETTID)
+CHECK_SYMBOL_EXISTS(getthrid unistd.h VMIME_HAVE_GETTHRID)
+
+CHECK_SYMBOL_EXISTS(SO_KEEPALIVE sys/socket.h VMIME_HAVE_SO_KEEPALIVE)
+CHECK_SYMBOL_EXISTS(SO_NOSIGPIPE sys/socket.h VMIME_HAVE_SO_NOSIGPIPE)
+
+CHECK_SYMBOL_EXISTS(MSG_NOSIGNAL sys/socket.h VMIME_HAVE_MSG_NOSIGNAL)
+
+CHECK_SYMBOL_EXISTS(strerror_r string.h VMIME_HAVE_STRERROR_R)
+
+FIND_PACKAGE(Threads)
+
+IF(VMIME_BUILD_SHARED_LIBRARY)
+ TARGET_LINK_LIBRARIES(
+ ${VMIME_LIBRARY_NAME}
+ ${TARGET_LINK_LIBRARIES}
+ ${CMAKE_THREAD_LIBS_INIT}
+ )
+ENDIF()
+
+FIND_LIBRARY(PTHREAD_LIB pthread)
+
+IF(PTHREAD_LIB)
+ SET(VMIME_HAVE_PTHREAD 1)
+
+ IF(VMIME_BUILD_SHARED_LIBRARY)
+ TARGET_LINK_LIBRARIES(
+ ${VMIME_LIBRARY_NAME}
+ ${TARGET_LINK_LIBRARIES}
+ ${PTHREAD_LIB}
+ )
+ ENDIF()
+ELSE(PTHREAD_LIB)
+ SET(VMIME_HAVE_PTHREAD 0)
+ENDIF(PTHREAD_LIB)
+
+# getaddrinfo_a() - GNU libc
+LIST(APPEND CMAKE_REQUIRED_DEFINITIONS -D_GNU_SOURCE)
+LIST(APPEND CMAKE_REQUIRED_LIBRARIES anl)
+CHECK_SYMBOL_EXISTS(getaddrinfo_a netdb.h VMIME_HAVE_GETADDRINFO_A)
+
+IF(VMIME_HAVE_GETADDRINFO_A)
+ IF(VMIME_BUILD_SHARED_LIBRARY)
+ TARGET_LINK_LIBRARIES(
+ ${VMIME_LIBRARY_NAME}
+ ${TARGET_LINK_LIBRARIES}
+ anl
+ )
+ ENDIF()
+ENDIF()
+
+
+##############################################################################
+# Additional compiler flags
+
+IF("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
+
+ SET(
+ CMAKE_CXX_FLAGS
+ "-D_REENTRANT=1 -W -Wall -pedantic -Warray-bounds-pointer-arithmetic -Wold-style-cast -Wconversion -Wcast-align -Wno-sign-conversion ${CMAKE_CXX_FLAGS}"
+ )
+
+ SET(CMAKE_CXX_FLAGS_RELEASE "-O2 ${CMAKE_CXX_FLAGS_RELEASE}")
+ SET(CMAKE_CXX_FLAGS_DEBUG "-O0 ${CMAKE_CXX_FLAGS_DEBUG}")
+ SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
+
+ #SET(CMAKE_EXE_LINKER_FLAGS "-s")
+
+ELSE()
+
+ IF(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
+
+ SET(
+ CMAKE_CXX_FLAGS
+ "-D_REENTRANT=1 -W -Wall -pedantic -Wpointer-arith -Wold-style-cast -Wconversion -Wcast-align -Wno-long-long ${CMAKE_CXX_FLAGS}"
+ )
+
+ SET(CMAKE_CXX_FLAGS_RELEASE "-O2 ${CMAKE_CXX_FLAGS_RELEASE}")
+ SET(CMAKE_CXX_FLAGS_DEBUG "-O0 ${CMAKE_CXX_FLAGS_DEBUG}")
+ SET(CMAKE_CXX_FLAGS_RELWITHDEBINFO "-O2 -g ${CMAKE_CXX_FLAGS_RELWITHDEBINFO}")
+
+ #SET(CMAKE_EXE_LINKER_FLAGS "-s")
+
+ ENDIF()
+
+ENDIF()
+
+
+##############################################################################
+# Documentation
+
+OPTION(
+ VMIME_BUILD_DOCUMENTATION
+ "Build documentation"
+ ON
+)
+
+IF(VMIME_BUILD_DOCUMENTATION)
+ FIND_PACKAGE(Doxygen)
+
+ IF(DOXYGEN_FOUND)
+ CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/Doxyfile.in ${CMAKE_BINARY_DIR}/Doxyfile @ONLY)
+
+ # Make a target so that documentation can be generated by running "make doc"
+ ADD_CUSTOM_TARGET(
+ doc
+ ${DOXYGEN_EXECUTABLE} ${CMAKE_BINARY_DIR}/Doxyfile
+ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
+ COMMENT "Generating API documentation with Doxygen" VERBATIM
+ )
+ ENDIF(DOXYGEN_FOUND)
+ENDIF(VMIME_BUILD_DOCUMENTATION)
+
+##############################################################################
+# Sanity checks
+
+# Maildir protocol is available only if file-system features are enabled
+IF(VMIME_HAVE_MESSAGING_FEATURES AND VMIME_HAVE_MESSAGING_PROTO_MAILDIR AND NOT VMIME_HAVE_FILESYSTEM_FEATURES)
+ MESSAGE(FATAL_ERROR "Maildir protocol requires file-system support (VMIME_HAVE_FILESYSTEM_FEATURES must be set to ON).")
+ENDIF()
+
+# Sendmail protocol is available only if file-system features are enabled
+IF(VMIME_HAVE_MESSAGING_FEATURES AND VMIME_HAVE_MESSAGING_PROTO_SENDMAIL AND NOT VMIME_HAVE_FILESYSTEM_FEATURES)
+ MESSAGE(FATAL_ERROR "Sendmail protocol requires file-system support (VMIME_HAVE_FILESYSTEM_FEATURES must be set to ON).")
+ENDIF()
+
+# Path to 'sendmail' must be specified if Sendmail protocol is enabled
+IF(VMIME_HAVE_MESSAGING_PROTO_SENDMAIL)
+ IF(NOT VMIME_SENDMAIL_PATH OR VMIME_SENDMAIL_PATH STREQUAL "")
+ MESSAGE(FATAL_ERROR "Enabling Sendmail protocol requires that you specify path to 'sendmail' binary.")
+ ENDIF()
+ENDIF()
+
+
+##############################################################################
+# Build examples
+
+IF(VMIME_BUILD_SAMPLES)
+ ADD_SUBDIRECTORY(examples)
+ENDIF()
+
+
+# Set our configure file
+CONFIGURE_FILE(cmake/config.hpp.cmake ${CMAKE_BINARY_DIR}/src/vmime/config.hpp)
+
+# PkgConfig post-configuration
+CONFIGURE_FILE(${CMAKE_CURRENT_SOURCE_DIR}/vmime.pc.in ${CMAKE_BINARY_DIR}/vmime.pc @ONLY)
+INSTALL(FILES ${CMAKE_BINARY_DIR}/vmime.pc DESTINATION "${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}/pkgconfig" COMPONENT headers)
+
+INCLUDE(CPack)
+
+IF(WIN32)
+ target_link_libraries(vmime crypt32)
+ENDIF()
diff --git a/vmime-master/COPYING b/vmime-master/COPYING
new file mode 100644
index 0000000..94a9ed0
--- /dev/null
+++ b/vmime-master/COPYING
@@ -0,0 +1,674 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+ The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works. By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users. We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors. You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+them if you wish), that you receive source code or can get it if you
+want it, that you can change the software or use pieces of it in new
+free programs, and that you know you can do these things.
+
+ To protect your rights, we need to prevent others from denying you
+these rights or asking you to surrender the rights. Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received. You must make sure that they, too, receive
+or can get the source code. And you must show them these terms so they
+know their rights.
+
+ Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+ For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software. For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+ Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so. This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software. The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable. Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products. If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+ Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary. To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ TERMS AND CONDITIONS
+
+ 0. Definitions.
+
+ "This License" refers to version 3 of the GNU General Public License.
+
+ "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+ "The Program" refers to any copyrightable work licensed under this
+License. Each licensee is addressed as "you". "Licensees" and
+"recipients" may be individuals or organizations.
+
+ To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy. The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+ A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+ To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy. Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+ To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies. Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+ An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License. If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+ 1. Source Code.
+
+ The "source code" for a work means the preferred form of the work
+for making modifications to it. "Object code" means any non-source
+form of a work.
+
+ A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+ The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form. A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+ The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities. However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work. For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+ The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+ The Corresponding Source for a work in source code form is that
+same work.
+
+ 2. Basic Permissions.
+
+ All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met. This License explicitly affirms your unlimited
+permission to run the unmodified Program. The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work. This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+ You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force. You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright. Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+ Conveying under any other circumstances is permitted solely under
+the conditions stated below. Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+ 3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+ No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+ When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+ 4. Conveying Verbatim Copies.
+
+ You may convey verbatim copies of the Program's source code as you
+receive it, in any medium, provided that you conspicuously and
+appropriately publish on each copy an appropriate copyright notice;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+ You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+ 5. Conveying Modified Source Versions.
+
+ You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+ a) The work must carry prominent notices stating that you modified
+ it, and giving a relevant date.
+
+ b) The work must carry prominent notices stating that it is
+ released under this License and any conditions added under section
+ 7. This requirement modifies the requirement in section 4 to
+ "keep intact all notices".
+
+ c) You must license the entire work, as a whole, under this
+ License to anyone who comes into possession of a copy. This
+ License will therefore apply, along with any applicable section 7
+ additional terms, to the whole of the work, and all its parts,
+ regardless of how they are packaged. This License gives no
+ permission to license the work in any other way, but it does not
+ invalidate such permission if you have separately received it.
+
+ d) If the work has interactive user interfaces, each must display
+ Appropriate Legal Notices; however, if the Program has interactive
+ interfaces that do not display Appropriate Legal Notices, your
+ work need not make them do so.
+
+ A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit. Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+ 6. Conveying Non-Source Forms.
+
+ You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+ a) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by the
+ Corresponding Source fixed on a durable physical medium
+ customarily used for software interchange.
+
+ b) Convey the object code in, or embodied in, a physical product
+ (including a physical distribution medium), accompanied by a
+ written offer, valid for at least three years and valid for as
+ long as you offer spare parts or customer support for that product
+ model, to give anyone who possesses the object code either (1) a
+ copy of the Corresponding Source for all the software in the
+ product that is covered by this License, on a durable physical
+ medium customarily used for software interchange, for a price no
+ more than your reasonable cost of physically performing this
+ conveying of source, or (2) access to copy the
+ Corresponding Source from a network server at no charge.
+
+ c) Convey individual copies of the object code with a copy of the
+ written offer to provide the Corresponding Source. This
+ alternative is allowed only occasionally and noncommercially, and
+ only if you received the object code with such an offer, in accord
+ with subsection 6b.
+
+ d) Convey the object code by offering access from a designated
+ place (gratis or for a charge), and offer equivalent access to the
+ Corresponding Source in the same way through the same place at no
+ further charge. You need not require recipients to copy the
+ Corresponding Source along with the object code. If the place to
+ copy the object code is a network server, the Corresponding Source
+ may be on a different server (operated by you or a third party)
+ that supports equivalent copying facilities, provided you maintain
+ clear directions next to the object code saying where to find the
+ Corresponding Source. Regardless of what server hosts the
+ Corresponding Source, you remain obligated to ensure that it is
+ available for as long as needed to satisfy these requirements.
+
+ e) Convey the object code using peer-to-peer transmission, provided
+ you inform other peers where the object code and Corresponding
+ Source of the work are being offered to the general public at no
+ charge under subsection 6d.
+
+ A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+ A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling. In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage. For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product. A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+ "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source. The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+ If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information. But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+ The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed. Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+ Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+ 7. Additional Terms.
+
+ "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law. If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+ When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it. (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.) You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+ Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+ a) Disclaiming warranty or limiting liability differently from the
+ terms of sections 15 and 16 of this License; or
+
+ b) Requiring preservation of specified reasonable legal notices or
+ author attributions in that material or in the Appropriate Legal
+ Notices displayed by works containing it; or
+
+ c) Prohibiting misrepresentation of the origin of that material, or
+ requiring that modified versions of such material be marked in
+ reasonable ways as different from the original version; or
+
+ d) Limiting the use for publicity purposes of names of licensors or
+ authors of the material; or
+
+ e) Declining to grant rights under trademark law for use of some
+ trade names, trademarks, or service marks; or
+
+ f) Requiring indemnification of licensors and authors of that
+ material by anyone who conveys the material (or modified versions of
+ it) with contractual assumptions of liability to the recipient, for
+ any liability that these contractual assumptions directly impose on
+ those licensors and authors.
+
+ All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10. If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term. If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+ If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+ Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+ 8. Termination.
+
+ You may not propagate or modify a covered work except as expressly
+provided under this License. Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+ However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+ Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+ Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License. If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+ 9. Acceptance Not Required for Having Copies.
+
+ You are not required to accept this License in order to receive or
+run a copy of the Program. Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance. However,
+nothing other than this License grants you permission to propagate or
+modify any covered work. These actions infringe copyright if you do
+not accept this License. Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+ 10. Automatic Licensing of Downstream Recipients.
+
+ Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License. You are not responsible
+for enforcing compliance by third parties with this License.
+
+ An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations. If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+ You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License. For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+ 11. Patents.
+
+ A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based. The
+work thus licensed is called the contributor's "contributor version".
+
+ A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version. For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+ Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+ In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement). To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+ If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients. "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+ If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+ A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License. You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+ Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+ 12. No Surrender of Others' Freedom.
+
+ If conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all. For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+ 13. Use with the GNU Affero General Public License.
+
+ Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work. The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+ 14. Revised Versions of this License.
+
+ The Free Software Foundation may publish revised and/or new versions of
+the GNU General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+ Each version is given a distinguishing version number. If the
+Program specifies that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation. If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+ If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+ Later license versions may give you additional or different
+permissions. However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+ 15. Disclaimer of Warranty.
+
+ THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
+APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
+HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
+OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
+IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
+ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
+
+ 16. Limitation of Liability.
+
+ IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
+GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
+USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
+DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
+PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
+EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGES.
+
+ 17. Interpretation of Sections 15 and 16.
+
+ If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+state the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+ If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+ <program> Copyright (C) <year> <name of author>
+ This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+ You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+ The GNU General Public License does not permit incorporating your program
+into proprietary programs. If your program is a subroutine library, you
+may consider it more useful to permit linking proprietary applications with
+the library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License. But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
diff --git a/vmime-master/COPYING.OpenSSL b/vmime-master/COPYING.OpenSSL
new file mode 100644
index 0000000..bf205f5
--- /dev/null
+++ b/vmime-master/COPYING.OpenSSL
@@ -0,0 +1,26 @@
+OpenSSL License Exception
+-------------------------
+
+Copyright (C) 2002-2020, Vincent Richard <vincent@vmime.org>
+
+This program is free software; you can redistribute it and/or modify it
+under the terms of the GNU General Public License 3 (GPL) as published by
+the Free Software Foundation.
+The full text of the GPL can be found in the COPYING file.
+
+In addition, as a special exception, the copyright holders give permission
+to link the code of portions of this program against the OpenSSL library
+according to the terms described here:
+
+You have permission to copy, modify, propagate, and distribute a work
+formed by combining OpenSSL with VMime, or a work derivative of such a
+combination, even if such copying, modification, propagation, or
+distribution would otherwise violate the terms of the GPL. You must
+comply with the GPL in all respects for all of the code used other than
+OpenSSL.
+
+You may include this OpenSSL exception and its grant of permissions when
+you distribute VMime. Inclusion of this notice with such a distribution
+constitutes a grant of such permission. If you do not wish to grant these
+permissions, delete this file.
+
diff --git a/vmime-master/Doxyfile.in b/vmime-master/Doxyfile.in
new file mode 100644
index 0000000..3b491c3
--- /dev/null
+++ b/vmime-master/Doxyfile.in
@@ -0,0 +1,1043 @@
+#
+# Doxygen settings for VMime
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+#
+
+#---------------------------------------------------------------------------
+# General configuration options
+#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = VMime
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = @CMAKE_CURRENT_BINARY_DIR@/doc/
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish, Dutch,
+# Finnish, French, German, Greek, Hungarian, Italian, Japanese, Japanese-en
+# (Japanese with english messages), Korean, Norwegian, Polish, Portuguese,
+# Romanian, Russian, Serbian, Slovak, Slovene, Spanish, Swedish and Ukrainian.
+
+OUTPUT_LANGUAGE = English
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these class will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = YES
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+#HIDE_IN_BODY_DOCS = NO
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = NO
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all inherited
+# members of a class in the documentation of that class as if those members were
+# ordinary class members. Constructors, destructors and assignment operators of
+# the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. It is allowed to use relative paths in the argument list.
+
+STRIP_FROM_PATH =
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower case letters. If set to YES upper case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# users are adviced to set this option to NO.
+
+CASE_SENSE_NAMES = YES
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = YES
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like the Qt-style comments (thus requiring an
+# explict @brief command for a brief description.
+
+JAVADOC_AUTOBRIEF = YES
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member
+# documentation.
+
+DETAILS_AT_TOP = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# reimplements.
+
+INHERIT_DOCS = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = NO
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 4
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consist of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C.
+# For instance some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources
+# only. Doxygen will then generate output that is more tailored for Java.
+# For instance namespaces will be presented as packages, qualified scopes
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = YES
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+#WARN_IF_DOC_ERROR = YES
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = @CMAKE_CURRENT_SOURCE_DIR@/src/ @CMAKE_CURRENT_SOURCE_DIR@/vmime/
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx *.hpp
+# *.h++ *.idl *.odl
+
+FILE_PATTERNS =
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or directories
+# that are symbolic links (a Unix filesystem feature) are excluded from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+
+EXCLUDE_PATTERNS = */config.hpp */IMAPTag* */IMAPParser* */IMAPUtils* */IMAPConnection* */md5* */smartPtr* */authHelper* */maildirUtils*
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output.
+
+INPUT_FILTER =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+
+SOURCE_BROWSER = NO
+# YES --> sources visibles
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default)
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default)
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = YES
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 1
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet
+
+HTML_STYLESHEET =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output dir.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non empty doxygen will try to run
+# the html help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the Html help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript and frames is required (for instance Mozilla, Netscape 4.0+,
+# or Internet explorer 4.0+). Note that for large projects the tree generation
+# can take a very long time. In such cases it is better to disable this feature.
+# Windows users are probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW = YES
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 300
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimised for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assigments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_XML = NO
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+#GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+#PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader. This is useful
+# if you want to understand what is going on. On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+#PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+#PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_PREDEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed.
+
+PREDEFINED = VMIME_BUILDING_DOC VMIME_HAVE_SASL_SUPPORT VMIME_HAVE_TLS_SUPPORT VMIME_HAVE_FILESYSTEM_FEATURES VMIME_HAVE_MESSAGING_FEATURES VMIME_HAVE_MESSAGING_PROTO_POP3 VMIME_HAVE_MESSAGING_PROTO_SMTP VMIME_HAVE_MESSAGING_PROTO_IMAP VMIME_HAVE_MESSAGING_PROTO_MAILDIR VMIME_HAVE_MESSAGING_PROTO_SENDMAIL
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse the
+# parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::addtions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tagfiles.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in Html, RTF and LaTeX) for classes with base or
+# super classes. Setting the tag to NO turns the diagrams off. Note that this
+# option is superceded by the HAVE_DOT option below. This is only a fallback. It is
+# recommended to install and use dot, since it yield more powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = YES
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found on the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+MAX_DOT_GRAPH_WIDTH = 1024
+
+# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+MAX_DOT_GRAPH_HEIGHT = 1024
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermedate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
+
+#---------------------------------------------------------------------------
+# Configuration::addtions related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE = NO
+
+# The CGI_NAME tag should be the name of the CGI script that
+# starts the search engine (doxysearch) with the correct parameters.
+# A script with this name will be generated by doxygen.
+
+#CGI_NAME = search.cgi
+
+# The CGI_URL tag should be the absolute URL to the directory where the
+# cgi binaries are located. See the documentation of your http daemon for
+# details.
+
+#CGI_URL =
+
+# The DOC_URL tag should be the absolute URL to the directory where the
+# documentation is located. If left blank the absolute path to the
+# documentation, with file:// prepended to it, will be used.
+
+#DOC_URL =
+
+# The DOC_ABSPATH tag should be the absolute path to the directory where the
+# documentation is located. If left blank the directory on the local machine
+# will be used.
+
+#DOC_ABSPATH =
+
+# The BIN_ABSPATH tag must point to the directory where the doxysearch binary
+# is installed.
+
+#BIN_ABSPATH = /usr/local/bin/
+
+# The EXT_DOC_PATHS tag can be used to specify one or more paths to
+# documentation generated for other projects. This allows doxysearch to search
+# the documentation for these projects as well.
+
+#EXT_DOC_PATHS =
+
diff --git a/vmime-master/HACKING b/vmime-master/HACKING
new file mode 100644
index 0000000..a1cf21c
--- /dev/null
+++ b/vmime-master/HACKING
@@ -0,0 +1,360 @@
+This file contains coding guidelines for VMime. You should follow them
+if you want to contribute to VMime. The rules below are not guidelines
+or recommendations, but strict rules.
+
+
+1. General rules
+ 1.1. Language
+ 1.2. Unit tests
+ 1.3. Version Control
+ 1.4. Warnings
+2. Style, indentation and braces
+ 2.1. Indentation
+ 2.2. Brace position
+ 2.3. "switch" statement
+ 2.4. Single instruction
+ 2.5. Line length
+ 2.6. Spaces and parentheses
+ 2.7. End-of-line character
+ 2.8. Short functions
+ 2.9. Limit Variable Scope
+3. Naming conventions
+ 3.1. Classes
+ 3.2. Variables/parameters/member variables
+ 3.3. Member variables
+ 3.4. Files
+ 3.5. Namespaces
+ 3.6. Constants
+4. Comments
+5. Miscellaneous
+
+
+
+1. General rules
+================
+
+1.1. Language
+-------------
+
+The project language is English. All comments, variable names, class names,
+commit messages and so on, must be in English.
+
+
+1.2. Unit tests
+---------------
+
+Unit tests are very important. For each new class you write, you should also
+write a unit test for it. If you write a new method, add a new test case in
+the unit test of the class.
+
+When you fix a bug, also add a new test case to ensure the bug will not
+happen anymore.
+
+
+1.3. Version Control
+--------------------
+
+Each commit MUST be done with a message ('-m' flag) that briefly describes what
+changes have been done.
+
+DO NOT use commit messages like -m "Updated"!
+
+
+1.4. Warnings
+-------------
+
+The code should compile WITHOUT ANY WARNING, even those for unused parameters!
+
+
+
+2. Style, indentation and braces
+================================
+
+2.1. Indentation
+----------------
+
+Use TABS (ASCII character #9) and _not_ SPACES. This allow everyone to set tab
+width to its preferred settings (eg. 4 or 8 spaces).
+
+
+2.2. Brace position
+-------------------
+
+Open braces should always be at the end of the line of the statement that
+begins the block. Contents of the brace should be indented by 1 tab.
+
+ if (expr) {
+
+ do_something();
+ do_another_thing();
+
+ } else {
+
+ do_something_else();
+ }
+
+In a function, the opening brace must always be followed by an empty line:
+
+ void header::appendField(const shared_ptr <headerField>& field) {
+
+ m_fields.push_back(field);
+ }
+
+A function with few arguments:
+
+ bool header::hasField(const string& fieldName) const {
+
+ ...
+ }
+
+A function with more arguments:
+
+ void header::parseImpl(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition
+ ) {
+
+ ...
+ }
+
+
+2.3. "switch" statement
+-----------------------
+
+ switch (expr) {
+
+ case 0:
+
+ something;
+ break;
+
+ case 1:
+
+ something_else;
+ break;
+
+ case 2: {
+
+ int var = 42;
+ another_thing;
+ break;
+ }
+ }
+
+
+2.4. Single instruction
+-----------------------
+
+Don't omit braces around simple single-statement body:
+
+ if (...) {
+ something;
+ }
+
+and not:
+
+ if (...)
+ something;
+
+
+2.5. Line length
+----------------
+
+If possible, each line of text should not exceed 100 characters, except if
+manual line wrapping breaks code clarity.
+
+Exception: if a comment line contains an example command or a literal URL
+longer than 100 characters, that line may be longer than 100 characters
+for ease of cut and paste.
+
+
+2.6. Spaces and parentheses
+---------------------------
+
+Put spaces around operators: =, >, <, !=, +, -, /, *, ^, %, ||, &&, &, |:
+
+ x = (a * (b + (c - d)))
+
+Do not put spaces around parentheses.
+
+ if ((a == b) || (c == d))
+
+Do not put spaces around "->":
+
+ object->method()
+
+Do not put spaces inside brackets:
+
+ x = array[index] and _NOT_: x = array[ index ]
+
+Do not use space between a function name and parenthesis. No extra spaces
+between parameters and arguments, just after commas:
+
+ method(arg1, arg2, ...)
+
+Do use a single space before flow control statements:
+
+ while (x == y) and _NOT_: while(x==y)
+
+
+2.7. End-of-line character
+--------------------------
+
+Configure your editor to use "\n" (UNIX convention) for end-of-line sequence,
+and not "\r\n" (Windows), nor "\n\r", nor any other combination.
+
+
+2.8. Short functions
+--------------------
+
+To the extent that it is feasible, functions should be kept small and focused.
+It is, however, recognized that long functions are sometimes appropriate, so no
+hard limit is placed on method length. If a function exceeds 40 lines or so,
+think about whether it can be broken up without harming the structure of the
+program.
+
+
+2.9. Limit Variable Scope
+-------------------------
+
+The scope of local variables should be kept to a minimum. By doing so, you
+increase the readability and maintainability of your code and reduce the
+likelihood of error. Each variable should be declared in the innermost block
+that encloses all uses of the variable.
+
+Local variables should be declared at the point they are first used. Nearly
+every local variable declaration should contain an initializer. If you don't
+yet have enough information to initialize a variable sensibly, you should
+postpone the declaration until you do.
+
+
+
+3. Naming conventions
+=====================
+
+3.1. Classes
+------------
+
+Classes names are in lower-case. However, each word should start with an
+upper-case letter.
+
+Examples: "object", "exampleClass", "anotherExampleClass"...
+
+
+3.2. Variables/parameters/member variables
+------------------------------------------
+
+Variable names should be enough explicit so that someone reading the code can
+instantly understand what the variable contains and is used for.
+
+Variables names are in lower-case.
+
+DO NOT use Hungarian notation.
+
+Examples: "address", "recipientMailbox", ...
+
+Avoid variable names with less than 5 characters, except for loop indices and
+iterators.
+
+NOTE: variable names like "it", "jt" and so on are commonly used when iterating
+over STL containers.
+
+
+3.3. Member variables
+---------------------
+
+Use a prefix for class members: "m_" for normal class members, and "sm_" for
+static members, if they are not public.
+
+Examples: "m_mailboxList", "sm_instance"...
+
+
+3.4. Files
+----------
+
+Use ".hpp" for header files, and ".cpp" for implementation files. ".inc" should
+be used for implementation files not directly compiled, but included from
+other implementation files.
+
+Files have to be named exactly like the class they define. For example, class
+"mailboxList" should be declared in "mailboxList.hpp" and implemented in
+"mailboxList.cpp".
+
+Both header and implementation files must be placed in 'src/vmime/' directory.
+
+
+3.5. Namespaces
+---------------
+
+Namespaces are named exactly like variables.
+
+
+3.6. Constants
+--------------
+
+Constants are ALL_CAPS_WITH_UNDERSCORES.
+
+
+
+4. Comments
+===========
+
+The // (two slashes) style of comment tags should be used in most situations.
+Where ever possible, place comments above the code instead of beside it.
+
+Comments can be placed at the end of a line when one or more spaces follow.
+Tabs should NOT be used to indent at the end of a line:
+
+ class myClass {
+
+ private:
+
+ int m_member1; // first member
+ int m_secondMember; // second member
+ };
+
+Note about special comment blocks: Doxygen is used to generate documentation
+from annotated C++ sources, so be sure to use available markings to annotate
+the purpose of the functions/classes and the meaning of the parameters.
+
+
+5. Miscellaneous
+================
+
+* No code should be put in header files, only declarations (except for
+ templates and inline functions).
+
+* Try to avoid public member variables. Write accessors instead (get/set).
+
+* Do NOT use 'using namespace' (and especially not in header files). All
+ namespaces should be explicitely named.
+
+* Use the 'get' and 'set' prefix for accessors:
+
+ Variable: m_foo
+ Get method: getFoo()
+ Set method: setFoo()
+
+* No more than one class per file (except for inner classes).
+
+* Put the #include for the class's header file first in the implementation
+ file.
+
+* Put the copyright header at the top of each file.
+
+* Write "unique inclusion #ifdef's" for header files:
+
+ #ifndef N1_N2_FILENAME_HPP_INCLUDED
+ #define N1_N2_FILENAME_HPP_INCLUDED
+
+ // ...
+
+ #endif // N1_N2_FILENAME_HPP_INCLUDED
+
+ where N1 is the top-level namespace, N2 the sub-namespace, and so on.
+ For example, class "vmime::utility::stringUtils" uses the following
+ #ifdef name: VMIME_UTILITY_STRINGUTILS_HPP_INCLUDED.
+
diff --git a/vmime-master/NEWS b/vmime-master/NEWS
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/vmime-master/NEWS
diff --git a/vmime-master/README b/vmime-master/README
new file mode 100644
index 0000000..7db9175
--- /dev/null
+++ b/vmime-master/README
@@ -0,0 +1,30 @@
+
+VMime is a powerful C++ class library for working with RFC-822 and MIME messages
+and Internet messaging services like IMAP, POP or SMTP.
+
+With VMime you can parse, generate and modify messages, and also connect to store
+and transport services to receive or send messages over the Internet. The library
+offers all the features to build a complete mail client.
+
+Key Features
+------------
+
+* it is free software! GNU GPL license (Commercial licenses available!)
+* fully RFC-compliant implementation
+* object-oriented and modular design
+* very easy-to-use (intuitive design)
+* well documented code
+* very high reliability
+* maximum portability
+
+Features Overview
+-----------------
+
+* RFC-2822 and multipart messages
+* aggregate documents and embedded objects
+* 8-bit MIME and encoded word extensions
+* full support for attachments
+* POP3, IMAP, SMTP, maildir and sendmail
+* SSL/TLS security layer and X.509 certificates (using GNU TLS)
+* SASL authentication (using GNU SASL)
+
diff --git a/vmime-master/README.autotools b/vmime-master/README.autotools
new file mode 100644
index 0000000..a67c1c8
--- /dev/null
+++ b/vmime-master/README.autotools
@@ -0,0 +1,13 @@
+Where are the ./configure script and the Makefile's?
+
+Configure and Make scripts are not included in the git source tree. They are
+automatically generated by the CMake script.
+
+Just use the following instruction to generate everything needed for the
+traditional "make" and "make install" build process.
+
+ cmake -G "Unix Makefiles"
+
+Please note that "configure" script is not needed anymore, as platform
+checks are now done by CMake.
+
diff --git a/vmime-master/build_for_losedows.sh b/vmime-master/build_for_losedows.sh
new file mode 100755
index 0000000..55b242f
--- /dev/null
+++ b/vmime-master/build_for_losedows.sh
@@ -0,0 +1,23 @@
+#!/bin/sh
+
+rm -rf build/
+mkdir build/
+
+# perhaps we'll also disable VMIME_HAVE_FILESYSTEM_FEATURES ?
+## perhaps we should change CMAKE_BUILD_TYPE to Release or MinSizeRel.
+cmake \
+ -D GNU_HOST=i686-w64-mingw32 \
+ -D CMAKE_TOOLCHAIN_FILE=./mingw_cross_toolchain.cmake \
+ -D OPENSSL_ROOT_DIR=../openssl-1.1.0h/ \
+ -D VMIME_TLS_SUPPORT_LIB=openssl \
+ -D VMIME_HAVE_SASL_SUPPORT=OFF \
+ -D VMIME_BUILD_DOCUMENTATION=OFF \
+ -D VMIME_HAVE_MESSAGING_PROTO_SENDMAIL=OFF \
+ -D VMIME_HAVE_MESSAGING_PROTO_MAILDIR=OFF \
+ -D CMAKE_BUILD_TYPE=MinSizeRel. \
+ -B build/ ./
+
+cd build/ && make vmime-static
+cd ../
+cp build/build/lib/libvmime.a .
+cp build/src/vmime/config.hpp src/vmime/
diff --git a/vmime-master/cmake/FindCppUnit.cmake b/vmime-master/cmake/FindCppUnit.cmake
new file mode 100644
index 0000000..d74a4f3
--- /dev/null
+++ b/vmime-master/cmake/FindCppUnit.cmake
@@ -0,0 +1,34 @@
+#
+# http://root.cern.ch/viewvc/trunk/cint/reflex/cmake/modules/FindCppUnit.cmake
+#
+# - Find CppUnit
+# This module finds an installed CppUnit package.
+#
+# It sets the following variables:
+# CPPUNIT_FOUND - Set to false, or undefined, if CppUnit isn't found.
+# CPPUNIT_INCLUDE_DIR - The CppUnit include directory.
+# CPPUNIT_LIBRARY - The CppUnit library to link against.
+
+FIND_PATH(CPPUNIT_INCLUDE_DIR cppunit/Test.h)
+FIND_LIBRARY(CPPUNIT_LIBRARY NAMES cppunit)
+
+IF (CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARY)
+ SET(CPPUNIT_FOUND TRUE)
+ENDIF (CPPUNIT_INCLUDE_DIR AND CPPUNIT_LIBRARY)
+
+IF (CPPUNIT_FOUND)
+
+ # show which CppUnit was found only if not quiet
+ IF (NOT CppUnit_FIND_QUIETLY)
+ MESSAGE(STATUS "Found CppUnit: ${CPPUNIT_LIBRARY}")
+ ENDIF (NOT CppUnit_FIND_QUIETLY)
+
+ELSE (CPPUNIT_FOUND)
+
+ # fatal error if CppUnit is required but not found
+ IF (CppUnit_FIND_REQUIRED)
+ MESSAGE(FATAL_ERROR "Could not find CppUnit")
+ ENDIF (CppUnit_FIND_REQUIRED)
+
+ENDIF (CPPUNIT_FOUND)
+
diff --git a/vmime-master/cmake/FindGSasl.cmake b/vmime-master/cmake/FindGSasl.cmake
new file mode 100644
index 0000000..31890a2
--- /dev/null
+++ b/vmime-master/cmake/FindGSasl.cmake
@@ -0,0 +1,51 @@
+# - Try to find the GNU sasl library (gsasl)
+#
+# Once done this will define
+#
+# GNUTLS_FOUND - System has gnutls
+# GNUTLS_INCLUDE_DIR - The gnutls include directory
+# GNUTLS_LIBRARIES - The libraries needed to use gnutls
+# GNUTLS_DEFINITIONS - Compiler switches required for using gnutls
+
+# Adapted from FindGnuTLS.cmake, which is:
+# Copyright 2009, Brad Hards, <bradh@kde.org>
+#
+# Changes are Copyright 2009, Michele Caini, <skypjack@gmail.com>
+#
+# Redistribution and use is allowed according to the terms of the BSD license.
+# For details see the accompanying COPYING-CMAKE-SCRIPTS file.
+
+
+IF (GSASL_INCLUDE_DIR AND GSASL_LIBRARIES)
+ # in cache already
+ SET(GSasl_FIND_QUIETLY TRUE)
+ENDIF (GSASL_INCLUDE_DIR AND GSASL_LIBRARIES)
+
+IF (NOT WIN32)
+ # use pkg-config to get the directories and then use these values
+ # in the FIND_PATH() and FIND_LIBRARY() calls
+ find_package(PkgConfig)
+ pkg_check_modules(PC_GSASL libgsasl)
+ SET(GSASL_DEFINITIONS ${PC_GSASL_CFLAGS_OTHER})
+ENDIF (NOT WIN32)
+
+FIND_PATH(GSASL_INCLUDE_DIR gsasl.h
+ HINTS
+ ${PC_GSASL_INCLUDEDIR}
+ ${PC_GSASL_INCLUDE_DIRS}
+ PATH_SUFFIXES gsasl
+ )
+
+FIND_LIBRARY(GSASL_LIBRARIES NAMES gsasl libgsasl
+ HINTS
+ ${PC_GSASL_LIBDIR}
+ ${PC_GSASL_LIBRARY_DIRS}
+ )
+
+INCLUDE(FindPackageHandleStandardArgs)
+
+# handle the QUIETLY and REQUIRED arguments and set GSASL_FOUND to TRUE if
+# all listed variables are TRUE
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(GSASL DEFAULT_MSG GSASL_LIBRARIES GSASL_INCLUDE_DIR)
+
+MARK_AS_ADVANCED(GSASL_INCLUDE_DIR GSASL_LIBRARIES)
diff --git a/vmime-master/cmake/FindICU.cmake b/vmime-master/cmake/FindICU.cmake
new file mode 100644
index 0000000..786f157
--- /dev/null
+++ b/vmime-master/cmake/FindICU.cmake
@@ -0,0 +1,314 @@
+# This module can find the International Components for Unicode (ICU) Library
+#
+# Requirements:
+# - CMake >= 2.8.3 (for new version of find_package_handle_standard_args)
+#
+# The following variables will be defined for your use:
+# - ICU_FOUND : were all of your specified components found (include dependencies)?
+# - ICU_INCLUDE_DIRS : ICU include directory
+# - ICU_LIBRARIES : ICU libraries
+# - ICU_VERSION : complete version of ICU (x.y.z)
+# - ICU_MAJOR_VERSION : major version of ICU
+# - ICU_MINOR_VERSION : minor version of ICU
+# - ICU_PATCH_VERSION : patch version of ICU
+# - ICU_<COMPONENT>_FOUND : were <COMPONENT> found? (FALSE for non specified component if it is not a dependency)
+#
+# For windows or non standard installation, define ICU_ROOT variable to point to the root installation of ICU. Two ways:
+# - run cmake with -DICU_ROOT=<PATH>
+# - define an environment variable with the same name before running cmake
+# With cmake-gui, before pressing "Configure":
+# 1) Press "Add Entry" button
+# 2) Add a new entry defined as:
+# - Name: ICU_ROOT
+# - Type: choose PATH in the selection list
+# - Press "..." button and select the root installation of ICU
+#
+# Example Usage:
+#
+# 1. Copy this file in the root of your project source directory
+# 2. Then, tell CMake to search this non-standard module in your project directory by adding to your CMakeLists.txt:
+# set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR})
+# 3. Finally call find_package() once, here are some examples to pick from
+#
+# Require ICU 4.4 or later
+# find_package(ICU 4.4 REQUIRED)
+#
+# if(ICU_FOUND)
+# include_directories(${ICU_INCLUDE_DIRS})
+# add_executable(myapp myapp.c)
+# target_link_libraries(myapp ${ICU_LIBRARIES})
+# endif(ICU_FOUND)
+
+#=============================================================================
+# Copyright (c) 2011-2012, julp
+# https://github.com/julp/FindICU.cmake
+#
+# Distributed under the OSI-approved BSD License
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+#=============================================================================
+
+find_package(PkgConfig QUIET)
+
+########## Private ##########
+set(ICU_PUBLIC_VAR_NS "ICU") # Prefix for all ICU relative public variables
+set(ICU_PRIVATE_VAR_NS "_${ICU_PUBLIC_VAR_NS}") # Prefix for all ICU relative internal variables
+set(PC_ICU_PRIVATE_VAR_NS "_PC${ICU_PRIVATE_VAR_NS}") # Prefix for all pkg-config relative internal variables
+
+function(icudebug _VARNAME)
+ if(${ICU_PUBLIC_VAR_NS}_DEBUG)
+ if(DEFINED ${ICU_PUBLIC_VAR_NS}_${_VARNAME})
+ message("${ICU_PUBLIC_VAR_NS}_${_VARNAME} = ${${ICU_PUBLIC_VAR_NS}_${_VARNAME}}")
+ else(DEFINED ${ICU_PUBLIC_VAR_NS}_${_VARNAME})
+ message("${ICU_PUBLIC_VAR_NS}_${_VARNAME} = <UNDEFINED>")
+ endif(DEFINED ${ICU_PUBLIC_VAR_NS}_${_VARNAME})
+ endif(${ICU_PUBLIC_VAR_NS}_DEBUG)
+endfunction(icudebug)
+
+set(${ICU_PRIVATE_VAR_NS}_ROOT "")
+if(DEFINED ENV{ICU_ROOT})
+ set(${ICU_PRIVATE_VAR_NS}_ROOT "$ENV{ICU_ROOT}")
+endif(DEFINED ENV{ICU_ROOT})
+if (DEFINED ICU_ROOT)
+ set(${ICU_PRIVATE_VAR_NS}_ROOT "${ICU_ROOT}")
+endif(DEFINED ICU_ROOT)
+
+set(${ICU_PRIVATE_VAR_NS}_BIN_SUFFIXES )
+set(${ICU_PRIVATE_VAR_NS}_LIB_SUFFIXES )
+if(CMAKE_SIZEOF_VOID_P EQUAL 8)
+ list(APPEND ${ICU_PRIVATE_VAR_NS}_BIN_SUFFIXES "bin64")
+ list(APPEND ${ICU_PRIVATE_VAR_NS}_LIB_SUFFIXES "lib64")
+endif(CMAKE_SIZEOF_VOID_P EQUAL 8)
+list(APPEND ${ICU_PRIVATE_VAR_NS}_BIN_SUFFIXES "bin")
+list(APPEND ${ICU_PRIVATE_VAR_NS}_LIB_SUFFIXES "lib")
+
+set(${ICU_PRIVATE_VAR_NS}_COMPONENTS )
+# <icu component name> <library name 1> ... <library name N>
+macro(icu_declare_component _NAME)
+ list(APPEND ${ICU_PRIVATE_VAR_NS}_COMPONENTS ${_NAME})
+ set("${ICU_PRIVATE_VAR_NS}_COMPONENTS_${_NAME}" ${ARGN})
+endmacro(icu_declare_component)
+
+icu_declare_component(data icudata)
+icu_declare_component(uc icuuc) # Common and Data libraries
+icu_declare_component(i18n icui18n icuin) # Internationalization library
+icu_declare_component(io icuio ustdio) # Stream and I/O Library
+icu_declare_component(le icule) # Layout library
+icu_declare_component(lx iculx) # Paragraph Layout library
+
+########## Public ##########
+set(${ICU_PUBLIC_VAR_NS}_FOUND TRUE)
+set(${ICU_PUBLIC_VAR_NS}_LIBRARIES )
+set(${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS )
+set(${ICU_PUBLIC_VAR_NS}_C_FLAGS "")
+set(${ICU_PUBLIC_VAR_NS}_CXX_FLAGS "")
+set(${ICU_PUBLIC_VAR_NS}_CPP_FLAGS "")
+set(${ICU_PUBLIC_VAR_NS}_C_SHARED_FLAGS "")
+set(${ICU_PUBLIC_VAR_NS}_CXX_SHARED_FLAGS "")
+set(${ICU_PUBLIC_VAR_NS}_CPP_SHARED_FLAGS "")
+foreach(${ICU_PRIVATE_VAR_NS}_COMPONENT ${${ICU_PRIVATE_VAR_NS}_COMPONENTS})
+ string(TOUPPER "${${ICU_PRIVATE_VAR_NS}_COMPONENT}" ${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT)
+ set("${ICU_PUBLIC_VAR_NS}_${${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT}_FOUND" FALSE) # may be done in the icu_declare_component macro
+endforeach(${ICU_PRIVATE_VAR_NS}_COMPONENT)
+
+# Check components
+if(NOT ${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS) # uc required at least
+ set(${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS uc)
+else(NOT ${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS)
+ list(APPEND ${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS uc)
+ list(REMOVE_DUPLICATES ${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS)
+ foreach(${ICU_PRIVATE_VAR_NS}_COMPONENT ${${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS})
+ if(NOT DEFINED ${ICU_PRIVATE_VAR_NS}_COMPONENTS_${${ICU_PRIVATE_VAR_NS}_COMPONENT})
+ message(FATAL_ERROR "Unknown ICU component: ${${ICU_PRIVATE_VAR_NS}_COMPONENT}")
+ endif(NOT DEFINED ${ICU_PRIVATE_VAR_NS}_COMPONENTS_${${ICU_PRIVATE_VAR_NS}_COMPONENT})
+ endforeach(${ICU_PRIVATE_VAR_NS}_COMPONENT)
+endif(NOT ${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS)
+
+# Includes
+find_path(
+ ${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS
+ NAMES unicode/utypes.h utypes.h
+ HINTS ${${ICU_PRIVATE_VAR_NS}_ROOT}
+ PATH_SUFFIXES "include"
+ DOC "Include directories for ICU"
+)
+
+if(${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS)
+ ########## <part to keep synced with tests/version/CMakeLists.txt> ##########
+ if(EXISTS "${${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS}/unicode/uvernum.h") # ICU >= 4
+ file(READ "${${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS}/unicode/uvernum.h" ${ICU_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS)
+ elseif(EXISTS "${${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS}/unicode/uversion.h") # ICU [2;4[
+ file(READ "${${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS}/unicode/uversion.h" ${ICU_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS)
+ elseif(EXISTS "${${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS}/unicode/utypes.h") # ICU [1.4;2[
+ file(READ "${${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS}/unicode/utypes.h" ${ICU_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS)
+ elseif(EXISTS "${${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS}/utypes.h") # ICU 1.3
+ file(READ "${${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS}/utypes.h" ${ICU_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS)
+ else()
+ message(FATAL_ERROR "ICU version header not found")
+ endif()
+
+ if(${ICU_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS MATCHES ".*# *define *ICU_VERSION *\"([0-9]+)\".*") # ICU 1.3
+ # [1.3;1.4[ as #define ICU_VERSION "3" (no patch version, ie all 1.3.X versions will be detected as 1.3.0)
+ set(${ICU_PUBLIC_VAR_NS}_MAJOR_VERSION "1")
+ set(${ICU_PUBLIC_VAR_NS}_MINOR_VERSION "${CMAKE_MATCH_1}")
+ set(${ICU_PUBLIC_VAR_NS}_PATCH_VERSION "0")
+ elseif(${ICU_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS MATCHES ".*# *define *U_ICU_VERSION_MAJOR_NUM *([0-9]+).*")
+ set(${ICU_PUBLIC_VAR_NS}_MAJOR_VERSION "${CMAKE_MATCH_1}")
+ #
+ # Since version 4.9.1, ICU release version numbering was totaly changed, see:
+ # - http://site.icu-project.org/download/49
+ # - http://userguide.icu-project.org/design#TOC-Version-Numbers-in-ICU
+ #
+ if(${ICU_PUBLIC_VAR_NS}_MAJOR_VERSION LESS 49)
+ string(REGEX REPLACE ".*# *define *U_ICU_VERSION_MINOR_NUM *([0-9]+).*" "\\1" ${ICU_PUBLIC_VAR_NS}_MINOR_VERSION "${${ICU_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS}")
+ string(REGEX REPLACE ".*# *define *U_ICU_VERSION_PATCHLEVEL_NUM *([0-9]+).*" "\\1" ${ICU_PUBLIC_VAR_NS}_PATCH_VERSION "${${ICU_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS}")
+ else(${ICU_PUBLIC_VAR_NS}_MAJOR_VERSION LESS 49)
+ string(REGEX MATCH [0-9]$ ${ICU_PUBLIC_VAR_NS}_MINOR_VERSION "${${ICU_PUBLIC_VAR_NS}_MAJOR_VERSION}")
+ string(REGEX REPLACE [0-9]$ "" ${ICU_PUBLIC_VAR_NS}_MAJOR_VERSION "${${ICU_PUBLIC_VAR_NS}_MAJOR_VERSION}")
+ string(REGEX REPLACE ".*# *define *U_ICU_VERSION_MINOR_NUM *([0-9]+).*" "\\1" ${ICU_PUBLIC_VAR_NS}_PATCH_VERSION "${${ICU_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS}")
+ endif(${ICU_PUBLIC_VAR_NS}_MAJOR_VERSION LESS 49)
+ elseif(${ICU_PRIVATE_VAR_NS}_VERSION_HEADER_CONTENTS MATCHES ".*# *define *U_ICU_VERSION *\"(([0-9]+)(\\.[0-9]+)*)\".*") # ICU [1.4;1.8[
+ # [1.4;1.8[ as #define U_ICU_VERSION "1.4.1.2" but it seems that some 1.4.1(?:\.\d)? have releasing error and appears as 1.4.0
+ set(${ICU_PRIVATE_VAR_NS}_FULL_VERSION "${CMAKE_MATCH_1}") # copy CMAKE_MATCH_1, no longer valid on the following if
+ if(${ICU_PRIVATE_VAR_NS}_FULL_VERSION MATCHES "^([0-9]+)\\.([0-9]+)$")
+ set(${ICU_PUBLIC_VAR_NS}_MAJOR_VERSION "${CMAKE_MATCH_1}")
+ set(${ICU_PUBLIC_VAR_NS}_MINOR_VERSION "${CMAKE_MATCH_2}")
+ set(${ICU_PUBLIC_VAR_NS}_PATCH_VERSION "0")
+ elseif(${ICU_PRIVATE_VAR_NS}_FULL_VERSION MATCHES "^([0-9]+)\\.([0-9]+)\\.([0-9]+)")
+ set(${ICU_PUBLIC_VAR_NS}_MAJOR_VERSION "${CMAKE_MATCH_1}")
+ set(${ICU_PUBLIC_VAR_NS}_MINOR_VERSION "${CMAKE_MATCH_2}")
+ set(${ICU_PUBLIC_VAR_NS}_PATCH_VERSION "${CMAKE_MATCH_3}")
+ endif()
+ else()
+ message(FATAL_ERROR "failed to detect ICU version")
+ endif()
+ set(${ICU_PUBLIC_VAR_NS}_VERSION "${${ICU_PUBLIC_VAR_NS}_MAJOR_VERSION}.${${ICU_PUBLIC_VAR_NS}_MINOR_VERSION}.${${ICU_PUBLIC_VAR_NS}_PATCH_VERSION}")
+ ########## </part to keep synced with tests/version/CMakeLists.txt> ##########
+
+ # Check dependencies (implies pkg-config)
+ if(PKG_CONFIG_FOUND)
+ set(${ICU_PRIVATE_VAR_NS}_COMPONENTS_DUP ${${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS})
+ foreach(${ICU_PRIVATE_VAR_NS}_COMPONENT ${${ICU_PRIVATE_VAR_NS}_COMPONENTS_DUP})
+ pkg_check_modules(PC_ICU_PRIVATE_VAR_NS "icu-${${ICU_PRIVATE_VAR_NS}_COMPONENT}" QUIET)
+
+ if(${PC_ICU_PRIVATE_VAR_NS}_FOUND)
+ foreach(${PC_ICU_PRIVATE_VAR_NS}_LIBRARY ${PC_ICU_LIBRARIES})
+ string(REGEX REPLACE "^icu" "" ${PC_ICU_PRIVATE_VAR_NS}_STRIPPED_LIBRARY ${${PC_ICU_PRIVATE_VAR_NS}_LIBRARY})
+ list(APPEND ${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS ${${PC_ICU_PRIVATE_VAR_NS}_STRIPPED_LIBRARY})
+ endforeach(${PC_ICU_PRIVATE_VAR_NS}_LIBRARY)
+ endif(${PC_ICU_PRIVATE_VAR_NS}_FOUND)
+ endforeach(${ICU_PRIVATE_VAR_NS}_COMPONENT)
+ list(REMOVE_DUPLICATES ${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS)
+ endif(PKG_CONFIG_FOUND)
+
+ # Check libraries
+ foreach(${ICU_PRIVATE_VAR_NS}_COMPONENT ${${ICU_PUBLIC_VAR_NS}_FIND_COMPONENTS})
+ set(${ICU_PRIVATE_VAR_NS}_POSSIBLE_RELEASE_NAMES )
+ set(${ICU_PRIVATE_VAR_NS}_POSSIBLE_DEBUG_NAMES )
+ foreach(${ICU_PRIVATE_VAR_NS}_BASE_NAME ${${ICU_PRIVATE_VAR_NS}_COMPONENTS_${${ICU_PRIVATE_VAR_NS}_COMPONENT}})
+ list(APPEND ${ICU_PRIVATE_VAR_NS}_POSSIBLE_RELEASE_NAMES "${${ICU_PRIVATE_VAR_NS}_BASE_NAME}")
+ list(APPEND ${ICU_PRIVATE_VAR_NS}_POSSIBLE_DEBUG_NAMES "${${ICU_PRIVATE_VAR_NS}_BASE_NAME}d")
+ list(APPEND ${ICU_PRIVATE_VAR_NS}_POSSIBLE_RELEASE_NAMES "${${ICU_PRIVATE_VAR_NS}_BASE_NAME}${ICU_MAJOR_VERSION}${ICU_MINOR_VERSION}")
+ list(APPEND ${ICU_PRIVATE_VAR_NS}_POSSIBLE_DEBUG_NAMES "${${ICU_PRIVATE_VAR_NS}_BASE_NAME}${ICU_MAJOR_VERSION}${ICU_MINOR_VERSION}d")
+ endforeach(${ICU_PRIVATE_VAR_NS}_BASE_NAME)
+
+ find_library(
+ ${ICU_PRIVATE_VAR_NS}_LIB_RELEASE_${${ICU_PRIVATE_VAR_NS}_COMPONENT}
+ NAMES ${${ICU_PRIVATE_VAR_NS}_POSSIBLE_RELEASE_NAMES}
+ HINTS ${${ICU_PRIVATE_VAR_NS}_ROOT}
+ PATH_SUFFIXES ${_ICU_LIB_SUFFIXES}
+ DOC "Release libraries for ICU"
+ )
+ find_library(
+ ${ICU_PRIVATE_VAR_NS}_LIB_DEBUG_${${ICU_PRIVATE_VAR_NS}_COMPONENT}
+ NAMES ${${ICU_PRIVATE_VAR_NS}_POSSIBLE_DEBUG_NAMES}
+ HINTS ${${ICU_PRIVATE_VAR_NS}_ROOT}
+ PATH_SUFFIXES ${_ICU_LIB_SUFFIXES}
+ DOC "Debug libraries for ICU"
+ )
+
+ string(TOUPPER "${${ICU_PRIVATE_VAR_NS}_COMPONENT}" ${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT)
+ if(NOT ${ICU_PRIVATE_VAR_NS}_LIB_RELEASE_${${ICU_PRIVATE_VAR_NS}_COMPONENT} AND NOT ${ICU_PRIVATE_VAR_NS}_LIB_DEBUG_${${ICU_PRIVATE_VAR_NS}_COMPONENT}) # both not found
+ set("${ICU_PUBLIC_VAR_NS}_${${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT}_FOUND" FALSE)
+ set("${ICU_PUBLIC_VAR_NS}_FOUND" FALSE)
+ else(NOT ${ICU_PRIVATE_VAR_NS}_LIB_RELEASE_${${ICU_PRIVATE_VAR_NS}_COMPONENT} AND NOT ${ICU_PRIVATE_VAR_NS}_LIB_DEBUG_${${ICU_PRIVATE_VAR_NS}_COMPONENT}) # one or both found
+ set("${ICU_PUBLIC_VAR_NS}_${${ICU_PRIVATE_VAR_NS}_UPPER_COMPONENT}_FOUND" TRUE)
+ if(NOT ${ICU_PRIVATE_VAR_NS}_LIB_RELEASE_${${ICU_PRIVATE_VAR_NS}_COMPONENT}) # release not found => we are in debug
+ set(${ICU_PRIVATE_VAR_NS}_LIB_${${ICU_PRIVATE_VAR_NS}_COMPONENT} "${${ICU_PRIVATE_VAR_NS}_LIB_DEBUG_${${ICU_PRIVATE_VAR_NS}_COMPONENT}}")
+ elseif(NOT ${ICU_PRIVATE_VAR_NS}_LIB_DEBUG_${${ICU_PRIVATE_VAR_NS}_COMPONENT}) # debug not found => we are in release
+ set(${ICU_PRIVATE_VAR_NS}_LIB_${${ICU_PRIVATE_VAR_NS}_COMPONENT} "${${ICU_PRIVATE_VAR_NS}_LIB_RELEASE_${${ICU_PRIVATE_VAR_NS}_COMPONENT}}")
+ else() # both found
+ set(
+ ${ICU_PRIVATE_VAR_NS}_LIB_${${ICU_PRIVATE_VAR_NS}_COMPONENT}
+ optimized ${${ICU_PRIVATE_VAR_NS}_LIB_RELEASE_${${ICU_PRIVATE_VAR_NS}_COMPONENT}}
+ debug ${${ICU_PRIVATE_VAR_NS}_LIB_DEBUG_${${ICU_PRIVATE_VAR_NS}_COMPONENT}}
+ )
+ endif()
+ list(APPEND ${ICU_PUBLIC_VAR_NS}_LIBRARIES ${${ICU_PRIVATE_VAR_NS}_LIB_${${ICU_PRIVATE_VAR_NS}_COMPONENT}})
+ endif(NOT ${ICU_PRIVATE_VAR_NS}_LIB_RELEASE_${${ICU_PRIVATE_VAR_NS}_COMPONENT} AND NOT ${ICU_PRIVATE_VAR_NS}_LIB_DEBUG_${${ICU_PRIVATE_VAR_NS}_COMPONENT})
+ endforeach(${ICU_PRIVATE_VAR_NS}_COMPONENT)
+
+ # Try to find out compiler flags
+ find_program(${ICU_PUBLIC_VAR_NS}_CONFIG_EXECUTABLE HINTS ${${ICU_PRIVATE_VAR_NS}_ROOT} icu-config)
+ if(${ICU_PUBLIC_VAR_NS}_CONFIG_EXECUTABLE)
+ execute_process(COMMAND ${${ICU_PUBLIC_VAR_NS}_CONFIG_EXECUTABLE} --cflags OUTPUT_VARIABLE ${ICU_PUBLIC_VAR_NS}_C_FLAGS OUTPUT_STRIP_TRAILING_WHITESPACE)
+ execute_process(COMMAND ${${ICU_PUBLIC_VAR_NS}_CONFIG_EXECUTABLE} --cxxflags OUTPUT_VARIABLE ${ICU_PUBLIC_VAR_NS}_CXX_FLAGS OUTPUT_STRIP_TRAILING_WHITESPACE)
+ execute_process(COMMAND ${${ICU_PUBLIC_VAR_NS}_CONFIG_EXECUTABLE} --cppflags OUTPUT_VARIABLE ${ICU_PUBLIC_VAR_NS}_CPP_FLAGS OUTPUT_STRIP_TRAILING_WHITESPACE)
+
+ execute_process(COMMAND ${${ICU_PUBLIC_VAR_NS}_CONFIG_EXECUTABLE} --cflags-dynamic OUTPUT_VARIABLE ${ICU_PUBLIC_VAR_NS}_C_SHARED_FLAGS OUTPUT_STRIP_TRAILING_WHITESPACE)
+ execute_process(COMMAND ${${ICU_PUBLIC_VAR_NS}_CONFIG_EXECUTABLE} --cxxflags-dynamic OUTPUT_VARIABLE ${ICU_PUBLIC_VAR_NS}_CXX_SHARED_FLAGS OUTPUT_STRIP_TRAILING_WHITESPACE)
+ execute_process(COMMAND ${${ICU_PUBLIC_VAR_NS}_CONFIG_EXECUTABLE} --cppflags-dynamic OUTPUT_VARIABLE ${ICU_PUBLIC_VAR_NS}_CPP_SHARED_FLAGS OUTPUT_STRIP_TRAILING_WHITESPACE)
+ endif(${ICU_PUBLIC_VAR_NS}_CONFIG_EXECUTABLE)
+
+ # Check find_package arguments
+ include(FindPackageHandleStandardArgs)
+ if(${ICU_PUBLIC_VAR_NS}_FIND_REQUIRED AND NOT ${ICU_PUBLIC_VAR_NS}_FIND_QUIETLY)
+ find_package_handle_standard_args(
+ ${ICU_PUBLIC_VAR_NS}
+ REQUIRED_VARS ${ICU_PUBLIC_VAR_NS}_LIBRARIES ${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS
+ VERSION_VAR ${ICU_PUBLIC_VAR_NS}_VERSION
+ )
+ else(${ICU_PUBLIC_VAR_NS}_FIND_REQUIRED AND NOT ${ICU_PUBLIC_VAR_NS}_FIND_QUIETLY)
+ find_package_handle_standard_args(${ICU_PUBLIC_VAR_NS} "ICU not found" ${ICU_PUBLIC_VAR_NS}_LIBRARIES ${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS)
+ endif(${ICU_PUBLIC_VAR_NS}_FIND_REQUIRED AND NOT ${ICU_PUBLIC_VAR_NS}_FIND_QUIETLY)
+else(${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS)
+ if(${ICU_PUBLIC_VAR_NS}_FIND_REQUIRED AND NOT ${ICU_PUBLIC_VAR_NS}_FIND_QUIETLY)
+ message(FATAL_ERROR "Could not find ICU include directory")
+ endif(${ICU_PUBLIC_VAR_NS}_FIND_REQUIRED AND NOT ${ICU_PUBLIC_VAR_NS}_FIND_QUIETLY)
+endif(${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS)
+
+mark_as_advanced(
+ ${ICU_PUBLIC_VAR_NS}_INCLUDE_DIRS
+ ${ICU_PUBLIC_VAR_NS}_LIBRARIES
+)
+
+# IN (args)
+icudebug("FIND_COMPONENTS")
+icudebug("FIND_REQUIRED")
+icudebug("FIND_QUIETLY")
+icudebug("FIND_VERSION")
+# OUT
+# Found
+icudebug("FOUND")
+icudebug("UC_FOUND")
+icudebug("I18N_FOUND")
+icudebug("IO_FOUND")
+icudebug("LE_FOUND")
+icudebug("LX_FOUND")
+icudebug("DATA_FOUND")
+# Flags
+icudebug("C_FLAGS")
+icudebug("CPP_FLAGS")
+icudebug("CXX_FLAGS")
+icudebug("C_SHARED_FLAGS")
+icudebug("CPP_SHARED_FLAGS")
+icudebug("CXX_SHARED_FLAGS")
+# Linking
+icudebug("INCLUDE_DIRS")
+icudebug("LIBRARIES")
+# Version
+icudebug("MAJOR_VERSION")
+icudebug("MINOR_VERSION")
+icudebug("PATCH_VERSION")
+icudebug("VERSION")
diff --git a/vmime-master/cmake/FindIconv.cmake b/vmime-master/cmake/FindIconv.cmake
new file mode 100644
index 0000000..6233657
--- /dev/null
+++ b/vmime-master/cmake/FindIconv.cmake
@@ -0,0 +1,61 @@
+# - Try to find Iconv
+# Once done this will define
+#
+# ICONV_FOUND - system has Iconv
+# ICONV_INCLUDE_DIR - the Iconv include directory
+# ICONV_LIBRARIES - Link these to use Iconv
+# ICONV_SECOND_ARGUMENT_IS_CONST - the second argument for iconv() is const
+#
+include(CheckCXXSourceCompiles)
+
+IF (ICONV_INCLUDE_DIR AND ICONV_LIBRARIES)
+ # Already in cache, be silent
+ SET(ICONV_FIND_QUIETLY TRUE)
+ENDIF (ICONV_INCLUDE_DIR AND ICONV_LIBRARIES)
+
+FIND_PATH(ICONV_INCLUDE_DIR iconv.h)
+
+IF(${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
+ FIND_LIBRARY(ICONV_LIBRARIES NAMES iconv libiconv libiconv-2 c HINTS "/opt/local/lib")
+ELSE()
+ FIND_LIBRARY(ICONV_LIBRARIES NAMES iconv libiconv libiconv-2 c)
+ENDIF()
+
+IF(ICONV_INCLUDE_DIR AND ICONV_LIBRARIES)
+ SET(ICONV_FOUND TRUE)
+ENDIF(ICONV_INCLUDE_DIR AND ICONV_LIBRARIES)
+
+set(CMAKE_REQUIRED_INCLUDES ${ICONV_INCLUDE_DIR})
+set(CMAKE_REQUIRED_LIBRARIES ${ICONV_LIBRARIES})
+IF(ICONV_FOUND)
+ check_cxx_source_compiles("
+ #include <iconv.h>
+ int main(){
+ iconv_t conv = 0;
+ const char* in = 0;
+ size_t ilen = 0;
+ char* out = 0;
+ size_t olen = 0;
+ iconv(conv, &in, &ilen, &out, &olen);
+ return 0;
+ }
+" ICONV_SECOND_ARGUMENT_IS_CONST )
+ENDIF(ICONV_FOUND)
+set(CMAKE_REQUIRED_INCLUDES)
+set(CMAKE_REQUIRED_LIBRARIES)
+
+IF(ICONV_FOUND)
+ IF(NOT ICONV_FIND_QUIETLY)
+ MESSAGE(STATUS "Found Iconv: ${ICONV_LIBRARIES}")
+ ENDIF(NOT ICONV_FIND_QUIETLY)
+ELSE(ICONV_FOUND)
+ IF(Iconv_FIND_REQUIRED)
+ MESSAGE(FATAL_ERROR "Could not find Iconv")
+ ENDIF(Iconv_FIND_REQUIRED)
+ENDIF(ICONV_FOUND)
+
+MARK_AS_ADVANCED(
+ ICONV_INCLUDE_DIR
+ ICONV_LIBRARIES
+ ICONV_SECOND_ARGUMENT_IS_CONST
+)
diff --git a/vmime-master/cmake/Utils.cmake b/vmime-master/cmake/Utils.cmake
new file mode 100644
index 0000000..fd8928e
--- /dev/null
+++ b/vmime-master/cmake/Utils.cmake
@@ -0,0 +1,13 @@
+
+# Installing headers and preserving the directory structure
+# Found here: http://www.semipol.de/archives/251
+MACRO(INSTALL_HEADERS_WITH_DIRECTORY HEADER_LIST COMPONENT_NAME REMOVE_PREFIX)
+
+ FOREACH(HEADER ${${HEADER_LIST}})
+ STRING(REGEX MATCH "(.*)[/\\]" DIR ${HEADER})
+ STRING(REPLACE "${REMOVE_PREFIX}" "" DIR ${DIR})
+ INSTALL(FILES ${HEADER} DESTINATION include/${DIR} COMPONENT ${COMPONENT_NAME})
+ ENDFOREACH(HEADER)
+
+ENDMACRO(INSTALL_HEADERS_WITH_DIRECTORY)
+
diff --git a/vmime-master/cmake/config.hpp.cmake b/vmime-master/cmake/config.hpp.cmake
new file mode 100644
index 0000000..c5e9fde
--- /dev/null
+++ b/vmime-master/cmake/config.hpp.cmake
@@ -0,0 +1,97 @@
+//
+// This file was automatically generated by CMake.
+//
+
+#ifndef VMIME_CONFIG_HPP_INCLUDED
+#define VMIME_CONFIG_HPP_INCLUDED
+
+
+#include "vmime/export.hpp"
+
+
+// Name of package
+#define VMIME_PACKAGE "@PROJECT_NAME@"
+
+// Version number of package
+#define VMIME_VERSION "@VMIME_VERSION@"
+#define VMIME_API "@VMIME_API_VERSION@"
+
+// Set to 1 if debugging should be activated
+#define VMIME_DEBUG @VMIME_DEBUG@
+
+// Byte order (set one or the other, but not both!)
+#define VMIME_BYTE_ORDER_BIG_ENDIAN @VMIME_BYTE_ORDER_BIG_ENDIAN@
+#define VMIME_BYTE_ORDER_LITTLE_ENDIAN @VMIME_BYTE_ORDER_LITTLE_ENDIAN@
+
+// Generic types
+#cmakedefine01 VMIME_HAVE_CSTDINT
+#if VMIME_HAVE_CSTDINT
+# include <cstdint>
+#endif
+
+// -- 8-bit
+typedef signed @VMIME_8BIT_TYPE@ vmime_int8;
+typedef unsigned @VMIME_8BIT_TYPE@ vmime_uint8;
+// -- 16-bit
+typedef signed @VMIME_16BIT_TYPE@ vmime_int16;
+typedef unsigned @VMIME_16BIT_TYPE@ vmime_uint16;
+// -- 32-bit
+typedef signed @VMIME_32BIT_TYPE@ vmime_int32;
+typedef unsigned @VMIME_32BIT_TYPE@ vmime_uint32;
+// -- 64-bit
+typedef signed @VMIME_64BIT_TYPE@ vmime_int64;
+typedef unsigned @VMIME_64BIT_TYPE@ vmime_uint64;
+
+#cmakedefine01 VMIME_HAVE_SIZE_T
+
+// Charset conversion support
+#cmakedefine01 VMIME_CHARSETCONV_LIB_IS_ICONV
+#cmakedefine01 VMIME_CHARSETCONV_LIB_IS_ICU
+#cmakedefine01 VMIME_CHARSETCONV_LIB_IS_WIN
+
+// Options
+// -- File-system support
+#cmakedefine01 VMIME_HAVE_FILESYSTEM_FEATURES
+// -- SASL support
+#cmakedefine01 VMIME_HAVE_SASL_SUPPORT
+// -- TLS/SSL support
+#cmakedefine01 VMIME_HAVE_TLS_SUPPORT
+#cmakedefine01 VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
+#cmakedefine01 VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+#define VMIME_HAVE_GNUTLS_PRIORITY_FUNCS @VMIME_HAVE_GNUTLS_PRIORITY_FUNCS@
+// -- Messaging support
+#cmakedefine01 VMIME_HAVE_MESSAGING_FEATURES
+// -- Messaging protocols
+#cmakedefine01 VMIME_HAVE_MESSAGING_PROTO_POP3
+#cmakedefine01 VMIME_HAVE_MESSAGING_PROTO_SMTP
+#cmakedefine01 VMIME_HAVE_MESSAGING_PROTO_IMAP
+#cmakedefine01 VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+#cmakedefine01 VMIME_HAVE_MESSAGING_PROTO_SENDMAIL
+// -- Platform-specific code
+#cmakedefine01 VMIME_PLATFORM_IS_POSIX
+#cmakedefine01 VMIME_PLATFORM_IS_WINDOWS
+#cmakedefine01 VMIME_HAVE_PTHREAD
+#cmakedefine01 VMIME_HAVE_GETADDRINFO
+#cmakedefine01 VMIME_HAVE_GETADDRINFO_A
+#cmakedefine01 VMIME_HAVE_GETTID
+#cmakedefine01 VMIME_HAVE_SYSCALL
+#cmakedefine01 VMIME_HAVE_SYSCALL_GETTID
+#cmakedefine01 VMIME_HAVE_GETTHRID
+#cmakedefine01 VMIME_HAVE_GMTIME_S
+#cmakedefine01 VMIME_HAVE_GMTIME_R
+#cmakedefine01 VMIME_HAVE_LOCALTIME_S
+#cmakedefine01 VMIME_HAVE_LOCALTIME_R
+#cmakedefine01 VMIME_HAVE_STRERROR_R
+#cmakedefine01 VMIME_HAVE_MLANG
+#cmakedefine01 VMIME_HAVE_SO_KEEPALIVE
+#cmakedefine01 VMIME_HAVE_SO_NOSIGPIPE
+#cmakedefine01 VMIME_HAVE_MSG_NOSIGNAL
+#cmakedefine01 VMIME_SHARED_PTR_USE_CXX
+#cmakedefine01 VMIME_SHARED_PTR_USE_BOOST
+
+
+#define VMIME_SENDMAIL_PATH "@VMIME_SENDMAIL_PATH@"
+
+
+#endif // VMIME_CONFIG_HPP_INCLUDED
+
diff --git a/vmime-master/config_header/config.hpp b/vmime-master/config_header/config.hpp
new file mode 100644
index 0000000..026b839
--- /dev/null
+++ b/vmime-master/config_header/config.hpp
@@ -0,0 +1,97 @@
+//
+// This file was automatically generated by CMake.
+//
+
+#ifndef VMIME_CONFIG_HPP_INCLUDED
+#define VMIME_CONFIG_HPP_INCLUDED
+
+
+#include "vmime/export.hpp"
+
+
+// Name of package
+#define VMIME_PACKAGE "vmime"
+
+// Version number of package
+#define VMIME_VERSION "0.9.2"
+#define VMIME_API "1.0.0"
+
+// Set to 1 if debugging should be activated
+#define VMIME_DEBUG 1
+
+// Byte order (set one or the other, but not both!)
+#define VMIME_BYTE_ORDER_BIG_ENDIAN 0
+#define VMIME_BYTE_ORDER_LITTLE_ENDIAN 1
+
+// Generic types
+#define VMIME_HAVE_CSTDINT 1
+#if VMIME_HAVE_CSTDINT
+# include <cstdint>
+#endif
+
+// -- 8-bit
+typedef signed char vmime_int8;
+typedef unsigned char vmime_uint8;
+// -- 16-bit
+typedef signed short vmime_int16;
+typedef unsigned short vmime_uint16;
+// -- 32-bit
+typedef signed int vmime_int32;
+typedef unsigned int vmime_uint32;
+// -- 64-bit
+typedef signed long long vmime_int64;
+typedef unsigned long long vmime_uint64;
+
+#define VMIME_HAVE_SIZE_T 1
+
+// Charset conversion support
+#define VMIME_CHARSETCONV_LIB_IS_ICONV 0
+#define VMIME_CHARSETCONV_LIB_IS_ICU 0
+#define VMIME_CHARSETCONV_LIB_IS_WIN 1
+
+// Options
+// -- File-system support
+#define VMIME_HAVE_FILESYSTEM_FEATURES 1
+// -- SASL support
+#define VMIME_HAVE_SASL_SUPPORT 0
+// -- TLS/SSL support
+#define VMIME_HAVE_TLS_SUPPORT 1
+#define VMIME_TLS_SUPPORT_LIB_IS_GNUTLS 0
+#define VMIME_TLS_SUPPORT_LIB_IS_OPENSSL 1
+#define VMIME_HAVE_GNUTLS_PRIORITY_FUNCS
+// -- Messaging support
+#define VMIME_HAVE_MESSAGING_FEATURES 1
+// -- Messaging protocols
+#define VMIME_HAVE_MESSAGING_PROTO_POP3 1
+#define VMIME_HAVE_MESSAGING_PROTO_SMTP 1
+#define VMIME_HAVE_MESSAGING_PROTO_IMAP 1
+#define VMIME_HAVE_MESSAGING_PROTO_MAILDIR 0
+#define VMIME_HAVE_MESSAGING_PROTO_SENDMAIL 0
+// -- Platform-specific code
+#define VMIME_PLATFORM_IS_POSIX 0
+#define VMIME_PLATFORM_IS_WINDOWS 1
+#define VMIME_HAVE_PTHREAD 0
+#define VMIME_HAVE_GETADDRINFO 0
+#define VMIME_HAVE_GETADDRINFO_A 0
+#define VMIME_HAVE_GETTID 0
+#define VMIME_HAVE_SYSCALL 0
+#define VMIME_HAVE_SYSCALL_GETTID 0
+#define VMIME_HAVE_GETTHRID 0
+#define VMIME_HAVE_GMTIME_S 0
+#define VMIME_HAVE_GMTIME_R 0
+#define VMIME_HAVE_LOCALTIME_S 0
+#define VMIME_HAVE_LOCALTIME_R 0
+#define VMIME_HAVE_STRERROR_R 0
+#define VMIME_HAVE_MLANG 0
+#define VMIME_HAVE_SO_KEEPALIVE 0
+#define VMIME_HAVE_SO_NOSIGPIPE 0
+#define VMIME_HAVE_MSG_NOSIGNAL 0
+#define VMIME_SHARED_PTR_USE_CXX 0
+#define VMIME_SHARED_PTR_USE_BOOST 0
+
+
+#define VMIME_SENDMAIL_PATH "/usr/lib/sendmail"
+
+
+#endif // VMIME_CONFIG_HPP_INCLUDED
+
diff --git a/vmime-master/contrib/punycode/punycode.c b/vmime-master/contrib/punycode/punycode.c
new file mode 100644
index 0000000..f669aa0
--- /dev/null
+++ b/vmime-master/contrib/punycode/punycode.c
@@ -0,0 +1,264 @@
+/*
+punycode.c from RFC 3492
+http://www.nicemice.net/idn/
+Adam M. Costello
+http://www.nicemice.net/amc/
+
+This is ANSI C code (C89) implementing Punycode (RFC 3492).
+
+*/
+
+#include <string.h>
+
+/*** Bootstring parameters for Punycode ***/
+
+enum { base = 36, tmin = 1, tmax = 26, skew = 38, damp = 700,
+ initial_bias = 72, initial_n = 0x80, delimiter = 0x2D };
+
+/* basic(cp) tests whether cp is a basic code point: */
+#define basic(cp) ((punycode_uint)(cp) < 0x80)
+
+/* delim(cp) tests whether cp is a delimiter: */
+#define delim(cp) ((cp) == delimiter)
+
+/* decode_digit(cp) returns the numeric value of a basic code */
+/* point (for use in representing integers) in the range 0 to */
+/* base-1, or base if cp is does not represent a value. */
+
+static punycode_uint decode_digit(punycode_uint cp)
+{
+ return cp - 48 < 10 ? cp - 22 : cp - 65 < 26 ? cp - 65 :
+ cp - 97 < 26 ? cp - 97 : (punycode_uint) base;
+}
+
+/* encode_digit(d,flag) returns the basic code point whose value */
+/* (when used for representing integers) is d, which needs to be in */
+/* the range 0 to base-1. The lowercase form is used unless flag is */
+/* nonzero, in which case the uppercase form is used. The behavior */
+/* is undefined if flag is nonzero and digit d has no uppercase form. */
+
+static char encode_digit(punycode_uint d, int flag)
+{
+ return char(d + 22 + 75 * (d < 26) - ((flag != 0) << 5));
+ /* 0..25 map to ASCII a..z or A..Z */
+ /* 26..35 map to ASCII 0..9 */
+}
+
+/* flagged(bcp) tests whether a basic code point is flagged */
+/* (uppercase). The behavior is undefined if bcp is not a */
+/* basic code point. */
+
+#define flagged(bcp) ((punycode_uint)(bcp) - 65 < 26)
+
+/* encode_basic(bcp,flag) forces a basic code point to lowercase */
+/* if flag is zero, uppercase if flag is nonzero, and returns */
+/* the resulting code point. The code point is unchanged if it */
+/* is caseless. The behavior is undefined if bcp is not a basic */
+/* code point. */
+
+static char encode_basic(punycode_uint bcp, int flag)
+{
+ bcp -= (bcp - 97 < 26) << 5;
+ return char(bcp + ((!flag && (bcp - 65 < 26)) << 5));
+}
+
+/*** Platform-specific constants ***/
+
+/* maxint is the maximum value of a punycode_uint variable: */
+static const punycode_uint maxint = -1U;
+/* Because maxint is unsigned, -1 becomes the maximum value. */
+
+/*** Bias adaptation function ***/
+
+static punycode_uint adapt(
+ punycode_uint delta, punycode_uint numpoints, int firsttime )
+{
+ punycode_uint k;
+
+ delta = firsttime ? delta / damp : delta >> 1;
+ /* delta >> 1 is a faster way of doing delta / 2 */
+ delta += delta / numpoints;
+
+ for (k = 0; delta > ((base - tmin) * tmax) / 2; k += base) {
+ delta /= base - tmin;
+ }
+
+ return k + (base - tmin + 1) * delta / (delta + skew);
+}
+
+/*** Main encode function ***/
+
+enum punycode_status punycode_encode(
+ punycode_uint input_length,
+ const punycode_uint input[],
+ const unsigned char case_flags[],
+ punycode_uint *output_length,
+ char output[] )
+{
+ punycode_uint n, delta, h, b, out, max_out, bias, j, m, q, k, t;
+
+ /* Initialize the state: */
+
+ n = initial_n;
+ delta = out = 0;
+ max_out = *output_length;
+ bias = initial_bias;
+
+ /* Handle the basic code points: */
+
+ for (j = 0; j < input_length; ++j) {
+ if (basic(input[j])) {
+ if (max_out - out < 2) return punycode_big_output;
+ output[out++] = char(
+ case_flags ? encode_basic(input[j], case_flags[j]) : input[j]
+ );
+ }
+ /* else if (input[j] < n) return punycode_bad_input; */
+ /* (not needed for Punycode with unsigned code points) */
+ }
+
+ h = b = out;
+
+ /* h is the number of code points that have been handled, b is the */
+ /* number of basic code points, and out is the number of characters */
+ /* that have been output. */
+
+ if (b > 0) output[out++] = delimiter;
+
+ /* Main encoding loop: */
+
+ while (h < input_length) {
+ /* All non-basic code points < n have been */
+ /* handled already. Find the next larger one: */
+
+ for (m = maxint, j = 0; j < input_length; ++j) {
+ /* if (basic(input[j])) continue; */
+ /* (not needed for Punycode) */
+ if (input[j] >= n && input[j] < m) m = input[j];
+ }
+
+ /* Increase delta enough to advance the decoder's */
+ /* <n,i> state to <m,0>, but guard against overflow: */
+
+ if (m - n > (maxint - delta) / (h + 1)) return punycode_overflow;
+ delta += (m - n) * (h + 1);
+ n = m;
+
+ for (j = 0; j < input_length; ++j) {
+ /* Punycode does not need to check whether input[j] is basic: */
+ if (input[j] < n /* || basic(input[j]) */ ) {
+ if (++delta == 0) return punycode_overflow;
+ }
+
+ if (input[j] == n) {
+ /* Represent delta as a generalized variable-length integer: */
+
+ for (q = delta, k = base; ; k += base) {
+ if (out >= max_out) return punycode_big_output;
+ t = k <= bias /* + tmin */ ? (punycode_uint) tmin : /* +tmin not needed */
+ k >= (punycode_uint) bias + (punycode_uint) tmax ? (punycode_uint) tmax : k - (punycode_uint) bias;
+ if (q < t) break;
+ output[out++] = encode_digit(t + (q - t) % (base - t), 0);
+ q = (q - t) / (base - t);
+ }
+
+ output[out++] = encode_digit(q, case_flags && case_flags[j]);
+ bias = adapt(delta, h + 1, h == b);
+ delta = 0;
+ ++h;
+ }
+ }
+
+ ++delta, ++n;
+ }
+
+ *output_length = out;
+ return punycode_success;
+}
+
+/*** Main decode function ***/
+
+enum punycode_status punycode_decode(
+ punycode_uint input_length,
+ const char input[],
+ punycode_uint *output_length,
+ punycode_uint output[],
+ unsigned char case_flags[] )
+{
+ punycode_uint n, out, i, max_out, bias,
+ b, j, in, oldi, w, k, digit, t;
+
+ /* Initialize the state: */
+
+ n = initial_n;
+ out = i = 0;
+ max_out = *output_length;
+ bias = initial_bias;
+
+ /* Handle the basic code points: Let b be the number of input code */
+ /* points before the last delimiter, or 0 if there is none, then */
+ /* copy the first b code points to the output. */
+
+ for (b = j = 0; j < input_length; ++j) if (delim(input[j])) b = j;
+ if (b > max_out) return punycode_big_output;
+
+ for (j = 0; j < b; ++j) {
+ if (case_flags) case_flags[out] = flagged(input[j]);
+ if (!basic(input[j])) return punycode_bad_input;
+ output[out++] = input[j];
+ }
+
+ /* Main decoding loop: Start just after the last delimiter if any */
+ /* basic code points were copied; start at the beginning otherwise. */
+
+ for (in = b > 0 ? b + 1 : 0; in < input_length; ++out) {
+
+ /* in is the index of the next character to be consumed, and */
+ /* out is the number of code points in the output array. */
+
+ /* Decode a generalized variable-length integer into delta, */
+ /* which gets added to i. The overflow checking is easier */
+ /* if we increase i as we go, then subtract off its starting */
+ /* value at the end to obtain delta. */
+
+ for (oldi = i, w = 1, k = base; ; k += base) {
+ if (in >= input_length) return punycode_bad_input;
+ digit = decode_digit(input[in++]);
+ if (digit >= base) return punycode_bad_input;
+ if (digit > (maxint - i) / w) return punycode_overflow;
+ i += digit * w;
+ t = k <= (punycode_uint) bias /* + tmin */ ? (punycode_uint) tmin : /* +tmin not needed */
+ k >= (punycode_uint) bias + (punycode_uint) tmax ? (punycode_uint) tmax : k - (punycode_uint) bias;
+ if (digit < t) break;
+ if (w > maxint / (base - t)) return punycode_overflow;
+ w *= (base - t);
+ }
+
+ bias = adapt(i - oldi, out + 1, oldi == 0);
+
+ /* i was supposed to wrap around from out+1 to 0, */
+ /* incrementing n each time, so we'll fix that now: */
+
+ if (i / (out + 1) > maxint - n) return punycode_overflow;
+ n += i / (out + 1);
+ i %= (out + 1);
+
+ /* Insert n at position i of the output: */
+
+ /* not needed for Punycode: */
+ /* if (decode_digit(n) <= base) return punycode_invalid_input; */
+ if (out >= max_out) return punycode_big_output;
+
+ if (case_flags) {
+ memmove(case_flags + i + 1, case_flags + i, out - i);
+ /* Case of last character determines uppercase flag: */
+ case_flags[i] = flagged(input[in - 1]);
+ }
+
+ memmove(output + i + 1, output + i, (out - i) * sizeof *output);
+ output[i++] = n;
+ }
+
+ *output_length = out;
+ return punycode_success;
+}
diff --git a/vmime-master/contrib/punycode/punycode.h b/vmime-master/contrib/punycode/punycode.h
new file mode 100644
index 0000000..fb02ee9
--- /dev/null
+++ b/vmime-master/contrib/punycode/punycode.h
@@ -0,0 +1,84 @@
+/*
+punycode.h from RFC 3492
+http://www.nicemice.net/idn/
+Adam M. Costello
+http://www.nicemice.net/amc/
+
+This is ANSI C code (C89) implementing Punycode (RFC 3492).
+
+*/
+
+#include <limits.h>
+
+enum punycode_status {
+ punycode_success,
+ punycode_bad_input, /* Input is invalid. */
+ punycode_big_output, /* Output would exceed the space provided. */
+ punycode_overflow /* Input needs wider integers to process. */
+};
+
+#if UINT_MAX >= (1 << 26) - 1
+typedef unsigned int punycode_uint;
+#else
+typedef unsigned long punycode_uint;
+#endif
+
+enum punycode_status punycode_encode(
+ punycode_uint input_length,
+ const punycode_uint input[],
+ const unsigned char case_flags[],
+ punycode_uint *output_length,
+ char output[] );
+
+ /* punycode_encode() converts Unicode to Punycode. The input */
+ /* is represented as an array of Unicode code points (not code */
+ /* units; surrogate pairs are not allowed), and the output */
+ /* will be represented as an array of ASCII code points. The */
+ /* output string is *not* null-terminated; it will contain */
+ /* zeros if and only if the input contains zeros. (Of course */
+ /* the caller can leave room for a terminator and add one if */
+ /* needed.) The input_length is the number of code points in */
+ /* the input. The output_length is an in/out argument: the */
+ /* caller passes in the maximum number of code points that it */
+ /* can receive, and on successful return it will contain the */
+ /* number of code points actually output. The case_flags array */
+ /* holds input_length boolean values, where nonzero suggests that */
+ /* the corresponding Unicode character be forced to uppercase */
+ /* after being decoded (if possible), and zero suggests that */
+ /* it be forced to lowercase (if possible). ASCII code points */
+ /* are encoded literally, except that ASCII letters are forced */
+ /* to uppercase or lowercase according to the corresponding */
+ /* uppercase flags. If case_flags is a null pointer then ASCII */
+ /* letters are left as they are, and other code points are */
+ /* treated as if their uppercase flags were zero. The return */
+ /* value can be any of the punycode_status values defined above */
+ /* except punycode_bad_input; if not punycode_success, then */
+ /* output_size and output might contain garbage. */
+
+enum punycode_status punycode_decode(
+ punycode_uint input_length,
+ const char input[],
+ punycode_uint *output_length,
+ punycode_uint output[],
+ unsigned char case_flags[] );
+
+ /* punycode_decode() converts Punycode to Unicode. The input is */
+ /* represented as an array of ASCII code points, and the output */
+ /* will be represented as an array of Unicode code points. The */
+ /* input_length is the number of code points in the input. The */
+ /* output_length is an in/out argument: the caller passes in */
+ /* the maximum number of code points that it can receive, and */
+ /* on successful return it will contain the actual number of */
+ /* code points output. The case_flags array needs room for at */
+ /* least output_length values, or it can be a null pointer if the */
+ /* case information is not needed. A nonzero flag suggests that */
+ /* the corresponding Unicode character be forced to uppercase */
+ /* by the caller (if possible), while zero suggests that it be */
+ /* forced to lowercase (if possible). ASCII code points are */
+ /* output already in the proper case, but their flags will be set */
+ /* appropriately so that applying the flags would be harmless. */
+ /* The return value can be any of the punycode_status values */
+ /* defined above; if not punycode_success, then output_length, */
+ /* output, and case_flags might contain garbage. On success, the */
+ /* decoder will never need to write an output_length greater than */
+ /* input_length, because of how the encoding is defined. */
diff --git a/vmime-master/contrib/utf8/utf8.h b/vmime-master/contrib/utf8/utf8.h
new file mode 100644
index 0000000..4e44514
--- /dev/null
+++ b/vmime-master/contrib/utf8/utf8.h
@@ -0,0 +1,34 @@
+// Copyright 2006 Nemanja Trifunovic
+
+/*
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+*/
+
+
+#ifndef UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731
+#define UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731
+
+#include "utf8/checked.h"
+#include "utf8/unchecked.h"
+
+#endif // header guard
diff --git a/vmime-master/contrib/utf8/utf8/checked.h b/vmime-master/contrib/utf8/utf8/checked.h
new file mode 100644
index 0000000..1331155
--- /dev/null
+++ b/vmime-master/contrib/utf8/utf8/checked.h
@@ -0,0 +1,327 @@
+// Copyright 2006 Nemanja Trifunovic
+
+/*
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+*/
+
+
+#ifndef UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
+#define UTF8_FOR_CPP_CHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
+
+#include "core.h"
+#include <stdexcept>
+
+namespace utf8
+{
+ // Base for the exceptions that may be thrown from the library
+ class exception : public ::std::exception {
+ };
+
+ // Exceptions that may be thrown from the library functions.
+ class invalid_code_point : public exception {
+ uint32_t cp;
+ public:
+ invalid_code_point(uint32_t cp) : cp(cp) {}
+ virtual const char* what() const throw() { return "Invalid code point"; }
+ uint32_t code_point() const {return cp;}
+ };
+
+ class invalid_utf8 : public exception {
+ uint8_t u8;
+ public:
+ invalid_utf8 (uint8_t u) : u8(u) {}
+ virtual const char* what() const throw() { return "Invalid UTF-8"; }
+ uint8_t utf8_octet() const {return u8;}
+ };
+
+ class invalid_utf16 : public exception {
+ uint16_t u16;
+ public:
+ invalid_utf16 (uint16_t u) : u16(u) {}
+ virtual const char* what() const throw() { return "Invalid UTF-16"; }
+ uint16_t utf16_word() const {return u16;}
+ };
+
+ class not_enough_room : public exception {
+ public:
+ virtual const char* what() const throw() { return "Not enough space"; }
+ };
+
+ /// The library API - functions intended to be called by the users
+
+ template <typename octet_iterator>
+ octet_iterator append(uint32_t cp, octet_iterator result)
+ {
+ if (!utf8::internal::is_code_point_valid(cp))
+ throw invalid_code_point(cp);
+
+ if (cp < 0x80) // one octet
+ *(result++) = static_cast<uint8_t>(cp);
+ else if (cp < 0x800) { // two octets
+ *(result++) = static_cast<uint8_t>((cp >> 6) | 0xc0);
+ *(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
+ }
+ else if (cp < 0x10000) { // three octets
+ *(result++) = static_cast<uint8_t>((cp >> 12) | 0xe0);
+ *(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
+ *(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
+ }
+ else { // four octets
+ *(result++) = static_cast<uint8_t>((cp >> 18) | 0xf0);
+ *(result++) = static_cast<uint8_t>(((cp >> 12) & 0x3f) | 0x80);
+ *(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
+ *(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
+ }
+ return result;
+ }
+
+ template <typename octet_iterator, typename output_iterator>
+ output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, uint32_t replacement)
+ {
+ while (start != end) {
+ octet_iterator sequence_start = start;
+ internal::utf_error err_code = utf8::internal::validate_next(start, end);
+ switch (err_code) {
+ case internal::UTF8_OK :
+ for (octet_iterator it = sequence_start; it != start; ++it)
+ *out++ = *it;
+ break;
+ case internal::NOT_ENOUGH_ROOM:
+ throw not_enough_room();
+ case internal::INVALID_LEAD:
+ out = utf8::append (replacement, out);
+ ++start;
+ break;
+ case internal::INCOMPLETE_SEQUENCE:
+ case internal::OVERLONG_SEQUENCE:
+ case internal::INVALID_CODE_POINT:
+ out = utf8::append (replacement, out);
+ ++start;
+ // just one replacement mark for the sequence
+ while (start != end && utf8::internal::is_trail(*start))
+ ++start;
+ break;
+ }
+ }
+ return out;
+ }
+
+ template <typename octet_iterator, typename output_iterator>
+ inline output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out)
+ {
+ static const uint32_t replacement_marker = utf8::internal::mask16(0xfffd);
+ return utf8::replace_invalid(start, end, out, replacement_marker);
+ }
+
+ template <typename octet_iterator>
+ uint32_t next(octet_iterator& it, octet_iterator end)
+ {
+ uint32_t cp = 0;
+ internal::utf_error err_code = utf8::internal::validate_next(it, end, cp);
+ switch (err_code) {
+ case internal::UTF8_OK :
+ break;
+ case internal::NOT_ENOUGH_ROOM :
+ throw not_enough_room();
+ case internal::INVALID_LEAD :
+ case internal::INCOMPLETE_SEQUENCE :
+ case internal::OVERLONG_SEQUENCE :
+ throw invalid_utf8(*it);
+ case internal::INVALID_CODE_POINT :
+ throw invalid_code_point(cp);
+ }
+ return cp;
+ }
+
+ template <typename octet_iterator>
+ uint32_t peek_next(octet_iterator it, octet_iterator end)
+ {
+ return utf8::next(it, end);
+ }
+
+ template <typename octet_iterator>
+ uint32_t prior(octet_iterator& it, octet_iterator start)
+ {
+ // can't do much if it == start
+ if (it == start)
+ throw not_enough_room();
+
+ octet_iterator end = it;
+ // Go back until we hit either a lead octet or start
+ while (utf8::internal::is_trail(*(--it)))
+ if (it == start)
+ throw invalid_utf8(*it); // error - no lead byte in the sequence
+ return utf8::peek_next(it, end);
+ }
+
+ /// Deprecated in versions that include "prior"
+ template <typename octet_iterator>
+ uint32_t previous(octet_iterator& it, octet_iterator pass_start)
+ {
+ octet_iterator end = it;
+ while (utf8::internal::is_trail(*(--it)))
+ if (it == pass_start)
+ throw invalid_utf8(*it); // error - no lead byte in the sequence
+ octet_iterator temp = it;
+ return utf8::next(temp, end);
+ }
+
+ template <typename octet_iterator, typename distance_type>
+ void advance (octet_iterator& it, distance_type n, octet_iterator end)
+ {
+ for (distance_type i = 0; i < n; ++i)
+ utf8::next(it, end);
+ }
+
+ template <typename octet_iterator>
+ typename std::iterator_traits<octet_iterator>::difference_type
+ distance (octet_iterator first, octet_iterator last)
+ {
+ typename std::iterator_traits<octet_iterator>::difference_type dist;
+ for (dist = 0; first < last; ++dist)
+ utf8::next(first, last);
+ return dist;
+ }
+
+ template <typename u16bit_iterator, typename octet_iterator>
+ octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result)
+ {
+ while (start != end) {
+ uint32_t cp = utf8::internal::mask16(*start++);
+ // Take care of surrogate pairs first
+ if (utf8::internal::is_lead_surrogate(cp)) {
+ if (start != end) {
+ uint32_t trail_surrogate = utf8::internal::mask16(*start++);
+ if (utf8::internal::is_trail_surrogate(trail_surrogate))
+ cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET;
+ else
+ throw invalid_utf16(static_cast<uint16_t>(trail_surrogate));
+ }
+ else
+ throw invalid_utf16(static_cast<uint16_t>(cp));
+
+ }
+ // Lone trail surrogate
+ else if (utf8::internal::is_trail_surrogate(cp))
+ throw invalid_utf16(static_cast<uint16_t>(cp));
+
+ result = utf8::append(cp, result);
+ }
+ return result;
+ }
+
+ template <typename u16bit_iterator, typename octet_iterator>
+ u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result)
+ {
+ while (start != end) {
+ uint32_t cp = utf8::next(start, end);
+ if (cp > 0xffff) { //make a surrogate pair
+ *result++ = static_cast<uint16_t>((cp >> 10) + internal::LEAD_OFFSET);
+ *result++ = static_cast<uint16_t>((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN);
+ }
+ else
+ *result++ = static_cast<uint16_t>(cp);
+ }
+ return result;
+ }
+
+ template <typename octet_iterator, typename u32bit_iterator>
+ octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result)
+ {
+ while (start != end)
+ result = utf8::append(*(start++), result);
+
+ return result;
+ }
+
+ template <typename octet_iterator, typename u32bit_iterator>
+ u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result)
+ {
+ while (start != end)
+ (*result++) = utf8::next(start, end);
+
+ return result;
+ }
+
+ // The iterator class
+ template <typename octet_iterator>
+ class iterator : public std::iterator <std::bidirectional_iterator_tag, uint32_t> {
+ octet_iterator it;
+ octet_iterator range_start;
+ octet_iterator range_end;
+ public:
+ iterator () {}
+ explicit iterator (const octet_iterator& octet_it,
+ const octet_iterator& range_start,
+ const octet_iterator& range_end) :
+ it(octet_it), range_start(range_start), range_end(range_end)
+ {
+ if (it < range_start || it > range_end)
+ throw std::out_of_range("Invalid utf-8 iterator position");
+ }
+ // the default "big three" are OK
+ octet_iterator base () const { return it; }
+ uint32_t operator * () const
+ {
+ octet_iterator temp = it;
+ return utf8::next(temp, range_end);
+ }
+ bool operator == (const iterator& rhs) const
+ {
+ if (range_start != rhs.range_start || range_end != rhs.range_end)
+ throw std::logic_error("Comparing utf-8 iterators defined with different ranges");
+ return (it == rhs.it);
+ }
+ bool operator != (const iterator& rhs) const
+ {
+ return !(operator == (rhs));
+ }
+ iterator& operator ++ ()
+ {
+ utf8::next(it, range_end);
+ return *this;
+ }
+ iterator operator ++ (int)
+ {
+ iterator temp = *this;
+ utf8::next(it, range_end);
+ return temp;
+ }
+ iterator& operator -- ()
+ {
+ utf8::prior(it, range_start);
+ return *this;
+ }
+ iterator operator -- (int)
+ {
+ iterator temp = *this;
+ utf8::prior(it, range_start);
+ return temp;
+ }
+ }; // class iterator
+
+} // namespace utf8
+
+#endif //header guard
+
+
diff --git a/vmime-master/contrib/utf8/utf8/core.h b/vmime-master/contrib/utf8/utf8/core.h
new file mode 100644
index 0000000..f858c4a
--- /dev/null
+++ b/vmime-master/contrib/utf8/utf8/core.h
@@ -0,0 +1,326 @@
+// Copyright 2006 Nemanja Trifunovic
+
+/*
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+*/
+
+
+#ifndef UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
+#define UTF8_FOR_CPP_CORE_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
+
+#include <iterator>
+
+namespace utf8
+{
+ typedef vmime_uint8 uint8_t;
+ typedef vmime_uint16 uint16_t;
+ typedef vmime_uint32 uint32_t;
+
+// Helper code - not intended to be directly called by the library users. May be changed at any time
+namespace internal
+{
+ // Unicode constants
+ // Leading (high) surrogates: 0xd800 - 0xdbff
+ // Trailing (low) surrogates: 0xdc00 - 0xdfff
+ const uint16_t LEAD_SURROGATE_MIN = 0xd800u;
+ const uint16_t LEAD_SURROGATE_MAX = 0xdbffu;
+ const uint16_t TRAIL_SURROGATE_MIN = 0xdc00u;
+ const uint16_t TRAIL_SURROGATE_MAX = 0xdfffu;
+ const uint16_t LEAD_OFFSET = LEAD_SURROGATE_MIN - (0x10000 >> 10);
+ const uint32_t SURROGATE_OFFSET = 0x10000u - (LEAD_SURROGATE_MIN << 10) - TRAIL_SURROGATE_MIN;
+
+ // Maximum valid value for a Unicode code point
+ const uint32_t CODE_POINT_MAX = 0x0010ffffu;
+
+ template<typename octet_type>
+ inline uint8_t mask8(octet_type oc)
+ {
+ return static_cast<uint8_t>(0xff & oc);
+ }
+ template<typename u16_type>
+ inline uint16_t mask16(u16_type oc)
+ {
+ return static_cast<uint16_t>(0xffff & oc);
+ }
+ template<typename octet_type>
+ inline bool is_trail(octet_type oc)
+ {
+ return ((utf8::internal::mask8(oc) >> 6) == 0x2);
+ }
+
+ template <typename u16>
+ inline bool is_lead_surrogate(u16 cp)
+ {
+ return (cp >= LEAD_SURROGATE_MIN && cp <= LEAD_SURROGATE_MAX);
+ }
+
+ template <typename u16>
+ inline bool is_trail_surrogate(u16 cp)
+ {
+ return (cp >= TRAIL_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);
+ }
+
+ template <typename u16>
+ inline bool is_surrogate(u16 cp)
+ {
+ return (cp >= LEAD_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX);
+ }
+
+ template <typename u32>
+ inline bool is_code_point_valid(u32 cp)
+ {
+ return (cp <= CODE_POINT_MAX && !utf8::internal::is_surrogate(cp));
+ }
+
+ template <typename octet_iterator>
+ inline typename std::iterator_traits<octet_iterator>::difference_type
+ sequence_length(octet_iterator lead_it)
+ {
+ uint8_t lead = utf8::internal::mask8(*lead_it);
+ if (lead < 0x80)
+ return 1;
+ else if ((lead >> 5) == 0x6)
+ return 2;
+ else if ((lead >> 4) == 0xe)
+ return 3;
+ else if ((lead >> 3) == 0x1e)
+ return 4;
+ else
+ return 0;
+ }
+
+ template <typename octet_difference_type>
+ inline bool is_overlong_sequence(uint32_t cp, octet_difference_type length)
+ {
+ if (cp < 0x80) {
+ if (length != 1)
+ return true;
+ }
+ else if (cp < 0x800) {
+ if (length != 2)
+ return true;
+ }
+ else if (cp < 0x10000) {
+ if (length != 3)
+ return true;
+ }
+
+ return false;
+ }
+
+ enum utf_error {UTF8_OK, NOT_ENOUGH_ROOM, INVALID_LEAD, INCOMPLETE_SEQUENCE, OVERLONG_SEQUENCE, INVALID_CODE_POINT};
+
+ /// Helper for get_sequence_x
+ template <typename octet_iterator>
+ utf_error increase_safely(octet_iterator& it, octet_iterator end)
+ {
+ if (++it == end)
+ return NOT_ENOUGH_ROOM;
+
+ if (!utf8::internal::is_trail(*it))
+ return INCOMPLETE_SEQUENCE;
+
+ return UTF8_OK;
+ }
+
+ #define UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(IT, END) {utf_error ret = increase_safely(IT, END); if (ret != UTF8_OK) return ret;}
+
+ /// get_sequence_x functions decode utf-8 sequences of the length x
+ template <typename octet_iterator>
+ utf_error get_sequence_1(octet_iterator& it, octet_iterator end, uint32_t& code_point)
+ {
+ if (it == end)
+ return NOT_ENOUGH_ROOM;
+
+ code_point = utf8::internal::mask8(*it);
+
+ return UTF8_OK;
+ }
+
+ template <typename octet_iterator>
+ utf_error get_sequence_2(octet_iterator& it, octet_iterator end, uint32_t& code_point)
+ {
+ if (it == end)
+ return NOT_ENOUGH_ROOM;
+
+ code_point = utf8::internal::mask8(*it);
+
+ UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
+
+ code_point = ((code_point << 6) & 0x7ff) + ((*it) & 0x3f);
+
+ return UTF8_OK;
+ }
+
+ template <typename octet_iterator>
+ utf_error get_sequence_3(octet_iterator& it, octet_iterator end, uint32_t& code_point)
+ {
+ if (it == end)
+ return NOT_ENOUGH_ROOM;
+
+ code_point = utf8::internal::mask8(*it);
+
+ UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
+
+ code_point = ((code_point << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff);
+
+ UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
+
+ code_point += (*it) & 0x3f;
+
+ return UTF8_OK;
+ }
+
+ template <typename octet_iterator>
+ utf_error get_sequence_4(octet_iterator& it, octet_iterator end, uint32_t& code_point)
+ {
+ if (it == end)
+ return NOT_ENOUGH_ROOM;
+
+ code_point = utf8::internal::mask8(*it);
+
+ UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
+
+ code_point = ((code_point << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff);
+
+ UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
+
+ code_point += (utf8::internal::mask8(*it) << 6) & 0xfff;
+
+ UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
+
+ code_point += (*it) & 0x3f;
+
+ return UTF8_OK;
+ }
+
+ #undef UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR
+
+ template <typename octet_iterator>
+ utf_error validate_next(octet_iterator& it, octet_iterator end, uint32_t& code_point)
+ {
+ // Save the original value of it so we can go back in case of failure
+ // Of course, it does not make much sense with i.e. stream iterators
+ octet_iterator original_it = it;
+
+ uint32_t cp = 0;
+ // Determine the sequence length based on the lead octet
+ typedef typename std::iterator_traits<octet_iterator>::difference_type octet_difference_type;
+ const octet_difference_type length = utf8::internal::sequence_length(it);
+
+ // Get trail octets and calculate the code point
+ utf_error err = UTF8_OK;
+ switch (length) {
+ case 0:
+ return INVALID_LEAD;
+ case 1:
+ err = utf8::internal::get_sequence_1(it, end, cp);
+ break;
+ case 2:
+ err = utf8::internal::get_sequence_2(it, end, cp);
+ break;
+ case 3:
+ err = utf8::internal::get_sequence_3(it, end, cp);
+ break;
+ case 4:
+ err = utf8::internal::get_sequence_4(it, end, cp);
+ break;
+ }
+
+ if (err == UTF8_OK) {
+ // Decoding succeeded. Now, security checks...
+ if (utf8::internal::is_code_point_valid(cp)) {
+ if (!utf8::internal::is_overlong_sequence(cp, length)){
+ // Passed! Return here.
+ code_point = cp;
+ ++it;
+ return UTF8_OK;
+ }
+ else
+ err = OVERLONG_SEQUENCE;
+ }
+ else
+ err = INVALID_CODE_POINT;
+ }
+
+ // Failure branch - restore the original value of the iterator
+ it = original_it;
+ return err;
+ }
+
+ template <typename octet_iterator>
+ inline utf_error validate_next(octet_iterator& it, octet_iterator end) {
+ uint32_t ignored;
+ return utf8::internal::validate_next(it, end, ignored);
+ }
+
+} // namespace internal
+
+ /// The library API - functions intended to be called by the users
+
+ // Byte order mark
+ const uint8_t bom[] = {0xef, 0xbb, 0xbf};
+
+ template <typename octet_iterator>
+ octet_iterator find_invalid(octet_iterator start, octet_iterator end)
+ {
+ octet_iterator result = start;
+ while (result != end) {
+ utf8::internal::utf_error err_code = utf8::internal::validate_next(result, end);
+ if (err_code != internal::UTF8_OK)
+ return result;
+ }
+ return result;
+ }
+
+ template <typename octet_iterator>
+ inline bool is_valid(octet_iterator start, octet_iterator end)
+ {
+ return (utf8::find_invalid(start, end) == end);
+ }
+
+ template <typename octet_iterator>
+ inline bool starts_with_bom (octet_iterator it, octet_iterator end)
+ {
+ return (
+ ((it != end) && (utf8::internal::mask8(*it++)) == bom[0]) &&
+ ((it != end) && (utf8::internal::mask8(*it++)) == bom[1]) &&
+ ((it != end) && (utf8::internal::mask8(*it)) == bom[2])
+ );
+ }
+
+ //Deprecated in release 2.3
+ template <typename octet_iterator>
+ inline bool is_bom (octet_iterator it)
+ {
+ return (
+ (utf8::internal::mask8(*it++)) == bom[0] &&
+ (utf8::internal::mask8(*it++)) == bom[1] &&
+ (utf8::internal::mask8(*it)) == bom[2]
+ );
+ }
+} // namespace utf8
+
+#endif // header guard
+
+
diff --git a/vmime-master/contrib/utf8/utf8/unchecked.h b/vmime-master/contrib/utf8/utf8/unchecked.h
new file mode 100644
index 0000000..cb24271
--- /dev/null
+++ b/vmime-master/contrib/utf8/utf8/unchecked.h
@@ -0,0 +1,228 @@
+// Copyright 2006 Nemanja Trifunovic
+
+/*
+Permission is hereby granted, free of charge, to any person or organization
+obtaining a copy of the software and accompanying documentation covered by
+this license (the "Software") to use, reproduce, display, distribute,
+execute, and transmit the Software, and to prepare derivative works of the
+Software, and to permit third-parties to whom the Software is furnished to
+do so, all subject to the following:
+
+The copyright notices in the Software and this entire statement, including
+the above license grant, this restriction and the following disclaimer,
+must be included in all copies of the Software, in whole or in part, and
+all derivative works of the Software, unless such copies or derivative
+works are solely in the form of machine-executable object code generated by
+a source language processor.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
+SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
+FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+DEALINGS IN THE SOFTWARE.
+*/
+
+
+#ifndef UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
+#define UTF8_FOR_CPP_UNCHECKED_H_2675DCD0_9480_4c0c_B92A_CC14C027B731
+
+#include "core.h"
+
+namespace utf8
+{
+ namespace unchecked
+ {
+ template <typename octet_iterator>
+ octet_iterator append(uint32_t cp, octet_iterator result)
+ {
+ if (cp < 0x80) // one octet
+ *(result++) = static_cast<uint8_t>(cp);
+ else if (cp < 0x800) { // two octets
+ *(result++) = static_cast<uint8_t>((cp >> 6) | 0xc0);
+ *(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
+ }
+ else if (cp < 0x10000) { // three octets
+ *(result++) = static_cast<uint8_t>((cp >> 12) | 0xe0);
+ *(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
+ *(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
+ }
+ else { // four octets
+ *(result++) = static_cast<uint8_t>((cp >> 18) | 0xf0);
+ *(result++) = static_cast<uint8_t>(((cp >> 12) & 0x3f)| 0x80);
+ *(result++) = static_cast<uint8_t>(((cp >> 6) & 0x3f) | 0x80);
+ *(result++) = static_cast<uint8_t>((cp & 0x3f) | 0x80);
+ }
+ return result;
+ }
+
+ template <typename octet_iterator>
+ uint32_t next(octet_iterator& it)
+ {
+ uint32_t cp = utf8::internal::mask8(*it);
+ typename std::iterator_traits<octet_iterator>::difference_type length = utf8::internal::sequence_length(it);
+ switch (length) {
+ case 1:
+ break;
+ case 2:
+ it++;
+ cp = ((cp << 6) & 0x7ff) + ((*it) & 0x3f);
+ break;
+ case 3:
+ ++it;
+ cp = ((cp << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff);
+ ++it;
+ cp += (*it) & 0x3f;
+ break;
+ case 4:
+ ++it;
+ cp = ((cp << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff);
+ ++it;
+ cp += (utf8::internal::mask8(*it) << 6) & 0xfff;
+ ++it;
+ cp += (*it) & 0x3f;
+ break;
+ }
+ ++it;
+ return cp;
+ }
+
+ template <typename octet_iterator>
+ uint32_t peek_next(octet_iterator it)
+ {
+ return utf8::unchecked::next(it);
+ }
+
+ template <typename octet_iterator>
+ uint32_t prior(octet_iterator& it)
+ {
+ while (utf8::internal::is_trail(*(--it))) ;
+ octet_iterator temp = it;
+ return utf8::unchecked::next(temp);
+ }
+
+ // Deprecated in versions that include prior, but only for the sake of consistency (see utf8::previous)
+ template <typename octet_iterator>
+ inline uint32_t previous(octet_iterator& it)
+ {
+ return utf8::unchecked::prior(it);
+ }
+
+ template <typename octet_iterator, typename distance_type>
+ void advance (octet_iterator& it, distance_type n)
+ {
+ for (distance_type i = 0; i < n; ++i)
+ utf8::unchecked::next(it);
+ }
+
+ template <typename octet_iterator>
+ typename std::iterator_traits<octet_iterator>::difference_type
+ distance (octet_iterator first, octet_iterator last)
+ {
+ typename std::iterator_traits<octet_iterator>::difference_type dist;
+ for (dist = 0; first < last; ++dist)
+ utf8::unchecked::next(first);
+ return dist;
+ }
+
+ template <typename u16bit_iterator, typename octet_iterator>
+ octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result)
+ {
+ while (start != end) {
+ uint32_t cp = utf8::internal::mask16(*start++);
+ // Take care of surrogate pairs first
+ if (utf8::internal::is_lead_surrogate(cp)) {
+ uint32_t trail_surrogate = utf8::internal::mask16(*start++);
+ cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET;
+ }
+ result = utf8::unchecked::append(cp, result);
+ }
+ return result;
+ }
+
+ template <typename u16bit_iterator, typename octet_iterator>
+ u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result)
+ {
+ while (start < end) {
+ uint32_t cp = utf8::unchecked::next(start);
+ if (cp > 0xffff) { //make a surrogate pair
+ *result++ = static_cast<uint16_t>((cp >> 10) + internal::LEAD_OFFSET);
+ *result++ = static_cast<uint16_t>((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN);
+ }
+ else
+ *result++ = static_cast<uint16_t>(cp);
+ }
+ return result;
+ }
+
+ template <typename octet_iterator, typename u32bit_iterator>
+ octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result)
+ {
+ while (start != end)
+ result = utf8::unchecked::append(*(start++), result);
+
+ return result;
+ }
+
+ template <typename octet_iterator, typename u32bit_iterator>
+ u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result)
+ {
+ while (start < end)
+ (*result++) = utf8::unchecked::next(start);
+
+ return result;
+ }
+
+ // The iterator class
+ template <typename octet_iterator>
+ class iterator : public std::iterator <std::bidirectional_iterator_tag, uint32_t> {
+ octet_iterator it;
+ public:
+ iterator () {}
+ explicit iterator (const octet_iterator& octet_it): it(octet_it) {}
+ // the default "big three" are OK
+ octet_iterator base () const { return it; }
+ uint32_t operator * () const
+ {
+ octet_iterator temp = it;
+ return utf8::unchecked::next(temp);
+ }
+ bool operator == (const iterator& rhs) const
+ {
+ return (it == rhs.it);
+ }
+ bool operator != (const iterator& rhs) const
+ {
+ return !(operator == (rhs));
+ }
+ iterator& operator ++ ()
+ {
+ ::std::advance(it, utf8::internal::sequence_length(it));
+ return *this;
+ }
+ iterator operator ++ (int)
+ {
+ iterator temp = *this;
+ ::std::advance(it, utf8::internal::sequence_length(it));
+ return temp;
+ }
+ iterator& operator -- ()
+ {
+ utf8::unchecked::prior(it);
+ return *this;
+ }
+ iterator operator -- (int)
+ {
+ iterator temp = *this;
+ utf8::unchecked::prior(it);
+ return temp;
+ }
+ }; // class iterator
+
+ } // namespace utf8::unchecked
+} // namespace utf8
+
+
+#endif // header guard
+
diff --git a/vmime-master/doc/book/.gitignore b/vmime-master/doc/book/.gitignore
new file mode 100644
index 0000000..5bb5584
--- /dev/null
+++ b/vmime-master/doc/book/.gitignore
@@ -0,0 +1,17 @@
+# PDFLatex
+*.log
+*.aux
+*.toc
+*.out
+*.pdf
+*.lo[flt]
+
+# Hevea
+*.haux
+*.htoc
+book.image.tex
+book.html
+
+images/Makefile2
+images/*.png
+
diff --git a/vmime-master/doc/book/basics.tex b/vmime-master/doc/book/basics.tex
new file mode 100644
index 0000000..94633ef
--- /dev/null
+++ b/vmime-master/doc/book/basics.tex
@@ -0,0 +1,823 @@
+\chapter{Basics}
+
+% ============================================================================
+\section{Reference counting}
+
+\subsection{Introduction} % --------------------------------------------------
+
+Since version 0.7.2cvs, VMime use smart pointers to simplify memory
+management. Smart pointers rely on
+RAII\footnote{Ressource Allocation is Initialisation} so that we do not need
+to bother with deleting an object (freeing memory) when it is not used
+anymore.
+
+There are two possibilities for owning a reference to an object. We can own a
+strong reference to an object: as long as we keep this reference, the object
+is not destroyed. Or we can own a weak reference to the object: the object can
+be destroyed if nobody owns a strong reference to it, in which case the weak
+reference becomes invalid.
+
+An object is destroyed as soon as the last strong reference to it is released.
+At the same tine, all weak references (if any) are automatically set to point
+to \vnull.
+
+In VMime, these two types of references are known as {\vcode vmime::shared\_ptr}
+and {\vcode vmime::weak\_ptr}, respectively.
+
+\vnote{since November 2013, we switched from an old, intrusive implementation
+of smart pointers to a more standard one: either Boost {\vcode shared\_ptr<>}
+implementation or standard C++ one if we are compiling in C++11. Here are the
+changes:
+
+{\vcode vmime::ref <>} is replaced with {\vcode vmime::shared\_ptr <>}
+
+{\vcode vmime::weak\_ref <>} is replaced with {\vcode vmime::weak\_ptr <>}
+
+{\vcode vmime::create <>} is replaced with {\vcode vmime::make\_shared <>}
+}
+
+\subsection{Instanciating reference-counted objects} % -----------------------
+
+In VMime, all objects that support reference counting inherit from the
+{\vcode vmime::object} class, which is responsible for
+incrementing/decrementing the counter and managing the object's life cycle.
+If you want to create a smart pointer to a new object instance, you should
+use the function {\vcode vmime::make\_shared} instead of the {\vcode new}
+operator.
+
+\begin{lstlisting}[caption={Smarts pointers and creating objects}]
+class myObject : public vmime::object {
+
+public:
+
+ myObject(const vmime::string& name)
+ : m_name(name) {
+
+ }
+
+ void sayHello() {
+
+ std::cout << "Hello " << m_name << std::endl;
+ }
+
+private:
+
+ vmime::string m_name;
+};
+
+int main() {
+
+ vmime::shared_ptr <myObject> obj =
+ vmime::make_shared <myObject>("world");
+
+ obj->sayHello();
+
+ return 0;
+
+} // Here, 'obj' gets automatically destroyed
+\end{lstlisting}
+
+\subsection{Using smart pointers} % ------------------------------------------
+
+Smart pointers are copiable, assignable and comparable. You can use them like
+you would use normal ("raw") C++ pointers (eg. you can write
+\lstinline{!ptr, ptr != NULL, ptr->method(), *ptr}...).
+
+Type safety is also guaranteed, and you can type cast smart pointers using
+the {\vcode static\_cast()}, {\vcode dynamic\_cast()} and {\vcode const\_cast()}
+equivalents on {\vcode vmime::shared\_ptr} and {\vcode vmime::weak\_ptr} objects:
+
+\begin{lstlisting}[caption={Casting smart pointers}]
+class myBase : public vmime::object { }
+class myObject : public myBase { }
+
+vmime::shared_ptr <myObject> obj = vmime::make_shared <myObject>();
+
+// Implicit downcast
+vmime::shared_ptr <myBase> base = obj;
+
+// Explicit upcast
+vmime::shared_ptr <myObject> obj2 = vmime::dynamicCast <myObject>(base);
+\end{lstlisting}
+
+Weak references are used to resolve reference cycles (an object which refers
+directly or indirectly to itself). The following example illustrates a
+typical problem of reference counting:
+
+\begin{lstlisting}
+class parent : public vmime::object {
+
+public:
+
+ void createChild(vmime::shared_ptr <child> c) {
+
+ m_child = c;
+ }
+
+private:
+
+ vmime::shared_ptr <child> m_child;
+};
+
+class child : public vmime::object {
+
+public:
+
+ child(vmime::shared_ptr <parent> p)
+ : m_parent(p) {
+
+ }
+
+private:
+
+ vmime::shared_ptr <parent> m_parent;
+};
+
+int main() {
+
+ vmime::shared_ptr <parent> p = vmime::make_shared <parent>();
+ vmime::shared_ptr <child> c = vmime::make_shared <child>();
+
+ p->setChild(c);
+}
+\end{lstlisting}
+
+In this example, neither {\vcode p} nor {\vcode c} will be deleted when
+exiting {\vcode main()}. That's because {\vcode p} indirectly points to itself
+{\em via} {\vcode c}, and {\em vice versa}. The solution is to use a weak
+reference to the parent:
+
+\begin{lstlisting}
+vmime::weak_ptr <parent> m_parent;
+\end{lstlisting}
+
+The decision to make the parent or the child a weak reference is purely
+semantic, and it depends on the context and the relationships between the
+objects. Note that when the parent is deleted, the {\vcode m\_parent} member
+of the child points to \vnull.
+
+More information about reference counting can be found on
+Wikipedia\footnote{http://en.wikipedia.org/wiki/Reference\_counting}.
+
+% ============================================================================
+\section{Error handling}
+
+In VMime, error handling is exclusively based on exceptions, there is no error
+codes, or things like that.
+
+VMime code may throw exceptions in many different situations: an unexpected
+error occurred, an operation is not supported, etc. You should catch them if
+you want to report failures to the user. This is also useful when debugging
+your program.
+
+VMime exceptions support chaining: an exception can be encapsulated into
+another exception to hide implementation details. The function
+{\vcode exception::other()} returns the next exception in the chain,
+or \vnull.
+
+Following is an example code for catching VMime exceptions and writing error
+messages to the console:
+
+\begin{lstlisting}[caption={Catching VMime exceptions}]
+std::ostream& operator<<(std::ostream& os, const vmime::exception& e) {
+
+ os << "* vmime::exceptions::" << e.name() << std::endl;
+ os << " what = " << e.what() << std::endl;
+
+ // Recursively print all encapsuled exceptions
+ if (e.other() != NULL) {
+ os << *e.other();
+ }
+
+ return os;
+}
+
+...
+
+try {
+
+ // ...some call to VMime...
+
+} catch (vmime::exception& e) {
+
+ std::cerr << e; // VMime exception
+
+} catch (std::exception& e) {
+
+ std::cerr << e.what(); // standard exception
+}
+\end{lstlisting}
+
+Read the source of {\vexample example6} if yo want to see a more complete
+example of using VMime exceptions (such as getting more detailed information
+by using specialized classes of {\vcode vmime::exception}).
+
+
+% ============================================================================
+\section{Basic objects}
+
+\subsection{The {\vcode component} class} % ----------------------------------
+
+In VMime, all the components of a message inherit from the same class
+{\vcode component}. This includes the message itself (classes {\vcode message}
+and {\vcode bodyPart}), the header, the header fields and the value of each
+header field, the body and all the parts in the message.
+
+The class component provide a common interface for parsing or generating all
+these components (methods {\vcode parse()} and {\vcode generate()}). It also
+provides additional functions to get some information about the parsing
+process or the structure (methods {\vcode getParsedOffset()},
+{\vcode getParsedLength()} and {\vcode getChildComponents()}).
+
+VMime also provides a set of classes corresponding to the basic types found
+in a message; for example a mailbox, a mailbox list, date/time information,
+media type, etc. They all inherit from {\vcode component} too.
+
+\subsection{Date and time} % -------------------------------------------------
+
+Date and time are used in several places in VMime, particularly in header
+fields (Date, Received, ...). VMime fully supports RFC-2822's date and time
+specification. The object {\vcode vmime::datetime} is used to manipulate date
+and time information, and to parse/generate it from/to RFC-2822 format.
+
+The following code snippet show various manners of using the
+{\vcode vmime::datetime} object:
+
+\begin{lstlisting}[caption={Using {\vcode vmime::datetime} object}]
+// Creating from string in RFC-2822 format
+vmime::datetime d1("Sat, 08 Oct 2005 14:07:52 +0200");
+
+// Creating from components
+vmime::datetime d2(
+ /* date */ 2005, vmime::datetime::OCTOBER, 8,
+ /* time */ 14, 7, 52,
+ /* zone */ vmime::datetime::GMT2
+);
+
+// Getting day of week
+const int dow = d2.getWeekDay(); // 'dow' should be datetime::SATURDAY
+\end{lstlisting}
+
+\subsection{Media type} % ----------------------------------------------------
+
+In MIME, the nature of the data contained in parts is identified using a
+media type. A general type (eg. \emph{image}) and a sub-type (eg. \emph{jpeg})
+are put together to form a media type (eg. \emph{image/jpeg}). This is also
+called the MIME type.
+
+There are a lot of media types officially registered, and vendor-specific
+types are possible (they start with ``x-'', eg.
+\emph{application/x-zip-compressed}).
+
+In VMime, the object {\vcode vmime::mediaType} represents a media type. There
+are also some constants for top-level types and sub-types in the
+{\vcode vmime::mediaTypes} namespace. For example, you can instanciate a new
+media type with:
+
+\begin{lstlisting}
+vmime::mediaType theType(
+ /* top-level type */ vmime::mediaTypes::IMAGE,
+ /* sub-type */ vmime::mediaTypes::IMAGE_JPEG
+);
+
+// theType.getType() is "image"
+// theType.getSubType() is "jpeg"
+// theType.generate() returns "image/jpeg"
+\end{lstlisting}
+
+For more information about media types, see
+RFC-2046\footnote{http://www.faqs.org/rfcs/rfc2046.html}.
+
+\subsection{Mailbox and mailbox groups} % ------------------------------------
+
+VMime provides several objects for working with mailboxes and addresses.
+
+The {\vcode vmime::address} class is an abstract type for representing an
+address: it can be either a mailbox (type {\vcode vmime::mailbox}) or a
+mailbox group (type {\vcode vmime::mailboxGroup}). A mailbox is composed of
+an email address (mandatory) and possibly a name. A mailbox group is simply
+a named list of mailboxes (see Figure \ref{uml_addr_mbox_mboxgroup}).
+
+\begin{lstlisting}[caption={Using mailboxes and mailbox groups}]
+vmime::shared_ptr <vmime::mailbox> mbox1 = vmime::make_shared <vmime::mailbox>
+ (/* name */ vmime::text("John Doe"), /* email */ "john.doe@acme.com");
+vmime::shared_ptr <vmime::mailbox> mbox2 = vmime::make_shared <vmime::mailbox>
+ (/* no name, email only */ "bill@acme.com");
+
+vmime::shared_ptr <vmime::mailboxGroup> grp = vmime::make_shared <vmime::mailboxGroup>();
+grp->appendMailbox(mbox1);
+grp->appendMailbox(mbox2);
+\end{lstlisting}
+
+\begin{figure}[ht!]
+ \center\includegraphics[width=0.7\textwidth]
+ {images/address-mailbox-mailboxgroup.png}\endcenter
+ \caption{Diagram for address-related classes}
+ \label{uml_addr_mbox_mboxgroup}
+\end{figure}
+
+
+% ============================================================================
+\section{Message, body parts and header}
+
+\subsection{Introduction to MIME messages} % ---------------------------------
+
+A MIME message is a recursive structure in which each part can contains one
+or more parts (or \emph{entities}). Each part is composed of a header and
+a body (actual contents). Figure \ref{uml_msg_body_header} shows how this
+model is implemented in VMime, and all classes that take part in it.
+
+\begin{figure}
+ \center\includegraphics[width=1.0\textwidth]
+ {images/message-body-header.png}\endcenter
+ \caption{Overall structure of MIME messages}
+ \label{uml_msg_body_header}
+\end{figure}
+
+
+\subsection{Header and header fields} % --------------------------------------
+
+\subsubsection{Standard header fields} % .....................................
+
+Header fields carry information about a message (or a part) and its contents.
+Each header field has a name and a value. All types that can be used as a
+field value inherit from the {\vcode headerFieldValue} class.
+
+You cannot instanciate header fields directly using their constructor.
+Instead, you should use the {\vcode headerFieldFactory} object. This ensures
+the right field type and value type is used for the specified field name.
+For more information about how to use header fields and the factory, see
+section \ref{msg-building-simple-message}.
+
+Some standard fields are officially registered and have their value type
+specified in a RFC. Table \ref{standard-fields} lists all the fields
+registered by default in VMime and the value type they contains.
+
+By default, all unregistered fields have a value of type {\vcode text}.
+
+\begin{table}[!ht]
+\begin{center}
+\noindent\begin{tabularx}{0.85\textwidth}{|X|X|}
+\hline
+ {\bf Field Name} &
+ {\bf Value Type} \\
+\hline
+\hline
+From & mailbox \\
+To & addressList \\
+Cc & addressList \\
+Bcc & addressList \\
+Sender & mailbox \\
+Date & datetime \\
+Received & relay \\
+Subject & text \\
+Reply-To & mailbox \\
+Delivered-To & mailbox \\
+Organization & text \\
+Return-Path & path \\
+Mime-Version & text \\
+Content-Type & mediaType \\
+Content-Transfer-Encoding & encoding \\
+Content-Description & text \\
+Content-Disposition & contentDisposition \\
+Content-Id & messageId \\
+Content-Location & text \\
+Message-Id & messageId \\
+In-Reply-To & messageIdSequence \\
+References & messageIdSequence \\
+Original-Message-Id & messageId \\
+Disposition & disposition \\
+Disposition-Notification-To & mailboxList \\
+\hline
+\end{tabularx}
+\end{center}
+\label{standard-fields}
+\caption{Standard fields and their types}
+\end{table}
+
+
+\subsubsection{Parameterized fields} % .......................................
+
+In addition to a value, some header fields can contain one or more
+\emph{name=value} couples which are called \emph{parameters}. For example,
+this is used in the \emph{Content-Type} field to give more information about
+the content:
+
+\begin{verbatim}
+ Content-Type: text/plain; charset="utf-8"
+\end{verbatim}
+
+Fields that support parameters inherit from the
+{\vcode parameterizedHeaderField} class which provides methods to deal with
+these parameters: {\vcode appendParameter()}, {\vcode getParameterAt()}...
+
+A parameter is identified by a name (eg. \emph{charset}) and associated to
+a value of type {\vcode vmime::text}. Parameters provide helper functions to
+convert automatically from basic types to text, and \emph{vice versa}. The
+following example illustrates it:
+
+\begin{lstlisting}[caption={Getting and setting parameter value in fields}]
+vmime::shared_ptr <vmime::parameterizedField> field =
+ header->findField <vmime::parameterizedField>("X-Field-That-Contains-Parameters");
+
+// Use setValue() to convert from a basic type to 'text'
+vmime::shared_ptr <vmime::parameter> prm = field->getParameter("my-date-param");
+prm->setValue(vmime::datetime::now());
+
+// Use getValueAs() to convert from 'text' to a basic type
+prm = field->getParameter("my-charset-param");
+const vmime::charset ch = prm->getValueAs <vmime::charset>();
+\end{lstlisting}
+
+Some fields provide easy access to their standard parameters (see
+Table \ref{standard-prm-fields}). This avoids finding the parameter and
+\emph{dynamic-casting} its value to the right type. The following code
+illustrates how to use it:
+
+\begin{lstlisting}
+vmime::shared_ptr <vmime::contentTypeField> field =
+ header->getField <vmime::contentTypeField>(vmime::fields::CONTENT_TYPE);
+
+// 1. First solution: the "hard" way
+vmime::shared_ptr <vmime::parameter> prm = field->findParameter("charset");
+const charset ch1 = prm->getValueAs <vmime::charset>();
+
+// 2. Second solution: the simple way
+const charset ch2 = field->getCharset();
+\end{lstlisting}
+
+\vnote{In both cases, an exception {\vcode no\_such\_parameter} can be
+thrown if the parameter does not exist, so be sure to catch it.}
+
+\begin{table}[ht!]
+\begin{center}
+\noindent\begin{tabularx}{0.85\textwidth}{|l|l|X|}
+\hline
+ {\bf Field Name} &
+ {\bf Field Type} &
+ {\bf Parameters} \\
+\hline
+\hline
+Content-Type & contentTypeField & boundary, charset, report-type \\
+\hline
+Content-Disposition & contentDispositionField & creation-date,
+modification-date, read-date, filename, size \\
+\hline
+\end{tabularx}
+\end{center}
+\label{standard-prm-fields}
+\caption{Standard parameterized fields}
+\end{table}
+
+
+
+% ============================================================================
+\section{Streams}
+
+\subsection{Streams and stream adapters} % -----------------------------------
+
+Streams permit reading or writing data whatever the underlying system is:
+a file on a hard disk, a socket connected to a remote service...
+
+There are two types of streams: input streams (from which you can read data)
+and output streams (in which you can write data). Some adapters are provided
+for compatibility and convenience, for example:
+
+\begin{itemize}
+\item {\vcode inputStreamAdapter} and {\vcode outputStreamAdapter}: allow
+to use standard C++ iostreams with VMime;
+\item {\vcode inputStreamStringAdapter} and
+{\vcode outputStreamStringAdapter}: use a {\vcode vmime::string} object to
+read/write data.
+\end{itemize}
+
+The following example shows two ways of writing the current date to the
+standard output, using stream adapters:
+
+\begin{lstlisting}[caption={Using stream adapters}]
+// Get current date and time
+const vmime::datetime date = vmime::datetime::now();
+
+// 1. Using outputStreamAdapter
+vmime::utility::outputStreamAdapter out(std::cout);
+
+std::cout << "Current date is: ";
+date.generate(out);
+std::cout << std::endl;
+
+// 2. Using outputStreamStringAdapter
+vmime::string dateStr;
+vmime::utility::outputStreamStringAdapter outStr(dateStr);
+
+date.generate(outStr);
+
+std::cout << "Current date is: " << dateStr << std::endl;
+\end{lstlisting}
+
+
+\subsection{Stream filters} % ------------------------------------------------
+
+Input and output streams can be filtered to perform inline conversions (for
+example, there is a filter to convert ``{\textbackslash}r{\textbackslash}n''
+sequences to ``{\textbackslash}n''). They inherit from
+{\vcode vmime::utility::filteredInputStream} or
+{\vcode vmime::utility::filteredOutputStream} and are used like adapters (some
+filters also accept parameters; read the documentation).
+
+The most useful filter in VMime (and probably the only one you will need) is
+the {\vcode charsetFilteredOutputStream}, which performs inline conversion
+of charsets. See \ref{section_charsets} to know how to use it.
+
+\vnote{After you have finished to use a filtered output stream, it is
+important to call {\vcode flush()} on it to flush the internal buffer.
+If {\vcode flush()} is not called, not all data may be written to the
+underlying stream.}
+
+
+% ============================================================================
+\section{Content handlers}
+
+\subsection{Introduction} % --------------------------------------------------
+
+Content handlers are an abstraction for data sources. They are currently used
+when some data need to be stored for later use (eg. body part contents,
+attachment data, ...). Data can be stored encoded or unencoded (for more
+information about encodings, see \ref{section_encodings}).
+
+\subsection{Extracting data from content handlers} % -------------------------
+
+You can extract data in a content handler using the {\vcode extract()} method
+(which automatically decodes data if encoded) or {\vcode extractRaw()} (which
+extracts data without perfoming any decoding).
+
+The following example shows how to extract the body text from a message, and
+writing it to the standard output with charset conversion:
+
+\begin{lstlisting}[caption={Using content handlers to extract body text from
+a message}]
+// Suppose we already have a message
+vmime::shared_ptr <vmime::message> msg;
+
+// Obtains a reference to the body contents
+vmime::shared_ptr <vmime::body> body = msg->getBody();
+vmime::shared_ptr <vmime::contentHandler> cts = body->getContents();
+
+vmime::utility::outputStreamAdapter out(std::cout);
+cts->extract(out);
+\end{lstlisting}
+
+\vnote{The body contents is extracted ``as is''. No charset conversion is
+performed. See \ref{section_charsets} to know more about conversion between
+charsets.}
+
+
+\subsection{Creating content handlers} % -------------------------------------
+
+When you are building a message, you may need to instanciate content handlers
+if you want to set the contents of a body part. The following code snippet
+shows how to set the body text of a part from a string:
+
+\begin{lstlisting}[caption={Setting the contents of a body part}]
+vmime::shared_ptr <vmime::bodyPart> part; // suppose we have a body part
+
+// Create a new content handler from a string
+vmime::shared_ptr <vmime::contentHandler> cth =
+ vmime::make_shared <vmime::stringContentHandler>("Put body contents here");
+
+// Set the contents
+part->getBody()->setContents(cth);
+\end{lstlisting}
+
+Content handlers are also used when creating attachments. The following
+example illustrates how to create an attachment from a file:
+
+\begin{lstlisting}[caption={Creating an attachment from a file}]
+// Create a stream from a file
+std::ifstream* fileStream = new std::ifstream();
+
+fileStream->open("/home/vincent/paris.jpg", std::ios::binary);
+
+if (!*fileStream) {
+ // handle error
+}
+
+vmime::shared_ptr <utility::stream> dataStream =
+ vmime::make_shared <vmime::utility::inputStreamPointerAdapter>(fileStream);
+
+ // NOTE: 'fileStream' will be automatically deleted
+ // when 'dataStream' is deleted
+
+// Create a new content handler
+vmime::shared_ptr <contentHandler> data =
+ vmime::make_shared <vmime::streamContentHandler>(dataStream, 0);
+
+// Now create the attachment
+ref <vmime::attachment> att = vmime::make_shared <vmime::defaultAttachment>(
+ /* attachment data */ data,
+ /* content type */ vmime::mediaType("image/jpeg"),
+ /* description */ vmime::text("Holiday photo"),
+ /* filename */ vmime::word("paris.jpg")
+);
+\end{lstlisting}
+
+You will see later that the {\vcode vmime::fileAttachment} class already
+encapsulates all the mechanics to create an attachment from a file.
+
+
+% ============================================================================
+\section{Character sets, charsets and conversions\label{section_charsets}}
+
+Quoting from RFC-2278: \emph{`` The term 'charset' is used to refer to a
+method of converting a sequence of octets into a sequence of characters.''}
+
+With the {\vcode vmime::charset} object, VMime supports conversion between
+charsets using the {\em iconv} library, which is available on almost all
+existing platforms. See {\vcode vmime::charset} and
+{\vcode vmime::charsetConverter} in the class documentation to know more
+about charset conversion.
+
+The following example shows how to convert data in one charset to another
+charset. The data is extracted from the body of a message and converted
+to UTF-8 charset:
+
+\begin{lstlisting}[caption={Extracting and converting body contents to a
+specified charset}]
+vmime::shared_ptr <vmime::message> msg; // we have a message
+
+// Obtain the content handler first
+vmime::shared_ptr <vmime::body> body = msg->getBody();
+vmime::shared_ptr <const vmime::contentHandler> cth = body->getContents();
+
+// Then, extract and convert the contents
+vmime::utility::outputStreamAdapter out(std::cout);
+vmime::utility::charsetFilteredOutputStream fout(
+ /* source charset */ body->getCharset(),
+ /* dest charset */ vmime::charset("utf-8"),
+ /* dest stream */ out
+);
+
+cth->extract(fout);
+
+fout.flush(); // Very important!
+\end{lstlisting}
+
+
+% ============================================================================
+\section{Non-ASCII text in header fields}
+
+MIME standard defines methods\footnote{See RFC-2047: Message Header Extensions
+for Non-ASCII Text} for dealing with data which is not 7-bit only (ie. the
+ASCII character set), in particular in header fields. For example, the field
+``Subject:'' use this data type.
+
+VMime is fully compatible with RFC-2047 and provides two objects for
+manipulating 8-bit data: {\vcode vmime::text} and {\vcode vmime::word}. A word
+represents textual information encoded in a specified charset. A text is
+composed of one or more words.
+
+RFC-2047 describes the process of encoding 8-bit data into a 7-bit form;
+basically, it relies on Base64 and Quoted-Printable encoding. Hopefully, all
+the encoding/decoding process is done internally by VMime, so creating text
+objects is fairly simple:
+
+\begin{lstlisting}[caption={Creating \vcode{vmime::text} objects}]
+vmime::string inText = "Linux dans un téléphone mobile";
+vmime::charset inCharset = "utf-8";
+
+vmime::text outText;
+outText.createFromString(inText, inCharset);
+
+// 'outText' now contains 3 words:
+// . <us-ascii> "Linux dans un "
+// . <utf-8> "téléphone "
+// . <us-ascii> "mobile"
+
+vmime::shared_ptr <vmime::header> header = myMessage->getHeader();
+header->Subject()->setValue(outText);
+\end{lstlisting}
+
+In general, you will not need to decode RFC-2047-encoded data as the process
+is totally transparent in VMime. If you really have to, you can use the
+{\vcode vmime::text::decodeAndUnfold()} static method to create a text object
+from encoded data.
+
+For example, say you have the following encoded data:
+
+\begin{verbatim}
+ Linux dans un =?UTF-8?B?dMOpbMOpcGhvbmUgbW9iaWxl?=
+\end{verbatim}
+
+You can simply decode it using the following code:
+
+\begin{lstlisting}[caption={Decoding RFC-2047-encoded data}]
+vmime::string inData =
+ "Linux dans un =?UTF-8?B?dMOpbMOpcGhvbmUgbW9iaWxl?=";
+
+vmime::text outText;
+vmime::text::decodeAndUnfold(inData, &outText);
+\end{lstlisting}
+
+{\vcode vmime::text} also provides a function to convert all the words to
+another charset in a single call. The following example shows how to convert
+text stored in the Subject field of a message:
+
+\begin{lstlisting}[caption={Converting data in a {\vcode vmime::text} to a
+specified charset}]
+vmime::shared_ptr <vmime::message> msg; // we have a message
+
+vmime::text subject = msg->getHeader()->Subject()->getValue();
+
+const vmime::string subjectText =
+ subject.getConvertedText(vmime::charset("utf-8"));
+
+// 'subjectText' now contains the subject in UTF-8 encoding
+\end{lstlisting}
+
+
+% ============================================================================
+\section{Encodings\label{section_encodings}}
+
+\subsection{Introduction} % --------------------------------------------------
+
+The MIME standard defines a certain number of encodings to allow data
+to be safely transmitted from one peer to another. VMime provides
+data encoding and decoding using the {\vcode vmime::utility::encoder::encoder} object.
+
+You should not need to use encoders directly, as all encoding/decoding
+process is handled internally by the library, but it is good to know
+they exist and how they work.
+
+\subsection{Using encoders} % ------------------------------------------------
+
+You can create an instance of an encoder using the 'vmime::utility::encoder::encoderFactory'
+object, giving the encoding name ({\it base64}, {\it quoted-printable}, ...).
+The following example creates an instance of the Base64 encoder to encode
+some data:
+
+\begin{lstlisting}[caption={A simple example of using an encoder}]
+vmime::shared_ptr <vmime::utility::encoder::encoder> enc =
+ vmime::utility::encoder::encoderFactory::getInstance()->create("base64");
+
+vmime::string inString("Some data to encode");
+vmime::utility::inputStreamStringAdapter in(inString);
+
+vmime::string outString;
+vmime::utility::outputStreamStringAdapter out(outString);
+
+enc->encode(in, out);
+
+std::cout << "Encoded data is:" << outString << std::endl;
+\end{lstlisting}
+
+\subsection{Enumerating available encoders} % --------------------------------
+
+The behaviour of the encoders can be configured using properties. However,
+not all encoders support properties. The following example\footnote{This is
+an excerpt from {\vexample example6}} enumerates available encoders and the
+supported properties for each of them:
+
+\begin{lstlisting}[caption={Enumerating encoders and their properties}]
+vmime::shared_ptr <vmime::utility::encoder::encoderFactory> ef =
+ vmime::utility::encoder::encoderFactory::getInstance();
+
+std::cout << "Available encoders:" << std::endl;
+
+for (int i = 0 ; i < ef->getEncoderCount() ; ++i) {
+
+ // Output encoder name
+ vmime::shared_ptr <const vmime::utility::encoder::encoderFactory::registeredEncoder>
+ enc = ef->getEncoderAt(i);
+
+ std::cout << " * " << enc->getName() << std::endl;
+
+ // Create an instance of the encoder to get its properties
+ vmime::shared_ptr <vmime::utility::encoder::encoder> e = enc->create();
+
+ std::vector <vmime::string> props = e->getAvailableProperties();
+ std::vector <vmime::string>::const_iterator it;
+
+ for (it = props.begin() ; it != props.end() ; ++it) {
+ std::cout << " - " << *it << std::endl;
+ }
+\end{lstlisting}
+
+
+% ============================================================================
+\section{Progress listeners}
+
+Progress listeners are used with objects that can notify you about the state
+of progress when they are performing an operation.
+
+The {\vcode vmime::utility::progressListener} interface is rather simple:
+
+\begin{lstlisting}
+void start(const int predictedTotal);
+void progress(const int current, const int currentTotal);
+void stop(const int total);
+\end{lstlisting}
+
+{\vcode start()} and {\vcode stop()} are called at the beginning and the end
+of the operation, respectively. {\vcode progress()} is called each time the
+status of progress changes (eg. a chunk of data has been processed). There is
+no unit specified for the values passed in argument. It depends on the
+notifier: it can be bytes, percent, number of messages...
diff --git a/vmime-master/doc/book/book.tex b/vmime-master/doc/book/book.tex
new file mode 100644
index 0000000..4db213a
--- /dev/null
+++ b/vmime-master/doc/book/book.tex
@@ -0,0 +1,118 @@
+\documentclass[11pt]{report}
+
+\title{{\Huge VMime Book} \\ \ \\ A Developer's Guide To VMime}
+\author{Vincent Richard \\ vincent@vmime.org}
+
+\usepackage{graphicx}
+\usepackage{tabularx}
+\usepackage{array}
+\usepackage{listings}
+\usepackage[usenames]{color}
+\usepackage{ucs}
+\usepackage[utf8x]{inputenc}
+\usepackage[vcentering,dvips]{geometry}
+%\usepackage{type1cm} % scalable Computer Modern fonts
+\usepackage{courier} % use Adobe Courier instead of Computer Modern Typewriter
+\usepackage{fancyheadings}
+\usepackage{hyperref}
+\usepackage{verbatim}
+\usepackage{footmisc}
+
+
+\setcounter{secnumdepth}{10}
+\setcounter{tocdepth}{10}
+
+\def\vcode{\tt}
+\def\vnull{{\tt NULL}}
+\newcommand{\vnote}[1]{{\sc note:} #1}
+\def\vexample{\tt\sc}
+\newcommand{\verti}[1]{\rotatebox{90}{#1\ }} % vertical text
+\def\vdot{$\bullet$}
+
+\sloppy % Disable "overfull \hbox..." warnings
+
+\newcommand{\Chapter}[1]{\chapter{#1} \setcounter{figure}{1}}
+
+% 'listings' configuration
+\definecolor{listingFrame}{rgb}{0.9,0.9,0.9}
+\lstset{language=C++,showstringspaces=false}
+\lstset{keywordstyle=\bf,commentstyle=\it}
+\lstset{captionpos=b,extendedchars=true,inputencoding=latin1}
+\lstset{fontadjust=true,basewidth={0.5em,0.4em},columns=fixed,flexiblecolumns=false}
+\lstset{frame=leftline,framerule=0.1cm,framesep=0.3cm,rulecolor=\color{listingFrame}}
+\lstset{abovecaptionskip=0.5cm,xleftmargin=1.1cm,aboveskip=0.5cm,belowskip=0.2cm}
+
+% 'hyperref' configuration
+\hypersetup{
+ backref=true,pagebackref=true,hyperindex=rue,colorlinks=true,
+ breaklinks=true,urlcolor=blue,linkcolor=black,bookmarks=true,bookmarksopen=true
+}
+
+% HTML output configuration
+%HEVEA\renewcommand{\includegraphics}[2][]{\imgsrc{#2}}
+%HEVEA\renewcommand{\verti}[1]{#1}
+%HEVEA\def\vdot{\bullet}
+%HEVEA\newcommand{\linespread}{}
+%HEVEA\newcommand{\clubpenalty}{}
+%HEVEA\newcommand{\widowpenalty}{}
+%HEVEA\newcommand{\geometry}{}
+
+
+% Page layout
+\geometry{papersize={210mm,297mm},total={160mm,230mm}}
+
+% Text layout
+\setlength{\skip\footins}{1cm} % margin between text and footnotes
+\clubpenalty=1000
+\addtolength{\parskip}{+0.3cm}
+\linespread{1.05}
+\widowpenalty=1000
+
+
+\begin{document}
+
+% Title page
+\maketitle
+\newpage
+
+% Table of contents
+\tableofcontents
+\newpage
+
+% Chapters
+\include{intro}
+\include{building}
+\include{start}
+\include{basics}
+\include{msg}
+\include{net}
+
+\thispagestyle{empty}
+\ \newpage
+
+
+%HEVEA\begin{comment}
+
+% List of listings
+\lstlistoflistings
+\addcontentsline{toc}{chapter}{Listings}
+
+% List of figures
+\listoffigures
+\addcontentsline{toc}{chapter}{List of figures}
+
+% List of table
+\listoftables
+\addcontentsline{toc}{chapter}{List of tables}
+
+%HEVEA\end{comment}
+
+
+% Appendixes
+\appendix
+
+\chapter{The GNU General Public License\label{appendix_license}}
+\verbatiminput{../../COPYING}
+
+\end{document}
+
diff --git a/vmime-master/doc/book/building.tex b/vmime-master/doc/book/building.tex
new file mode 100644
index 0000000..9feeedc
--- /dev/null
+++ b/vmime-master/doc/book/building.tex
@@ -0,0 +1,175 @@
+\label{chapter_building}
+\chapter{Building and Installing VMime}
+
+% ============================================================================
+\section{Introduction}
+
+If no pre-build packages of VMime is available for your system, or if for some
+reason you want to compile it yourself from scratch, this section will guide
+you through the process.
+
+% ============================================================================
+\section{What you need}
+
+To build VMime from the sources, you will need the following:
+
+\begin{itemize}
+\item a working C++ compiler with good STL implementation and also a good
+support for templates (for example, \href{http://gcc.gnu.org/}{GNU GCC}) ;
+\item \href{http://www.cmake.org/}{CMake} build system ;
+\item either \href{http://www.icu-project.org}{ICU library} or an usable
+{\vcode iconv()} implementation (see
+\href{http://www.gnu.org/software/libiconv/}{libiconv of GNU Project}) ;
+\item the \href{http://www.gnu.org/software/gsasl/}{GNU SASL Library} if you
+want SASL\footnote{Simple Authentication and Security Layer} support ;
+\item either the \href{http://www.openssl.org}{OpenSSL library} or the
+\href{http://www.gnu.org/software/gnutls/}{GNU TLS Library} if you
+want SSL and TLS\footnote{Transport Layer Security} support ;
+\end{itemize}
+
+% ============================================================================
+\section{Obtaining source files}
+
+You can download a package containing the source files of the latest release
+of the VMime library from the \href{http://www.vmime.org/}{VMime web site}.
+
+You can also obtain the current development version from the Git repository,
+which is currently hosted at GitHub. It can be checked out through anonymous
+access with the following instruction:
+
+\begin{verbatim}
+ git clone git://github.com/kisli/vmime
+\end{verbatim}
+
+% ============================================================================
+\section{Compiling and installing}
+
+VMime relies on CMake for building. CMake is an open source, cross-platform
+build system. It will generate all build scripts required to compile VMime on
+your platform.
+
+First, extract the tarball or checkout the VMime source code into a directory
+somewhere on your system, let's call it {\vcode /path/to/vmime-source}. Then,
+create a build directory, which will contain all intermediate build files and
+the final libraries, let's call it {\vcode /path/to/vmime-build}.
+
+From the build directory, run {\vcode cmake} with the {\vcode -G} argument
+corresponding to your platform/choice. For example, if you are on a
+Unix-compatible platform (like GNU/Linux or MacOS) and want to use the
+{\vcode make} utility for building, type:
+
+\begin{verbatim}
+ $ cd /path/to/vmime-build
+ $ cmake -G "Unix Makefiles" /path/to/vmime-source
+\end{verbatim}
+
+CMake will perform some tests on your system to check for libs installed
+and some platform-specific includes, and create all files needed for
+compiling the project. Additionally, a {\vcode src/vmime/config.hpp} file
+with the parameters detected for your system will be created.
+
+Next, you can start the compilation process:
+
+\begin{verbatim}
+ $ cmake --build .
+\end{verbatim}
+
+Please wait a few minutes while the compilation runs (you should have some
+time to have a coffee right now!). If you get errors during the compilation,
+be sure your system meet the requirements given at the beginning of the
+chapter. You can also try to get a newer version (from the Git repository, for
+example) or to get some help on VMime user forums.
+
+If everything compiled successfully, you can install the library and
+the development files on your system:
+
+\begin{verbatim}
+ # make install
+\end{verbatim}
+
+\vnote{you must do that with superuser rights (root) if you chose to install
+the library into the default location (ie: /usr/lib and /usr/include).}
+
+Now, you are done! You can jump to the next chapter to know how to use VMime
+in your program...
+
+
+% ============================================================================
+\section{\label{custom-build}Customizing build}
+
+You should not modify the {\vcode config.hpp} file directly. Instead, you
+should run {\vcode cmake} again, and specify your build options on the command
+line. For example, to force using OpenSSL library instead of GnuTLS for TLS
+support, type:
+
+\begin{verbatim}
+ $ cmake -G "Unix Makefiles" -DVMIME_TLS_SUPPORT_LIB=openssl
+\end{verbatim}
+
+If you want to enable or disable some features in VMime, you can obtain some
+help by typing {\vcode cmake -L}. The defaults should be OK though. For a
+complate list of build options, you can also refer to section
+\ref{build-options}, page \pageref{build-options}. For more information about
+using CMake, go to \href{http://www.cmake.org/}{the CMake web site}.
+
+\vnote{Delete the {\vcode CMakeCache.txt} file if you changed configuration
+or if something changed on your system, as CMake may cache some values to
+speed things up.}
+
+You can also use another build backend, like
+Ninja\footnote{\url{https://ninja-build.org/}}, if you have it on your system:
+
+\begin{verbatim}
+ $ cd /path/to/vmime-build
+ $ cmake -G Ninja /path/to/vmime-source
+ $ ninja
+ # ninja install
+\end{verbatim}
+
+To install VMime in a directory different from the default directory
+({\vcode /usr} on GNU/Linux systems), set the
+{\vcode CMAKE\_INSTALL\_PREFIX} option:
+
+\begin{verbatim}
+ $ cmake -DCMAKE_INSTALL_PREFIX=/opt/ ...
+\end{verbatim}
+
+
+% ============================================================================
+\section{\label{build-options}Build options}
+
+Some options can be given to CMake to control the build:
+
+\begin{table}[!ht]
+\noindent\begin{tabularx}{1.0\textwidth}{|l|X|}
+\hline
+ {\bf Option name} &
+ {\bf Description} \\
+\hline
+\hline
+VMIME\_BUILD\_SHARED\_LIBRARY &
+Set to ON to build a shared version (.so) of the library (default is ON). \\
+\hline
+VMIME\_BUILD\_STATIC\_LIBRARY &
+Set to ON to build a static version (.a) of the library (default is ON). \\
+\hline
+VMIME\_BUILD\_TESTS &
+Set to ON to build unit tests (default is OFF). \\
+\hline
+VMIME\_TLS\_SUPPORT\_LIB &
+Set to either "openssl" or "gnutls" to force using either OpenSSL or GNU TLS
+for SSL/TLS support (default depends on which libraries are available on
+your system). \\
+\hline
+VMIME\_CHARSETCONV\_LIB &
+Set to either "iconv", "icu" or "win" (Windows only) to force using iconv, ICU
+or Windows built-in API for converting between charsets (default value depends
+on which libraries are available on your system). \\
+\hline
+CMAKE\_BUILD\_TYPE &
+Set the build type: either "Release" or "Debug". In Debug build, optimizations
+are disabled and debugging information are enabled. \\
+\hline
+\end{tabularx}
+\caption{CMake build options}
+\end{table}
diff --git a/vmime-master/doc/book/images/address-mailbox-mailboxgroup.svg b/vmime-master/doc/book/images/address-mailbox-mailboxgroup.svg
new file mode 100644
index 0000000..a7752d4
--- /dev/null
+++ b/vmime-master/doc/book/images/address-mailbox-mailboxgroup.svg
@@ -0,0 +1,355 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://web.resource.org/cc/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="453.27998pt"
+ height="307.89001pt"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.42.2"
+ sodipodi:docbase="/home/vincent/projects/vmime/doc/book/images"
+ sodipodi:docname="address-mailbox-mailboxgroup.svg"
+ inkscape:export-xdpi="73.779999"
+ inkscape:export-ydpi="73.779999">
+ <defs
+ id="defs3">
+ <marker
+ inkscape:stockid="Torso"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Torso"
+ style="overflow:visible">
+ <g
+ id="g2045"
+ transform="scale(0.7)">
+ <path
+ sodipodi:nodetypes="ccccc"
+ id="path1128"
+ d="M -4.7792281,-3.2395420 C -2.4288541,-2.8736027 0.52103922,-1.3019943 0.25792722,0.38794346 C -0.0051877922,2.0778819 -2.2126741,2.6176539 -4.5630471,2.2517169 C -6.9134221,1.8857769 -8.5210350,0.75201414 -8.2579220,-0.93792336 C -7.9948090,-2.6278615 -7.1296041,-3.6054813 -4.7792281,-3.2395420 z "
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;marker-start:none;marker-mid:none;marker-end:none" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path1909"
+ d="M 4.4598789,0.088665736 C -2.5564571,-4.3783320 5.2248769,-3.9061806 -0.84829578,-8.7197331"
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000pt;marker-end:none" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path1910"
+ d="M 4.9298719,0.057520736 C -1.3872731,1.7494689 1.8027579,5.4782079 -4.9448731,7.5462725"
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000pt;marker-start:none;marker-end:none" />
+ <rect
+ transform="matrix(0.527536,-0.849533,0.887668,0.460484,0.000000,0.000000)"
+ y="-1.7408575"
+ x="-10.391706"
+ height="2.7608147"
+ width="2.6366582"
+ id="rect2035"
+ style="fill-rule:evenodd;stroke-width:1.0000000pt;marker-end:none" />
+ <rect
+ transform="matrix(0.671205,-0.741272,0.790802,0.612072,0.000000,0.000000)"
+ y="-7.9629307"
+ x="4.9587269"
+ height="2.8614161"
+ width="2.7327356"
+ id="rect2036"
+ style="fill-rule:evenodd;stroke-width:1.0000000pt;marker-end:none" />
+ <path
+ transform="matrix(6.793608e-17,-1.109517,1.109517,6.793608e-17,25.96648,19.71619)"
+ d="M 16.779951 -28.685045 A 0.60731727 0.60731727 0 1 0 15.565317,-28.685045 A 0.60731727 0.60731727 0 1 0 16.779951 -28.685045 z"
+ sodipodi:ry="0.60731727"
+ sodipodi:rx="0.60731727"
+ sodipodi:cy="-28.685045"
+ sodipodi:cx="16.172634"
+ id="path2037"
+ style="fill:#ff0000;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000pt;marker-start:none;marker-end:none"
+ sodipodi:type="arc" />
+ <path
+ transform="matrix(6.793608e-17,-1.109517,1.109517,6.793608e-17,26.82450,16.99126)"
+ d="M 16.779951 -28.685045 A 0.60731727 0.60731727 0 1 0 15.565317,-28.685045 A 0.60731727 0.60731727 0 1 0 16.779951 -28.685045 z"
+ sodipodi:ry="0.60731727"
+ sodipodi:rx="0.60731727"
+ sodipodi:cy="-28.685045"
+ sodipodi:cx="16.172634"
+ id="path2038"
+ style="fill:#ff0000;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000pt;marker-start:none;marker-end:none"
+ sodipodi:type="arc" />
+ </g>
+ </marker>
+ <marker
+ inkscape:stockid="TriangleOutL"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="TriangleOutL"
+ style="overflow:visible">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path5324"
+ d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none"
+ transform="scale(0.8)" />
+ </marker>
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="1.0000000"
+ inkscape:pageshadow="2"
+ inkscape:zoom="1.0000000"
+ inkscape:cx="248.49444"
+ inkscape:cy="298.91345"
+ inkscape:document-units="px"
+ inkscape:current-layer="layer1"
+ inkscape:window-width="1150"
+ inkscape:window-height="986"
+ inkscape:window-x="0"
+ inkscape:window-y="30"
+ fill="#ff0000"
+ inkscape:showpageshadow="true"
+ showguides="true"
+ showgrid="false"
+ inkscape:grid-bbox="false"
+ inkscape:grid-points="false" />
+ <metadata
+ id="metadata4">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <cc:license
+ rdf:resource="http://creativecommons.org/licenses/GPL/2.0/" />
+ </cc:Work>
+ <cc:License
+ rdf:about="http://creativecommons.org/licenses/GPL/2.0/">
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Reproduction" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Distribution" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/Notice" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/ShareAlike" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/SourceCode" />
+ </cc:License>
+ </rdf:RDF>
+ </metadata>
+ <path
+ id="path5442"
+ d="M 303.65293,104.37647 L 303.65293,173.68448"
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
+ <path
+ id="path5440"
+ d="M 462.39333,172.39335 L 462.39333,240.10630"
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
+ <path
+ id="path5438"
+ d="M 139.24323,172.39335 L 139.24323,240.10630"
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-dasharray:none;stroke-opacity:1.0000000"
+ d="M 257.32713,293.92642 L 392.05898,293.92642"
+ id="path2543" />
+ <rect
+ style="fill:#e0f5cc;fill-opacity:1.0000000;stroke:#000000;stroke-width:1.2500000;stroke-miterlimit:4.0000000;stroke-dasharray:none;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
+ id="rect1291"
+ width="132.69368"
+ height="105.95705"
+ x="237.85556"
+ y="13.003311" />
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="245.51651"
+ y="55.887268"
+ id="text1293"
+ sodipodi:linespacing="125.00000%"><tspan
+ sodipodi:role="line"
+ id="tspan2242"
+ x="245.51651"
+ y="55.887268">isEmpty() : bool</tspan><tspan
+ sodipodi:role="line"
+ id="tspan2244"
+ x="245.51651"
+ y="70.887268">isGroup() : bool</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="279.65814"
+ y="29.038483"
+ id="text2347"
+ sodipodi:linespacing="125.00000%"><tspan
+ sodipodi:role="line"
+ id="tspan2222"
+ x="279.65814"
+ y="29.038483">address</tspan></text>
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-dasharray:none;stroke-opacity:1.0000000"
+ d="M 238.27499,37.373470 L 370.37704,37.373470"
+ id="path2351" />
+ <rect
+ style="fill:#f5f5c8;fill-opacity:1.0000000;stroke:#000000;stroke-width:1.0000000;stroke-miterlimit:4.0000000;stroke-dasharray:none;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
+ id="rect2433"
+ width="242.87289"
+ height="157.12062"
+ x="17.947495"
+ y="215.62213" />
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125%;writing-mode:lr;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="24.265694"
+ y="258.30316"
+ id="text2435"
+ sodipodi:linespacing="125%"><tspan
+ sodipodi:role="line"
+ id="tspan2315"
+ x="24.265694"
+ y="258.30316">getName() : string</tspan><tspan
+ sodipodi:role="line"
+ id="tspan2317"
+ x="24.265694"
+ y="273.30316">setName(n : string) : void</tspan><tspan
+ sodipodi:role="line"
+ id="tspan2319"
+ x="24.265694"
+ y="288.30316">appendMailbox(m : ref &lt;mailbox&gt;)</tspan><tspan
+ sodipodi:role="line"
+ id="tspan2321"
+ x="24.265694"
+ y="303.30316">getMailboxCount() : int</tspan><tspan
+ sodipodi:role="line"
+ id="tspan2323"
+ x="24.265694"
+ y="318.30316">getMailboxAt(i : int) : ref &lt;mailbox&gt;</tspan><tspan
+ sodipodi:role="line"
+ id="tspan2325"
+ x="24.265694"
+ y="333.30316">...</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="91.950951"
+ y="231.45441"
+ id="text2439"
+ sodipodi:linespacing="125.00000%"><tspan
+ sodipodi:role="line"
+ id="tspan2246"
+ x="91.950951"
+ y="231.45441">mailboxGroup</tspan></text>
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-dasharray:none;stroke-opacity:1.0000000"
+ d="M 19.330207,239.78939 L 260.20091,239.78939"
+ id="path2443" />
+ <rect
+ style="fill:#f5f5c8;fill-opacity:1.0000000;stroke:#000000;stroke-width:1.2500000;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
+ id="rect2447"
+ width="174.79645"
+ height="124.30678"
+ x="373.27942"
+ y="215.33472" />
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="380.74768"
+ y="258.15143"
+ id="text2449"
+ sodipodi:linespacing="125.00000%"><tspan
+ sodipodi:role="line"
+ id="tspan2286"
+ x="380.74768"
+ y="258.15143">getName() : text</tspan><tspan
+ sodipodi:role="line"
+ id="tspan2288"
+ x="380.74768"
+ y="273.15143">setName(n : text) : void</tspan><tspan
+ sodipodi:role="line"
+ id="tspan2290"
+ x="380.74768"
+ y="288.15143">getEmail() : string</tspan><tspan
+ sodipodi:role="line"
+ id="tspan2292"
+ x="380.74768"
+ y="303.15143">setEmail(e : string) : void</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;text-align:start;line-height:125.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="434.7478"
+ y="231.30267"
+ id="text2453"
+ sodipodi:linespacing="125.00000%"><tspan
+ sodipodi:role="line"
+ id="tspan2276"
+ x="434.74780"
+ y="231.30267">mailbox</tspan></text>
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 373.64397,239.63760 L 547.69600,239.63760"
+ id="path2457" />
+ <rect
+ style="fill:#ffffff;fill-opacity:1.0000000;stroke:#000000;stroke-width:1.2500457;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
+ id="rect2541"
+ width="15.541327"
+ height="15.541327"
+ x="-23.443876"
+ y="392.33624"
+ transform="matrix(0.707107,-0.707107,0.707107,0.707107,0.000000,0.000000)" />
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="344.41357"
+ y="289.23822"
+ id="text2545"
+ sodipodi:linespacing="100.00000%"><tspan
+ id="tspan5160"
+ sodipodi:role="line"
+ y="289.23822"
+ x="344.41357">0..n</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-align:start;line-height:125.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="293.07501"
+ y="312.23822"
+ id="text2549"
+ sodipodi:linespacing="125.00000%"><tspan
+ sodipodi:role="line"
+ id="tspan2294"
+ x="293.07501"
+ y="312.23822">mailboxes</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="289.07501"
+ y="289.23822"
+ id="text2553"
+ sodipodi:linespacing="100.00000%"><tspan
+ id="tspan5158"
+ sodipodi:role="line"
+ y="289.23822"
+ x="289.07501">0</tspan></text>
+ <path
+ id="path2575"
+ d="M 290.22642,134.62157 L 318.11534,134.62157 L 303.70606,120.21230 L 290.22642,134.62157 z "
+ style="fill:#ffffff;fill-opacity:1.0000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
+ </g>
+ <path
+ id="path5436"
+ d="M 139.78693,173.17443 L 461.72537,173.17443"
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000;stroke-dasharray:none" />
+</svg>
diff --git a/vmime-master/doc/book/images/message-body-header.svg b/vmime-master/doc/book/images/message-body-header.svg
new file mode 100644
index 0000000..29923fa
--- /dev/null
+++ b/vmime-master/doc/book/images/message-body-header.svg
@@ -0,0 +1,716 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://web.resource.org/cc/"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://inkscape.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="707.28000pt"
+ height="612.89000pt"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.42.2"
+ sodipodi:docbase="/home/vincent/projects/vmime/doc/book/images"
+ sodipodi:docname="message-body-header.svg"
+ inkscape:export-xdpi="73.779999"
+ inkscape:export-ydpi="73.779999">
+ <defs
+ id="defs3">
+ <marker
+ inkscape:stockid="Torso"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Torso"
+ style="overflow:visible">
+ <g
+ id="g2045"
+ transform="scale(0.7)">
+ <path
+ sodipodi:nodetypes="ccccc"
+ id="path1128"
+ d="M -4.7792281,-3.2395420 C -2.4288541,-2.8736027 0.52103922,-1.3019943 0.25792722,0.38794346 C -0.0051877922,2.0778819 -2.2126741,2.6176539 -4.5630471,2.2517169 C -6.9134221,1.8857769 -8.5210350,0.75201414 -8.2579220,-0.93792336 C -7.9948090,-2.6278615 -7.1296041,-3.6054813 -4.7792281,-3.2395420 z "
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;marker-start:none;marker-mid:none;marker-end:none" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path1909"
+ d="M 4.4598789,0.088665736 C -2.5564571,-4.3783320 5.2248769,-3.9061806 -0.84829578,-8.7197331"
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000pt;marker-end:none" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path1910"
+ d="M 4.9298719,0.057520736 C -1.3872731,1.7494689 1.8027579,5.4782079 -4.9448731,7.5462725"
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000pt;marker-start:none;marker-end:none" />
+ <rect
+ transform="matrix(0.527536,-0.849533,0.887668,0.460484,0.000000,0.000000)"
+ y="-1.7408575"
+ x="-10.391706"
+ height="2.7608147"
+ width="2.6366582"
+ id="rect2035"
+ style="fill-rule:evenodd;stroke-width:1.0000000pt;marker-end:none" />
+ <rect
+ transform="matrix(0.671205,-0.741272,0.790802,0.612072,0.000000,0.000000)"
+ y="-7.9629307"
+ x="4.9587269"
+ height="2.8614161"
+ width="2.7327356"
+ id="rect2036"
+ style="fill-rule:evenodd;stroke-width:1.0000000pt;marker-end:none" />
+ <path
+ transform="matrix(6.793608e-17,-1.109517,1.109517,6.793608e-17,25.96648,19.71619)"
+ d="M 16.779951 -28.685045 A 0.60731727 0.60731727 0 1 0 15.565317,-28.685045 A 0.60731727 0.60731727 0 1 0 16.779951 -28.685045 z"
+ sodipodi:ry="0.60731727"
+ sodipodi:rx="0.60731727"
+ sodipodi:cy="-28.685045"
+ sodipodi:cx="16.172634"
+ id="path2037"
+ style="fill:#ff0000;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000pt;marker-start:none;marker-end:none"
+ sodipodi:type="arc" />
+ <path
+ transform="matrix(6.793608e-17,-1.109517,1.109517,6.793608e-17,26.82450,16.99126)"
+ d="M 16.779951 -28.685045 A 0.60731727 0.60731727 0 1 0 15.565317,-28.685045 A 0.60731727 0.60731727 0 1 0 16.779951 -28.685045 z"
+ sodipodi:ry="0.60731727"
+ sodipodi:rx="0.60731727"
+ sodipodi:cy="-28.685045"
+ sodipodi:cx="16.172634"
+ id="path2038"
+ style="fill:#ff0000;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000pt;marker-start:none;marker-end:none"
+ sodipodi:type="arc" />
+ </g>
+ </marker>
+ <marker
+ inkscape:stockid="TriangleOutL"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="TriangleOutL"
+ style="overflow:visible">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path5324"
+ d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none"
+ transform="scale(0.8)" />
+ </marker>
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="1.00000000"
+ inkscape:cx="394.46478"
+ inkscape:cy="380.70648"
+ inkscape:document-units="px"
+ inkscape:current-layer="svg2"
+ inkscape:window-width="1150"
+ inkscape:window-height="986"
+ inkscape:window-x="0"
+ inkscape:window-y="30" />
+ <metadata
+ id="metadata4">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ <cc:license
+ rdf:resource="http://creativecommons.org/licenses/GPL/2.0/" />
+ </cc:Work>
+ <cc:License
+ rdf:about="http://creativecommons.org/licenses/GPL/2.0/">
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Reproduction" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/Distribution" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/Notice" />
+ <cc:permits
+ rdf:resource="http://web.resource.org/cc/DerivativeWorks" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/ShareAlike" />
+ <cc:requires
+ rdf:resource="http://web.resource.org/cc/SourceCode" />
+ </cc:License>
+ </rdf:RDF>
+ </metadata>
+ <path
+ id="path2407"
+ d="M 253.02743,136.68448 L 253.02743,67.376470"
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
+ <path
+ id="path5442"
+ d="M 635.99153,281.37647 L 635.99153,350.68448"
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
+ <path
+ id="path5440"
+ d="M 783.39333,349.39335 L 783.39333,417.10630"
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
+ <path
+ id="path5438"
+ d="M 446.06998,349.39335 L 446.06998,417.10630"
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 16.987518,219.56412 L 153.50367,219.56412"
+ id="path2375" />
+ <path
+ id="path2345"
+ d="M 508.29892,263.82217 L 105.85472,471.31117"
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
+ <path
+ id="path2347"
+ d="M 502.39025,252.30315 L 515.17042,277.09145 L 521.37461,257.68108 L 502.39025,252.30315 z "
+ style="fill:#ffffff;fill-opacity:1.0000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
+ <g
+ transform="matrix(1.828236e-17,1.000000,-1.000000,1.828236e-17,533.0981,623.6004)"
+ id="g2321">
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M -100.36367,371.67294 L 26.017722,371.67294"
+ id="path2323" />
+ <g
+ id="g2325"
+ transform="translate(-113.9177,-82.19766)">
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000"
+ d="M 140.20049,454.12696 L 129.75724,443.68372"
+ id="path2327" />
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 139.84823,453.80527 L 129.66343,463.99007"
+ id="path2329" />
+ </g>
+ </g>
+ <path
+ id="path2241"
+ d="M 507.60723,180.01568 L 350.16119,180.01568"
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
+ <rect
+ style="fill:#dcf5e6;fill-opacity:1.0000000;stroke:#000000;stroke-width:1.2500000;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
+ id="rect1291"
+ width="236.14607"
+ height="157.54773"
+ x="522.13733"
+ y="126.86942" />
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:120.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="529.52441"
+ y="169.54865"
+ id="text1293"
+ sodipodi:linespacing="120.00000%"><tspan
+ id="tspan5228"
+ sodipodi:role="line"
+ y="169.54865"
+ x="529.52441">parse(buf : string) : void</tspan><tspan
+ id="tspan5230"
+ sodipodi:role="line"
+ y="183.94865"
+ x="529.52441">generate(out : outputStream) : void</tspan><tspan
+ id="tspan5232"
+ sodipodi:role="line"
+ y="198.34865"
+ x="529.52441" /><tspan
+ id="tspan5234"
+ sodipodi:role="line"
+ y="212.74865"
+ x="529.52441">clone() : ref &lt;component&gt;</tspan><tspan
+ id="tspan5236"
+ sodipodi:role="line"
+ y="227.14865"
+ x="529.52441">copyFrom(src : component) : void</tspan><tspan
+ id="tspan5238"
+ sodipodi:role="line"
+ y="241.54865"
+ x="529.52441">getChildComponents() : vector</tspan><tspan
+ id="tspan5240"
+ sodipodi:role="line"
+ y="255.94865"
+ x="529.52441">getParsedOffset() : int</tspan><tspan
+ id="tspan5242"
+ sodipodi:role="line"
+ y="270.34865"
+ x="529.52441">getParsedLength() : int</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="609.02057"
+ y="142.69992"
+ id="text2347"
+ sodipodi:linespacing="100.00000%"><tspan
+ id="tspan5172"
+ sodipodi:role="line"
+ y="142.69992"
+ x="609.02057">component</tspan></text>
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 522.50261,151.03487 L 758.16522,151.03487"
+ id="path2351" />
+ <rect
+ style="fill:#f5f5c8;fill-opacity:1.0000000;stroke:#000000;stroke-width:1.2500000;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
+ id="rect2353"
+ width="218.71376"
+ height="151.16983"
+ x="145.51056"
+ y="133.04831" />
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:120.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="154.6483"
+ y="175.75391"
+ id="text2355"
+ sodipodi:linespacing="120.00000%"><tspan
+ id="tspan2349"
+ sodipodi:role="line"
+ y="175.75391"
+ x="154.64830">getBody() : ref &lt;body&gt;</tspan><tspan
+ id="tspan2351"
+ sodipodi:role="line"
+ y="190.15391"
+ x="154.64830">getHeader() : ref &lt;header&gt;</tspan><tspan
+ id="tspan2353"
+ sodipodi:role="line"
+ y="204.55391"
+ x="154.64830">getParentPart() : ref &lt;bodyPart&gt;</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="222.66418"
+ y="148.90518"
+ id="text2375"
+ sodipodi:linespacing="100.00000%"><tspan
+ id="tspan5272"
+ sodipodi:role="line"
+ y="148.90518"
+ x="222.66418">bodyPart</tspan></text>
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 145.87565,157.24013 L 363.84409,157.24013"
+ id="path2379" />
+ <g
+ transform="matrix(1.828236e-17,1.000000,-1.000000,1.828236e-17,548.9327,384.9312)"
+ id="g2247">
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M -100.36367,371.67294 L 26.017722,371.67294"
+ id="path2387" />
+ <g
+ id="g2395"
+ transform="translate(-113.9177,-82.19766)">
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000"
+ d="M 140.20049,454.12696 L 129.75724,443.68372"
+ id="path2389" />
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 139.84823,453.80527 L 129.66343,463.99007"
+ id="path2393" />
+ </g>
+ </g>
+ <text
+ sodipodi:linespacing="100.00000%"
+ xml:space="preserve"
+ style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="138.11696"
+ y="382.06345"
+ id="text2403"><tspan
+ id="tspan2273"
+ sodipodi:role="line"
+ y="382.06345"
+ x="138.11696">body</tspan></text>
+ <rect
+ style="fill:#f5f5c8;fill-opacity:1.0000000;stroke:#000000;stroke-width:1.2500000;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
+ id="rect2433"
+ width="276.37778"
+ height="157.12062"
+ x="304.96820"
+ y="412.46472" />
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:120.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="313.24988"
+ y="455.14575"
+ id="text2435"
+ sodipodi:linespacing="120.00000%"><tspan
+ id="tspan5256"
+ sodipodi:role="line"
+ y="455.14575"
+ x="313.24988">hasField(name : string) : bool</tspan><tspan
+ id="tspan5258"
+ sodipodi:role="line"
+ y="469.54575"
+ x="313.24988">findField(name : string) : ref &lt;headerField&gt;</tspan><tspan
+ id="tspan5260"
+ sodipodi:role="line"
+ y="483.94575"
+ x="313.24988">findAllFields(name : string) : vector</tspan><tspan
+ id="tspan5262"
+ sodipodi:role="line"
+ y="498.34575"
+ x="313.24988">getField(name : string) : ref &lt;headerField&gt;</tspan><tspan
+ id="tspan5264"
+ sodipodi:role="line"
+ y="512.74575"
+ x="313.24988">appendField(f : ref &lt;headerField&gt;) : void</tspan><tspan
+ id="tspan5266"
+ sodipodi:role="line"
+ y="527.14575"
+ x="313.24988">...</tspan><tspan
+ id="tspan5268"
+ sodipodi:role="line"
+ y="541.54576"
+ x="313.24988">getFieldAt(pos : int) : ref &lt;headerField&gt;</tspan><tspan
+ id="tspan5270"
+ sodipodi:role="line"
+ y="555.94576"
+ x="313.24988">getFieldCount() : int</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="412.95099"
+ y="428.297"
+ id="text2439"
+ sodipodi:linespacing="100.00000%"><tspan
+ id="tspan5154"
+ sodipodi:role="line"
+ y="428.29700"
+ x="412.95099">header</tspan></text>
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 306.34976,436.63194 L 580.95005,436.63194"
+ id="path2443" />
+ <rect
+ style="fill:#f5f5c8;fill-opacity:1.0000000;stroke:#000000;stroke-width:1.2500000;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
+ id="rect2447"
+ width="174.79645"
+ height="124.30678"
+ x="694.27942"
+ y="412.17731" />
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:120.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="701.74768"
+ y="454.99402"
+ id="text2449"
+ sodipodi:linespacing="120.00000%"><tspan
+ id="tspan5176"
+ sodipodi:role="line"
+ y="454.99402"
+ x="701.74768">getName() : string</tspan><tspan
+ id="tspan5178"
+ sodipodi:role="line"
+ y="469.39402"
+ x="701.74768">getValue() : component</tspan><tspan
+ id="tspan5180"
+ sodipodi:role="line"
+ y="483.79402"
+ x="701.74768">setValue(val : component)</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="738.73987"
+ y="428.14526"
+ id="text2453"
+ sodipodi:linespacing="100.00000%"><tspan
+ id="tspan5152"
+ sodipodi:role="line"
+ y="428.14526"
+ x="738.73987">headerField</tspan></text>
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 694.64397,436.48015 L 868.69600,436.48015"
+ id="path2457" />
+ <rect
+ style="fill:#ffffff;fill-opacity:1.0000000;stroke:#000000;stroke-width:1.2500381;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
+ id="rect2541"
+ width="15.541226"
+ height="15.541226"
+ x="65.401291"
+ y="759.55469"
+ transform="matrix(0.707107,-0.707107,0.707107,0.707107,0.000000,0.000000)" />
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 605.07226,490.76897 L 694.31385,490.76897"
+ id="path2543" />
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="661.23236"
+ y="486.08081"
+ id="text2545"
+ sodipodi:linespacing="100.00000%"><tspan
+ id="tspan5160"
+ sodipodi:role="line"
+ y="486.08081"
+ x="661.23236">0..n</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="626.90173"
+ y="509.08081"
+ id="text2549"
+ sodipodi:linespacing="100.00000%"><tspan
+ id="tspan5156"
+ sodipodi:role="line"
+ y="509.08081"
+ x="626.90173">fields</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="611.56311"
+ y="486.08081"
+ id="text2553"
+ sodipodi:linespacing="100.00000%"><tspan
+ id="tspan5158"
+ sodipodi:role="line"
+ y="486.08081"
+ x="611.56311">0</tspan></text>
+ <path
+ id="path2575"
+ d="M 622.56502,300.28297 L 650.45394,300.28297 L 636.04466,285.87370 L 622.56502,300.28297 z "
+ style="fill:#ffffff;fill-opacity:1.0000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
+ <rect
+ style="fill:#f5f5c8;fill-opacity:1.0000000;stroke:#000000;stroke-width:1.2500000;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
+ id="rect2225"
+ width="171.85686"
+ height="151.16983"
+ x="74.698677"
+ y="412.04831" />
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:120.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="82.183701"
+ y="454.75391"
+ id="text2227"
+ sodipodi:linespacing="120.00000%"><tspan
+ id="tspan2377"
+ sodipodi:role="line"
+ y="454.75391"
+ x="82.183701">getContents() : ref &lt;ch&gt;</tspan><tspan
+ id="tspan2379"
+ sodipodi:role="line"
+ y="469.15391"
+ x="82.183701">getCharset() : charset</tspan><tspan
+ id="tspan2381"
+ sodipodi:role="line"
+ y="483.55391"
+ x="82.183701">getEncoding() : encoding</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="141.69556"
+ y="427.90518"
+ id="text2231"
+ sodipodi:linespacing="100.00000%"><tspan
+ id="tspan2237"
+ sodipodi:role="line"
+ y="427.90518"
+ x="141.69556">body</tspan></text>
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 75.063282,436.24013 L 246.17599,436.24013"
+ id="path2235" />
+ <path
+ id="path2239"
+ d="M 506.13949,167.78737 L 506.13949,195.67630 L 520.54876,181.26702 L 506.13949,167.78737 z "
+ style="fill:#ffffff;fill-opacity:1.0000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
+ <g
+ transform="matrix(1.828236e-17,1.000000,-1.000000,1.828236e-17,548.9327,384.9312)"
+ id="g2253">
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M -100.36367,371.67294 L 26.017722,371.67294"
+ id="path2255" />
+ <g
+ id="g2257"
+ transform="translate(-113.9177,-82.19766)">
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000"
+ d="M 140.20049,454.12696 L 129.75724,443.68372"
+ id="path2259" />
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 139.84823,453.80527 L 129.66343,463.99007"
+ id="path2261" />
+ </g>
+ </g>
+ <g
+ transform="matrix(1.828236e-17,1.000000,-1.000000,1.828236e-17,704.8357,384.9312)"
+ id="g2263">
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M -100.36367,371.67294 L 26.017722,371.67294"
+ id="path2265" />
+ <g
+ id="g2267"
+ transform="translate(-113.9177,-82.19766)">
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000"
+ d="M 140.20049,454.12696 L 129.75724,443.68372"
+ id="path2269" />
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 139.84823,453.80527 L 129.66343,463.99007"
+ id="path2271" />
+ </g>
+ </g>
+ <text
+ sodipodi:linespacing="100.00000%"
+ xml:space="preserve"
+ style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="342.21133"
+ y="384.8981"
+ id="text2275"><tspan
+ id="tspan2279"
+ sodipodi:role="line"
+ y="384.89810"
+ x="342.21133">header</tspan></text>
+ <rect
+ style="fill:#f5f5c8;fill-opacity:1.0000000;stroke:#000000;stroke-width:1.2500000;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
+ id="rect2283"
+ width="223.48137"
+ height="99.596283"
+ x="46.366730"
+ y="650.83508" />
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:120.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="53.664009"
+ y="693.75391"
+ id="text2285"
+ sodipodi:linespacing="120.00000%"><tspan
+ id="tspan2337"
+ sodipodi:role="line"
+ y="693.75391"
+ x="53.664009">extract(out : outputStream) : void</tspan><tspan
+ id="tspan2339"
+ sodipodi:role="line"
+ y="708.15391"
+ x="53.664009">getLength() : int</tspan><tspan
+ id="tspan2341"
+ sodipodi:role="line"
+ y="722.55391"
+ x="53.664009">getEncoding() : encoding</tspan><tspan
+ id="tspan2343"
+ sodipodi:role="line"
+ y="736.95391"
+ x="53.664009">isEmpty() : bool</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="107.50659"
+ y="666.90515"
+ id="text2289"
+ sodipodi:linespacing="100.00000%"><tspan
+ id="tspan2295"
+ sodipodi:role="line"
+ y="666.90515"
+ x="107.50659">contentHandler</tspan></text>
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 46.694654,675.24013 L 269.50523,675.24013"
+ id="path2293" />
+ <text
+ sodipodi:linespacing="100.00000%"
+ xml:space="preserve"
+ style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="96.439804"
+ y="606.38623"
+ id="text2313"><tspan
+ id="tspan2331"
+ sodipodi:role="line"
+ y="606.38623"
+ x="96.439804">contents</tspan></text>
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2343873;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 16.600928,494.52517 L 54.665082,494.52517"
+ id="path2357" />
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="114.21628"
+ y="211.67206"
+ id="text2359"
+ sodipodi:linespacing="100.00000%"><tspan
+ id="tspan2361"
+ sodipodi:role="line"
+ y="211.67206"
+ x="114.21628">0..n</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="15.201084"
+ y="211.39832"
+ id="text2363"
+ sodipodi:linespacing="100.00000%"><tspan
+ id="tspan2371"
+ sodipodi:role="line"
+ y="211.39832"
+ x="15.201084">sub-parts</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="37.547035"
+ y="486.67206"
+ id="text2367"
+ sodipodi:linespacing="100.00000%"><tspan
+ id="tspan2369"
+ sodipodi:role="line"
+ y="486.67206"
+ x="37.547035">0</tspan></text>
+ <rect
+ style="fill:#ffffff;fill-opacity:1.0000000;stroke:#000000;stroke-width:1.2500843;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
+ id="rect2355"
+ width="15.541844"
+ height="15.541844"
+ x="-313.66727"
+ y="385.82047"
+ transform="matrix(0.707107,-0.707107,0.707107,0.707107,0.000000,0.000000)" />
+ <rect
+ style="fill:#f5f5c8;fill-opacity:1.0000000;stroke:#000000;stroke-width:1.2500000;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
+ id="rect2383"
+ width="171.85686"
+ height="67.987976"
+ x="169.86403"
+ y="15.308525" />
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="228.35699"
+ y="31.574478"
+ id="text2393"
+ sodipodi:linespacing="100.00000%"><tspan
+ id="tspan2399"
+ sodipodi:role="line"
+ y="31.574478"
+ x="228.35699">message</tspan></text>
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 170.22863,39.909422 L 341.34134,39.909422"
+ id="path2397" />
+ <path
+ id="path2405"
+ d="M 266.45394,117.77798 L 238.56502,117.77798 L 252.97430,132.18725 L 266.45394,117.77798 z "
+ style="fill:#ffffff;fill-opacity:1.0000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
+ </g>
+ <path
+ id="path5436"
+ d="M 446.81292,350.17443 L 782.69938,350.17443"
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2515085;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
+ <path
+ id="path2373"
+ d="M 16.806908,219.05029 L 16.806908,493.94805"
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2522694;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
+</svg>
diff --git a/vmime-master/doc/book/images/messaging-services.svg b/vmime-master/doc/book/images/messaging-services.svg
new file mode 100644
index 0000000..fe4f8c8
--- /dev/null
+++ b/vmime-master/doc/book/images/messaging-services.svg
@@ -0,0 +1,617 @@
+<?xml version="1.0" encoding="UTF-8" standalone="no"?>
+<!-- Created with Inkscape (http://www.inkscape.org/) -->
+
+<svg
+ xmlns:dc="http://purl.org/dc/elements/1.1/"
+ xmlns:cc="http://creativecommons.org/ns#"
+ xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
+ xmlns:svg="http://www.w3.org/2000/svg"
+ xmlns="http://www.w3.org/2000/svg"
+ xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
+ xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
+ width="629.28000pt"
+ height="615.89000pt"
+ id="svg2"
+ sodipodi:version="0.32"
+ inkscape:version="0.48.0 r9654"
+ sodipodi:docname="messaging-services.svg"
+ inkscape:export-filename="/home/vincent/www/vmime/documentation/images/design-messaging.png"
+ inkscape:export-xdpi="74.639999"
+ inkscape:export-ydpi="74.639999"
+ version="1.1">
+ <defs
+ id="defs3">
+ <marker
+ inkscape:stockid="Torso"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="Torso"
+ style="overflow:visible">
+ <g
+ id="g2045"
+ transform="scale(0.7)">
+ <path
+ sodipodi:nodetypes="ccccc"
+ id="path1128"
+ d="M -4.7792281,-3.2395420 C -2.4288541,-2.8736027 0.52103922,-1.3019943 0.25792722,0.38794346 C -0.0051877922,2.0778819 -2.2126741,2.6176539 -4.5630471,2.2517169 C -6.9134221,1.8857769 -8.5210350,0.75201414 -8.2579220,-0.93792336 C -7.9948090,-2.6278615 -7.1296041,-3.6054813 -4.7792281,-3.2395420 z "
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;marker-start:none;marker-mid:none;marker-end:none" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path1909"
+ d="M 4.4598789,0.088665736 C -2.5564571,-4.3783320 5.2248769,-3.9061806 -0.84829578,-8.7197331"
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000pt;marker-end:none" />
+ <path
+ sodipodi:nodetypes="cc"
+ id="path1910"
+ d="M 4.9298719,0.057520736 C -1.3872731,1.7494689 1.8027579,5.4782079 -4.9448731,7.5462725"
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000pt;marker-start:none;marker-end:none" />
+ <rect
+ transform="matrix(0.527536,-0.849533,0.887668,0.460484,0.000000,0.000000)"
+ y="-1.7408575"
+ x="-10.391706"
+ height="2.7608147"
+ width="2.6366582"
+ id="rect2035"
+ style="fill-rule:evenodd;stroke-width:1.0000000pt;marker-end:none" />
+ <rect
+ transform="matrix(0.671205,-0.741272,0.790802,0.612072,0.000000,0.000000)"
+ y="-7.9629307"
+ x="4.9587269"
+ height="2.8614161"
+ width="2.7327356"
+ id="rect2036"
+ style="fill-rule:evenodd;stroke-width:1.0000000pt;marker-end:none" />
+ <path
+ transform="matrix(6.793608e-17,-1.109517,1.109517,6.793608e-17,25.96648,19.71619)"
+ d="m 16.779951,-28.685045 c 0,0.335412 -0.271905,0.607317 -0.607317,0.607317 -0.335412,0 -0.607317,-0.271905 -0.607317,-0.607317 0,-0.335412 0.271905,-0.607318 0.607317,-0.607318 0.335412,0 0.607317,0.271906 0.607317,0.607318 z"
+ sodipodi:ry="0.60731727"
+ sodipodi:rx="0.60731727"
+ sodipodi:cy="-28.685045"
+ sodipodi:cx="16.172634"
+ id="path2037"
+ style="fill:#ff0000;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000pt;marker-start:none;marker-end:none"
+ sodipodi:type="arc" />
+ <path
+ transform="matrix(6.793608e-17,-1.109517,1.109517,6.793608e-17,26.82450,16.99126)"
+ d="m 16.779951,-28.685045 c 0,0.335412 -0.271905,0.607317 -0.607317,0.607317 -0.335412,0 -0.607317,-0.271905 -0.607317,-0.607317 0,-0.335412 0.271905,-0.607318 0.607317,-0.607318 0.335412,0 0.607317,0.271906 0.607317,0.607318 z"
+ sodipodi:ry="0.60731727"
+ sodipodi:rx="0.60731727"
+ sodipodi:cy="-28.685045"
+ sodipodi:cx="16.172634"
+ id="path2038"
+ style="fill:#ff0000;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000pt;marker-start:none;marker-end:none"
+ sodipodi:type="arc" />
+ </g>
+ </marker>
+ <marker
+ inkscape:stockid="TriangleOutL"
+ orient="auto"
+ refY="0.0"
+ refX="0.0"
+ id="TriangleOutL"
+ style="overflow:visible">
+ <path
+ sodipodi:nodetypes="cccc"
+ id="path5324"
+ d="M 5.77,0.0 L -2.88,5.0 L -2.88,-5.0 L 5.77,0.0 z "
+ style="fill-rule:evenodd;stroke:#000000;stroke-width:1.0pt;marker-start:none"
+ transform="scale(0.8)" />
+ </marker>
+ </defs>
+ <sodipodi:namedview
+ id="base"
+ pagecolor="#ffffff"
+ bordercolor="#666666"
+ borderopacity="1.0"
+ inkscape:pageopacity="0.0"
+ inkscape:pageshadow="2"
+ inkscape:zoom="0.75785828"
+ inkscape:cx="365.32198"
+ inkscape:cy="407.27112"
+ inkscape:document-units="px"
+ inkscape:current-layer="svg2"
+ inkscape:window-width="1150"
+ inkscape:window-height="986"
+ inkscape:window-x="69"
+ inkscape:window-y="33"
+ showgrid="false"
+ inkscape:window-maximized="0" />
+ <metadata
+ id="metadata4">
+ <rdf:RDF>
+ <cc:Work
+ rdf:about="">
+ <dc:format>image/svg+xml</dc:format>
+ <dc:type
+ rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
+ </cc:Work>
+ </rdf:RDF>
+ </metadata>
+ <path
+ id="path5442"
+ d="M 495.30781,321.26414 L 495.30781,390.57215"
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
+ <path
+ id="path5440"
+ d="M 662.55216,389.28102 L 662.55216,456.99397"
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
+ <path
+ id="path5438"
+ d="M 325.22881,389.28102 L 325.22881,456.99397"
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
+ <g
+ inkscape:label="Layer 1"
+ inkscape:groupmode="layer"
+ id="layer1">
+ <g
+ transform="matrix(0.866025,0.499999,-0.499999,0.866025,111.0615,336.6054)"
+ id="g3452">
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-dasharray:5.0000000 5.0000000 ;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
+ d="M 278.87323,198.08204 L 405.25462,198.08204"
+ id="path3454" />
+ <g
+ transform="matrix(-1.000000,-1.845854e-17,1.845854e-17,-1.000000,684.3929,415.9391)"
+ style="stroke-width:1.2500000;stroke-miterlimit:4.0000000"
+ id="g3456">
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000"
+ d="M 278.87321,217.60074 L 289.31646,228.04398"
+ id="path3458" />
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000"
+ d="M 279.22547,217.92243 L 289.41027,207.73763"
+ id="path3460" />
+ </g>
+ </g>
+ <g
+ transform="matrix(-0.499998,0.866024,-0.866024,-0.499998,528.2205,319.3107)"
+ id="g3396">
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-dasharray:5.0000000 5.0000000 ;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
+ d="M 278.87323,198.08204 L 405.25462,198.08204"
+ id="path3398" />
+ <g
+ transform="matrix(-1.000000,-1.845854e-17,1.845854e-17,-1.000000,684.3929,415.9391)"
+ style="stroke-width:1.2500000;stroke-miterlimit:4.0000000"
+ id="g3400">
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000"
+ d="M 278.87321,217.60074 L 289.31646,228.04398"
+ id="path3402" />
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000"
+ d="M 279.22547,217.92243 L 289.41027,207.73763"
+ id="path3404" />
+ </g>
+ </g>
+ <g
+ transform="matrix(0.500000,0.866024,-0.866024,0.500000,431.6077,-252.3913)"
+ id="g3200">
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-dasharray:5.0000000 5.0000000 ;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
+ d="M 278.87323,198.08204 L 405.25462,198.08204"
+ id="path3202" />
+ <g
+ transform="matrix(-1.000000,-1.845854e-17,1.845854e-17,-1.000000,684.3929,415.9391)"
+ style="stroke-width:1.2500000;stroke-miterlimit:4.0000000"
+ id="g3204">
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000"
+ d="M 278.87321,217.60074 L 289.31646,228.04398"
+ id="path3206" />
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000"
+ d="M 279.22547,217.92243 L 289.41027,207.73763"
+ id="path3208" />
+ </g>
+ </g>
+ <g
+ transform="matrix(0.499999,-0.866025,0.866025,0.499999,-54.36140,359.0658)"
+ id="g3168">
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-dasharray:5.0000000 5.0000000 ;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
+ d="M 278.87323,198.08204 L 405.25462,198.08204"
+ id="path3156" />
+ <g
+ transform="matrix(-1.000000,-1.845854e-17,1.845854e-17,-1.000000,684.3929,415.9391)"
+ style="stroke-width:1.2500000;stroke-miterlimit:4.0000000"
+ id="g3158">
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000"
+ d="M 278.87321,217.60074 L 289.31646,228.04398"
+ id="path3160" />
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000"
+ d="M 279.22547,217.92243 L 289.41027,207.73763"
+ id="path3162" />
+ </g>
+ </g>
+ <rect
+ style="fill:#f5f5c8;fill-opacity:1.0000000;stroke:#000000;stroke-width:1.2500000;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
+ id="rect1291"
+ width="144.63049"
+ height="123.75754"
+ x="423.21133"
+ y="200.65219" />
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:120.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="430.8407"
+ y="243.43631"
+ id="text1293"
+ sodipodi:linespacing="120.00000%"><tspan
+ id="tspan3116"
+ sodipodi:role="line"
+ y="243.43631"
+ x="430.84070">connect() : void</tspan><tspan
+ id="tspan3118"
+ sodipodi:role="line"
+ y="257.83631"
+ x="430.84070">disconnect() : void</tspan><tspan
+ id="tspan3120"
+ sodipodi:role="line"
+ y="272.23631"
+ x="430.84070">isConnected() : bool</tspan><tspan
+ id="tspan3122"
+ sodipodi:role="line"
+ y="286.63631"
+ x="430.84070">noop() : void</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="473.4863"
+ y="216.58759"
+ id="text2347"
+ sodipodi:linespacing="100.00000%"><tspan
+ id="tspan2932"
+ sodipodi:role="line"
+ y="216.58759"
+ x="473.48630">service</tspan></text>
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 423.62452,224.92254 L 567.67587,224.92254"
+ id="path2351" />
+ <rect
+ style="fill:#f5f5c8;fill-opacity:1.0000000;stroke:#000000;stroke-width:1.2500000;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
+ id="rect2353"
+ width="254.50919"
+ height="106.53888"
+ x="40.771675"
+ y="200.75146" />
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:120.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="49.807129"
+ y="243.64157"
+ id="text2355"
+ sodipodi:linespacing="120.00000%"><tspan
+ id="tspan3148"
+ sodipodi:role="line"
+ y="243.64157"
+ x="49.807129">getTransport(url : url) : ref &lt;transport&gt;</tspan><tspan
+ id="tspan3150"
+ sodipodi:role="line"
+ y="258.04157"
+ x="49.807129">getStore(url : url) : ref &lt;store&gt;</tspan><tspan
+ id="tspan3152"
+ sodipodi:role="line"
+ y="272.44157"
+ x="49.807129">getProperties() : propertySet</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="143.33478"
+ y="216.79285"
+ id="text2375"
+ sodipodi:linespacing="100.00000%"><tspan
+ id="tspan3124"
+ sodipodi:role="line"
+ y="216.79285"
+ x="143.33478">session</tspan></text>
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 41.137120,225.12780 L 294.90028,225.12780"
+ id="path2379" />
+ <rect
+ style="fill:#f5f5c8;fill-opacity:1.0000000;stroke:#000000;stroke-width:1.2500000;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
+ id="rect2433"
+ width="219.00885"
+ height="100.80741"
+ x="215.20381"
+ y="429.00940" />
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:120.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="223.58997"
+ y="472.3562"
+ id="text2435"
+ sodipodi:linespacing="120.00000%"><tspan
+ id="tspan3110"
+ sodipodi:role="line"
+ y="472.35620"
+ x="223.58997">getDefaultFolder() : ref &lt;folder&gt;</tspan><tspan
+ id="tspan3112"
+ sodipodi:role="line"
+ y="486.75620"
+ x="223.58997">getRootFolder() : ref &lt;folder&gt;</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="309.11777"
+ y="445.50742"
+ id="text2439"
+ sodipodi:linespacing="100.00000%"><tspan
+ id="tspan2936"
+ sodipodi:role="line"
+ y="445.50742"
+ x="309.11777">store</tspan></text>
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 216.61640,453.84241 L 433.36337,453.84241"
+ id="path2443" />
+ <rect
+ style="fill:#f5f5c8;fill-opacity:1.0000000;stroke:#000000;stroke-width:1.2500000;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
+ id="rect2447"
+ width="219.00674"
+ height="101.04262"
+ x="553.75336"
+ y="428.77499" />
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:120.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="561.0639"
+ y="472.20447"
+ id="text2449"
+ sodipodi:linespacing="120.00000%"><tspan
+ id="tspan3114"
+ sodipodi:role="line"
+ y="472.20447"
+ x="561.06390">send(msg : ref &lt;message&gt;) : void</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="632.07196"
+ y="445.35568"
+ id="text2453"
+ sodipodi:linespacing="100.00000%"><tspan
+ id="tspan2934"
+ sodipodi:role="line"
+ y="445.35568"
+ x="632.07196">transport</tspan></text>
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 554.08593,453.69062 L 771.88660,453.69062"
+ id="path2457" />
+ <path
+ id="path2575"
+ d="M 481.88130,340.17064 L 509.77022,340.17064 L 495.36094,325.76137 L 481.88130,340.17064 z "
+ style="fill:#ffffff;fill-opacity:1.0000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.0000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
+ <g
+ transform="translate(17.15883,45.55696)"
+ id="g3136">
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 405.51967,217.85706 L 279.13828,217.85706"
+ id="path2265" />
+ <g
+ style="stroke-width:1.2500000;stroke-miterlimit:4.0000000"
+ id="g3132">
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000"
+ d="M 278.87321,217.60074 L 289.31646,228.04398"
+ id="path2269" />
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000"
+ d="M 279.22547,217.92243 L 289.41027,207.73763"
+ id="path2271" />
+ </g>
+ </g>
+ <text
+ sodipodi:linespacing="100.00000%"
+ xml:space="preserve"
+ style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="335.37018"
+ y="257.45505"
+ id="text2275"><tspan
+ id="tspan3146"
+ sodipodi:role="line"
+ y="257.45505"
+ x="335.37018">session</tspan></text>
+ <text
+ transform="matrix(0.500000,0.866025,-0.866025,0.500000,0.000000,0.000000)"
+ sodipodi:linespacing="100.00000%"
+ xml:space="preserve"
+ style="font-size:11.999973px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="313.42676"
+ y="-318.0412"
+ id="text3174"><tspan
+ id="tspan3178"
+ sodipodi:role="line"
+ y="-318.04120"
+ x="313.42676">&lt;instanciates&gt;</tspan></text>
+ <rect
+ style="fill:#f5f5c8;fill-opacity:1.0000000;stroke:#000000;stroke-width:1.2500000;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
+ id="rect3180"
+ width="253.81813"
+ height="96.037521"
+ x="234.02649"
+ y="9.0948601" />
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:120.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="241.24963"
+ y="52.019093"
+ id="text3182"
+ sodipodi:linespacing="120.00000%"><tspan
+ id="tspan3218"
+ sodipodi:role="line"
+ y="52.019093"
+ x="241.24963">create(protocol : string) : ref &lt;service&gt;</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="312.24161"
+ y="25.170307"
+ id="text3192"
+ sodipodi:linespacing="100.00000%"><tspan
+ id="tspan3198"
+ sodipodi:role="line"
+ y="25.170307"
+ x="312.24161">serviceFactory</tspan></text>
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2500000;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 234.44127,33.505080 L 487.67742,33.505080"
+ id="path3196" />
+ <text
+ transform="matrix(0.500000,-0.866025,0.866025,0.500000,0.000000,0.000000)"
+ sodipodi:linespacing="100.00000%"
+ xml:space="preserve"
+ style="font-size:11.999965px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="-19.006903"
+ y="316.46106"
+ id="text3210"><tspan
+ id="tspan3214"
+ sodipodi:role="line"
+ y="316.46106"
+ x="-19.006903">&lt;uses&gt;</tspan></text>
+ <rect
+ style="fill:#f5f5c8;fill-opacity:1.0000000;stroke:#000000;stroke-width:1.2500000;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
+ id="rect3362"
+ width="244.86130"
+ height="116.61144"
+ x="14.277589"
+ y="572.10736" />
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:120.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="22.589966"
+ y="615.3562"
+ id="text3364"
+ sodipodi:linespacing="120.00000%"><tspan
+ id="tspan3386"
+ sodipodi:role="line"
+ y="615.35620"
+ x="22.589966">getName() : string</tspan><tspan
+ id="tspan3388"
+ sodipodi:role="line"
+ y="629.75620"
+ x="22.589966">open() : void</tspan><tspan
+ id="tspan3390"
+ sodipodi:role="line"
+ y="644.15620"
+ x="22.589966">close() : void</tspan><tspan
+ id="tspan3392"
+ sodipodi:role="line"
+ y="658.55620"
+ x="22.589966">getMessages(int from, int to) : vector</tspan><tspan
+ id="tspan3394"
+ sodipodi:role="line"
+ y="672.95620"
+ x="22.589966">...</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="119.45631"
+ y="588.50739"
+ id="text3370"
+ sodipodi:linespacing="100.00000%"><tspan
+ id="tspan3376"
+ sodipodi:role="line"
+ y="588.50739"
+ x="119.45631">folder</tspan></text>
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2449049;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 15.691587,596.84241 L 258.28817,596.84241"
+ id="path3374" />
+ <text
+ transform="matrix(0.500000,-0.866025,0.866025,0.500000,0.000000,0.000000)"
+ sodipodi:linespacing="100.00000%"
+ xml:space="preserve"
+ style="font-size:11.999992px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="-398.12543"
+ y="406.40524"
+ id="text3406"><tspan
+ id="tspan3408"
+ sodipodi:role="line"
+ y="406.40524"
+ x="-398.12543">&lt;instanciates&gt;</tspan></text>
+ <rect
+ style="fill:#f5f5c8;fill-opacity:1.0000000;stroke:#000000;stroke-width:1.2500000;stroke-miterlimit:4.0000000;stroke-dashoffset:0.0000000;stroke-opacity:1.0000000"
+ id="rect3410"
+ width="244.86130"
+ height="140.35690"
+ x="365.27762"
+ y="617.23462" />
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:120.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="373.59"
+ y="660.3562"
+ id="text3412"
+ sodipodi:linespacing="120.00000%"><tspan
+ id="tspan3440"
+ sodipodi:role="line"
+ y="660.35620"
+ x="373.59000">getNumber() : int</tspan><tspan
+ id="tspan3442"
+ sodipodi:role="line"
+ y="674.75620"
+ x="373.59000">getFlags() : int</tspan><tspan
+ id="tspan3444"
+ sodipodi:role="line"
+ y="689.15620"
+ x="373.59000">getHeader() : int</tspan><tspan
+ id="tspan3446"
+ sodipodi:role="line"
+ y="703.55620"
+ x="373.59000">getStructure() : structure</tspan><tspan
+ id="tspan3448"
+ sodipodi:role="line"
+ y="717.95620"
+ x="373.59000">extract(out : outputStream) : void</tspan><tspan
+ id="tspan3450"
+ sodipodi:role="line"
+ y="732.35620"
+ x="373.59000">...</tspan></text>
+ <text
+ xml:space="preserve"
+ style="font-size:12.000000px;font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="459.11771"
+ y="633.50739"
+ id="text3424"
+ sodipodi:linespacing="100.00000%"><tspan
+ id="tspan3430"
+ sodipodi:role="line"
+ y="633.50739"
+ x="459.11771">message</tspan></text>
+ <path
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2449049;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000"
+ d="M 366.69159,641.84241 L 609.28817,641.84241"
+ id="path3428" />
+ <text
+ transform="matrix(0.866025,0.500000,-0.500000,0.866025,0.000000,0.000000)"
+ sodipodi:linespacing="100.00000%"
+ xml:space="preserve"
+ style="font-size:11.999992px;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;line-height:100.00000%;writing-mode:lr-tb;text-anchor:start;fill:#000000;fill-opacity:1.0000000;stroke:none;stroke-width:1.0000000px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1.0000000;font-family:Bitstream Vera Sans"
+ x="558.315"
+ y="419.37476"
+ id="text3462"><tspan
+ id="tspan3464"
+ sodipodi:role="line"
+ y="419.37476"
+ x="558.31500">&lt;instanciates&gt;</tspan></text>
+ </g>
+ <path
+ id="path5436"
+ d="M 325.97175,390.06210 L 661.85821,390.06210"
+ style="fill:none;fill-opacity:0.75000000;fill-rule:evenodd;stroke:#000000;stroke-width:1.2515085;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4.0000000;stroke-opacity:1.0000000" />
+ <rect
+ y="170.36218"
+ x="668.00000"
+ height="76.000000"
+ width="134.00000"
+ id="rect3360"
+ style="stroke-opacity:1.0000000;stroke-dashoffset:0.0000000;stroke-miterlimit:4.0000000;stroke-linejoin:miter;stroke-linecap:round;stroke-width:1.2500000;stroke:none;fill-rule:nonzero;fill-opacity:1.0000000;fill:none" />
+</svg>
diff --git a/vmime-master/doc/book/intro.tex b/vmime-master/doc/book/intro.tex
new file mode 100644
index 0000000..fe7bcf5
--- /dev/null
+++ b/vmime-master/doc/book/intro.tex
@@ -0,0 +1,90 @@
+\chapter{Introduction}
+
+% ============================================================================
+\section{Overview}
+
+VMime is a powerful C++ class library for working with MIME messages and
+Internet messaging services like IMAP, POP or SMTP.
+
+With VMime you can parse, generate and modify messages, and also connect to
+store and transport services to receive or send messages over the Internet.
+The library offers all the features to build a complete mail client.
+
+The main objectives of this library are:
+
+\begin{itemize}
+\item fully RFC-compliant implementation;
+\item object-oriented and modular design;
+\item very easy-to-use (intuitive design);
+\item well documented code;
+\item very high reliability;
+\item maximum portability.
+\end{itemize}
+
+
+% ============================================================================
+\section{Features}
+
+\noindent MIME features:
+
+\begin{itemize}
+\item Full support for RFC-2822 and multipart messages (RFC-1521)
+\item Aggregate documents (MHTML) and embedded objects (RFC-2557)
+\item Message Disposition Notification (RFC-3798)
+\item 8-bit MIME (RFC-2047)
+\item Encoded word extensions (RFC-2231)
+\item Attachments
+\end{itemize}
+
+\noindent Network features:
+
+\begin{itemize}
+\item Support for IMAP, POP3 and maildir stores
+\item Support for SMTP and sendmail transport methods
+\item Extraction of whole message or specific parts
+\item TLS/SSL security layer
+\item SASL authentication
+\end{itemize}
+
+
+% ============================================================================
+\section{Copyright and license}
+
+VMime library is Free Software and is licensed under the terms of the GNU
+General Public License\footnote{See Appendix \ref{appendix_license} and
+\url{http://www.gnu.org/copyleft/gpl.html}} (GPL) version 3:
+
+\begin{verbatim}
+ Copyright (C) 2002 Vincent Richard
+
+ VMime library is free software; you can redistribute it and/or
+ modify it under the terms of the GNU General Public License as
+ published by the Free Software Foundation; either version 3 of
+ the License, or (at your option) any later version.
+
+ VMime is distributed in the hope that it will be useful, but
+ WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ Linking this library statically or dynamically with other
+ modules is making a combined work based on this library.
+ Thus, the terms and conditions of the GNU General Public
+ License cover the whole combination.
+\end{verbatim}
+
+\newpage
+\noindent This document is released under the terms of the
+GNU Free Documentation
+License\footnote{See \url{http://www.gnu.org/copyleft/fdl.html}} (FDL):
+
+\begin{verbatim}
+ Copyright (C) 2004 Vincent Richard
+
+ Permission is granted to copy, distribute and/or modify
+ this document under the terms of the GNU Free Documentation
+ License, Version 1.2 or any later version published by the
+ Free Software Foundation; with no Invariant Sections, no
+ Front-Cover Texts, and no Back-Cover Texts.
+\end{verbatim}
+
diff --git a/vmime-master/doc/book/msg.tex b/vmime-master/doc/book/msg.tex
new file mode 100644
index 0000000..ce9d8a8
--- /dev/null
+++ b/vmime-master/doc/book/msg.tex
@@ -0,0 +1,430 @@
+\chapter{Parsing and Building Messages}
+
+% ============================================================================
+\section{Parsing messages}
+
+\subsection{Introduction} % --------------------------------------------------
+
+Parsing is the process of creating a structured representation (for example,
+a hierarchy of C++ objects) of a message from its ``textual'' representation
+(the raw data that is actually sent on the Internet).
+
+For example, say you have the following email in a file called "hello.eml":
+
+\begin{verbatim}
+Date: Thu, Oct 13 2005 15:22:46 +0200
+From: Vincent <vincent@vmime.org>
+To: you@vmime.org
+Subject: Hello from VMime!
+
+A simple message to test VMime
+\end{verbatim}
+
+The following code snippet shows how you can easily obtain a
+{\vcode vmime::message} object from data in this file:
+
+\begin{lstlisting}[caption={Parsing a message from a file}]
+// Read data from file
+std::ifstream file;
+file.open("hello.eml", std::ios::in | std::ios::binary);
+
+vmime::utility::inputStreamAdapter is(file);
+
+vmime::string data;
+vmime::utility::outputStreamStringAdapter os(data);
+
+vmime::utility::bufferedStreamCopy(is, os);
+
+// Actually parse the message
+vmime::shared_ptr <vmime::message> msg = vmime::make_shared <vmime::message>();
+msg->parse(data);
+
+vmime::shared_ptr <vmime::header> hdr = msg->getHeader();
+vmime::shared_ptr <vmime::body> bdy = msg->getBody();
+
+// Now, you can extract some of its components
+vmime::charset ch(vmime::charsets::UTF_8);
+
+std::cout
+ << "The subject of the message is: "
+ << hdr->Subject()->getValue <vmime::text>()->getConvertedText(ch)
+ << std::endl
+ << "It was sent by: "
+ << hdr->From()->getValue <vmime::mailbox>()->getName().getConvertedText(ch)
+ << " (email: " << hdr->From()->getValue <vmime::mailbox>()->getEmail() << ")"
+ << std::endl;
+\end{lstlisting}
+
+The output of this program is:
+
+\begin{verbatim}
+The subject of the message is: Hello from VMime!
+It was sent by: Vincent (email: vincent@vmime.org)
+\end{verbatim}
+
+
+\subsection{Using the {\vcode vmime::messageParser} object} % ----------------
+
+The {\vcode vmime::messageParser} object allows to parse messages in a more
+simple manner. You can obtain all the text parts and attachments as well as
+basic fields (expeditor, recipients, subject...), without dealing with
+MIME message structure.
+
+\begin{lstlisting}[caption={Using {\vcode vmime::messageParser} to parse
+more complex messages}]
+// Read data from file
+std::ifstream file;
+file.open("hello.eml", std::ios::in | std::ios::binary);
+
+vmime::utility::inputStreamAdapter is(file);
+
+vmime::string data;
+vmime::utility::outputStreamStringAdapter os(data);
+
+vmime::utility::bufferedStreamCopy(is, os);
+
+// Actually parse the message
+vmime::shared_ptr <vmime::message> msg = vmime::make_shared <vmime::message>();
+msg->parse(data);
+
+// Here start the differences with the previous example
+vmime::messageParser mp(msg);
+
+// Output information about attachments
+std::cout << "Message has " << mp.getAttachmentCount()
+ << " attachment(s)" << std::endl;
+
+for (int i = 0 ; i < mp.getAttachmentCount() ; ++i) {
+
+ vmime::shared_ptr <const vmime::attachment> att = mp.getAttachmentAt(i);
+ std::cout << " - " << att->getType().generate() << std::endl;
+}
+
+// Output information about text parts
+std::cout << "Message has " << mp.getTextPartCount()
+ << " text part(s)" << std::endl;
+
+for (int i = 0 ; i < mp.getTextPartCount() ; ++i) {
+
+ vmime::shared_ptr <const vmime::textPart> tp = mp.getTextPartAt(i);
+
+ // text/html
+ if (tp->getType().getSubType() == vmime::mediaTypes::TEXT_HTML) {
+
+ vmime::shared_ptr <const vmime::htmlTextPart> htp =
+ vmime::dynamicCast <const vmime::htmlTextPart>(tp);
+
+ // HTML text is in tp->getText()
+ // Plain text is in tp->getPlainText()
+
+ // Enumerate embedded objects
+ for (int j = 0 ; j < htp->getObjectCount() ; ++j) {
+
+ vmime::shared_ptr <const vmime::htmlTextPart::embeddedObject> obj =
+ htp->getObjectAt(j);
+
+ // Identifier (Content-Id or Content-Location) is obj->getId()
+ // Object data is in obj->getData()
+ }
+
+ // text/plain or anything else
+ } else {
+
+ // Text is in tp->getText()
+ }
+}
+\end{lstlisting}
+
+
+% ============================================================================
+\section{Building messages}
+
+\subsection{A simple message\label{msg-building-simple-message}} % -----------
+
+Of course, you can build a MIME message from scratch by creating the various
+objects that compose it (parts, fields, etc.). The following is an example of
+how to achieve it:
+
+\begin{lstlisting}[caption={Building a simple message from scratch}]
+vmime::shared_ptr <vmime::message> msg = vmime::make_shared <vmime::message>();
+
+vmime::shared_ptr <vmime::header> hdr = msg->getHeader();
+vmime::shared_ptr <vmime::body> bdy = msg->getBody();
+
+vmime::shared_ptr <vmime::headerFieldFactory> hfFactory =
+ vmime::headerFieldFactory::getInstance();
+
+// Append a 'Date:' field
+vmime::shared_ptr <vmime::headerField> dateField =
+ hfFactory->create(vmime::fields::DATE);
+
+dateField->setValue(vmime::datetime::now());
+hdr->appendField(dateField);
+
+// Append a 'Subject:' field
+vmime::shared_ptr <vmime::headerField> subjectField =
+ hfFactory->create(vmime::fields::SUBJECT);
+
+subjectField->setValue(vmime::text("Message subject"));
+hdr->appendField(subjectField);
+
+// Append a 'From:' field
+vmime::shared_ptr <vmime::headerField> fromField =
+ hfFactory->create(vmime::fields::FROM);
+
+fromField->setValue(vmime::make_shared <vmime::mailbox>("me@vmime.org"));
+hdr->appendField(fromField);
+
+// Append a 'To:' field
+vmime::shared_ptr <vmime::headerField> toField =
+ hfFactory->create(vmime::fields::TO);
+
+vmime::shared_ptr <vmime::mailboxList> recipients =
+ vmime::make_shared <vmime::mailboxList>();
+
+recipients->appendMailbox
+ (vmime::make_shared <vmime::mailbox>("you@vmime.org"));
+
+toField->setValue(recipients);
+hdr->appendField(toField);
+
+// Set the body contents
+bdy->setContents(
+ vmime::make_shared <vmime::stringContentHandler>(
+ "This is the text of your message..."
+ )
+);
+
+// Output raw message data to standard output
+vmime::utility::outputStreamAdapter out(std::cout);
+msg->generate(out);
+\end{lstlisting}
+
+As you can see, this is a little fastidious. Hopefully, VMime also offers a
+more simple way for creating messages. The {\vcode vmime::messageBuilder}
+object can create basic messages that you can then customize.
+
+The following code can be used to build exactly the same message as in the
+previous example, using the {\vcode vmime::messageBuilder} object:
+
+\begin{lstlisting}[caption={Building a simple message
+using {\vcode vmime::messageBuilder}}]
+try {
+
+ vmime::messageBuilder mb;
+
+ // Fill in some header fields and message body
+ mb.setSubject(vmime::text("Message subject"));
+ mb.setExpeditor(vmime::mailbox("me@vmime.org"));
+ mb.getRecipients().appendAddress(
+ vmime::make_shared <vmime::mailbox>("you@vmime.org")
+ );
+
+ mb.getTextPart()->setCharset(vmime::charsets::ISO8859_15);
+ mb.getTextPart()->setText(
+ vmime::make_shared <vmime::stringContentHandler>(
+ "This is the text of your message..."
+ )
+ );
+
+ // Message construction
+ vmime::shared_ptr <vmime::message> msg = mb.construct();
+
+ // Output raw message data to standard output
+ vmime::utility::outputStreamAdapter out(std::cout);
+ msg->generate(out);
+
+// VMime exception
+} catch (vmime::exception& e) {
+
+ std::cerr << "vmime::exception: " << e.what() << std::endl;
+
+// Standard exception
+} catch (std::exception& e) {
+
+ std::cerr << "std::exception: " << e.what() << std::endl;
+}
+\end{lstlisting}
+
+
+\subsection{Adding an attachment} % ------------------------------------------
+
+Dealing with attachments is quite simple. Add the following code to the
+previous example to attach a file to the message:
+
+\begin{lstlisting}[caption={Building a message with an attachment using
+{\vcode vmime::messageBuilder}}]
+// Create an attachment
+vmime::shared_ptr <vmime::fileAttachment> att =
+ vmime::make_shared <vmime::fileAttachment>(
+ /* full path to file */ "/home/vincent/paris.jpg",
+ /* content type */ vmime::mediaType("image/jpeg),
+ /* description */ vmime::text("My holidays in Paris")
+ );
+
+// You can also set some infos about the file
+att->getFileInfo().setFilename("paris.jpg");
+att->getFileInfo().setCreationDate(
+ vmime::datetime("30 Apr 2003 14:30:00 +0200")
+);
+
+// Add this attachment to the message
+mb.appendAttachment(att);
+\end{lstlisting}
+
+
+\subsection{HTML messages and embedded objects} % ----------------------------
+
+VMime also supports aggregate messages, which permits to build MIME messages
+containing HTML text and embedded objects (such as images). For more information
+about aggregate messages, please read RFC-2557 (\emph{MIME Encapsulation of
+Aggregate Documents, such as HTML}).
+
+Creating such messages is quite easy, using the {\vcode vmime::messageBuilder}
+object. The following code constructs a message containing text in both plain
+and HTML format, and a JPEG image:
+
+\begin{lstlisting}[caption={Building an HTML message with an embedded image
+using the {\vcode vmime::messageBuilder}}]
+// Fill in some header fields
+mb.setSubject(vmime::text("An HTML message"));
+mb.setExpeditor(vmime::mailbox("me@vmime.org"));
+mb.getRecipients().appendAddress(
+ vmime::make_shared <vmime::mailbox>("you@vmime.org")
+);
+
+// Set the content-type to "text/html": a text part factory must be
+// available for the type you are using. The following code will make
+// the message builder construct the two text parts.
+mb.constructTextPart(
+ vmime::mediaType(
+ vmime::mediaTypes::TEXT,
+ vmime::mediaTypes::TEXT_HTML
+ )
+);
+
+// Set contents of the text parts; the message is available in two formats:
+// HTML and plain text. The HTML format also includes an embedded image.
+vmime::shared_ptr <vmime::htmlTextPart> textPart =
+ vmime::dynamicCast <vmime::htmlTextPart>(mb.getTextPart());
+
+// -- Add the JPEG image (the returned identifier is used to identify the
+// -- embedded object in the HTML text, the famous "CID", or "Content-Id").
+// -- Note: you can also read data from a file; see the next example.
+const vmime::string id = textPart->addObject("<...image data...>",
+ vmime::mediaType(vmime::mediaTypes::IMAGE, vmime::mediaTypes::IMAGE_JPEG));
+
+// -- Set the text
+textPart->setCharset(vmime::charsets::ISO8859_15);
+
+textPart->setText(
+ vmime::make_shared <vmime::stringContentHandler>(
+ "This is the <b>HTML text</b>, and the image:<br/>"
+ "<img src=\"") + id + vmime::string("\"/>"
+ )
+);
+
+textPart->setPlainText(
+ vmime::make_shared <vmime::stringContentHandler>(
+ "This is the plain text."
+ )
+);
+\end{lstlisting}
+
+This will create a message having the following structure:
+
+\begin{verbatim}
+multipart/alternative
+ text/plain
+ multipart/related
+ text/html
+ image/jpeg
+\end{verbatim}
+
+You can easily tell VMime to read the embedded object data from a file. The
+following code opens the file \emph{/path/to/image.jpg}, connects it to an
+input stream, then add an embedded object:
+
+\begin{lstlisting}
+vmime::utility::fileSystemFactory* fs =
+ vmime::platform::getHandler()->getFileSystemFactory();
+
+vmime::shared_ptr <vmime::utility::file> imageFile =
+ fs->create(fs->stringToPath("/path/to/image.jpg"));
+
+vmime::shared_ptr <vmime::contentHandler> imageCts =
+ vmime::make_shared <vmime::streamContentHandler>(
+ imageFile->getFileReader()->getInputStream(),
+ imageFile->getLength()
+ );
+
+const vmime::string cid = textPart.addObject(
+ imageCts,
+ vmime::mediaType(
+ vmime::mediaTypes::IMAGE,
+ vmime::mediaTypes::IMAGE_JPEG
+ )
+);
+\end{lstlisting}
+
+
+% ============================================================================
+\section{Working with attachments: the attachment helper}
+
+The {\vcode attachmentHelper} object allows listing all attachments in a
+message, as well as adding new attachments, without using the
+{\vcode messageParser} and {\vcode messageBuilders} objects. It can work
+directly on messages and body parts.
+
+To use it, you do not need any knowledge about how attachment parts should
+be organized in a MIME message.
+
+The following code snippet tests if a body part is an attachment, and if so,
+extract its contents to the standard output:
+
+\begin{lstlisting}[caption={Testing if a body part is an attachment}]
+vmime::shared_ptr <vmime::bodyPart> part; // suppose we have a body part
+
+if (vmime::attachmentHelper::isBodyPartAnAttachment(part)) {
+
+ // The body part contains an attachment, get it
+ vmime::shared_ptr <const vmime::attachment> attach =
+ attachmentHelper::getBodyPartAttachment(part);
+
+ // Extract attachment data to standard output
+ vmime::utility::outputStreamAdapter out(std::cout);
+ attach->getData()->extract(out);
+}
+\end{lstlisting}
+
+You can also easily extract all attachments from a message:
+
+\begin{lstlisting}[caption={Extracting all attachments from a message}]
+vmime::shared_ptr <vmime::message> msg; // suppose we have a message
+
+const std::vector <ref <const attachment> > atts =
+ attachmentHelper::findAttachmentsInMessage(msg);
+\end{lstlisting}
+
+Finally, the {\vcode attachmentHelper} object can be used to add an
+attachment to an existing message, whatever it contains (text parts,
+attachments, ...). The algorithm can modify the structure of the
+message if needed (eg. add a \emph{multipart/mixed} part if no one
+exists in the message). Simply call the {\vcode addAttachment}
+function:
+
+\begin{lstlisting}[caption={Adding an attachment to an existing message}]
+vmime::shared_ptr <vmime::message> msg; // suppose we have a message
+
+// Create an attachment
+vmime::shared_ptr <vmime::fileAttachment> att =
+ vmime::make_shared <vmime::fileAttachment>(
+ /* full path to file */ "/home/vincent/paris.jpg",
+ /* content type */ vmime::mediaType("image/jpeg),
+ /* description */ vmime::text("My holidays in Paris")
+ );
+
+// Attach it to the message
+vmime::attachmentHelper::addAttachment(msg, att);
+\end{lstlisting}
+
diff --git a/vmime-master/doc/book/net.tex b/vmime-master/doc/book/net.tex
new file mode 100644
index 0000000..3fab903
--- /dev/null
+++ b/vmime-master/doc/book/net.tex
@@ -0,0 +1,1203 @@
+\chapter{Working with Messaging Services}
+
+% ============================================================================
+\section{Introduction}
+
+In addition to parsing and building MIME messages, VMime also offers a lot of
+features to work with messaging services. This includes connecting to remote
+messaging stores (like IMAP or POP3), local stores (maildir) and transport
+services (send messages over SMTP or local sendmail), through an unified
+interface (see Figure \ref{uml_messaging_module}). That means that you can
+use independently IMAP of POP3 without having to change any line of code.
+
+Source code of {\vexample Example6} covers all features presented in this
+chapter, so it is important you take some time to read it.
+
+\begin{figure}
+ \center\includegraphics[width=0.9\textwidth]
+ {images/messaging-services.png}\endcenter
+ \caption{Overall structure of the messaging module}
+ \label{uml_messaging_module}
+\end{figure}
+
+The interface is composed of five classes:
+
+\begin{itemize}
+\item {\vcode vmime::net::service}: this is the base interface for a
+messaging service. It can be either a store service or a transport
+service.
+
+\item {\vcode vmime::net::serviceFactory}: create instances of a service.
+This is used internally by the session object (see below).
+
+\item {\vcode vmime::net::store}: interface for a store service. A store
+service offers access to a set of folders containing messages. This is
+used for IMAP, POP3 and maildir.
+
+\item {\vcode vmime::net::transport}: interface for a transport service.
+A transport service is capable of sending messages. This is used for
+SMTP and sendmail.
+
+\item {\vcode vmime::net::session}: a session object is used to store the
+parameters used by a service (eg. connection parameters). Each service
+instance is associated with only one session. The session object is capable
+of creating instances of services.
+\end{itemize}
+
+The following classes are specific to store services:
+
+\begin{itemize}
+\item {\vcode vmime::net::folder}: a folder can either contain other folders
+or messages, or both.
+
+\item {\vcode vmime::net::message}: this is the interface for dealing with
+messages. For a given message, you can have access to its flags, its MIME
+structure and you can also extract the whole message data or given parts (if
+supported by the underlying protocol).
+\end{itemize}
+
+
+% ============================================================================
+\section{Working with sessions}
+
+\subsection{Setting properties} % --------------------------------------------
+
+Sessions are used to store configuration parameters for services. They
+contains a set of typed properties that can modify the behaviour of the
+services. Before using a messaging service, you must create and
+initialize a session object:
+
+\begin{lstlisting}
+vmime::shared_ptr <vmime::net::session> theSession = vmime::net::session::create();
+\end{lstlisting}
+
+Session properties include:
+
+\begin{itemize}
+\item connection parameters: host and port to connect to;
+\item authentication parameters: user credentials required to use the
+service (if any);
+\item protocol-specific parameters: enable or disable extensions (eg. APOP
+support in POP3).
+\end{itemize}
+
+Properties are stored using a dotted notation, to specify the service type,
+the protocol name, the category and the name of the property:
+
+\begin{verbatim}
+ {service_type}.{protocol}.category.name
+\end{verbatim}
+
+An example of property is \emph{store.pop3.options.apop} (used to enable or
+disable the use of APOP authentication). The \emph{store.pop3} part is called
+the \emph{prefix}. This allow specifying different values for the same
+property depending on the protocol used.
+
+The session properties are stored in a {\vcode vmime::propertySet} object.
+To set the value of a property, you can use either:
+
+\begin{lstlisting}
+theSession->getProperties().setProperty("property-name", value);
+\end{lstlisting}
+
+or:
+
+\begin{lstlisting}
+theSession->getProperties()["property-name"] = value;
+\end{lstlisting}
+
+
+\subsection{Available properties} % ------------------------------------------
+
+Following is a list of available properties and the protocols they apply to,
+as the time of writing this documentation\footnote{You can get an up-to-date
+list of the properties by running \vexample{Example7}}. For better clarity,
+the prefixes do not appear in this table.
+
+\begin{table}[!ht]
+\noindent\begin{tabularx}{1.0\textwidth}{|l|c|X|c|c|c|c|c|c|c|c|}
+\hline
+ {\bf Property name} &
+ {\bf Type} &
+ {\bf Description} &
+ \verti{\bf POP3} &
+ \verti{\bf POP3S} &
+ \verti{\bf IMAP} &
+ \verti{\bf IMAPS} &
+ \verti{\bf SMTP} &
+ \verti{\bf SMTPS} &
+ \verti{\bf maildir} &
+ \verti{\bf sendmail} \\
+\hline
+\hline
+options.sasl & bool & Set to {\vcode true} to use SASL authentication, if
+available. & \vdot & \vdot & \vdot & \vdot & \vdot & \vdot & & \\
+\hline
+options.sasl.fallback & bool & Fail if SASL authentication failed (do not
+try other authentication mechanisms). & \vdot & \vdot & \vdot & \vdot &
+\vdot & \vdot & & \\
+\hline
+auth.username\footnote{You should use authenticators
+instead.\label{fn_auth_username}} & string & Set the username of the account
+to connect to. & \vdot & \vdot & \vdot & \vdot & \vdot & \vdot & & \\
+\hline
+auth.password\footref{fn_auth_username} & string & Set the password of the
+account. & \vdot & \vdot & \vdot & \vdot & \vdot & \vdot & & \\
+\hline
+connection.tls & bool & Set to {\vcode true} to start a secured connection
+using STARTTLS extension, if available. & \vdot & & \vdot & & \vdot & & & \\
+\hline
+connection.tls.required & bool & Fail if a secured connection cannot be
+started. & \vdot & & \vdot & & \vdot & & & \\
+\hline
+server.address & string & Server host name or IP address. &\vdot & \vdot &
+\vdot & \vdot & \vdot & \vdot & & \\
+\hline
+server.port & int & Server port. & \vdot & \vdot & \vdot & \vdot &
+\vdot & \vdot & & \\
+\hline
+server.rootpath & string & Root directory for mail repository (eg.
+\emph{/home/vincent/Mail}). & & & & & & & \vdot & \\
+\hline
+\end{tabularx}
+\caption{Properties common to all protocols}
+\end{table}
+
+\newpage
+These are the protocol-specific options:
+
+\begin{table}[!ht]
+\noindent\begin{tabularx}{1.0\textwidth}{|l|c|X|}
+\hline
+ {\bf Property name} &
+ {\bf Type} &
+ {\bf Description} \\
+% POP3/POP3S
+\hline
+\multicolumn{3}{|c|}{POP3, POP3S} \\
+\hline
+store.pop3.options.apop & bool & Enable or disable authentication with
+APOP (if SASL is enabled, this occurs after all SASL mechanisms have been
+tried). \\
+\hline
+store.pop3.options.apop.fallback & bool & If set to {\vcode true} and
+APOP fails, the authentication process fails (ie. unsecure plain text
+authentication is not used). \\
+\hline
+% SMTP
+\multicolumn{3}{|c|}{SMTP, SMTPS} \\
+\hline
+transport.smtp.options.need-authentication & bool & Set to \emph{true} if
+the server requires to authenticate before sending messages. \\
+\hline
+transport.smtp.options.pipelining & bool & Set to {\vcode false} to disable
+command pipelining, if the server supports it (default is {\vcode true}). \\
+\hline
+transport.smtp.options.chunking & bool & Set to {\vcode false} to disable
+CHUNKING extension, if the server supports it (default is {\vcode true}). \\
+\hline
+% sendmail
+\multicolumn{3}{|c|}{sendmail} \\
+\hline
+transport.sendmail.binpath & string & The path to the \emph{sendmail}
+executable on your system. The default is the one found by the configuration
+script when VMime was built. \\
+\hline
+\end{tabularx}
+\caption{Protocol-specific options}
+\end{table}
+
+
+\subsection{Instanciating services} % ----------------------------------------
+
+You can create a service either by specifying its protocol name, or by
+specifying the URL of the service. Creation by name is deprecated so
+this chapter only presents the latter option.
+
+The URL scheme for connecting to services is:
+
+\begin{verbatim}
+ protocol://[username[:password]@]host[:port]/[root-path]
+\end{verbatim}
+
+\vnote{For local services (ie. \emph{sendmail} and \emph{maildir}), the host
+part is not used, but it must not be empty (you can use "localhost").}
+
+The following table shows an example URL for each service:
+
+\noindent\begin{tabularx}{1.0\textwidth}{|c|X|}
+\hline
+ {\bf Service} &
+ {\bf Connection URL} \\
+\hline
+imap, imaps & {\tt imap://imap.example.com},
+{\tt imaps://vincent:pass@example.com} \\
+\hline
+pop3, pop3s & {\tt pop3://pop3.example.com} \\
+\hline
+smtp, smtps & {\tt smtp://smtp.example.com} \\
+\hline
+maildir & {\tt maildir://localhost/home/vincent/Mail} (host not used) \\
+\hline
+sendmail & {\tt sendmail://localhost} (host not used, always localhost) \\
+\hline
+\end{tabularx}
+
+\newpage
+
+When you have the connection URL, instanciating the service is quite simple.
+Depending on the type of service, you will use either {\vcode getStore()} or
+{\vcode getTransport()}. For example, for store services, use:
+
+\begin{lstlisting}
+vmime::utility:url url("imap://user:pass@imap.example.com");
+vmime::shared_ptr <vmime::net::store> st = sess->getStore(url);
+\end{lstlisting}
+
+and for transport services:
+
+\begin{lstlisting}
+vmime::utility:url url("smtp://smtp.example.com");
+vmime::shared_ptr <vmime::net::transport> tr = sess->getTransport(url);
+\end{lstlisting}
+
+
+% ============================================================================
+\section{User credentials and authenticators}
+
+Some services need some user credentials (eg. username and password) to open
+a session. In VMime, user credentials can be specified in the session
+properties or by using a custom authenticator (callback).
+
+\begin{lstlisting}[caption={Setting user credentials using session
+properties}]
+vmime::shared_ptr <vmime::net::session> sess; // Suppose we have a session
+
+sess->getProperties()["store.imap.auth.username"] = "vincent";
+sess->getProperties()["store.imap.auth.password"] = "my-password";
+\end{lstlisting}
+
+Although not recommended, you can also specify username and password
+directly in the connection URL,
+ie: \emph{imap://username:password@imap.example.com/}. This works only for
+services requiring an username and a password as user credentials, and no
+other information.
+
+Sometimes, it may not be very convenient to set username/password in the
+session properties, or not possible (eg. extended SASL mechanisms) . That's
+why VMime offers an alternate way of getting user credentials: the
+{\vcode authenticator} object. Basically, an authenticator is an object that
+can return user credentials on-demand (like a callback).
+
+Currently, there are two types of authenticator in VMime: a basic
+authenticator (class {\vcode vmime::security::authenticator}) and, if SASL
+support is enabled, a SASL authenticator
+(class {\vcode vmime::security::sasl::SASLAuthenticator}). Usually, you
+should use the default implementations, or at least make your own
+implementation inherit from them.
+
+The following example shows how to use a custom authenticator to request
+the user to enter her/his credentials:
+
+\begin{lstlisting}[caption={A simple interactive authenticator}]
+class myAuthenticator : public vmime::security::defaultAuthenticator {
+
+ const string getUsername() const {
+
+ std::cout << "Enter your username: " << std::endl;
+
+ vmime::string res;
+ std::getline(std::cin, res);
+
+ return res;
+ }
+
+ const string getPassword() const {
+
+ std::cout << "Enter your password: " << std::endl;
+
+ vmime::string res;
+ std::getline(std::cin, res);
+
+ return res;
+ }
+};
+\end{lstlisting}
+
+This is how to use it:
+
+\begin{lstlisting}
+// First, create a session
+vmime::shared_ptr <vmime::net::session> sess = vmime::net::session::create();
+
+// Next, initialize a service which will use our authenticator
+vmime::shared_ptr <vmime::net::store> st = sess->getStore(
+ vmime::utility::url("imap://imap.example.com"),
+ /* use our authenticator */ vmime::make_shared <myAuthenticator>()
+);
+\end{lstlisting}
+
+\vnote{An authenticator object should be used with one and only one service
+at a time. This is required because the authentication process may need to
+retrieve the service name (SASL).}
+
+Of course, this example is quite simplified. For example, if several
+authentication mechanisms are tried, the user may be requested to enter the
+same information multiple times. See {\vexample Example6} for a more complex
+implementation of an authenticator, with caching support.
+
+If you want to use SASL (ie. if \emph{options.sasl} is set to \emph{true}),
+your authenticator must inherit from
+{\vcode vmime::security::sasl::SASLAuthenticator} or
+{\vcode vmime::security::sasl::defaultSASLAuthenticator}, even if you do not
+use the SASL-specific methods {\vcode getAcceptableMechanisms()} and
+{\vcode setSASLMechanism()}. Have a look at {\vexample Example6} to see an
+implementation of an SASL authenticator.
+
+\begin{lstlisting}[caption={A simple SASL authenticator}]
+class mySASLAuthenticator : public vmime::security::sasl::defaultSASLAuthenticator {
+
+ typedef vmime::security::sasl::SASLMechanism mechanism; // save us typing
+
+ const std::vector <vmime::shared_ptr <mechanism> > getAcceptableMechanisms(
+ const std::vector <vmime::shared_ptr <mechanism> >& available,
+ const vmime::shared_ptr <mechanism>& suggested
+ ) const {
+
+ // Here, you can sort the SASL mechanisms in the order they will be
+ // tried. If no SASL mechanism is acceptable (ie. for example, not
+ // enough secure), you can return an empty list.
+ //
+ // If you do not want to bother with this, you can simply return
+ // the default list, which is ordered by security strength.
+ return defaultSASLAuthenticator::
+ getAcceptableMechanisms(available, suggested);
+ }
+
+ void setSASLMechanism(const vmime::shared_ptr <mechanism>& mech) {
+
+ // This is called when the authentication process is going to
+ // try the specified mechanism.
+ //
+ // The mechanism name is in mech->getName()
+
+ defaultSASLAuthenticator::setSASLMechanism(mech);
+ }
+
+ // ...implement getUsername() and getPassword()...
+};
+\end{lstlisting}
+
+
+% ============================================================================
+\section{Using transport service}
+
+You have two possibilities for giving message data to the service when you
+want to send a message:
+
+\begin{itemize}
+\item either you have a reference to a message (type {\vcode vmime::message})
+and you can simply call {\vcode send(msg)};
+\item or you only have raw message data (as a string, for example), and you
+have to call the second overload of {\vcode send()}, which takes additional
+parameters (corresponding to message envelope);
+\end{itemize}
+
+The following example illustrates the use of a transport service to send a
+message using the second method:
+
+\begin{lstlisting}[caption={Using a transport service}]
+const vmime::string msgData =
+ "From: me@example.org \r\n"
+ "To: you@example.org \r\n"
+ "Date: Sun, Oct 30 2005 17:06:42 +0200 \r\n"
+ "Subject: Test \r\n"
+ "\r\n"
+ "Message body";
+
+// Create a new session
+vmime::utility::url url("smtp://example.com");
+
+vmime::shared_ptr <vmime::net::session> sess = vmime::net::session::create();
+
+// Create an instance of the transport service
+vmime::shared_ptr <vmime::net::transport> tr = sess->getTransport(url);
+
+// Connect it
+tr->connect();
+
+// Send the message
+vmime::utility::inputStreamStringAdapter is(msgData);
+
+vmime::mailbox from("me@example.org");
+vmime::mailboxList to;
+to.appendMailbox(vmime::make_shared <vmime::mailbox>("you@example.org"));
+
+tr->send(
+ /* expeditor */ from,
+ /* recipient(s) */ to,
+ /* data */ is,
+ /* total length */ msgData.length()
+);
+
+// We have finished using the service
+tr->disconnect();
+\end{lstlisting}
+
+\vnote{Exceptions can be thrown at any time when using a service. For better
+clarity, exceptions are not caught here, but be sure to catch them in your own
+application to provide error feedback to the user.}
+
+If you use SMTP, you can enable authentication by setting some properties
+on the session object ({\vcode service::setProperty()} is a shortcut for
+setting properties on the session with the correct prefix):
+
+\begin{lstlisting}
+tr->setProperty("options.need-authentication", true);
+tr->setProperty("auth.username", "user");
+tr->setProperty("auth.password", "password");
+\end{lstlisting}
+
+
+% ============================================================================
+\section{Using store service}
+
+\subsection{Connecting to a store} % -----------------------------------------
+
+The first basic step for using a store service is to connect to it. The
+following example shows how to initialize a session and instanciate the
+store service:
+
+\begin{lstlisting}[caption={Connecting to a store service}]
+// Create a new session
+vmime::utility::url url("imap://vincent:password@imap:example.org");
+
+vmime::shared_ptr <vmime::net::session> sess = vmime::net::session::create();
+
+// Create an instance of the transport service
+vmime::shared_ptr <vmime::net::store> store = sess->getStore(url);
+
+// Connect it
+store->connect();
+\end{lstlisting}
+
+\vnote{{\vexample Example6} contains a more complete example for connecting
+to a store service, with support for a custom authenticator.}
+
+\subsection{Opening a folder} % ----------------------------------------------
+
+You can open a folder using two different access modes: either in
+\emph{read-only} mode (where you can only read message flags and contents), or
+in \emph{read-write} mode (where you can read messages, but also delete them
+or add new ones). When you have a reference to a folder, simply call the
+{\vcode open()} method with the desired access mode:
+
+\begin{lstlisting}
+folder->open(vmime::net::folder::MODE_READ_WRITE);
+\end{lstlisting}
+
+\vnote{Not all stores support the \emph{read-write} mode. By default, if the
+\emph{read-write} mode is not available, the folder silently fall backs on
+the \emph{read-only} mode, unless the \emph{failIfModeIsNotAvailable} argument
+to {\vcode open()} is set to true.}
+
+Call {\vcode getDefaultFolder()} on the store to obtain a reference to the
+default folder, which is usually the INBOX folder (where messages arrive when
+they are received).
+
+You can also open a specific folder by specifying its path. The following
+example will open a folder named \emph{bar}, which is a child of \emph{foo}
+in the root folder:
+
+\begin{lstlisting}[caption={Opening a folder from its path}]
+vmime::net::folder::path path;
+path /= vmime::net::folder::path::component("foo");
+path /= vmime::net::folder::path::component("bar");
+
+vmime::shared_ptr <vmime::net::folder> fld = store->getFolder(path);
+fld->open(vmime::net::folder::MODE_READ_WRITE);
+\end{lstlisting}
+
+\vnote{You can specify a path as a string as there is no way to get the
+separator used to delimitate path components. Always use {\vcode operator/=}
+or {\vcode appendComponent}.}
+
+\vnote{Path components are of type {\vcode vmime::word}, which means that
+VMime supports folder names with extended characters, not only 7-bit
+US-ASCII. However, be careful that this may not be supported by the
+underlying store protocol (IMAP supports it, because it uses internally a
+modified UTF-7 encoding).}
+
+\subsection{Fetching messages} % ---------------------------------------------
+
+You can fetch some information about a message without having to download the
+whole message. Moreover, folders support fetching for multiple messages in
+a single request, for better performance. The following items are currently
+available for fetching:
+
+\begin{itemize}
+\item {\bf envelope}: sender, recipients, date and subject;
+\item {\bf structure}: MIME structure of the message;
+\item {\bf content-info}: content-type of the root part;
+\item {\bf flags}: message flags;
+\item {\bf size}: message size;
+\item {\bf header}: retrieve all the header fields of a message;
+\item {\bf uid}: unique identifier of a message;
+\item {\bf importance}: fetch header fields suitable for use with
+{\vcode misc::importanceHelper}.
+\end{itemize}
+
+\vnote{Not all services support all fetchable items. Call
+{\vcode getFetchCapabilities()} on a folder to know which information can be
+fetched by a service.}
+
+The following code shows how to list all the messages in a folder, and
+retrieve basic information to show them to the user:
+
+\begin{lstlisting}[caption={Fetching information about multiple messages}]
+std::vector <ref <vmime::net::message> > allMessages =
+ folder->getMessages(vmime::net::messageSet::byNumber(1, -1));
+ // -1 is a special value to mean "the number of the last message in the folder"
+
+folder->fetchMessages(
+ allMessages,
+ vmime::net::fetchAttributes::FLAGS |
+ vmime::net::fetchAttributes::ENVELOPE
+);
+
+for (unsigned int i = 0 ; i < allMessages.size() ; ++i) {
+
+ vmime::shared_ptr <vmime::net::message> msg = allMessages[i];
+
+ const int flags = msg->getFlags();
+
+ std::cout << "Message " << i << ":" << std::endl;
+
+ if (flags & vmime::net::message::FLAG_SEEN) {
+ std::cout << " - is read" << std::endl;
+ }
+ if (flags & vmime::net::message::FLAG_DELETED) {
+ std::cout << " - is deleted" << std::endl;
+ }
+
+ vmime::shared_ptr <const vmime::header> hdr = msg->getHeader();
+
+ std::cout << " - sent on " << hdr->Date()->generate() << std::endl;
+ std::cout << " - sent by " << hdr->From()->generate() << std::endl;
+}
+\end{lstlisting}
+
+IMAP supports fetching specific header fields of a message. Here is how to use
+the {\vcode fetchAttributes} object to do it:
+
+\begin{lstlisting}[caption={Using fetchAttributes object to fetch specific header fields of a message}]
+
+// Fetch message flags and the "Received" and "X-Mailer" header fields
+vmime::net::fetchAttributes fetchAttribs;
+fetchAttribs.add(vmime::net::fetchAttributes::FLAGS);
+fetchAttribs.add("Received");
+fetchAttribs.add("X-Mailer");
+
+folder->fetchMessages(allMessages, fetchAttribs);
+\end{lstlisting}
+
+
+\subsection{Extracting messages and parts}
+
+To extract the whole contents of a message (including headers), use the
+{\vcode extract()} method on a {\vcode vmime::net::message} object. The
+following example extracts the first message in the default folder:
+
+\begin{lstlisting}[caption={Extracting messages}]
+// Get a reference to the folder and to its first message
+vmime::shared_ptr <vmime::net::folder> folder = store->getDefaultFolder();
+vmime::shared_ptr <vmime::net::message> msg = folder->getMessage(1);
+
+// Write the message contents to the standard output
+vmime::utility::outputStreamAdapter out(std::cout);
+msg->extract(out);
+\end{lstlisting}
+
+Some protocols (like IMAP) also support the extraction of specific MIME parts
+of a message without downloading the whole message. This can save bandwidth
+and time. The method {\vcode extractPart()} is used in this case:
+
+\begin{lstlisting}[caption={Extracting a specific MIME part of a message}]
+// Fetching structure is required before extracting a part
+folder->fetchMessage(msg, vmime::net::fetchAttributes::STRUCTURE);
+
+// Now, we can extract the part
+msg->extractPart(msg->getStructure()->getPartAt(0)->getPartAt(1));
+\end{lstlisting}
+
+Suppose we have a message with the following structure:
+
+\begin{verbatim}
+ multipart/mixed
+ text/html
+ image/jpeg [*]
+\end{verbatim}
+
+The previous example will extract the header and body of the \emph{image/jpeg}
+part.
+
+\subsection{Deleting messages} % ---------------------------------------------
+
+The following example will delete the second and the third message from the
+store.
+
+\begin{lstlisting}[caption={Deleting messages}]
+vmime::shared_ptr <vmime::net::folder> folder = store->getDefaultFolder();
+
+folder->deleteMessages(vmime::net::messageSet::byNumber(/* from */ 2, /* to */ 3));
+
+// This is equivalent
+std::vector <int> nums;
+nums.push_back(2);
+nums.push_back(3);
+folder->deleteMessages(vmime::net::messageSet::byNumber(nums));
+
+// This is also equivalent (but will require 2 roundtrips to server)
+folder->deleteMessages(vmime::net::messageSet::byNumber(2));
+folder->deleteMessages(vmime::net::messageSet::byNumber(2)); // renumbered, 3 becomes 2
+\end{lstlisting}
+
+\subsection{Events} % --------------------------------------------------------
+
+As a result of executing some operation (or from time to time, even if no
+operation has been performed), a store service can send events to notify you
+that something has changed (eg. the number of messages in a folder). These
+events may allow you to update the user interface associated to a message
+store.
+
+Currently, there are three types of event:
+
+\begin{itemize}
+\item {\bf message change}: sent when the number of messages in a folder
+has changed (ie. some messages have been added or removed);
+\item {\bf message count change}: sent when one or more message(s) have
+changed (eg. flags or deleted status);
+\item {\bf folder change}: sent when a folder has been created, renamed or
+deleted.
+\end{itemize}
+
+You can register a listener for each event type by using the corresponding
+methods on a {\vcode folder} object: {\vcode addMessageChangedListener()},
+{\vcode addMessageCountListener()} or {\vcode addFolderListener()}. For more
+information, please read the class documentation for
+{\vcode vmime::net::events} namespace.
+
+
+% ============================================================================
+\section{Handling timeouts}
+
+Unexpected errors can occur while messaging services are performing
+operations and waiting a response from the server (eg. server stops
+responding, network link falls down). As all operations as synchronous,
+they can be ``blocked'' a long time before returning (in fact, they loop
+until they either receive a response from the server, or the underlying
+socket system returns an error).
+
+VMime provides a mechanism to control the duration of operations. This
+mechanism allows the program to cancel an operation that is currently
+running.
+
+An interface called {\vcode timeoutHandler} is provided:
+
+\begin{lstlisting}
+class timeoutHandler : public object {
+
+ /** Called to test if the time limit has been reached.
+ *
+ * @return true if the timeout delay is elapsed
+ */
+ virtual const bool isTimeOut() = 0;
+
+ /** Called to reset the timeout counter.
+ */
+ virtual void resetTimeOut() = 0;
+
+ /** Called when the time limit has been reached (when
+ * isTimeOut() returned true).
+ *
+ * @return true to continue (and reset the timeout)
+ * or false to cancel the current operation
+ */
+ virtual const bool handleTimeOut() = 0;
+};
+\end{lstlisting}
+
+While the operation runs, the service calls {\vcode isTimeout()} at variable
+intervals. If the {\vcode isTimeout()} function returns {\vcode true},
+then {\vcode handleTimeout()} is called. If the {\vcode handleTimeout()}
+function returns {\vcode false}, the operation is cancelled and
+an {\vcode operation\_timed\_out} exception is thrown. Else, if
+{\vcode handleTimeout()} returns true, the operation continues and the
+timeout counter is reset.
+The function {\vcode resetTimeout()} is called each time data has
+been received from the server to reset the timeout delay.
+
+When using a service, a default timeout handler is set: if an operation
+is blocked for more than 30 seconds (ie. network link is down and no data
+was received since 30 seconds), an {\vcode operation\_timed\_out} exception
+is thrown.
+
+The following example shows how to implement a simple timeout handler:
+
+\begin{lstlisting}[caption={Implementing a simple timeout handler}]
+class myTimeoutHandler : public vmime::net::timeoutHandler {
+
+public:
+
+ myTimeoutHandler() {
+
+ m_startTime = time(NULL);
+ }
+
+ const bool isTimeOut() {
+
+ return time(NULL) >= m_startTime + 30; // 30 seconds timeout
+ }
+
+ void resetTimeOut() {
+
+ m_startTime = time(NULL);
+ }
+
+ const bool handleTimeOut() {
+
+ std::cout << "Operation timed out." << std::endl;
+ << "Press [Y] to continue, or [N] to "
+ << "cancel the operation." << std::endl;
+
+ std::string response;
+ std::cin >> response;
+
+ return response == "y" || response == "Y";
+ }
+
+private:
+
+ time_t m_startTime;
+};
+\end{lstlisting}
+
+To make the service use your timeout handler, you need to write a factory
+class, to allow the service to create instances of the handler class. This
+is required because the service can use several connections to the server
+simultaneously, and each connection needs its own timeout handler.
+
+\begin{lstlisting}
+class myTimeoutHandlerFactory : public vmime::net::timeoutHandlerFactory {
+
+public:
+
+ ref <timeoutHandler> create() {
+
+ return vmime::make_shared <myTimeoutHandler>();
+ }
+};
+\end{lstlisting}
+
+Then, call the {\vcode setTimeoutHandlerFactory()} method on the service object
+to set the timeout handler factory to use during the session:
+
+\begin{lstlisting}
+theService->setTimeoutHandlerFactory(vmime::make_shared <myTimeoutHandlerFactory>());
+\end{lstlisting}
+
+
+% ============================================================================
+\newpage
+\section{Secured connection using TLS/SSL}
+
+\subsection{Introduction} % --------------------------------------------------
+
+If you have enabled TLS support in VMime, you can configure messaging services
+so that they use a secured connection.
+
+Quoting from RFC-2246 - the TLS 1.0 protocol specification: \emph{`` The TLS
+protocol provides communications privacy over the Internet. The protocol
+allows client/server applications to communicate in a way that is designed
+to prevent eavesdropping, tampering, or message forgery.''}
+
+TLS has the following advantages:
+
+\begin{itemize}
+\item authentication: server identity can be verified;
+\item privacy: transmission of data between client and server cannot be read
+by someone in the middle of the connection;
+\item integrity: original data which is transferred between a client and a
+server can not be modified by an attacker without being detected.
+\end{itemize}
+
+\vnote{What is the difference between SSL and TLS? SSL is a protocol designed
+by Netscape. TLS is a standard protocol, and is partly based on version 3 of
+the SSL protocol. The two protocols are not interoperable, but TLS does
+support a mechanism to back down to SSL 3.}
+
+VMime offers two possibilities for using a secured connection:
+
+\begin{itemize}
+\item you can connect to a server listening on a special port (eg. IMAPS
+instead of IMAP): this is the classical use of SSL, but is now deprecated;
+\item connect to a server listening on the default port, and then begin a
+secured connection: this is STARTTLS.
+\end{itemize}
+
+
+\subsection{Setting up a secured connection} % -------------------------------
+
+\subsubsection{Connecting to a ``secured'' port} % ...........................
+
+To use the classical SSL/TLS way, simply use the ``S'' version of the protocol
+to connect to the server (eg. \emph{imaps} instead of \emph{imap}). This is
+currently available for SMTP, POP3 and IMAP.
+
+\begin{lstlisting}
+vmime::shared_ptr <vmime::net::store> store =
+ theSession->getStore(vmime::utility::url("imaps://example.org"));
+\end{lstlisting}
+
+\subsubsection{Using STARTTLS} % .............................................
+
+To make the service start a secured session using the STARTTLS method, simply
+set the \emph{connection.tls} property:
+
+\begin{lstlisting}
+theService->setProperty("connection.tls", true);
+\end{lstlisting}
+
+\vnote{If, for some reason, a secured connection cannot be started, the
+default behaviour is to fallback on a normal connection. To make
+{\vcode connect()} fail if STARTTLS fails, set the
+\emph{connection.tls.required} to \emph{true}.}
+
+\subsection{Certificate verification} % --------------------------------------
+
+\subsubsection{How it works} % ...............................................
+
+If you tried the previous examples, a
+{\vcode certificateException} might have been thrown.
+This is because the default certificate verifier in VMime did not manage to
+verify the certificate, and so could not trust it.
+
+Basically, when you connect to a server using TLS, the server responds with
+a list of certificates, called a certificate chain (usually, certificates are
+of type X.509\footnote{And VMime currently supports only X.509 certificates}).
+The certificate chain is ordered so that the first certificate is the subject
+certificate, the second is the subject's issuer one, the third is the issuer's
+issuer, and so on.
+
+To decide whether the server can be trusted or not, you have to verify that
+\emph{each} certificate is valid (ie. is trusted). For more information
+about X.509 and certificate verification, see related articles on Wikipedia
+\footnote{See \url{http://wikipedia.org/wiki/Public\_key\_certificate}}.
+
+\subsubsection{Using the default certificate verifier} % .....................
+
+The default certificate verifier maintains a list of root (CAs) and user
+certificates that are trusted. By default, the list is empty. So, you have
+to initialize it before using the verifier.
+
+The algorithm\footnote{See
+\url{http://wikipedia.org/wiki/Certification\_path\_validation\_algorithm}}
+used is quite simple:
+
+\begin{enumerate}
+\item for every certificate in the chain, verify that the certificate has been
+issued by the next certificate in the chain;
+\item for every certificate in the chain, verify that the certificate is valid
+at the current time;
+\item ensure that the first certificate's subject name matches the hostname
+of the server;
+\item decide whether the subject's certificate can be trusted:
+ \begin{itemize}
+ \item first, verify that the the last certificate in the chain was
+ issued by a third-party that we trust (root CAs);
+ \item if the issuer certificate cannot be verified against root CAs,
+ compare the subject's certificate against the trusted certificates
+ (the certificates the user has decided to trust).
+ \end{itemize}
+\end{enumerate}
+
+First, we need some code to load existing X.509 certificates:
+
+\begin{lstlisting}[caption={Reading a X.509 certificate from a file}]
+vmime::shared_ptr <vmime::security::cert::X509Certificate>
+ loadX509CertificateFromFile(const std::string& path) {
+
+ std::ifstream certFile;
+ certFile.open(path.c_str(), std::ios::in | std::ios::binary);
+
+ if (!certFile) {
+ // ...handle error...
+ }
+
+ vmime::utility::inputStreamAdapter is(certFile);
+ vmime::shared_ptr <vmime::security::cert::X509Certificate> cert;
+
+ cert = vmime::security::cert::X509Certificate::import(is);
+
+ return cert;
+}
+\end{lstlisting}
+
+Then, we can use the {\vcode loadX509CertificateFromFile} function to load
+certificates and initialize the certificate verifier:
+
+\begin{lstlisting}[caption={Using the default certificate verifier}]
+vmime::shared_ptr <vmime::security::cert::defaultCertificateVerifier> vrf =
+ vmime::make_shared <vmime::security::cert::defaultCertificateVerifier>();
+
+// Load root CAs (such as Verisign or Thawte)
+std::vector <vmime::shared_ptr <vmime::security::cert::X509Certificate> > rootCAs;
+
+rootCAs.push_back(loadX509CertificateFromFile("/path/to/root-ca1.cer");
+rootCAs.push_back(loadX509CertificateFromFile("/path/to/root-ca2.cer");
+rootCAs.push_back(loadX509CertificateFromFile("/path/to/root-ca3.cer");
+
+vrf->setX509RootCAs(rootCAs);
+
+// Then, load certificates that the user explicitely chose to trust
+std::vector <vmime::shared_ptr <vmime::security::cert::X509Certificate> > trusted;
+
+trusted.push_back(loadX509CertificateFromFile("/path/to/trusted-site1.cer");
+trusted.push_back(loadX509CertificateFromFile("/path/to/trusted-site2.cer");
+
+vrf->setX509TrustedCerts(trusted);
+\end{lstlisting}
+
+
+\subsubsection{Writing your own certificate verifier} % ......................
+
+If you need to do more complex verifications on certificates, you will have to
+write your own verifier. Your verifier should inherit from the
+{\vcode vmime::security::cert::certificateVerifier} class and implement the
+method {\vcode verify()}. Then, if the specified certificate chain is trusted,
+simply return from the function, or else throw a
+{\vcode certificateException}.
+
+The following example shows how to implement an interactive certificate
+verifier which relies on the user's decision, and nothing else (you SHOULD NOT
+use this in a production application as this is obviously a serious security
+issue):
+
+\begin{lstlisting}[caption={A custom certificate verifier}]
+class myCertVerifier : public vmime::security::cert::certificateVerifier {
+
+public:
+
+ void verify(const vmime::shared_ptr <certificateChain>& certs) {
+
+ // Obtain the subject's certificate
+ vmime::shared_ptr <vmime::security::cert::certificate> cert = chain->getAt(0);
+
+ std::cout << std::endl;
+ std::cout << "Server sent a '" << cert->getType() << "'"
+ << " certificate." << std::endl;
+ std::cout << "Do you want to accept this certificate? (Y/n) ";
+ std::cout.flush();
+
+ std::string answer;
+ std::getline(std::cin, answer);
+
+ if (answer.length() != 0 && (answer[0] == 'Y' || answer[0] == 'y')) {
+ return; // OK, we trust the certificate
+ }
+
+ // Don't trust this certificate
+ throw vmime::security::cert::certificateException();
+ }
+};
+\end{lstlisting}
+
+\vnote{In production code, it may be a good idea to remember user's decisions
+about which certificates to trust and which not. See {\vexample Example6} for
+a basic cache implementation.}
+
+Finally, to make the service use your own certificate verifier, simply write:
+
+\begin{lstlisting}
+theService->setCertificateVerifier(vmime::make_shared <myCertVerifier>());
+\end{lstlisting}
+
+\subsection{SSL/TLS Properties} % --------------------------------------------
+
+If you want to customize behavior or set some options on TLS/SSL connection,
+you may use the TLSProperties object, and pass it to the service session. The
+TLS/SSL options must be set {\em before} creating any service with the session
+(ie. before calling either {\vcode getStore()} or {\vcode getTransport()} on
+the session), or they will not be used.
+
+The following example shows how to set the cipher suite preferences for TLS:
+
+\begin{lstlisting}[caption={Setting TLS cipher suite preferences}]
+vmime::shared_ptr <vmime::net::session> sess = /* ... */;
+
+vmime::shared_ptr <vmime::net::tls::TLSProperties> tlsProps =
+ vmime::make_shared <vmime::net::tls::TLSProperties>();
+
+// for OpenSSL
+tlsProps->setCipherString("HIGH:!ADH:@STRENGTH");
+
+// for GNU TLS
+tlsProps->setCipherString("NORMAL:%SSL3_RECORD_VERSION");
+
+sess->setTLSProperties(tlsProps);
+\end{lstlisting}
+
+Please note that the cipher suite string format and meaning depend on the
+underlying TLS library (either OpenSSL or GNU TLS):
+
+\begin{itemize}
+\item for GNU TLS, read this: \newline
+\url{http://gnutls.org/manual/html\_node/Priority-Strings.html}
+
+\item for OpenSSL, read this: \newline
+\url{http://www.openssl.org/docs/apps/ciphers.html#CIPHER\_STRINGS}
+\end{itemize}
+
+You may also set cipher suite preferences using predefined constants that
+map to generic security modes:
+
+\begin{lstlisting}[caption={Setting TLS cipher suite preferences using predefined modes}]
+sess->setCipherSuite(vmime::net::tls::TLSProperties::CIPHERSUITE_HIGH);
+\end{lstlisting}
+
+The following constants are available:
+
+\noindent\begin{tabularx}{1.0\textwidth}{|l|X|}
+\hline
+ {\bf Constant} &
+ {\bf Meaning} \\
+\hline
+ CIPHERSUITE\_HIGH &
+ High encryption cipher suites ($>$ 128 bits) \\
+\hline
+ CIPHERSUITE\_MEDIUM &
+ Medium encryption cipher suites ($>=$ 128 bits) \\
+\hline
+ CIPHERSUITE\_LOW &
+ Low encryption cipher suites ($>=$ 64 bits) \\
+\hline
+ CIPHERSUITE\_DEFAULT &
+ Default cipher suite (actual cipher suites used depends
+ on the underlying SSL/TLS library) \\
+\hline
+\end{tabularx}
+
+
+% ============================================================================
+\section{Tracing connection}
+
+Connection tracing is used to log what is sent and received on the wire
+between the client and the server, and may help debugging.
+
+First, you have to create your own tracer, which must implement the
+{\vcode vmime::net::tracer} interface. Here is an example of a tracer which
+simply logs to the standard output:
+
+\begin{lstlisting}[caption={A simple tracer}]
+class myTracer : public vmime::net::tracer {
+
+public:
+
+ myTracer(const vmime::string& proto, const int connectionId)
+ : m_proto(proto),
+ m_connectionId(connectionId) {
+
+ }
+
+ // Called by VMime to trace what is sent on the socket
+ void traceSend(const vmime::string& line) {
+
+ std::cout << "[" << m_proto << ":" << m_connectionId
+ << "] C: " << line << std::endl;
+ }
+
+ // Called by VMime to trace what is received from the socket
+ void traceReceive(const vmime::string& line) {
+
+ std::cout << "[" < < m_proto << ":" << m_connectionId
+ << "] S: " << line << std::endl;
+ }
+
+private:
+
+ const vmime::string m_proto;
+ const int m_connectionId;
+};
+\end{lstlisting}
+
+Also create a factory class, used to instanciate your tracer objects:
+
+\begin{lstlisting}
+class myTracerFactory : public vmime::net::tracerFactory {
+
+public:
+
+ vmime::shared_ptr <vmime::net::tracer> create(
+ const vmime::shared_ptr <vmime::net::service>& serv,
+ const int connectionId
+ ) {
+
+ return vmime::make_shared <myTracer>(
+ serv->getProtocolName(), connectionId
+ );
+ }
+};
+\end{lstlisting}
+
+Next, we have to tell VMime to use it. When you create your service
+(either store or transport), simply call the {\vcode setTracerFactory}
+on the service and pass an instance of your factory class:
+
+\begin{lstlisting}[caption={Enabling tracer on a connection}]
+vmime::shared_ptr <vmime::net::transport> store =
+ session->getStore("imaps://user:password@imap.myserver.com");
+
+// Enable tracing communication between client and server
+store->setTracerFactory(vmime::make_shared <myTracerFactory>());
+\end{lstlisting}
+
+That's all! Now, everything which is sent on/received from the socket
+will be logged using your tracer object. Here is an example of a trace
+session for IMAP:
+
+\begin{verbatim}
+[imaps:1] S: * OK [CAPABILITY IMAP4rev1 LITERAL+ SASL-IR
+ LOGIN-REFERRALS ID ENABLE IDLE AUTH=PLAIN] Dovecot ready.
+[imaps:1] C: a001 AUTHENTICATE PLAIN
+[imaps:1] S: +
+[imaps:1] C: {...SASL exchange: 52 bytes of data...}
+[imaps:1] S: a001 OK [CAPABILITY IMAP4rev1 LITERAL+ SASL-IR
+ LOGIN-REFERRALS ID ENABLE IDLE SORT SPECIAL-USE QUOTA] Logged in
+[imaps:1] C: a002 LIST "" ""
+[imaps:1] S: * LIST (\Noselect) "." ""
+[imaps:1] S: a002 OK List completed.
+[imaps:1] C: a003 CAPABILITY
+[imaps:1] S: * CAPABILITY IMAP4rev1 LITERAL+ SASL-IR
+ LOGIN-REFERRALS ID ENABLE IDLE SORT SPECIAL-USE QUOTA
+[imaps:1] S: a003 OK Capability completed.
+[imaps:1] C: a003 SELECT INBOX (CONDSTORE)
+[imaps:1] S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft
+ $NotJunk NonJunk JunkRecorded $MDNSent NotJunk $Forwarded
+ Junk $Junk Forwarded $MailFlagBit1)
+[imaps:1] S: * OK [PERMANENTFLAGS (\Answered \Flagged \Deleted
+ \Seen \Draft $NotJunk NonJunk JunkRecorded $MDNSent NotJunk
+ $Forwarded Junk $Junk Forwarded $MailFlagBit1 \*)]
+ Flags permitted.
+[imaps:1] S: * 104 EXISTS
+[imaps:1] S: * 0 RECENT
+[imaps:1] S: * OK [UNSEEN 6] First unseen.
+[imaps:1] S: * OK [UIDVALIDITY 1268127585] UIDs valid
+[imaps:1] S: * OK [UIDNEXT 32716] Predicted next UID
+[imaps:1] S: * OK [HIGHESTMODSEQ 148020] Highest
+[imaps:1] S: a003 OK [READ-WRITE] Select completed.
+\end{verbatim}
+
+Please note that no sensitive data (ie. login or password) will be traced.
+Same, {\em blob} data such as message content or SASL exchanges will be logged
+as a marker which indicates how many bytes were sent/received (eg. "{...SASL
+exchange: 52 bytes of data...}"").
diff --git a/vmime-master/doc/book/start.tex b/vmime-master/doc/book/start.tex
new file mode 100644
index 0000000..f169330
--- /dev/null
+++ b/vmime-master/doc/book/start.tex
@@ -0,0 +1,111 @@
+\chapter{Getting Started}
+
+% ============================================================================
+\section{Using VMime in your programs}
+
+First, make sure you have successfully compiled and installed VMime using the
+instructions described in Chapter \ref{chapter_building}. To use VMime in your
+program, you simply have to include VMime headers:
+
+\begin{lstlisting}
+#include <vmime/vmime.hpp>
+\end{lstlisting}
+
+\vnote{for versions older than 0.6.1, include $<$vmime/vmime$>$.}
+
+As of version 0.6.1, VMime uses {\vcode pkg-config} to simplify compiling and
+linking with VMime. The {\vcode pkg-config} utility is used to detect the
+appropriate compiler and linker flags needed for a library.
+
+You can simply build your program with:
+
+\begin{verbatim}
+ $ g++ `pkg-config --cflags --libs vmime` -static -o myprog myprog.cpp
+\end{verbatim}
+
+to use the static version, or with:
+
+\begin{verbatim}
+ $ g++ `pkg-config --cflags vmime` -o myprog myprog.cpp `pkg-config --libs vmime`
+\end{verbatim}
+
+to use the shared version.
+
+\vnote{it is highly recommended that you link your program against the shared
+version of the library.}
+
+All VMime classes and global functions are defined in the namespace
+{\vcode vmime}, so prefix explicitely all your declarations which use VMime
+with {\vcode vmime::}, or import the {\vcode vmime} namespace into the global
+namespace with the C++ keywork {\vcode using} (not recommended, though).
+
+
+% ============================================================================
+\section{If you can not (or do not want to) use {\vcode pkg-config}}
+
+{\bf Linking with the shared library (.so):} compile your program with the
+{\vcode -lvmime} flag. You can use the -L path flag if the library file is
+not in a standard path (ie. not in /usr/lib or /usr/local/lib).
+
+\vnote{if you want to link your program with the shared version of VMime
+library, make sure the library has been compiled using CMake build system
+({\vcode make}, then {\vcode make install}). When you compile with SCons,
+only the static library is built and installed.}
+
+{\bf Linking with the static library (.a):} follow the same procedure as for
+shared linking and append the flag -static to force static linking. Although
+static linking is possible, you are encouraged to use the shared (dynamic)
+version of the library.
+
+
+% ============================================================================
+\section{Platform-dependent code}
+
+While the most part of VMime code is pure ANSI C++, there are some features
+that are platform-specific: file management (opening/reading/writing files),
+network code (socket, DNS resolution) and time management. All the
+non-portable stuff is done by a bridge object called a platform handler (see
+{\vcode vmime::platform}).
+
+If your platform is POSIX-compatible (eg. GNU/Linux, *BSD) or is Windows,
+then you are lucky: VMime has built-in support for these platforms. If not,
+don't worry, the sources of the built-in platform handlers are very well
+documented, so writing you own should not be very difficult.
+
+If your VMime version is $<=$ 0.9.1, you should tell VMime which platform
+handler you want to use at the beginning of your program (before using
+\emph{any} VMime object, or calling \emph{any} VMime global function).
+
+So, if your platform is POSIX, your program should look like this:
+
+\begin{lstlisting}[caption={Initializing VMime and the platform handler}]
+#include <vmime/vmime.hpp>
+#include <vmime/platforms/posix/posixHandler.hpp>
+
+int main() {
+
+ vmime::platform::
+ setHandler <vmime::platforms::posix::posixHandler>();
+
+ // Now, you can use VMime
+ // ...do what you want, it's your program...
+}
+\end{lstlisting}
+
+For using VMime on Windows, include
+{\vcode vmime/platforms/windows/windowsHandler.hpp} and use the following line
+to initialize the platform handler:
+
+\begin{lstlisting}
+vmime::platform::
+ setHandler <vmime::platforms::windows::windowsHandler>();
+\end{lstlisting}
+
+\vnote{since version 0.9.2, this is not needed any more: the platform
+handler is installed automatically using the platform detected during the
+build configuration.}
+
+\vnote{since version 0.8.1, {\vcode vmime::platformDependant} was renamed
+to {\vcode vmime::platform}. The old name has been kept for compatibility
+but it is recommended that you update your code, if needed.}
+
diff --git a/vmime-master/examples/CMakeLists.txt b/vmime-master/examples/CMakeLists.txt
new file mode 100644
index 0000000..9e6998f
--- /dev/null
+++ b/vmime-master/examples/CMakeLists.txt
@@ -0,0 +1,38 @@
+
+IF(VMIME_BUILD_SAMPLES)
+
+ ADD_SUBDIRECTORY(viewer)
+
+ FILE(
+ GLOB
+ VMIME_SAMPLES_SRC_FILES
+ ${CMAKE_SOURCE_DIR}/examples/*.cpp
+ )
+
+ # Build one file for each sample
+ FOREACH(VMIME_SAMPLE_SRC_FILE ${VMIME_SAMPLES_SRC_FILES})
+
+ GET_FILENAME_COMPONENT(VMIME_SAMPLE_NAME "${VMIME_SAMPLE_SRC_FILE}" NAME_WE)
+
+ ADD_EXECUTABLE(
+ ${VMIME_SAMPLE_NAME}
+ ${VMIME_SAMPLE_SRC_FILE}
+ )
+
+ TARGET_LINK_LIBRARIES(
+ ${VMIME_SAMPLE_NAME}
+ ${VMIME_LIBRARY_NAME}
+ )
+
+ ADD_DEPENDENCIES(
+ ${VMIME_SAMPLE_NAME}
+ ${VMIME_LIBRARY_NAME}
+ )
+
+ ENDFOREACH()
+
+ELSE()
+
+ MESSAGE(FATAL_ERROR "Examples are not to be built (set VMIME_BUILD_SAMPLES to YES.")
+
+ENDIF()
diff --git a/vmime-master/examples/example1.cpp b/vmime-master/examples/example1.cpp
new file mode 100644
index 0000000..c698fa7
--- /dev/null
+++ b/vmime-master/examples/example1.cpp
@@ -0,0 +1,107 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+//
+// EXAMPLE DESCRIPTION:
+// ====================
+// This sample program demonstrate the use of the messageBuilder component
+// to build a simple message.
+//
+// For more information, please visit:
+// http://www.vmime.org/
+//
+
+#include <iostream>
+#include <locale>
+#include <clocale>
+
+#include "vmime/vmime.hpp"
+#include "vmime/platforms/posix/posixHandler.hpp"
+
+
+int main() {
+
+ std::cout << std::endl;
+
+ // Set the global C and C++ locale to the user-configured locale.
+ // The locale should use UTF-8 encoding for these tests to run successfully.
+ try {
+ std::locale::global(std::locale(""));
+ } catch (std::exception &) {
+ std::setlocale(LC_ALL, "");
+ }
+
+ try {
+
+ vmime::messageBuilder mb;
+
+ // Fill in the basic fields
+ mb.setExpeditor(vmime::mailbox("me@somewhere.com"));
+
+ vmime::addressList to;
+ to.appendAddress(vmime::make_shared <vmime::mailbox>("you@elsewhere.com"));
+
+ mb.setRecipients(to);
+
+ vmime::addressList bcc;
+ bcc.appendAddress(vmime::make_shared <vmime::mailbox>("you-bcc@nowhere.com"));
+
+ mb.setBlindCopyRecipients(bcc);
+
+ mb.setSubject(vmime::text("My first message generated with vmime::messageBuilder"));
+
+ // Message body
+ mb.getTextPart()->setText(
+ vmime::make_shared <vmime::stringContentHandler>(
+ "I'm writing this short text to test message construction " \
+ "using the vmime::messageBuilder component."
+ )
+ );
+
+ // Construction
+ vmime::shared_ptr <vmime::message> msg = mb.construct();
+
+ // Raw text generation
+ std::cout << "Generated message:" << std::endl;
+ std::cout << "==================" << std::endl;
+
+ vmime::utility::outputStreamAdapter out(std::cout);
+ msg->generate(out);
+
+ // VMime exception
+ } catch (vmime::exception& e) {
+
+ std::cout << "vmime::exception: " << e.what() << std::endl;
+ throw;
+
+ // Standard exception
+ } catch (std::exception& e) {
+
+ std::cout << "std::exception: " << e.what() << std::endl;
+ throw;
+ }
+
+ std::cout << std::endl;
+
+ return 0;
+}
diff --git a/vmime-master/examples/example2.cpp b/vmime-master/examples/example2.cpp
new file mode 100644
index 0000000..da01d75
--- /dev/null
+++ b/vmime-master/examples/example2.cpp
@@ -0,0 +1,121 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+//
+// EXAMPLE DESCRIPTION:
+// ====================
+// This sample program demonstrate the use of the messageBuilder component
+// to build a simple message with an attachment.
+//
+// For more information, please visit:
+// http://www.vmime.org/
+//
+
+#include <iostream>
+#include <locale>
+#include <clocale>
+
+#include "vmime/vmime.hpp"
+#include "vmime/platforms/posix/posixHandler.hpp"
+
+
+int main() {
+
+ std::cout << std::endl;
+
+ // Set the global C and C++ locale to the user-configured locale.
+ // The locale should use UTF-8 encoding for these tests to run successfully.
+ try {
+ std::locale::global(std::locale(""));
+ } catch (std::exception &) {
+ std::setlocale(LC_ALL, "");
+ }
+
+ try {
+
+ vmime::messageBuilder mb;
+
+ // Fill in the basic fields
+ mb.setExpeditor(vmime::mailbox("me@somewhere.com"));
+
+ vmime::addressList to;
+ to.appendAddress(vmime::make_shared <vmime::mailbox>("you@elsewhere.com"));
+
+ mb.setRecipients(to);
+
+ vmime::addressList bcc;
+ bcc.appendAddress(vmime::make_shared <vmime::mailbox>("you-bcc@nowhere.com"));
+
+ mb.setBlindCopyRecipients(bcc);
+
+ mb.setSubject(vmime::text("My first message generated with vmime::messageBuilder"));
+
+ // Message body
+ mb.getTextPart()->setText(
+ vmime::make_shared <vmime::stringContentHandler>(
+ "I'm writing this short text to test message construction " \
+ "with attachment, using the vmime::messageBuilder component."
+ )
+ );
+
+ // Adding an attachment
+ vmime::shared_ptr <vmime::fileAttachment> a =
+ vmime::make_shared <vmime::fileAttachment>(
+ __FILE__, // full path to file
+ vmime::mediaType("application/octet-stream"), // content type
+ vmime::text("My first attachment") // description
+ );
+
+ a->getFileInfo().setFilename("example2.cpp");
+ a->getFileInfo().setCreationDate(vmime::datetime("30 Apr 2003 14:30:00 +0200"));
+
+ mb.attach(a);
+
+ // Construction
+ vmime::shared_ptr <vmime::message> msg = mb.construct();
+
+ // Raw text generation
+ vmime::string dataToSend = msg->generate();
+
+ std::cout << "Generated message:" << std::endl;
+ std::cout << "==================" << std::endl;
+ std::cout << std::endl;
+ std::cout << dataToSend << std::endl;
+
+ // VMime exception
+ } catch (vmime::exception& e) {
+
+ std::cout << "vmime::exception: " << e.what() << std::endl;
+ throw;
+
+ // Standard exception
+ } catch (std::exception& e) {
+
+ std::cout << "std::exception: " << e.what() << std::endl;
+ throw;
+ }
+
+ std::cout << std::endl;
+
+ return 0;
+}
diff --git a/vmime-master/examples/example3.cpp b/vmime-master/examples/example3.cpp
new file mode 100644
index 0000000..b452225
--- /dev/null
+++ b/vmime-master/examples/example3.cpp
@@ -0,0 +1,153 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+//
+// EXAMPLE DESCRIPTION:
+// ====================
+// This sample program demonstrate the use of the messageBuilder component
+// to build a complex message (HTML content, plain text and embedded image).
+//
+// For more information, please visit:
+// http://www.vmime.org/
+//
+
+#include <iostream>
+#include <locale>
+#include <clocale>
+
+#include "vmime/vmime.hpp"
+#include "vmime/platforms/posix/posixHandler.hpp"
+
+
+int main() {
+
+ std::cout << std::endl;
+
+ // Set the global C and C++ locale to the user-configured locale.
+ // The locale should use UTF-8 encoding for these tests to run successfully.
+ try {
+ std::locale::global(std::locale(""));
+ } catch (std::exception &) {
+ std::setlocale(LC_ALL, "");
+ }
+
+ try {
+
+ vmime::messageBuilder mb;
+
+ // Fill in the basic fields
+ mb.setExpeditor(vmime::mailbox("me@somewhere.com"));
+
+ vmime::addressList to;
+ to.appendAddress(vmime::make_shared <vmime::mailbox>("you@elsewhere.com"));
+
+ mb.setRecipients(to);
+
+ vmime::addressList bcc;
+ bcc.appendAddress(vmime::make_shared <vmime::mailbox>("you-bcc@nowhere.com"));
+
+ mb.setBlindCopyRecipients(bcc);
+
+ mb.setSubject(vmime::text("My first message generated with vmime::messageBuilder"));
+
+ // Set the content-type to "text/html"
+ mb.constructTextPart(
+ vmime::mediaType(
+ vmime::mediaTypes::TEXT,
+ vmime::mediaTypes::TEXT_HTML
+ )
+ );
+
+ // Fill in the text part: the message is available in two formats: HTML and plain text.
+ // HTML text part also includes an inline image (embedded into the message).
+ vmime::htmlTextPart& textPart =
+ *vmime::dynamicCast <vmime::htmlTextPart>(mb.getTextPart());
+
+ // -- embed an image (the returned "CID" (content identifier) is used to reference
+ // -- the image into HTML content).
+ vmime::shared_ptr <vmime::utility::fileSystemFactory> fs =
+ vmime::platform::getHandler()->getFileSystemFactory();
+
+ vmime::shared_ptr <vmime::utility::file> imageFile =
+ fs->create(fs->stringToPath("/path/to/image.jpg"));
+
+ vmime::shared_ptr <vmime::utility::fileReader> fileReader =
+ imageFile->getFileReader();
+
+ vmime::shared_ptr <vmime::contentHandler> imageCts =
+ vmime::make_shared <vmime::streamContentHandler>(
+ fileReader->getInputStream(),
+ imageFile->getLength()
+ );
+
+ vmime::shared_ptr <const vmime::htmlTextPart::embeddedObject> obj =
+ textPart.addObject(
+ imageCts,
+ vmime::mediaType(
+ vmime::mediaTypes::IMAGE,
+ vmime::mediaTypes::IMAGE_JPEG
+ )
+ );
+
+ // -- message text
+ textPart.setText(
+ vmime::make_shared <vmime::stringContentHandler>(
+ vmime::string("This is the <b>HTML text</b>.<br/>"
+ "<img src=\"") + obj->getReferenceId() + vmime::string("\"/>")
+ )
+ );
+
+ textPart.setPlainText(
+ vmime::make_shared <vmime::stringContentHandler>(
+ "This is the plain text (without HTML formatting)."
+ )
+ );
+
+ // Construction
+ vmime::shared_ptr <vmime::message> msg = mb.construct();
+
+ // Raw text generation
+ vmime::string dataToSend = msg->generate();
+
+ std::cout << "Generated message:" << std::endl;
+ std::cout << "==================" << std::endl;
+ std::cout << std::endl;
+ std::cout << dataToSend << std::endl;
+
+ // VMime exception
+ } catch (vmime::exception& e) {
+
+ std::cout << "vmime::exception: " << e.what() << std::endl;
+ throw;
+
+ // Standard exception
+ } catch (std::exception& e) {
+
+ std::cout << "std::exception: " << e.what() << std::endl;
+ throw;
+ }
+
+ std::cout << std::endl;
+
+ return 0;
+}
diff --git a/vmime-master/examples/example4.cpp b/vmime-master/examples/example4.cpp
new file mode 100644
index 0000000..4d50c2e
--- /dev/null
+++ b/vmime-master/examples/example4.cpp
@@ -0,0 +1,108 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+//
+// EXAMPLE DESCRIPTION:
+// ====================
+// This sample program demonstrate the use of the messageParser component
+// to enumerate the text parts in a message.
+//
+// For more information, please visit:
+// http://www.vmime.org/
+//
+
+#include <iostream>
+#include <locale>
+#include <clocale>
+
+#include "vmime/vmime.hpp"
+#include "vmime/platforms/posix/posixHandler.hpp"
+
+
+int main() {
+
+ std::cout << std::endl;
+
+ // Set the global C and C++ locale to the user-configured locale.
+ // The locale should use UTF-8 encoding for these tests to run successfully.
+ try {
+ std::locale::global(std::locale(""));
+ } catch (std::exception &) {
+ std::setlocale(LC_ALL, "");
+ }
+
+ try {
+
+ vmime::messageParser mp("<...MIME message content...>");
+
+ // Enumerate text parts
+ for (size_t i = 0 ; i < mp.getTextPartCount() ; ++i) {
+
+ const vmime::textPart& part = *mp.getTextPartAt(i);
+
+ // Output content-type of the part
+ std::cout << part.getType().generate() << std::endl;
+
+ // text/html
+ if (part.getType().getSubType() == vmime::mediaTypes::TEXT_HTML) {
+
+ const vmime::htmlTextPart& hp = dynamic_cast<const vmime::htmlTextPart&>(part);
+
+ // HTML text is in "hp.getText()"
+ // Corresponding plain text is in "hp.getPlainText()"
+
+ // Enumerate embedded objects (eg. images)
+ for (size_t j = 0 ; j < hp.getObjectCount() ; ++j) {
+
+ const vmime::htmlTextPart::embeddedObject& obj = *hp.getObjectAt(j);
+
+ // Identifier (content-id or content-location) is in "obj.getId()"
+ // Object data is in "obj.getData()"
+ }
+
+ // text/plain
+ } else {
+
+ const vmime::textPart& tp = dynamic_cast<const vmime::textPart&>(part);
+
+ // Text is in "tp.getText()"
+ }
+ }
+
+ // VMime exception
+ } catch (vmime::exception& e) {
+
+ std::cout << "vmime::exception: " << e.what() << std::endl;
+ throw;
+
+ // Standard exception
+ } catch (std::exception& e) {
+
+ std::cout << "std::exception: " << e.what() << std::endl;
+ throw;
+ }
+
+ std::cout << std::endl;
+
+ return 0;
+}
diff --git a/vmime-master/examples/example5.cpp b/vmime-master/examples/example5.cpp
new file mode 100644
index 0000000..24d5cbf
--- /dev/null
+++ b/vmime-master/examples/example5.cpp
@@ -0,0 +1,85 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+//
+// EXAMPLE DESCRIPTION:
+// ====================
+// This sample program demonstrate the use of the messageParser component
+// to enumerate the attachments in a message.
+//
+// For more information, please visit:
+// http://www.vmime.org/
+//
+
+#include <iostream>
+#include <locale>
+#include <clocale>
+
+#include "vmime/vmime.hpp"
+#include "vmime/platforms/posix/posixHandler.hpp"
+
+
+int main() {
+
+ std::cout << std::endl;
+
+ // Set the global C and C++ locale to the user-configured locale.
+ // The locale should use UTF-8 encoding for these tests to run successfully.
+ try {
+ std::locale::global(std::locale(""));
+ } catch (std::exception &) {
+ std::setlocale(LC_ALL, "");
+ }
+
+ try {
+
+ vmime::messageParser mp("<...MIME message content...>");
+
+ // Enumerate attachments
+ for (size_t i = 0 ; i < mp.getAttachmentCount() ; ++i) {
+
+ const vmime::attachment& att = *mp.getAttachmentAt(i);
+
+ // Media type (content type) is in "att.getType()"
+ // Name is in "att.getName()"
+ // Description is in "att.getDescription()"
+ // Data is in "att.getData()"
+ }
+
+ // VMime exception
+ } catch (vmime::exception& e) {
+
+ std::cout << "vmime::exception: " << e.what() << std::endl;
+ throw;
+
+ // Standard exception
+ } catch (std::exception& e) {
+
+ std::cout << "std::exception: " << e.what() << std::endl;
+ throw;
+ }
+
+ std::cout << std::endl;
+
+ return 0;
+}
diff --git a/vmime-master/examples/example6.cpp b/vmime-master/examples/example6.cpp
new file mode 100644
index 0000000..add24b3
--- /dev/null
+++ b/vmime-master/examples/example6.cpp
@@ -0,0 +1,938 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include <iostream>
+#include <sstream>
+#include <vector>
+#include <map>
+#include <locale>
+#include <clocale>
+
+#include "vmime/vmime.hpp"
+#include "vmime/platforms/posix/posixHandler.hpp"
+
+#include "example6_tracer.hpp"
+#include "example6_authenticator.hpp"
+#include "example6_certificateVerifier.hpp"
+#include "example6_timeoutHandler.hpp"
+
+
+// Global session object
+static vmime::shared_ptr <vmime::net::session> g_session = vmime::net::session::create();
+
+
+/** Returns the messaging protocols supported by VMime.
+ *
+ * @param type service type (vmime::net::service::TYPE_STORE or
+ * vmime::net::service::TYPE_TRANSPORT)
+ */
+static const std::string findAvailableProtocols(const vmime::net::service::Type type) {
+
+ vmime::shared_ptr <vmime::net::serviceFactory> sf =
+ vmime::net::serviceFactory::getInstance();
+
+ std::ostringstream res;
+ size_t count = 0;
+
+ for (size_t i = 0 ; i < sf->getServiceCount() ; ++i) {
+
+ const vmime::net::serviceFactory::registeredService& serv = *sf->getServiceAt(i);
+
+ if (serv.getType() == type) {
+
+ if (count != 0) {
+ res << ", ";
+ }
+
+ res << serv.getName();
+ ++count;
+ }
+ }
+
+ return res.str();
+}
+
+
+// Exception helper
+static std::ostream& operator<<(std::ostream& os, const vmime::exception& e) {
+
+ os << "* vmime::exceptions::" << e.name() << std::endl;
+ os << " what = " << e.what() << std::endl;
+
+ // More information for special exceptions
+ if (dynamic_cast <const vmime::exceptions::command_error*>(&e)) {
+
+ const vmime::exceptions::command_error& cee =
+ dynamic_cast <const vmime::exceptions::command_error&>(e);
+
+ os << " command = " << cee.command() << std::endl;
+ os << " response = " << cee.response() << std::endl;
+ }
+
+ if (dynamic_cast <const vmime::exceptions::invalid_response*>(&e)) {
+
+ const vmime::exceptions::invalid_response& ir =
+ dynamic_cast <const vmime::exceptions::invalid_response&>(e);
+
+ os << " response = " << ir.response() << std::endl;
+ }
+
+ if (dynamic_cast <const vmime::exceptions::connection_greeting_error*>(&e)) {
+
+ const vmime::exceptions::connection_greeting_error& cgee =
+ dynamic_cast <const vmime::exceptions::connection_greeting_error&>(e);
+
+ os << " response = " << cgee.response() << std::endl;
+ }
+
+ if (dynamic_cast <const vmime::exceptions::authentication_error*>(&e)) {
+
+ const vmime::exceptions::authentication_error& aee =
+ dynamic_cast <const vmime::exceptions::authentication_error&>(e);
+
+ os << " response = " << aee.response() << std::endl;
+ }
+
+ if (dynamic_cast <const vmime::exceptions::filesystem_exception*>(&e)) {
+
+ const vmime::exceptions::filesystem_exception& fse =
+ dynamic_cast <const vmime::exceptions::filesystem_exception&>(e);
+
+ os << " path = " << vmime::platform::getHandler()->
+ getFileSystemFactory()->pathToString(fse.path()) << std::endl;
+ }
+
+ if (e.other()) {
+ os << *e.other();
+ }
+
+ return os;
+}
+
+
+/** Print the MIME structure of a message on the standard output.
+ *
+ * @param s structure object
+ * @param level current depth
+ */
+static void printStructure(
+ vmime::shared_ptr <const vmime::net::messageStructure> s,
+ const int level = 0
+) {
+
+ for (size_t i = 0 ; i < s->getPartCount() ; ++i) {
+
+ vmime::shared_ptr <const vmime::net::messagePart> part = s->getPartAt(i);
+
+ for (int j = 0 ; j < level * 2 ; ++j) {
+ std::cout << " ";
+ }
+
+ std::cout
+ << (part->getNumber() + 1) << ". "
+ << part->getType().generate()
+ << " [" << part->getSize() << " byte(s)]"
+ << std::endl;
+
+ printStructure(part->getStructure(), level + 1);
+ }
+}
+
+
+static const vmime::string getFolderPathString(vmime::shared_ptr <vmime::net::folder> f) {
+
+ const vmime::string n = f->getName().getBuffer();
+
+ if (n.empty()) { // root folder
+
+ return "/";
+
+ } else {
+
+ vmime::shared_ptr <vmime::net::folder> p = f->getParent();
+ return getFolderPathString(p) + n + "/";
+ }
+}
+
+
+/** Print folders and sub-folders on the standard output.
+ *
+ * @param folder current folder
+ */
+static void printFolders(vmime::shared_ptr <vmime::net::folder> folder, const int level = 0) {
+
+ for (int j = 0 ; j < level * 2 ; ++j) {
+ std::cout << " ";
+ }
+
+ const vmime::net::folderAttributes attr = folder->getAttributes();
+ std::ostringstream attrStr;
+
+ if (attr.getSpecialUse() == vmime::net::folderAttributes::SPECIALUSE_ALL) {
+ attrStr << " \\use:All";
+ } else if (attr.getSpecialUse() == vmime::net::folderAttributes::SPECIALUSE_ARCHIVE) {
+ attrStr << " \\use:Archive";
+ } else if (attr.getSpecialUse() == vmime::net::folderAttributes::SPECIALUSE_DRAFTS) {
+ attrStr << " \\use:Drafts";
+ } else if (attr.getSpecialUse() == vmime::net::folderAttributes::SPECIALUSE_FLAGGED) {
+ attrStr << " \\use:Flagged";
+ } else if (attr.getSpecialUse() == vmime::net::folderAttributes::SPECIALUSE_JUNK) {
+ attrStr << " \\use:Junk";
+ } else if (attr.getSpecialUse() == vmime::net::folderAttributes::SPECIALUSE_SENT) {
+ attrStr << " \\use:Sent";
+ } else if (attr.getSpecialUse() == vmime::net::folderAttributes::SPECIALUSE_TRASH) {
+ attrStr << " \\use:Trash";
+ } else if (attr.getSpecialUse() == vmime::net::folderAttributes::SPECIALUSE_IMPORTANT) {
+ attrStr << " \\use:Important";
+ }
+
+ if (attr.getFlags() & vmime::net::folderAttributes::FLAG_HAS_CHILDREN) {
+ attrStr << " \\flag:HasChildren";
+ }
+ if (attr.getFlags() & vmime::net::folderAttributes::FLAG_NO_OPEN) {
+ attrStr << " \\flag:NoOpen";
+ }
+
+ for (size_t i = 0, n = attr.getUserFlags().size() ; i < n ; ++i) {
+ attrStr << " \\" << attr.getUserFlags()[i];
+ }
+
+ std::cout << getFolderPathString(folder);
+ std::cout << " " << attrStr.str();
+ std::cout << std::endl;
+
+ std::vector <vmime::shared_ptr <vmime::net::folder> > subFolders = folder->getFolders(false);
+
+ for (unsigned int i = 0 ; i < subFolders.size() ; ++i) {
+ printFolders(subFolders[i], level + 1);
+ }
+}
+
+
+/** Print a menu on the standard output.
+ *
+ * @param choices menu choices
+ */
+static unsigned int printMenu(const std::vector <std::string>& choices) {
+
+ std::cout << std::endl;
+
+ for (unsigned int i = 0 ; i < choices.size() ; ++i) {
+ std::cout << " " << (i + 1) << ". " << choices[i] << std::endl;
+ }
+
+ std::cout << std::endl;
+ std::cout << " Your choice? [1-" << choices.size() << "] ";
+ std::cout.flush();
+
+ std::string line;
+ std::getline(std::cin, line);
+
+ std::istringstream iss(line);
+
+ unsigned int choice = 0;
+ iss >> choice;
+
+ std::cout << std::endl;
+
+ if (choice < 1 || choice > choices.size()) {
+ return 0;
+ } else {
+ return choice;
+ }
+}
+
+
+/** Send a message interactively.
+ */
+static void sendMessage() {
+
+ try {
+
+ // Request user to enter an URL
+ std::cout << "Enter an URL to connect to transport service." << std::endl;
+ std::cout << "Available protocols: " << findAvailableProtocols(vmime::net::service::TYPE_TRANSPORT) << std::endl;
+ std::cout << "(eg. smtp://myserver.com, sendmail://localhost)" << std::endl;
+ std::cout << "> ";
+ std::cout.flush();
+
+ vmime::string urlString;
+ std::getline(std::cin, urlString);
+
+ vmime::utility::url url(urlString);
+
+ vmime::shared_ptr <vmime::net::transport> tr;
+
+ if (url.getUsername().empty() || url.getPassword().empty()) {
+ tr = g_session->getTransport(url, vmime::make_shared <interactiveAuthenticator>());
+ } else {
+ tr = g_session->getTransport(url);
+ }
+
+#if VMIME_HAVE_TLS_SUPPORT
+
+ // Enable TLS support if available
+ tr->setProperty("connection.tls", true);
+
+ // Set the time out handler
+ tr->setTimeoutHandlerFactory(vmime::make_shared <timeoutHandlerFactory>());
+
+ // Set the object responsible for verifying certificates, in the
+ // case a secured connection is used (TLS/SSL)
+ tr->setCertificateVerifier(
+ vmime::make_shared <interactiveCertificateVerifier>()
+ );
+
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+ // You can also set some properties (see example7 to know the properties
+ // available for each service). For example, for SMTP:
+ if (!url.getUsername().empty() || !url.getPassword().empty()) {
+ tr->setProperty("options.need-authentication", true);
+ }
+
+ // Trace communication between client and server
+ vmime::shared_ptr <std::ostringstream> traceStream = vmime::make_shared <std::ostringstream>();
+ tr->setTracerFactory(vmime::make_shared <myTracerFactory>(traceStream));
+
+ // Information about the mail
+ std::cout << "Enter email of the expeditor (eg. me@somewhere.com): ";
+ std::cout.flush();
+
+ vmime::string fromString;
+ std::getline(std::cin, fromString);
+
+ vmime::mailbox from(fromString);
+ vmime::mailboxList to;
+
+ for (bool cont = true ; cont ; ) {
+
+ std::cout << "Enter email of the recipient (empty to stop): ";
+ std::cout.flush();
+
+ vmime::string toString;
+ std::getline(std::cin, toString);
+
+ cont = (toString.size() != 0);
+
+ if (cont) {
+ to.appendMailbox(vmime::make_shared <vmime::mailbox>(toString));
+ }
+ }
+
+ std::cout << "Enter message data, including headers (end with '.' on a single line):" << std::endl;
+
+ std::ostringstream data;
+
+ for (bool cont = true ; cont ; ) {
+
+ std::string line;
+ std::getline(std::cin, line);
+
+ if (line == ".") {
+ cont = false;
+ } else {
+ data << line << "\r\n";
+ }
+ }
+
+ // Connect to server
+ tr->connect();
+
+ // Send the message
+ vmime::string msgData = data.str();
+ vmime::utility::inputStreamStringAdapter vis(msgData);
+
+ tr->send(from, to, vis, msgData.length());
+
+ // Note: you could also write this:
+ // vmime::message msg;
+ // ...
+ // tr->send(&msg);
+
+ // Display connection log
+ std::cout << std::endl;
+ std::cout << "Connection Trace:" << std::endl;
+ std::cout << "=================" << std::endl;
+ std::cout << traceStream->str();
+
+ tr->disconnect();
+
+ } catch (vmime::exception& e) {
+
+ std::cerr << std::endl;
+ std::cerr << e << std::endl;
+ throw;
+
+ } catch (std::exception& e) {
+
+ std::cerr << std::endl;
+ std::cerr << "std::exception: " << e.what() << std::endl;
+ throw;
+ }
+}
+
+
+/** Connect to a message store interactively.
+ */
+static void connectStore() {
+
+ try {
+
+ // Request user to enter an URL
+ std::cout << "Enter an URL to connect to store service." << std::endl;
+ std::cout << "Available protocols: " << findAvailableProtocols(vmime::net::service::TYPE_STORE) << std::endl;
+ std::cout << "(eg. pop3://user:pass@myserver.com, imap://myserver.com:123)" << std::endl;
+ std::cout << "> ";
+ std::cout.flush();
+
+ vmime::string urlString;
+ std::getline(std::cin, urlString);
+
+ vmime::utility::url url(urlString);
+
+ // If no authenticator is given in argument to getStore(), a default one
+ // is used. Its behaviour is to get the user credentials from the
+ // session properties "auth.username" and "auth.password".
+ vmime::shared_ptr <vmime::net::store> st;
+
+ if (url.getUsername().empty() || url.getPassword().empty()) {
+ st = g_session->getStore(url, vmime::make_shared <interactiveAuthenticator>());
+ } else {
+ st = g_session->getStore(url);
+ }
+
+#if VMIME_HAVE_TLS_SUPPORT
+
+ // Enable TLS support if available
+ st->setProperty("connection.tls", true);
+
+ // Set the time out handler
+ st->setTimeoutHandlerFactory(vmime::make_shared <timeoutHandlerFactory>());
+
+ // Set the object responsible for verifying certificates, in the
+ // case a secured connection is used (TLS/SSL)
+ st->setCertificateVerifier(
+ vmime::make_shared <interactiveCertificateVerifier>()
+ );
+
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+ // Trace communication between client and server
+ vmime::shared_ptr <std::ostringstream> traceStream = vmime::make_shared <std::ostringstream>();
+ st->setTracerFactory(vmime::make_shared <myTracerFactory>(traceStream));
+
+ // Connect to the mail store
+ st->connect();
+
+ // Display some information about the connection
+ vmime::shared_ptr <vmime::net::connectionInfos> ci = st->getConnectionInfos();
+
+ std::cout << std::endl;
+ std::cout << "Connected to '" << ci->getHost() << "' (port " << ci->getPort() << ")" << std::endl;
+ std::cout << "Connection is " << (st->isSecuredConnection() ? "" : "NOT ") << "secured." << std::endl;
+
+ // Open the default folder in this store
+ vmime::shared_ptr <vmime::net::folder> f = st->getDefaultFolder();
+// vmime::shared_ptr <vmime::net::folder> f = st->getFolder(vmime::utility::path("a"));
+
+ f->open(vmime::net::folder::MODE_READ_WRITE);
+
+ vmime::size_t count = f->getMessageCount();
+
+ std::cout << std::endl;
+ std::cout << count << " message(s) in your inbox" << std::endl;
+
+ for (bool cont = true ; cont ; ) {
+
+ typedef std::map <vmime::size_t, vmime::shared_ptr <vmime::net::message> > MessageList;
+ MessageList msgList;
+
+ try {
+
+ std::vector <std::string> choices;
+
+ choices.push_back("Show message flags");
+ choices.push_back("Show message structure");
+ choices.push_back("Show message header");
+ choices.push_back("Show message envelope");
+ choices.push_back("Extract whole message");
+ choices.push_back("Extract attachments");
+ choices.push_back("Status");
+ choices.push_back("List folders");
+ choices.push_back("Change folder");
+ choices.push_back("Add message (to the current folder)");
+ choices.push_back("Copy message (into the current folder)");
+ choices.push_back("Display trace output");
+ choices.push_back("Return to main menu");
+
+ const int choice = printMenu(choices);
+
+ // Request message number
+ vmime::shared_ptr <vmime::net::message> msg;
+
+ if (choice == 1 || choice == 2 || choice == 3 || choice == 4 ||
+ choice == 5 || choice == 6 || choice == 11) {
+
+ std::cout << "Enter message number: ";
+ std::cout.flush();
+
+ std::string line;
+ std::getline(std::cin, line);
+
+ std::istringstream iss(line);
+
+ vmime::size_t num = 0;
+ iss >> num;
+
+ if (num < 1 || num > f->getMessageCount()) {
+
+ std::cerr << "Invalid message number." << std::endl;
+ continue;
+ }
+
+ MessageList::iterator it = msgList.find(num);
+
+ if (it != msgList.end()) {
+
+ msg = (*it).second;
+
+ } else {
+
+ msg = f->getMessage(num);
+ msgList.insert(MessageList::value_type(num, msg));
+ }
+
+ std::cout << std::endl;
+ }
+
+ switch (choice) {
+
+ // Show message flags
+ case 1:
+
+ f->fetchMessage(msg, vmime::net::fetchAttributes::FLAGS);
+
+ if (msg->getFlags() & vmime::net::message::FLAG_SEEN) {
+ std::cout << "FLAG_SEEN" << std::endl;
+ }
+ if (msg->getFlags() & vmime::net::message::FLAG_RECENT) {
+ std::cout << "FLAG_RECENT" << std::endl;
+ }
+ if (msg->getFlags() & vmime::net::message::FLAG_REPLIED) {
+ std::cout << "FLAG_REPLIED" << std::endl;
+ }
+ if (msg->getFlags() & vmime::net::message::FLAG_DELETED) {
+ std::cout << "FLAG_DELETED" << std::endl;
+ }
+ if (msg->getFlags() & vmime::net::message::FLAG_MARKED) {
+ std::cout << "FLAG_MARKED" << std::endl;
+ }
+ if (msg->getFlags() & vmime::net::message::FLAG_PASSED) {
+ std::cout << "FLAG_PASSED" << std::endl;
+ }
+
+ break;
+
+ // Show message structure
+ case 2:
+
+ f->fetchMessage(msg, vmime::net::fetchAttributes::STRUCTURE);
+ printStructure(msg->getStructure());
+ break;
+
+ // Show message header
+ case 3:
+
+ f->fetchMessage(msg, vmime::net::fetchAttributes::FULL_HEADER);
+ std::cout << msg->getHeader()->generate() << std::endl;
+ break;
+
+ // Show message envelope
+ case 4: {
+
+ vmime::net::fetchAttributes attr(vmime::net::fetchAttributes::ENVELOPE);
+
+ // If you also want to fetch "Received: " fields:
+ //attr.add("Received");
+
+ f->fetchMessage(msg, attr);
+
+ std::cout << msg->getHeader()->generate() << std::endl;
+
+ break;
+ }
+ // Extract whole message
+ case 5: {
+
+ vmime::utility::outputStreamAdapter out(std::cout);
+ msg->extract(out);
+
+ break;
+ }
+ // Extract attachments
+ case 6: {
+
+ vmime::shared_ptr <vmime::message> parsedMsg = msg->getParsedMessage();
+
+ std::vector <vmime::shared_ptr <const vmime::attachment> > attchs =
+ vmime::attachmentHelper::findAttachmentsInMessage(parsedMsg);
+
+ if (attchs.size() > 0) {
+
+ std::cout << attchs.size() << " attachments found." << std::endl;
+
+ for (std::vector <vmime::shared_ptr <const vmime::attachment> >::iterator
+ it = attchs.begin() ; it != attchs.end() ; ++it) {
+
+ vmime::shared_ptr <const vmime::attachment> att = *it;
+
+ // Get attachment size
+ vmime::size_t size = 0;
+
+ if (att->getData()->isEncoded()) {
+ size = att->getData()->getEncoding().getEncoder()->getDecodedSize(att->getData()->getLength());
+ } else {
+ size = att->getData()->getLength();
+ }
+
+ std::cout << "Found attachment '" << att->getName().getBuffer() << "'"
+ << ", size is " << size << " bytes:" << std::endl;
+
+ // Get attachment data
+ std::cout << std::endl;
+ std::cout << "========== BEGIN CONTENT ==========" << std::endl;
+
+ vmime::utility::outputStreamAdapter osa(std::cout);
+ att->getData()->extract(osa);
+
+ std::cout << std::endl;
+ std::cout << "========== END CONTENT ==========" << std::endl;
+
+ // Or write it to a file
+ /*
+ vmime::shared_ptr <vmime::utility::fileSystemFactory> fsf
+ = vmime::platform::getHandler()->getFileSystemFactory();
+
+ vmime::shared_ptr <vmime::utility::file> file
+ = fsf->create(vmime::utility::path::fromString
+ ("/path/to/attachment-file", "/", vmime::charsets::UTF_8));
+ // -or- ("C:\\Temp\\attachment-file", "\\", vmime::charsets::UTF_8));
+
+ file->createFile();
+
+ vmime::shared_ptr <vmime::utility::outputStream> output =
+ file->getFileWriter()->getOutputStream();
+
+ att->getData()->extract(*output.get());
+ */
+ }
+
+ } else {
+
+ std::cout << "No attachments found." << std::endl;
+ }
+
+ break;
+ }
+ // Status
+ case 7: {
+
+ vmime::size_t count, unseen;
+ f->status(count, unseen);
+
+ std::cout << "Status: count=" << count << ", unseen=" << unseen << std::endl;
+ break;
+ }
+ // List folders
+ case 8: {
+
+ vmime::shared_ptr <vmime::net::folder> root = st->getRootFolder();
+
+ printFolders(root);
+ break;
+ }
+ // Change folder
+ case 9: {
+
+ std::cout << "Enter folder path (eg. /root/subfolder):" << std::endl;
+ std::cout.flush();
+
+ std::string path;
+ std::getline(std::cin, path);
+
+ vmime::shared_ptr <vmime::net::folder> newFolder = st->getRootFolder();
+
+ for (std::string::size_type s = 0, p = 0 ; ; s = p + 1) {
+
+ p = path.find_first_of('/', s);
+
+ const std::string x = (p == std::string::npos)
+ ? std::string(path.begin() + s, path.end())
+ : std::string(path.begin() + s, path.begin() + p);
+
+ if (!x.empty()) {
+ newFolder = newFolder->getFolder(vmime::utility::path::component(x));
+ }
+
+ if (p == std::string::npos) {
+ break;
+ }
+ }
+
+ newFolder->open(vmime::net::folder::MODE_READ_WRITE);
+
+ count = newFolder->getMessageCount();
+
+ std::cout << std::endl;
+ std::cout << count << " message(s) in this folder" << std::endl;
+
+ f->close(true); // 'true' to expunge deleted messages
+ f = newFolder;
+
+ break;
+ }
+ // Add message
+ case 10: {
+
+ vmime::messageBuilder mb;
+
+ mb.setExpeditor(vmime::mailbox("me@somewhere.com"));
+
+ vmime::addressList to;
+ to.appendAddress(vmime::make_shared <vmime::mailbox>("you@elsewhere.com"));
+ mb.setRecipients(to);
+
+ mb.setSubject(vmime::text("Test message from VMime example6"));
+ mb.getTextPart()->setText(
+ vmime::make_shared <vmime::stringContentHandler>(
+ "Body of test message from VMime example6."
+ )
+ );
+
+ vmime::shared_ptr <vmime::message> msg = mb.construct();
+
+ vmime::net::messageSet set = f->addMessage(msg);
+
+ if (set.isEmpty()) {
+
+ std::cout << "Message has successfully been added, "
+ << "but its UID/number is not known." << std::endl;
+
+ } else {
+
+ const vmime::net::messageRange& range = set.getRangeAt(0);
+
+ if (set.isUIDSet()) {
+
+ const vmime::net::message::uid uid =
+ dynamic_cast <const vmime::net::UIDMessageRange&>(range).getFirst();
+
+ std::cout << "Message has successfully been added, "
+ << "its UID is '" << uid << "'." << std::endl;
+
+ } else {
+
+ const vmime::size_t number =
+ dynamic_cast <const vmime::net::numberMessageRange&>(range).getFirst();
+
+ std::cout << "Message has successfully been added, "
+ << "its number is '" << number << "'." << std::endl;
+ }
+ }
+
+ break;
+ }
+ // Copy message
+ case 11: {
+
+ vmime::net::messageSet set = f->copyMessages(f->getFullPath(),
+ vmime::net::messageSet::byNumber(msg->getNumber()));
+
+ if (set.isEmpty()) {
+
+ std::cout << "Message has successfully been copied, "
+ << "but its UID/number is not known." << std::endl;
+
+ } else {
+
+ const vmime::net::messageRange& range = set.getRangeAt(0);
+
+ if (set.isUIDSet()) {
+
+ const vmime::net::message::uid uid =
+ dynamic_cast <const vmime::net::UIDMessageRange&>(range).getFirst();
+
+ std::cout << "Message has successfully been copied, "
+ << "its UID is '" << uid << "'." << std::endl;
+
+ } else {
+
+ const vmime::size_t number =
+ dynamic_cast <const vmime::net::numberMessageRange&>(range).getFirst();
+
+ std::cout << "Message has successfully been copied, "
+ << "its number is '" << number << "'." << std::endl;
+ }
+ }
+
+ break;
+ }
+ // Display trace output
+ case 12:
+
+ std::cout << std::endl;
+ std::cout << "Connection Trace:" << std::endl;
+ std::cout << "=================" << std::endl;
+ std::cout << traceStream->str();
+ break;
+
+ // Main menu
+ case 13:
+
+ f->close(true); // 'true' to expunge deleted messages
+ cont = false;
+ break;
+ }
+
+/*
+ // Append message
+ std::istringstream iss(
+ "From: me@localhost\r\n"
+ "To: you@localhost\r\n"
+ "Subject: Message Text\r\n"
+ "\r\n"
+ "This is a test message...\r\n"
+ "Bye bye!\r\n"
+ );
+
+ f->addMessage(iss, iss.str().size());
+
+ // Folder renaming
+ {
+ vmime::shared_ptr <vmime::net::folder> f = st->getFolder(vmime::net::folder::path("c"));
+ f->rename(vmime::net::folder::path("c2"));
+
+ vmime::shared_ptr <vmime::net::folder> g = st->getFolder(vmime::net::folder::path("c2"));
+ g->rename(vmime::net::folder::path("c"));
+ }
+
+ // Message copy: copy all messages from 'f' to 'g'
+ {
+ vmime::shared_ptr <vmime::net::folder> g = st->getFolder(vmime::net::folder::path("TEMP"));
+
+ if (!g->exists()) {
+ g->create(vmime::net::folder::TYPE_CONTAINS_MESSAGES);
+ }
+
+ f->copyMessages(g->getFullPath());
+ }
+*/
+
+ } catch (vmime::exception& e) {
+
+ std::cerr << std::endl;
+ std::cerr << e << std::endl;
+
+ } catch (std::exception& e) {
+
+ std::cerr << std::endl;
+ std::cerr << "std::exception: " << e.what() << std::endl;
+ }
+
+ } // for(cont)
+
+ st->disconnect();
+
+ } catch (vmime::exception& e) {
+
+ std::cerr << std::endl;
+ std::cerr << e << std::endl;
+ throw;
+
+ } catch (std::exception& e) {
+
+ std::cerr << std::endl;
+ std::cerr << "std::exception: " << e.what() << std::endl;
+ throw;
+ }
+}
+
+
+/* Show the main menu.
+ *
+ * @return true to quit the program, false to continue
+ */
+static bool menu() {
+
+ std::vector <std::string> items;
+
+ items.push_back("Connect to a message store");
+ items.push_back("Send a message");
+ items.push_back("Quit");
+
+ switch (printMenu(items)) {
+
+ // Connect to store
+ case 1:
+
+ connectStore();
+ return false;
+
+ // Send a message
+ case 2:
+
+ sendMessage();
+ return false;
+
+ // Quit
+ case 3:
+
+ return true;
+
+ // Other choice
+ default:
+
+ return false;
+ }
+}
+
+
+int main() {
+
+ // Set the global C and C++ locale to the user-configured locale.
+ // The locale should use UTF-8 encoding for these tests to run successfully.
+ try {
+ std::locale::global(std::locale(""));
+ } catch (std::exception &) {
+ std::setlocale(LC_ALL, "");
+ }
+
+ for (bool quit = false ; !quit ; ) {
+
+ // Loop on main menu
+ quit = menu();
+ }
+
+ return 0;
+}
diff --git a/vmime-master/examples/example6_authenticator.hpp b/vmime-master/examples/example6_authenticator.hpp
new file mode 100644
index 0000000..56f0239
--- /dev/null
+++ b/vmime-master/examples/example6_authenticator.hpp
@@ -0,0 +1,112 @@
+
+
+#if VMIME_HAVE_SASL_SUPPORT
+
+// SASL authentication handler
+class interactiveAuthenticator : public vmime::security::sasl::defaultSASLAuthenticator {
+
+ const std::vector <vmime::shared_ptr <vmime::security::sasl::SASLMechanism> >
+ getAcceptableMechanisms(
+ const std::vector <vmime::shared_ptr <vmime::security::sasl::SASLMechanism> >& available,
+ const vmime::shared_ptr <vmime::security::sasl::SASLMechanism>& suggested
+ ) const {
+
+ std::cout << std::endl << "Available SASL mechanisms:" << std::endl;
+
+ for (unsigned int i = 0 ; i < available.size() ; ++i) {
+
+ std::cout << " " << available[i]->getName();
+
+ if (suggested && available[i]->getName() == suggested->getName()) {
+ std::cout << "(suggested)";
+ }
+ }
+
+ std::cout << std::endl << std::endl;
+
+ return defaultSASLAuthenticator::getAcceptableMechanisms(available, suggested);
+ }
+
+ void setSASLMechanism(const vmime::shared_ptr <vmime::security::sasl::SASLMechanism>& mech) {
+
+ std::cout << "Trying '" << mech->getName() << "' authentication mechanism" << std::endl;
+
+ defaultSASLAuthenticator::setSASLMechanism(mech);
+ }
+
+ const vmime::string getUsername() const {
+
+ if (m_username.empty()) {
+ m_username = getUserInput("Username");
+ }
+
+ return m_username;
+ }
+
+ const vmime::string getPassword() const {
+
+ if (m_password.empty()) {
+ m_password = getUserInput("Password");
+ }
+
+ return m_password;
+ }
+
+ static const vmime::string getUserInput(const std::string& prompt) {
+
+ std::cout << prompt << ": ";
+ std::cout.flush();
+
+ vmime::string res;
+ std::getline(std::cin, res);
+
+ return res;
+ }
+
+private:
+
+ mutable vmime::string m_username;
+ mutable vmime::string m_password;
+};
+
+#else // !VMIME_HAVE_SASL_SUPPORT
+
+// Simple authentication handler
+class interactiveAuthenticator : public vmime::security::defaultAuthenticator {
+
+ const vmime::string getUsername() const {
+
+ if (m_username.empty()) {
+ m_username = getUserInput("Username");
+ }
+
+ return m_username;
+ }
+
+ const vmime::string getPassword() const {
+
+ if (m_password.empty()) {
+ m_password = getUserInput("Password");
+ }
+
+ return m_password;
+ }
+
+ static const vmime::string getUserInput(const std::string& prompt) {
+
+ std::cout << prompt << ": ";
+ std::cout.flush();
+
+ vmime::string res;
+ std::getline(std::cin, res);
+
+ return res;
+ }
+
+private:
+
+ mutable vmime::string m_username;
+ mutable vmime::string m_password;
+};
+
+#endif // VMIME_HAVE_SASL_SUPPORT
diff --git a/vmime-master/examples/example6_certificateVerifier.hpp b/vmime-master/examples/example6_certificateVerifier.hpp
new file mode 100644
index 0000000..3d8bf82
--- /dev/null
+++ b/vmime-master/examples/example6_certificateVerifier.hpp
@@ -0,0 +1,64 @@
+
+
+#if VMIME_HAVE_TLS_SUPPORT
+
+// Certificate verifier (TLS/SSL)
+class interactiveCertificateVerifier : public vmime::security::cert::defaultCertificateVerifier {
+
+public:
+
+ void verify(
+ const vmime::shared_ptr <vmime::security::cert::certificateChain>& chain,
+ const vmime::string& hostname
+ ) {
+
+ try {
+
+ setX509TrustedCerts(m_trustedCerts);
+
+ defaultCertificateVerifier::verify(chain, hostname);
+
+ } catch (vmime::security::cert::certificateException&) {
+
+ // Obtain subject's certificate
+ vmime::shared_ptr <vmime::security::cert::certificate> cert = chain->getAt(0);
+
+ std::cout << std::endl;
+ std::cout << "Server sent a '" << cert->getType() << "'" << " certificate." << std::endl;
+ std::cout << "Do you want to accept this certificate? (Y/n) ";
+ std::cout.flush();
+
+ std::string answer;
+ std::getline(std::cin, answer);
+
+ if (answer.length() != 0 &&
+ (answer[0] == 'Y' || answer[0] == 'y')) {
+
+ // Accept it, and remember user's choice for later
+ if (cert->getType() == "X.509") {
+
+ m_trustedCerts.push_back(
+ vmime::dynamicCast <vmime::security::cert::X509Certificate>(cert)
+ );
+
+ setX509TrustedCerts(m_trustedCerts);
+ defaultCertificateVerifier::verify(chain, hostname);
+ }
+
+ return;
+ }
+
+ throw vmime::security::cert::certificateException("User did not accept the certificate.");
+ }
+ }
+
+private:
+
+ static std::vector <vmime::shared_ptr <vmime::security::cert::X509Certificate> > m_trustedCerts;
+};
+
+
+std::vector <vmime::shared_ptr <vmime::security::cert::X509Certificate> >
+ interactiveCertificateVerifier::m_trustedCerts;
+
+#endif // VMIME_HAVE_TLS_SUPPORT
diff --git a/vmime-master/examples/example6_timeoutHandler.hpp b/vmime-master/examples/example6_timeoutHandler.hpp
new file mode 100644
index 0000000..7999084
--- /dev/null
+++ b/vmime-master/examples/example6_timeoutHandler.hpp
@@ -0,0 +1,60 @@
+#include <ctime>
+
+
+/** Time out handler.
+ * Used to stop the current operation after too much time, or if the user
+ * requested cancellation.
+ */
+class timeoutHandler : public vmime::net::timeoutHandler {
+
+public:
+
+ timeoutHandler()
+ : m_start(time(NULL)) {
+
+ }
+
+ bool isTimeOut() {
+
+ // This is a cancellation point: return true if you want to cancel
+ // the current operation. If you return true, handleTimeOut() will
+ // be called just after this, and before actually cancelling the
+ // operation
+
+ // 10 seconds timeout
+ return (time(NULL) - m_start) >= 10; // seconds
+ }
+
+ void resetTimeOut() {
+
+ // Called at the beginning of an operation (eg. connecting,
+ // a read() or a write() on a socket...)
+ m_start = time(NULL);
+ }
+
+ bool handleTimeOut() {
+
+ // If isTimeOut() returned true, this function will be called. This
+ // allows you to interact with the user, ie. display a prompt to
+ // know whether he wants to cancel the operation.
+
+ // If you return false here, the operation will be actually cancelled.
+ // If true, the time out is reset and the operation continues.
+ return false;
+ }
+
+private:
+
+ time_t m_start;
+};
+
+
+class timeoutHandlerFactory : public vmime::net::timeoutHandlerFactory {
+
+public:
+
+ vmime::shared_ptr <vmime::net::timeoutHandler> create() {
+
+ return vmime::make_shared <timeoutHandler>();
+ }
+};
diff --git a/vmime-master/examples/example6_tracer.hpp b/vmime-master/examples/example6_tracer.hpp
new file mode 100644
index 0000000..27090cf
--- /dev/null
+++ b/vmime-master/examples/example6_tracer.hpp
@@ -0,0 +1,59 @@
+
+/** Tracer used to demonstrate logging communication between client and server.
+ */
+class myTracer : public vmime::net::tracer {
+
+public:
+
+ myTracer(
+ const vmime::shared_ptr <std::ostringstream>& stream,
+ const vmime::shared_ptr <vmime::net::service>& serv,
+ const int connectionId
+ )
+ : m_stream(stream),
+ m_service(serv),
+ m_connectionId(connectionId) {
+
+ }
+
+ void traceSend(const vmime::string& line) {
+
+ *m_stream << "[" << m_service->getProtocolName() << ":" << m_connectionId
+ << "] C: " << line << std::endl;
+ }
+
+ void traceReceive(const vmime::string& line) {
+
+ *m_stream << "[" << m_service->getProtocolName() << ":" << m_connectionId
+ << "] S: " << line << std::endl;
+ }
+
+private:
+
+ vmime::shared_ptr <std::ostringstream> m_stream;
+ vmime::shared_ptr <vmime::net::service> m_service;
+ const int m_connectionId;
+};
+
+
+class myTracerFactory : public vmime::net::tracerFactory {
+
+public:
+
+ myTracerFactory(const vmime::shared_ptr <std::ostringstream>& stream)
+ : m_stream(stream) {
+
+ }
+
+ vmime::shared_ptr <vmime::net::tracer> create(
+ const vmime::shared_ptr <vmime::net::service>& serv,
+ const int connectionId
+ ) {
+
+ return vmime::make_shared <myTracer>(m_stream, serv, connectionId);
+ }
+
+private:
+
+ vmime::shared_ptr <std::ostringstream> m_stream;
+};
diff --git a/vmime-master/examples/example7.cpp b/vmime-master/examples/example7.cpp
new file mode 100644
index 0000000..db96dbd
--- /dev/null
+++ b/vmime-master/examples/example7.cpp
@@ -0,0 +1,118 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+//
+// EXAMPLE DESCRIPTION:
+// ====================
+// This sample program demonstrates how to enumerate encoders and
+// messaging services in VMime.
+//
+// For more information, please visit:
+// http://www.vmime.org/
+//
+
+#include <iostream>
+#include <locale>
+#include <clocale>
+
+#include "vmime/vmime.hpp"
+#include "vmime/platforms/posix/posixHandler.hpp"
+
+
+int main() {
+
+ // Enumerate encoders
+ vmime::shared_ptr <vmime::utility::encoder::encoderFactory> ef =
+ vmime::utility::encoder::encoderFactory::getInstance();
+
+ std::cout << "Available encoders:" << std::endl;
+
+ for (size_t i = 0 ; i < ef->getEncoderCount() ; ++i) {
+
+ vmime::shared_ptr <const vmime::utility::encoder::encoderFactory::registeredEncoder>
+ enc = ef->getEncoderAt(i);
+
+ std::cout << " * " << enc->getName() << std::endl;
+
+ vmime::shared_ptr <vmime::utility::encoder::encoder> e =
+ vmime::utility::encoder::encoderFactory::getInstance()->create(enc->getName());
+
+ std::vector <vmime::string> props = e->getAvailableProperties();
+
+ for (std::vector <vmime::string>::const_iterator it = props.begin() ; it != props.end() ; ++it) {
+ std::cout << " - " << *it << std::endl;
+ }
+ }
+
+ std::cout << std::endl;
+
+ // Enumerate messaging services and their properties
+ vmime::shared_ptr <vmime::net::serviceFactory> sf =
+ vmime::net::serviceFactory::getInstance();
+
+ std::cout << "Available messaging services:" << std::endl;
+
+ for (size_t i = 0 ; i < sf->getServiceCount() ; ++i) {
+
+ const vmime::net::serviceFactory::registeredService& serv = *sf->getServiceAt(i);
+
+ std::cout << " * " << serv.getName() << std::endl;
+
+ std::vector <vmime::net::serviceInfos::property> props =
+ serv.getInfos().getAvailableProperties();
+
+ for (std::vector <vmime::net::serviceInfos::property>::const_iterator it = props.begin() ;
+ it != props.end() ; ++it) {
+
+ const vmime::net::serviceInfos::property& p = *it;
+
+ const vmime::string name = serv.getInfos().getPropertyPrefix() + p.getName();
+
+ vmime::string type;
+
+ switch (p.getType()) {
+ case vmime::net::serviceInfos::property::TYPE_INTEGER: type = "TYPE_INTEGER"; break;
+ case vmime::net::serviceInfos::property::TYPE_STRING: type = "TYPE_STRING"; break;
+ case vmime::net::serviceInfos::property::TYPE_BOOLEAN: type = "TYPE_BOOLEAN"; break;
+ default: type = "(unknown)"; break;
+ }
+
+ vmime::string flags;
+
+ if (p.getFlags() & vmime::net::serviceInfos::property::FLAG_REQUIRED) {
+ flags += " FLAG_REQUIRED";
+ }
+ if (p.getFlags() & vmime::net::serviceInfos::property::FLAG_HIDDEN) {
+ flags += " FLAG_HIDDEN";
+ }
+
+ std::cout << " - " << serv.getInfos().getPropertyPrefix() + p.getName();
+ std::cout << " (type=" << type << ", flags=" << flags;
+ std::cout << ", defaultValue=" << p.getDefaultValue() << ")" << std::endl;
+ }
+ }
+
+ std::cout << std::endl;
+
+ return 0;
+}
diff --git a/vmime-master/examples/viewer/CMakeLists.txt b/vmime-master/examples/viewer/CMakeLists.txt
new file mode 100644
index 0000000..c8d9316
--- /dev/null
+++ b/vmime-master/examples/viewer/CMakeLists.txt
@@ -0,0 +1,31 @@
+
+IF(VMIME_BUILD_SAMPLES)
+
+ FIND_PACKAGE(PkgConfig REQUIRED)
+ PKG_CHECK_MODULES(GTK3 REQUIRED gtk+-3.0)
+
+ INCLUDE_DIRECTORIES(${GTK3_INCLUDE_DIRS})
+ LINK_DIRECTORIES(${GTK3_LIBRARY_DIRS})
+ ADD_DEFINITIONS(${GTK3_CFLAGS_OTHER})
+
+ ADD_EXECUTABLE(
+ viewer
+ viewer.cpp
+ )
+
+ TARGET_LINK_LIBRARIES(
+ viewer
+ ${VMIME_LIBRARY_NAME}
+ ${GTK3_LIBRARIES}
+ )
+
+ ADD_DEPENDENCIES(
+ viewer
+ ${VMIME_LIBRARY_NAME}
+ )
+
+ELSE()
+
+ MESSAGE(FATAL_ERROR "Examples are not to be built (set VMIME_BUILD_SAMPLES to YES.")
+
+ENDIF()
diff --git a/vmime-master/examples/viewer/viewer.cpp b/vmime-master/examples/viewer/viewer.cpp
new file mode 100644
index 0000000..a03120a
--- /dev/null
+++ b/vmime-master/examples/viewer/viewer.cpp
@@ -0,0 +1,294 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+//
+// EXAMPLE DESCRIPTION:
+// ====================
+// A simple MIME viewer to show all the components of a message.
+// The user interface is written using GTK+ 2.6.
+//
+// For more information, please visit:
+// http://www.vmime.org/
+//
+
+#include <iostream>
+#include <fstream>
+#include <vector>
+#include <typeinfo>
+
+#include <gtk/gtk.h>
+
+#include "vmime/vmime.hpp"
+#include "vmime/platforms/posix/posixHandler.hpp"
+
+
+
+GtkWidget* window = NULL;
+GtkWidget* treeView = NULL;
+GtkWidget* textArea = NULL;
+
+GtkTreeStore* treeModel = NULL;
+
+vmime::shared_ptr <vmime::message> currentMessage;
+
+
+
+void insertRowInModel(
+ GtkTreeStore* model,
+ vmime::shared_ptr <vmime::component> comp,
+ GtkTreeIter* parent = NULL
+) {
+
+ GtkTreeIter iter;
+
+ gtk_tree_store_append(model, &iter, parent);
+ gtk_tree_store_set(model, &iter, 0, typeid(*comp).name(), 1, comp.get(), -1);
+
+ const std::vector <vmime::shared_ptr <vmime::component> > children = comp->getChildComponents();
+
+ for (int i = 0 ; i < children.size() ; ++i) {
+ insertRowInModel(model, children[i], &iter);
+ }
+}
+
+
+void updateTreeView() {
+
+ GtkTreeStore* model = GTK_TREE_STORE(gtk_tree_view_get_model(GTK_TREE_VIEW(treeView)));
+
+ g_object_ref(model);
+ gtk_tree_view_set_model(GTK_TREE_VIEW(treeView), NULL);
+
+ gtk_tree_store_clear(model);
+
+ insertRowInModel(model, currentMessage);
+
+ gtk_tree_view_set_model(GTK_TREE_VIEW(treeView), GTK_TREE_MODEL(model));
+ g_object_unref(model);
+}
+
+
+static void treeViewSelChanged(GtkTreeView* treeView, gpointer userData) {
+
+ GtkTreePath* path = NULL;
+ GtkTreeViewColumn* col = NULL;
+
+ gtk_tree_view_get_cursor(treeView, &path, &col);
+
+ GtkTreeIter iter;
+ gtk_tree_model_get_iter(GTK_TREE_MODEL(treeModel), &iter, path);
+
+ vmime::component* comp = NULL;
+ gtk_tree_model_get(GTK_TREE_MODEL(treeModel), &iter, 1, &comp, -1);
+
+ GtkTextBuffer* textBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW(textArea));
+ GtkTextIter start, end;
+
+ gtk_text_buffer_get_iter_at_offset(textBuffer, &start, comp->getParsedOffset());
+ gtk_text_buffer_get_iter_at_offset(textBuffer, &end, comp->getParsedOffset() + comp->getParsedLength());
+
+ gtk_text_buffer_select_range(textBuffer, &start, &end);
+
+ gtk_text_view_scroll_to_iter(GTK_TEXT_VIEW(textArea), &start, 0.0, FALSE, 0.0, 0.0);
+
+ gtk_tree_path_free(path);
+}
+
+
+static void destroy(GtkWidget* widget, gpointer data) {
+
+ gtk_main_quit();
+}
+
+
+void openFile(const std::string& filename) {
+
+ std::ifstream file;
+ file.open(filename.c_str(), std::ios::in | std::ios::binary);
+
+ if (!file) {
+ std::cerr << "Can't open file '" << filename << "'." << std::endl;
+ return;
+ }
+
+ vmime::string data;
+ char buffer[16384];
+
+ do {
+ file.read(buffer, sizeof(buffer));
+ data += vmime::string(buffer, file.gcount());
+ } while (file.gcount());
+
+ vmime::shared_ptr <vmime::message> msg = vmime::make_shared <vmime::message>();
+ msg->parse(data);
+
+ currentMessage = msg;
+
+ char* convData = g_convert_with_fallback(data.c_str(), data.length(),
+ "UTF-8", "ISO-8859-1", "?", NULL, NULL, NULL);
+
+ if (!convData) {
+
+ gtk_text_buffer_set_text(gtk_text_view_get_buffer(GTK_TEXT_VIEW(textArea)),
+ "GLib UTF-8 conversion error.", -1);
+
+ } else {
+
+ gtk_text_buffer_set_text(gtk_text_view_get_buffer(GTK_TEXT_VIEW(textArea)),
+ convData, strlen(convData));
+
+ g_free(convData);
+ }
+
+ updateTreeView();
+}
+
+
+static void onFileOpen() {
+
+ GtkWidget* dlg = gtk_file_chooser_dialog_new(
+ "Open Message File",
+ GTK_WINDOW(window),
+ GTK_FILE_CHOOSER_ACTION_OPEN,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
+ NULL
+ );
+
+ if (gtk_dialog_run(GTK_DIALOG(dlg)) == GTK_RESPONSE_ACCEPT) {
+
+ char* filename = gtk_file_chooser_get_filename(GTK_FILE_CHOOSER(dlg));
+
+ openFile(filename);
+
+ g_free(filename);
+ }
+
+ gtk_widget_destroy(dlg);
+}
+
+
+
+// UI definitions
+static const GtkActionEntry uiActions[] = {
+ { "FileMenu", NULL, "_File" },
+ { "FileOpen", GTK_STOCK_OPEN, "_Open...", "<control>O", NULL, G_CALLBACK(onFileOpen) },
+ { "FileExit", GTK_STOCK_QUIT, "_Exit", "<control>Q", NULL, G_CALLBACK(gtk_main_quit) }
+};
+
+static const char* uiDefinition =
+ "<ui>" \
+ " <menubar name=\"MainMenuBar\">" \
+ " <menu action=\"FileMenu\">" \
+ " <menuitem action=\"FileOpen\"/>" \
+ " <menuitem action=\"FileExit\"/>" \
+ " </menu>" \
+ " </menubar>" \
+ "</ui>";
+
+
+int main(int argc, char* argv[]) {
+
+ // VMime initialization
+ vmime::platform::setHandler<vmime::platforms::posix::posixHandler>();
+
+ // GTK+ initialization
+ gtk_init(&argc, &argv);
+
+ // Create a new window
+ window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+
+ gtk_window_set_default_size(GTK_WINDOW(window), 800, 550);
+ gtk_window_set_title(GTK_WINDOW(window), "VMime Viewer Example");
+
+ g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(destroy), NULL);
+
+ GtkWidget* vbox = gtk_vbox_new(FALSE, 0);
+ gtk_container_add(GTK_CONTAINER(window), vbox);
+
+ // Menubar
+ GtkActionGroup* actionGroup = gtk_action_group_new ("Actions");
+ gtk_action_group_add_actions(actionGroup, uiActions, G_N_ELEMENTS(uiActions), NULL);
+
+ GtkUIManager* uiManager = gtk_ui_manager_new();
+ gtk_ui_manager_insert_action_group(uiManager, actionGroup, 1);
+ gtk_ui_manager_add_ui_from_string(uiManager, uiDefinition, -1, NULL);
+
+ GtkWidget* menuBar = gtk_ui_manager_get_widget(uiManager, "/MainMenuBar");
+
+ gtk_box_pack_start(GTK_BOX(vbox), menuBar, FALSE, FALSE, 0);
+
+ // Horizontal Pane
+ GtkWidget* hpane = gtk_hpaned_new();
+ gtk_box_pack_start(GTK_BOX(vbox), hpane, TRUE, TRUE, 0);
+
+ // Tree View
+ treeModel = gtk_tree_store_new(2, G_TYPE_STRING, G_TYPE_POINTER);
+
+ treeView = gtk_tree_view_new();
+
+ g_signal_connect(G_OBJECT(treeView), "cursor-changed", G_CALLBACK(treeViewSelChanged), NULL);
+
+ GtkWidget* scroll = gtk_scrolled_window_new(NULL, NULL);
+
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll), GTK_SHADOW_IN);
+ gtk_container_add(GTK_CONTAINER(scroll), treeView);
+
+ gtk_paned_add1(GTK_PANED(hpane), scroll);
+
+ GtkTreeViewColumn* col = gtk_tree_view_column_new();
+ gtk_tree_view_column_set_title(col, "Component Name");
+ gtk_tree_view_append_column(GTK_TREE_VIEW(treeView), col);
+
+ GtkCellRenderer* renderer = gtk_cell_renderer_text_new();
+
+ gtk_tree_view_column_pack_start(col, renderer, TRUE);
+ gtk_tree_view_column_add_attribute(col, renderer, "text", 0);
+
+ gtk_tree_view_set_model(GTK_TREE_VIEW(treeView), GTK_TREE_MODEL(treeModel));
+ g_object_unref(treeModel);
+
+ gtk_widget_set_size_request(treeView, 200, 100);
+
+ // Text Area
+ textArea = gtk_text_view_new();
+
+ gtk_text_view_set_editable(GTK_TEXT_VIEW(textArea), FALSE);
+
+ scroll = gtk_scrolled_window_new(NULL, NULL);
+
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
+ gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scroll), GTK_SHADOW_IN);
+ gtk_container_add(GTK_CONTAINER(scroll), textArea);
+
+ gtk_paned_add2(GTK_PANED(hpane), scroll);
+
+ // Show main window
+ gtk_widget_show_all(window);
+
+ // GTK main loop
+ gtk_main();
+
+ return 0;
+}
diff --git a/vmime-master/mingw_cross_toolchain.cmake b/vmime-master/mingw_cross_toolchain.cmake
new file mode 100644
index 0000000..d8727f1
--- /dev/null
+++ b/vmime-master/mingw_cross_toolchain.cmake
@@ -0,0 +1,14 @@
+SET(CMAKE_SYSTEM_NAME Windows)
+SET(CMAKE_CROSSCOMPILING TRUE)
+
+IF("${GNU_HOST}" STREQUAL "")
+ SET(GNU_HOST i686-w64-mingw32)
+ENDIF()
+
+# specify the cross compiler
+SET(CMAKE_C_COMPILER_TARGET ${GNU_HOST})
+SET(CMAKE_C_COMPILER ${GNU_HOST}-gcc)
+SET(CMAKE_CXX_COMPILER_TARGET ${GNU_HOST})
+SET(CMAKE_CXX_COMPILER ${GNU_HOST}-g++)
+SET(CMAKE_RC_COMPILER_TARGET ${GNU_HOST})
+SET(CMAKE_RC_COMPILER ${GNU_HOST}-windres)
diff --git a/vmime-master/src/vmime/address.cpp b/vmime-master/src/vmime/address.cpp
new file mode 100644
index 0000000..3bc434f
--- /dev/null
+++ b/vmime-master/src/vmime/address.cpp
@@ -0,0 +1,236 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/address.hpp"
+
+#include "vmime/mailbox.hpp"
+#include "vmime/mailboxGroup.hpp"
+
+#include "vmime/parserHelpers.hpp"
+
+
+namespace vmime {
+
+
+address::address() {
+
+}
+
+
+/*
+
+ RFC #2822:
+ 3.4. ADDRESS SPECIFICATION
+
+ Addresses occur in several message header fields to indicate senders
+ and recipients of messages. An address may either be an individual
+ mailbox, or a group of mailboxes.
+
+address = mailbox / group
+
+mailbox = name-addr / addr-spec
+
+name-addr = [display-name] angle-addr
+
+angle-addr = [CFWS] "<" addr-spec ">" [CFWS] / obs-angle-addr
+
+group = display-name ":" [mailbox-list / CFWS] ";"
+ [CFWS]
+
+display-name = phrase
+
+mailbox-list = (mailbox *("," mailbox)) / obs-mbox-list
+
+address-list = (address *("," address)) / obs-addr-list
+
+*/
+
+shared_ptr <address> address::parseNext(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition,
+ bool *isLastAddressOfGroup
+) {
+
+ bool escaped = false;
+ bool quoted = false;
+ bool quotedRFC2047 = false;
+ bool inRouteAddr = false;
+ bool isGroup = false;
+ bool stop = false;
+ int commentLevel = 0;
+
+ if (isLastAddressOfGroup) {
+ *isLastAddressOfGroup = false;
+ }
+
+ size_t pos = position;
+
+ while (pos < end && parserHelpers::isSpace(buffer[pos])) {
+ ++pos;
+ }
+
+ const size_t start = pos;
+
+ while (!stop && pos < end) {
+
+ if (escaped) {
+
+ escaped = false;
+
+ } else {
+
+ switch (buffer[pos]) {
+
+ case '\\':
+
+ escaped = true;
+ break;
+
+ case '"':
+
+ quoted = !quoted;
+ break;
+
+ case '<':
+
+ inRouteAddr = true;
+ break;
+
+ case '>':
+
+ inRouteAddr = false;
+ break;
+
+ case '(':
+
+ ++commentLevel;
+ break;
+
+ case ')':
+
+ if (commentLevel > 0) {
+ --commentLevel;
+ }
+
+ break;
+
+ case '=':
+
+ if (commentLevel == 0 && !quoted && !quotedRFC2047 && pos + 1 < end && buffer[pos + 1] == '?') {
+ ++pos;
+ quotedRFC2047 = true;
+ }
+
+ break;
+
+ case '?':
+
+ if (commentLevel == 0 && quotedRFC2047 && pos + 1 < end && buffer[pos + 1] == '=') {
+ ++pos;
+ quotedRFC2047 = false;
+ }
+
+ break;
+
+ default:
+ {
+ if (commentLevel == 0 && !quoted && !quotedRFC2047 && !inRouteAddr) {
+
+ switch (buffer[pos]) {
+
+ case ';':
+
+ if (isGroup) {
+
+ if (pos + 1 < end && buffer[pos + 1] == ',') {
+ ++pos;
+ }
+ }
+
+ if (isLastAddressOfGroup) {
+ *isLastAddressOfGroup = true;
+ }
+
+ stop = true;
+ break;
+
+ case ':':
+
+ isGroup = true;
+ break;
+
+ case ',':
+
+ if (!isGroup) {
+ stop = true;
+ }
+
+ break;
+ }
+ }
+
+ break;
+ }
+
+ }
+ }
+
+ if (!stop) {
+ ++pos;
+ }
+ }
+
+ if (newPosition) {
+
+ if (pos == end) {
+ *newPosition = end;
+ } else {
+ *newPosition = pos + 1; // ',' or ';'
+ }
+ }
+
+ // Parse extracted address (mailbox or group)
+ if (pos != start) {
+
+ shared_ptr <address> parsedAddress;
+
+ if (isGroup) {
+ parsedAddress = make_shared <mailboxGroup>();
+ } else {
+ parsedAddress = make_shared <mailbox>();
+ }
+
+ parsedAddress->parse(ctx, buffer, start, pos, NULL);
+ parsedAddress->setParsedBounds(start, pos);
+
+ return parsedAddress;
+ }
+
+ return null;
+}
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/address.hpp b/vmime-master/src/vmime/address.hpp
new file mode 100644
index 0000000..f83f238
--- /dev/null
+++ b/vmime-master/src/vmime/address.hpp
@@ -0,0 +1,89 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_ADDRESS_HPP_INCLUDED
+#define VMIME_ADDRESS_HPP_INCLUDED
+
+
+#include "vmime/base.hpp"
+#include "vmime/headerFieldValue.hpp"
+
+
+namespace vmime {
+
+
+/** Abstract class representing a mailbox or a group of mailboxes.
+ *
+ * This class define a common behaviour for the mailbox
+ * and mailboxGroup classes.
+ */
+class VMIME_EXPORT address : public headerFieldValue {
+
+protected:
+
+ address();
+
+public:
+
+ /** Check whether this address is empty (no mailboxes specified
+ * if this is a mailboxGroup -or- no email specified if this is
+ * a mailbox).
+ *
+ * @return true if this address is empty
+ */
+ virtual bool isEmpty() const = 0;
+
+ /** Test whether this is object is a mailboxGroup.
+ *
+ * @return true if this is a mailboxGroup, false otherwise
+ */
+ virtual bool isGroup() const = 0;
+
+ virtual shared_ptr <component> clone() const = 0;
+
+ /** Parse an address from an input buffer.
+ *
+ * @param ctx parsing context
+ * @param buffer input buffer
+ * @param position position in the input buffer
+ * @param end end position in the input buffer
+ * @param newPosition will receive the new position in the input buffer
+ * @param isLastAddressOfGroup will be set to true if this is the last address
+ * of a group (end delimiter was found), or false otherwise (may be set to NULL)
+ * @return a new address object, or null if no more address is available in the input buffer
+ */
+ static shared_ptr <address> parseNext(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition,
+ bool *isLastAddressOfGroup
+ );
+};
+
+
+} // vmime
+
+
+#endif // VMIME_ADDRESS_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/addressList.cpp b/vmime-master/src/vmime/addressList.cpp
new file mode 100644
index 0000000..03c9e8f
--- /dev/null
+++ b/vmime-master/src/vmime/addressList.cpp
@@ -0,0 +1,328 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/addressList.hpp"
+#include "vmime/parserHelpers.hpp"
+#include "vmime/exception.hpp"
+#include "vmime/mailboxList.hpp"
+#include "vmime/mailboxGroup.hpp"
+
+
+namespace vmime {
+
+
+addressList::addressList() {
+
+}
+
+
+addressList::addressList(const addressList& addrList)
+ : headerFieldValue() {
+
+ copyFrom(addrList);
+}
+
+
+addressList::~addressList() {
+
+ removeAllAddresses();
+}
+
+
+void addressList::parseImpl(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition
+) {
+
+ removeAllAddresses();
+
+ size_t pos = position;
+
+ while (pos < end) {
+
+ shared_ptr <address> parsedAddress = address::parseNext(ctx, buffer, pos, end, &pos, NULL);
+
+ if (parsedAddress) {
+ m_list.push_back(parsedAddress);
+ }
+ }
+
+ setParsedBounds(position, end);
+
+ if (newPosition) {
+ *newPosition = end;
+ }
+}
+
+
+void addressList::generateImpl(
+ const generationContext& ctx,
+ utility::outputStream& os,
+ const size_t curLinePos,
+ size_t* newLinePos
+) const {
+
+ size_t pos = curLinePos;
+
+ generationContext tmpCtx(ctx);
+ tmpCtx.setMaxLineLength(tmpCtx.getMaxLineLength() - 2);
+
+ if (!m_list.empty()) {
+
+ for (std::vector <shared_ptr <address> >::const_iterator i = m_list.begin() ; ; ) {
+
+ (*i)->generate(ctx, os, pos, &pos);
+
+ if (++i == m_list.end()) {
+ break;
+ }
+
+ os << ", ";
+ pos += 2;
+ }
+ }
+
+ if (newLinePos) {
+ *newLinePos = pos;
+ }
+}
+
+
+void addressList::copyFrom(const component& other) {
+
+ const addressList& addrList = dynamic_cast <const addressList&>(other);
+
+ removeAllAddresses();
+
+ for (std::vector <shared_ptr <address> >::const_iterator it = addrList.m_list.begin() ;
+ it != addrList.m_list.end() ; ++it) {
+
+ m_list.push_back(vmime::clone(*it));
+ }
+}
+
+
+addressList& addressList::operator=(const addressList& other) {
+
+ copyFrom(other);
+ return *this;
+}
+
+
+addressList& addressList::operator=(const mailboxList& other) {
+
+ removeAllAddresses();
+
+ for (size_t i = 0 ; i < other.getMailboxCount() ; ++i) {
+ m_list.push_back(dynamicCast <address>(other.getMailboxAt(i)->clone()));
+ }
+
+ return *this;
+}
+
+
+shared_ptr <component> addressList::clone() const {
+
+ return make_shared <addressList>(*this);
+}
+
+
+void addressList::appendAddress(const shared_ptr <address> &addr) {
+
+ m_list.push_back(addr);
+}
+
+
+void addressList::insertAddressBefore(const shared_ptr <address>& beforeAddress, const shared_ptr <address>& addr) {
+
+ const std::vector <shared_ptr <address> >::iterator it = std::find(
+ m_list.begin(), m_list.end(), beforeAddress
+ );
+
+ if (it == m_list.end()) {
+ throw std::out_of_range("Invalid position");
+ }
+
+ m_list.insert(it, addr);
+}
+
+
+void addressList::insertAddressBefore(const size_t pos, const shared_ptr <address>& addr) {
+
+ if (pos >= m_list.size()) {
+ throw std::out_of_range("Invalid position");
+ }
+
+ m_list.insert(m_list.begin() + pos, addr);
+}
+
+
+void addressList::insertAddressAfter(
+ const shared_ptr <address>& afterAddress,
+ const shared_ptr <address>& addr
+) {
+
+ const std::vector <shared_ptr <address> >::iterator it = std::find(
+ m_list.begin(), m_list.end(), afterAddress
+ );
+
+ if (it == m_list.end()) {
+ throw std::out_of_range("Invalid position");
+ }
+
+ m_list.insert(it + 1, addr);
+}
+
+
+void addressList::insertAddressAfter(const size_t pos, const shared_ptr <address>& addr) {
+
+ if (pos >= m_list.size()) {
+ throw std::out_of_range("Invalid position");
+ }
+
+ m_list.insert(m_list.begin() + pos + 1, addr);
+}
+
+
+void addressList::removeAddress(const shared_ptr <address>& addr) {
+
+ const std::vector <shared_ptr <address> >::iterator it = std::find(
+ m_list.begin(), m_list.end(), addr
+ );
+
+ if (it == m_list.end()) {
+ throw std::out_of_range("Invalid position");
+ }
+
+ m_list.erase(it);
+}
+
+
+void addressList::removeAddress(const size_t pos) {
+
+ if (pos >= m_list.size()) {
+ throw std::out_of_range("Invalid position");
+ }
+
+ const std::vector <shared_ptr <address> >::iterator it = m_list.begin() + pos;
+
+ m_list.erase(it);
+}
+
+
+void addressList::removeAllAddresses() {
+
+ m_list.clear();
+}
+
+
+size_t addressList::getAddressCount() const {
+
+ return m_list.size();
+}
+
+
+bool addressList::isEmpty() const {
+
+ return m_list.empty();
+}
+
+
+shared_ptr <address> addressList::getAddressAt(const size_t pos) {
+
+ return m_list[pos];
+}
+
+
+const shared_ptr <const address> addressList::getAddressAt(const size_t pos) const {
+
+ return m_list[pos];
+}
+
+
+const std::vector <shared_ptr <const address> > addressList::getAddressList() const {
+
+ std::vector <shared_ptr <const address> > list;
+
+ list.reserve(m_list.size());
+
+ for (std::vector <shared_ptr <address> >::const_iterator it = m_list.begin() ;
+ it != m_list.end() ; ++it) {
+
+ list.push_back(*it);
+ }
+
+ return list;
+}
+
+
+const std::vector <shared_ptr <address> > addressList::getAddressList() {
+
+ return m_list;
+}
+
+
+const std::vector <shared_ptr <component> > addressList::getChildComponents() {
+
+ std::vector <shared_ptr <component> > list;
+
+ copy_vector(m_list, list);
+
+ return list;
+}
+
+
+shared_ptr <mailboxList> addressList::toMailboxList() const {
+
+ shared_ptr <mailboxList> res = make_shared <mailboxList>();
+
+ for (std::vector <shared_ptr <address> >::const_iterator it = m_list.begin() ;
+ it != m_list.end() ; ++it) {
+
+ shared_ptr <const address> addr = *it;
+
+ if (addr->isGroup()) {
+
+ const std::vector <shared_ptr <const mailbox> > mailboxes =
+ dynamicCast <const mailboxGroup>(addr)->getMailboxList();
+
+ for (std::vector <shared_ptr <const mailbox> >::const_iterator jt = mailboxes.begin() ;
+ jt != mailboxes.end() ; ++jt) {
+
+ res->appendMailbox(vmime::clone(*jt));
+ }
+
+ } else {
+
+ res->appendMailbox(dynamicCast <mailbox>(addr->clone()));
+ }
+ }
+
+ return res;
+}
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/addressList.hpp b/vmime-master/src/vmime/addressList.hpp
new file mode 100644
index 0000000..69cbd74
--- /dev/null
+++ b/vmime-master/src/vmime/addressList.hpp
@@ -0,0 +1,198 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_ADDRESSLIST_HPP_INCLUDED
+#define VMIME_ADDRESSLIST_HPP_INCLUDED
+
+
+#include "vmime/base.hpp"
+#include "vmime/headerFieldValue.hpp"
+
+#include "vmime/address.hpp"
+
+
+namespace vmime {
+
+
+class mailboxList;
+
+
+/** A list of addresses.
+ */
+class VMIME_EXPORT addressList : public headerFieldValue {
+
+public:
+
+ addressList();
+ addressList(const addressList& addrList);
+
+ ~addressList();
+
+
+ shared_ptr <component> clone() const;
+ void copyFrom(const component& other);
+ addressList& operator=(const addressList& other);
+ addressList& operator=(const mailboxList& other);
+
+ const std::vector <shared_ptr <component> > getChildComponents();
+
+
+ /** Add a address at the end of the list.
+ *
+ * @param addr address to append
+ */
+ void appendAddress(const shared_ptr <address>& addr);
+
+ /** Insert a new address before the specified address.
+ *
+ * @param beforeAddress address before which the new address will be inserted
+ * @param addr address to insert
+ * @throw std::out_of_range if the address is not in the list
+ */
+ void insertAddressBefore(
+ const shared_ptr <address>& beforeAddress,
+ const shared_ptr <address>& addr
+ );
+
+ /** Insert a new address before the specified position.
+ *
+ * @param pos position at which to insert the new address (0 to insert at
+ * the beginning of the list)
+ * @param addr address to insert
+ * @throw std::out_of_range if the position is out of range
+ */
+ void insertAddressBefore(const size_t pos, const shared_ptr <address>& addr);
+
+ /** Insert a new address after the specified address.
+ *
+ * @param afterAddress address after which the new address will be inserted
+ * @param addr address to insert
+ * @throw std::out_of_range if the address is not in the list
+ */
+ void insertAddressAfter(
+ const shared_ptr <address>& afterAddress,
+ const shared_ptr <address>& addr
+ );
+
+ /** Insert a new address after the specified position.
+ *
+ * @param pos position of the address before the new address
+ * @param addr address to insert
+ * @throw std::out_of_range if the position is out of range
+ */
+ void insertAddressAfter(const size_t pos, const shared_ptr <address>& addr);
+
+ /** Remove the specified address from the list.
+ *
+ * @param addr address to remove
+ * @throw std::out_of_range if the address is not in the list
+ */
+ void removeAddress(const shared_ptr <address>& addr);
+
+ /** Remove the address at the specified position.
+ *
+ * @param pos position of the address to remove
+ * @throw std::out_of_range if the position is out of range
+ */
+ void removeAddress(const size_t pos);
+
+ /** Remove all addresses from the list.
+ */
+ void removeAllAddresses();
+
+ /** Return the number of addresses in the list.
+ *
+ * @return number of addresses
+ */
+ size_t getAddressCount() const;
+
+ /** Tests whether the list of addresses is empty.
+ *
+ * @return true if there is no address, false otherwise
+ */
+ bool isEmpty() const;
+
+ /** Return the address at the specified position.
+ *
+ * @param pos position
+ * @return address at position 'pos'
+ * @throw std::out_of_range if the position is out of range
+ */
+ shared_ptr <address> getAddressAt(const size_t pos);
+
+ /** Return the address at the specified position.
+ *
+ * @param pos position
+ * @return address at position 'pos'
+ * @throw std::out_of_range if the position is out of range
+ */
+ const shared_ptr <const address> getAddressAt(const size_t pos) const;
+
+ /** Return the address list.
+ *
+ * @return list of addresses
+ */
+ const std::vector <shared_ptr <const address> > getAddressList() const;
+
+ /** Return the address list.
+ *
+ * @return list of addresses
+ */
+ const std::vector <shared_ptr <address> > getAddressList();
+
+ /** Return a list of mailboxes.
+ * If some addresses are actually groups, mailboxes are recursively
+ * extracted from these groups.
+ *
+ * @return list of mailboxes
+ */
+ shared_ptr <mailboxList> toMailboxList() const;
+
+private:
+
+ std::vector <shared_ptr <address> > m_list;
+
+protected:
+
+ // Component parsing & assembling
+ void parseImpl(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition = NULL
+ );
+
+ void generateImpl(
+ const generationContext& ctx,
+ utility::outputStream& os,
+ const size_t curLinePos = 0,
+ size_t* newLinePos = NULL
+ ) const;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_ADDRESSLIST_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/attachment.hpp b/vmime-master/src/vmime/attachment.hpp
new file mode 100644
index 0000000..be20e33
--- /dev/null
+++ b/vmime-master/src/vmime/attachment.hpp
@@ -0,0 +1,116 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_ATTACHMENT_HPP_INCLUDED
+#define VMIME_ATTACHMENT_HPP_INCLUDED
+
+
+#include "vmime/base.hpp"
+
+#include "vmime/bodyPart.hpp"
+#include "vmime/mediaType.hpp"
+#include "vmime/text.hpp"
+#include "vmime/contentHandler.hpp"
+#include "vmime/encoding.hpp"
+
+
+namespace vmime {
+
+
+/** Base class for all types of attachment.
+ */
+class VMIME_EXPORT attachment : public object {
+
+ friend class messageBuilder;
+ friend class messageParser;
+ friend class attachmentHelper;
+
+protected:
+
+ attachment() { }
+
+public:
+
+ virtual ~attachment() { }
+
+ /** Return the media type of this attachment.
+ *
+ * @return content type of the attachment
+ */
+ virtual const mediaType getType() const = 0;
+
+ /** Return the description of this attachment.
+ *
+ * @return attachment description, or an empty text
+ * if no description is available
+ */
+ virtual const text getDescription() const = 0;
+
+ /** Return the (file) name of this attachment.
+ *
+ * @return attachment name, or an empty word if no
+ * name is available
+ */
+ virtual const word getName() const = 0;
+
+ /** Return the data contained in this attachment.
+ *
+ * @return attachment data
+ */
+ virtual const shared_ptr <const contentHandler> getData() const = 0;
+
+ /** Return the encoding used for this attachment.
+ *
+ * @return attachment data encoding
+ */
+ virtual const encoding getEncoding() const = 0;
+
+ /** Return the part in which the attachment has been found.
+ * This can be a vmime::bodyPart or a vmime::net::part object.
+ *
+ * @return attachment part or NULL if the attachment is not
+ * attached to a part
+ */
+ virtual shared_ptr <const object> getPart() const = 0;
+
+ /** Return the header of the attachment part.
+ *
+ * @return attachment part header or NULL if the attachment
+ * is not attached to a part
+ */
+ virtual shared_ptr <const header> getHeader() const = 0;
+
+protected:
+
+ /** Generate the attachment in the specified body part.
+ *
+ * @param parent body part in which to generate the attachment
+ */
+ virtual void generateIn(const shared_ptr <bodyPart>& parent) const = 0;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_ATTACHMENT_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/attachmentHelper.cpp b/vmime-master/src/vmime/attachmentHelper.cpp
new file mode 100644
index 0000000..8605122
--- /dev/null
+++ b/vmime-master/src/vmime/attachmentHelper.cpp
@@ -0,0 +1,339 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/attachmentHelper.hpp"
+
+#include "vmime/bodyPartAttachment.hpp"
+#include "vmime/parsedMessageAttachment.hpp"
+#include "vmime/generatedMessageAttachment.hpp"
+
+#include "vmime/disposition.hpp"
+#include "vmime/emptyContentHandler.hpp"
+
+#include <iterator>
+
+
+namespace vmime {
+
+
+// static
+bool attachmentHelper::isBodyPartAnAttachment(
+ const shared_ptr <const bodyPart>& part,
+ const unsigned int options
+) {
+
+ // First, try with "Content-Disposition" field.
+ // If not present, we will try with "Content-Type" field.
+ shared_ptr <const contentDispositionField> cdf =
+ part->getHeader()->findField <contentDispositionField>(fields::CONTENT_DISPOSITION);
+
+ if (cdf) {
+
+ const contentDisposition disp = *cdf->getValue <contentDisposition>();
+
+ if (disp.getName() != contentDispositionTypes::INLINE) {
+ return true;
+ }
+
+ if ((options & INLINE_OBJECTS) == 0) {
+
+ // If the Content-Disposition is 'inline' and there is no
+ // Content-Id or Content-Location field, it may be an attachment
+ if (!part->getHeader()->hasField(vmime::fields::CONTENT_ID) &&
+ !part->getHeader()->hasField(vmime::fields::CONTENT_LOCATION)) {
+
+ // If this is the root part, it might not be an attachment
+ if (!part->getParentPart()) {
+ return false;
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+ }
+
+ // Assume "attachment" if type is not "text/..." or "multipart/...".
+ mediaType type;
+ bool hasContentTypeName = false;
+
+ shared_ptr <const contentTypeField> ctf =
+ part->getHeader()->findField <contentTypeField>(fields::CONTENT_TYPE);
+
+ if (ctf) {
+
+ type = *ctf->getValue <mediaType>();
+
+ if (ctf->hasParameter("name")) {
+ hasContentTypeName = true;
+ }
+
+ } else {
+
+ // If this is the root part and no Content-Type field is present,
+ // then this may not be a MIME message, so do not assume it is
+ // an attachment
+ if (!part->getParentPart()) {
+ return false;
+ }
+
+ // No "Content-type" field: assume "application/octet-stream".
+ type = mediaType(
+ mediaTypes::APPLICATION,
+ mediaTypes::APPLICATION_OCTET_STREAM
+ );
+ }
+
+ if (type.getType() != mediaTypes::TEXT &&
+ type.getType() != mediaTypes::MULTIPART) {
+
+ // Compatibility with (obsolete) RFC-1341: if there is a "name" parameter
+ // on the "Content-Type" field, then we assume it is an attachment
+ if (hasContentTypeName) {
+ return true;
+ }
+
+ if ((options & INLINE_OBJECTS) == 0) {
+
+ // If a "Content-Id" field is present, it might be an
+ // embedded object (MHTML messages)
+ if (part->getHeader()->hasField(vmime::fields::CONTENT_ID)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+
+// static
+shared_ptr <const attachment> attachmentHelper::getBodyPartAttachment(
+ const shared_ptr <const bodyPart>& part,
+ const unsigned int options
+) {
+
+ if (!isBodyPartAnAttachment(part, options)) {
+ return null;
+ }
+
+ mediaType type;
+
+ shared_ptr <const contentTypeField> ctf =
+ part->getHeader()->findField <contentTypeField>(fields::CONTENT_TYPE);
+
+ if (ctf) {
+
+ type = *ctf->getValue <mediaType>();
+
+ } else {
+
+ // No "Content-type" field: assume "application/octet-stream".
+ type = mediaType(
+ mediaTypes::APPLICATION,
+ mediaTypes::APPLICATION_OCTET_STREAM
+ );
+ }
+
+ if (type.getType() == mediaTypes::MESSAGE &&
+ type.getSubType() == mediaTypes::MESSAGE_RFC822) {
+
+ return make_shared <generatedMessageAttachment>(part);
+
+ } else {
+
+ return make_shared <bodyPartAttachment>(part);
+ }
+}
+
+
+// static
+const std::vector <shared_ptr <const attachment> >
+ attachmentHelper::findAttachmentsInMessage(
+ const shared_ptr <const message>& msg,
+ const unsigned int options
+ ) {
+
+ return findAttachmentsInBodyPart(msg, options);
+}
+
+
+// static
+const std::vector <shared_ptr <const attachment> >
+ attachmentHelper::findAttachmentsInBodyPart(
+ const shared_ptr <const bodyPart>& part,
+ const unsigned int options
+ ) {
+
+ std::vector <shared_ptr <const attachment> > atts;
+
+ // Test this part
+ if (isBodyPartAnAttachment(part, options)) {
+
+ atts.push_back(getBodyPartAttachment(part, options));
+
+ // Find in sub-parts
+ } else {
+
+ shared_ptr <const body> bdy = part->getBody();
+
+ for (size_t i = 0 ; i < bdy->getPartCount() ; ++i) {
+
+ std::vector <shared_ptr <const attachment> > partAtts =
+ findAttachmentsInBodyPart(bdy->getPartAt(i), options);
+
+ std::copy(partAtts.begin(), partAtts.end(), std::back_inserter(atts));
+ }
+ }
+
+ return atts;
+}
+
+
+// static
+void attachmentHelper::addAttachment(const shared_ptr <message>& msg, const shared_ptr <attachment>& att) {
+
+ // We simply search for a "multipart/mixed" part. If no one exists,
+ // create it in the root part. This (very simple) algorithm should
+ // work in the most cases.
+
+ vmime::mediaType mpMixed(
+ vmime::mediaTypes::MULTIPART,
+ vmime::mediaTypes::MULTIPART_MIXED
+ );
+
+ shared_ptr <bodyPart> part = findBodyPart(msg, mpMixed);
+
+ if (!part) { // create it
+
+ if (msg->getBody()->getPartCount() != 0) {
+
+ // Create a new container part for the parts that were in
+ // the root part of the message
+ shared_ptr <bodyPart> container = make_shared <bodyPart>();
+
+ if (msg->getHeader()->hasField(fields::CONTENT_TYPE)) {
+
+ container->getHeader()->ContentType()->setValue(
+ msg->getHeader()->ContentType()->getValue()
+ );
+ }
+
+ if (msg->getHeader()->hasField(fields::CONTENT_TRANSFER_ENCODING)) {
+
+ container->getHeader()->ContentTransferEncoding()->setValue(
+ msg->getHeader()->ContentTransferEncoding()->getValue()
+ );
+ }
+
+ // Move parts from the root part to this new part
+ const std::vector <shared_ptr <bodyPart> > partList =
+ msg->getBody()->getPartList();
+
+ msg->getBody()->removeAllParts();
+
+ for (unsigned int i = 0 ; i < partList.size() ; ++i) {
+ container->getBody()->appendPart(partList[i]);
+ }
+
+ msg->getBody()->appendPart(container);
+
+ } else {
+
+ // The message is a simple (RFC-822) message, and do not
+ // contains any MIME part. Move the contents from the
+ // root to a new child part.
+ shared_ptr <bodyPart> child = make_shared <bodyPart>();
+
+ if (msg->getHeader()->hasField(fields::CONTENT_TYPE)) {
+
+ child->getHeader()->ContentType()->setValue(
+ msg->getHeader()->ContentType()->getValue()
+ );
+ }
+
+ if (msg->getHeader()->hasField(fields::CONTENT_TRANSFER_ENCODING)) {
+
+ child->getHeader()->ContentTransferEncoding()->setValue(
+ msg->getHeader()->ContentTransferEncoding()->getValue()
+ );
+ }
+
+ child->getBody()->setContents(msg->getBody()->getContents());
+ msg->getBody()->setContents(make_shared <emptyContentHandler>());
+
+ msg->getBody()->appendPart(child);
+ }
+
+ // Set the root part to 'multipart/mixed'
+ msg->getHeader()->ContentType()->setValue(mpMixed);
+
+ msg->getHeader()->removeAllFields(vmime::fields::CONTENT_DISPOSITION);
+ msg->getHeader()->removeAllFields(vmime::fields::CONTENT_TRANSFER_ENCODING);
+
+ part = msg;
+ }
+
+ // Generate the attachment part
+ att->generateIn(part);
+}
+
+
+// static
+shared_ptr <bodyPart> attachmentHelper::findBodyPart(
+ const shared_ptr <bodyPart>& part,
+ const mediaType& type
+) {
+
+ if (part->getBody()->getContentType() == type) {
+ return part;
+ }
+
+ // Try in sub-parts
+ shared_ptr <body> bdy = part->getBody();
+
+ for (size_t i = 0 ; i < bdy->getPartCount() ; ++i) {
+
+ shared_ptr <bodyPart> found = findBodyPart(bdy->getPartAt(i), type);
+
+ if (found) {
+ return found;
+ }
+ }
+
+ return null;
+}
+
+
+// static
+void attachmentHelper::addAttachment(const shared_ptr <message>& msg, const shared_ptr <message>& amsg) {
+
+ shared_ptr <attachment> att = make_shared <parsedMessageAttachment>(amsg);
+ addAttachment(msg, att);
+}
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/attachmentHelper.hpp b/vmime-master/src/vmime/attachmentHelper.hpp
new file mode 100644
index 0000000..f28819f
--- /dev/null
+++ b/vmime-master/src/vmime/attachmentHelper.hpp
@@ -0,0 +1,137 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_ATTACHMENTHELPER_HPP_INCLUDED
+#define VMIME_ATTACHMENTHELPER_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+#include "vmime/attachment.hpp"
+#include "vmime/message.hpp"
+
+
+namespace vmime {
+
+
+/** Retrieve attachment information from message parts.
+ */
+class VMIME_EXPORT attachmentHelper {
+
+public:
+
+ /** Options for use with the following functions:
+ * findAttachmentsInMessage,
+ * getBodyPartAttachment,
+ * and isBodyPartAnAttachment.
+ */
+ enum FindOptions {
+ INLINE_OBJECTS = (1 << 0) /**< Recognize and return inline objects. The aim is to
+ consider MHTML objects (parts with a "Content-Id" or
+ a "Content-Location", such as inline images) as attachments. */
+ };
+
+ /** Test whether a body part is an attachment.
+ *
+ * @param part message part to test
+ * @param options search options (see FindOptions)
+ * @return true if the part is an attachment, false otherwise
+ */
+ static bool isBodyPartAnAttachment(
+ const shared_ptr <const bodyPart>& part,
+ const unsigned int options = 0
+ );
+
+ /** Return attachment information in the specified body part.
+ * If the specified body part does not contain attachment
+ * information (ie. is not an attachment), NULL is returned.
+ *
+ * @param part message part in which to search
+ * @param options search options (see FindOptions)
+ * @return attachment found in the part, or NULL
+ */
+ static shared_ptr <const attachment> getBodyPartAttachment(
+ const shared_ptr <const bodyPart>& part,
+ const unsigned int options = 0
+ );
+
+ /** Find all attachments contained in the specified part
+ * and all its children parts.
+ * This is simply a recursive call to getBodyPartAttachment().
+ *
+ * @param part part in which to search
+ * @param options search options (see FindOptions)
+ * @return a list of attachments found
+ */
+ static const std::vector <shared_ptr <const attachment> >
+ findAttachmentsInBodyPart(
+ const shared_ptr <const bodyPart>& part,
+ const unsigned int options = 0
+ );
+
+ /** Find all attachments contained in the specified message.
+ * This is simply a recursive call to getBodyPartAttachment().
+ *
+ * @param msg message in which to search
+ * @param options search options (see FindOptions)
+ * @return a list of attachments found
+ */
+ static const std::vector <shared_ptr <const attachment> >
+ findAttachmentsInMessage(
+ const shared_ptr <const message>& msg,
+ const unsigned int options = 0
+ );
+
+ /** Add an attachment to the specified message.
+ *
+ * @param msg message into which to add the attachment
+ * @param att attachment to add
+ */
+ static void addAttachment(
+ const shared_ptr <message>& msg,
+ const shared_ptr <attachment>& att
+ );
+
+ /** Add a message attachment to the specified message.
+ *
+ * @param msg message into which to add the attachment
+ * @param amsg message to attach
+ */
+ static void addAttachment(
+ const shared_ptr <message>& msg,
+ const shared_ptr <message>& amsg
+ );
+
+protected:
+
+ static shared_ptr <bodyPart> findBodyPart(
+ const shared_ptr <bodyPart>& part,
+ const mediaType& type
+ );
+};
+
+
+} // vmime
+
+
+#endif // VMIME_ATTACHMENTHELPER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/base.cpp b/vmime-master/src/vmime/base.cpp
new file mode 100644
index 0000000..395d7b3
--- /dev/null
+++ b/vmime-master/src/vmime/base.cpp
@@ -0,0 +1,158 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+#include "vmime/charset.hpp"
+#include "vmime/base.hpp"
+
+#include "vmime/utility/encoder/encoder.hpp"
+#include "vmime/utility/encoder/b64Encoder.hpp"
+#include "vmime/utility/encoder/qpEncoder.hpp"
+
+#include "vmime/text.hpp"
+
+#include "vmime/parserHelpers.hpp"
+
+#include "vmime/utility/stringUtils.hpp"
+
+// For initializing
+#include "vmime/utility/encoder/encoderFactory.hpp"
+#include "vmime/headerFieldFactory.hpp"
+#include "vmime/textPartFactory.hpp"
+#include "vmime/generationContext.hpp"
+#include "vmime/parsingContext.hpp"
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+ #include "vmime/net/serviceFactory.hpp"
+#endif
+
+
+namespace vmime {
+
+
+/** "Null" (empty) string.
+ */
+const string NULL_STRING;
+
+/** "Null" (empty) text.
+ */
+const text NULL_TEXT;
+
+/** "Null" (empty) word.
+ */
+const word NULL_WORD("", vmime::charset(vmime::charsets::US_ASCII));
+
+
+/** Return the library name (eg: "libvmime").
+ *
+ * @return library name
+ */
+const string libname() { return (VMIME_PACKAGE); }
+
+/** Return the library version (eg: "0.5.2").
+ *
+ * @return library version
+ */
+const string libversion() { return (VMIME_VERSION " (" __DATE__ " " __TIME__ ")"); }
+
+/** Return the library API version (eg: "6:1:6").
+ *
+ * @return library API version
+ */
+const string libapi() { return (VMIME_API); }
+
+
+// New line sequence to be used when folding header fields.
+const string NEW_LINE_SEQUENCE = "\r\n ";
+const size_t NEW_LINE_SEQUENCE_LENGTH = 1; // space
+
+/** The CR-LF sequence.
+ */
+const string CRLF = "\r\n";
+
+
+/** The current MIME version supported by VMime.
+ */
+const string SUPPORTED_MIME_VERSION = "1.0";
+
+
+#ifndef VMIME_BUILDING_DOC
+
+/** Null shared pointer.
+ */
+nullPtrType null;
+
+#endif // VMIME_BUILDING_DOC
+
+
+// Line length limits
+namespace lineLengthLimits {
+
+ const size_t infinite = std::numeric_limits <size_t>::max();
+}
+
+
+const size_t npos = std::numeric_limits <size_t>::max();
+
+
+
+#ifndef VMIME_BUILDING_DOC
+
+//
+// V-Mime Initializer
+// ====================
+//
+// Force instanciation of singletons. This is to prevent problems that might
+// happen in multithreaded applications...
+//
+// WARNING: we put the initializer at the end of this compilation unit. This
+// ensures this object is initialized _after_ all other global variables in
+// the same compilation unit (in particular "lineLengthLimits::infinite",
+// which is used by the generate() function (called from "textPartFactory"
+// constructor, for example).
+//
+
+struct initializer {
+
+ initializer() {
+
+ parsingContext::getDefaultContext();
+ generationContext::getDefaultContext();
+
+ utility::encoder::encoderFactory::getInstance();
+ headerFieldFactory::getInstance();
+ textPartFactory::getInstance();
+
+ #if VMIME_HAVE_MESSAGING_FEATURES
+ net::serviceFactory::getInstance();
+ #endif
+ }
+};
+
+initializer theInitializer;
+
+#endif // VMIME_BUILDING_DOC
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/base.hpp b/vmime-master/src/vmime/base.hpp
new file mode 100644
index 0000000..7782477
--- /dev/null
+++ b/vmime-master/src/vmime/base.hpp
@@ -0,0 +1,258 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_BASE_HPP_INCLUDED
+#define VMIME_BASE_HPP_INCLUDED
+
+
+#include <string>
+#include <vector>
+#include <map>
+#include <sstream>
+#include <cctype>
+#include <locale>
+
+#include "vmime/config.hpp"
+#include "vmime/types.hpp"
+#include "vmime/constants.hpp"
+
+
+namespace vmime {
+
+ class text;
+ class word;
+ class charset;
+
+
+ // "Null" strings
+ extern VMIME_EXPORT const string NULL_STRING;
+
+ extern VMIME_EXPORT const text NULL_TEXT;
+ extern VMIME_EXPORT const word NULL_WORD;
+
+#ifndef VMIME_BUILDING_DOC
+
+ // Null pointer
+ struct nullPtrType {
+
+ template <typename T>
+ operator shared_ptr <T>() { return shared_ptr <T>(); }
+ };
+
+ extern nullPtrType VMIME_EXPORT null;
+
+#endif // VMIME_BUILDING_DOC
+
+
+ //
+ // Library name and version
+ //
+
+ const string VMIME_EXPORT libname();
+ const string VMIME_EXPORT libversion();
+ const string VMIME_EXPORT libapi();
+
+
+ //
+ // Helpful functions used for array -> iterator conversion
+ //
+
+ template <typename T, size_t N>
+ inline T const* cbegin(T const (&array)[N]) {
+
+ return array;
+ }
+
+ template <typename T, size_t N>
+ inline T const* cend(T const (&array)[N]) {
+
+ return array + N;
+ }
+
+ template <typename T, size_t N>
+ inline T* begin(T (&array)[N]) {
+
+ return array;
+ }
+
+ template <typename T, size_t N>
+ inline T* end(T (&array)[N]) {
+
+ return array + N;
+ }
+
+ template <typename T, size_t N>
+ inline size_t count(T const (&/* array */)[N]) {
+
+ return N;
+ }
+
+
+ // Copy one vector to another, with type conversion
+
+ template <class T1, class T2>
+ void copy_vector(const T1& v1, T2& v2) {
+
+ const typename T1::size_type count = v1.size();
+
+ v2.resize(count);
+
+ for (typename T1::size_type i = 0 ; i < count ; ++i) {
+ v2[i] = v1[i];
+ }
+ }
+
+
+ /*
+
+ RFC#2822
+ 2.1.1. Line Length Limits
+
+ There are two limits that this standard places on the number of
+ characters in a line. Each line of characters MUST be no more than
+ 998 characters, and SHOULD be no more than 78 characters, excluding
+ the CRLF.
+
+ The 998 character limit is due to limitations in many implementations
+ which send, receive, or store Internet Message Format messages that
+ simply cannot handle more than 998 characters on a line. Receiving
+ implementations would do well to handle an arbitrarily large number
+ of characters in a line for robustness sake. However, there are so
+ many implementations which (in compliance with the transport
+ requirements of [RFC2821]) do not accept messages containing more
+ than 1000 character including the CR and LF per line, it is important
+ for implementations not to create such messages.
+
+ The more conservative 78 character recommendation is to accommodate
+ the many implementations of user interfaces that display these
+ messages which may truncate, or disastrously wrap, the display of
+ more than 78 characters per line, in spite of the fact that such
+ implementations are non-conformant to the intent of this specification
+ (and that of [RFC2821] if they actually cause information to be lost).
+ Again, even though this limitation is put on messages, it is encumbant
+ upon implementations which display messages to handle an arbitrarily
+ large number of characters in a line (certainly at least up to the 998
+ character limit) for the sake of robustness.
+ */
+
+ namespace lineLengthLimits {
+
+ extern VMIME_EXPORT const size_t infinite;
+
+ enum {
+ max = 998,
+ convenient = 78
+ };
+ }
+
+
+ // New line sequence to be used when folding header fields.
+ extern VMIME_EXPORT const string NEW_LINE_SEQUENCE;
+ extern VMIME_EXPORT const size_t NEW_LINE_SEQUENCE_LENGTH;
+
+
+ // CR-LF sequence
+ extern VMIME_EXPORT const string CRLF;
+
+
+ // Mime version
+ extern VMIME_EXPORT const string SUPPORTED_MIME_VERSION;
+
+ /** Utility classes. */
+ namespace utility { }
+
+
+ /** Constant value with the greatest possible value for an element
+ * of type size_t. The meaning is "infinite" or "until the end".
+ */
+ extern VMIME_EXPORT const size_t npos;
+
+
+ /** Clone helper (using a shared_ptr).
+ * This is an alias for dynamic_pointer_cast <T>(obj->clone()).
+ */
+ template <class T>
+ shared_ptr <T> clone(const shared_ptr <T>& obj) {
+
+ return dynamic_pointer_cast <T>(obj->clone());
+ }
+
+ /** Clone helper (using a const shared_ptr).
+ * This is an alias for dynamic_pointer_cast <T>(obj->clone()).
+ */
+ template <class T>
+ shared_ptr <T> clone(const shared_ptr <const T>& obj) {
+
+ return dynamic_pointer_cast <T>(obj->clone());
+ }
+
+ /** Clone helper (using a const reference).
+ * This is an alias for dynamic_pointer_cast <T>(obj.clone()).
+ */
+ template <class T>
+ shared_ptr <T> clone(const T& obj) {
+
+ return dynamic_pointer_cast <T>(obj.clone());
+ }
+
+ /** Downcast helper.
+ * Usage: vmime::dynamicCast <DerivedType>(obj), where 'obj' is of
+ * type Type, and DerivedType is derived from Type.
+ */
+ template <class X, class Y>
+ shared_ptr <X> dynamicCast(const shared_ptr <Y>& obj) {
+
+ return dynamic_pointer_cast <X, Y>(obj);
+ }
+
+ /** Const cast helper.
+ */
+ template <class X, class Y>
+ shared_ptr <X> constCast(const shared_ptr <Y>& obj) {
+
+ return const_pointer_cast <X, Y>(obj);
+ }
+
+ /** Inherit from this class to indicate the subclass is not copyable,
+ * ie. you want to prohibit copy construction and copy assignment.
+ */
+ class VMIME_EXPORT noncopyable {
+
+ protected:
+
+ noncopyable() { }
+ virtual ~noncopyable() { }
+
+ private:
+
+ noncopyable(const noncopyable&);
+ void operator=(const noncopyable&);
+ };
+
+} // vmime
+
+
+#include "vmime/utility/stream.hpp"
+
+
+#endif // VMIME_BASE_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/body.cpp b/vmime-master/src/vmime/body.cpp
new file mode 100644
index 0000000..a3875b9
--- /dev/null
+++ b/vmime-master/src/vmime/body.cpp
@@ -0,0 +1,1111 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/bodyPart.hpp"
+#include "vmime/body.hpp"
+
+#include "vmime/contentTypeField.hpp"
+#include "vmime/text.hpp"
+
+#include "vmime/utility/random.hpp"
+
+#include "vmime/utility/seekableInputStreamRegionAdapter.hpp"
+#include "vmime/utility/outputStreamAdapter.hpp"
+
+#include "vmime/parserHelpers.hpp"
+
+#include "vmime/emptyContentHandler.hpp"
+#include "vmime/stringContentHandler.hpp"
+#include "vmime/streamContentHandler.hpp"
+
+
+namespace vmime {
+
+
+body::body()
+ : m_contents(make_shared <emptyContentHandler>()) {
+
+}
+
+
+body::~body() {
+
+}
+
+
+/*
+ * boundaryStart: will become the index for "\r\n--marker"
+ * boundaryEnd: will become the index after "marker", i.e. index for potential trailing "--", "\r\n", etc.
+ * return value: index for "marker"
+ */
+// static
+size_t body::findNextBoundaryPosition(
+ const shared_ptr <utility::parserInputStreamAdapter>& parser,
+ const string& boundary,
+ const size_t position,
+ const size_t end,
+ size_t* boundaryStart,
+ size_t* boundaryEnd
+) {
+
+ size_t pos = position;
+
+ for (; pos != npos && pos < end; ++pos) {
+
+ pos = parser->findNext(boundary, pos);
+
+ if (pos == npos) {
+ break; // not found
+ }
+
+ if (pos == 0) {
+ // Boundary is a prefix of another, continue the search (same for the other "continue"s)
+ continue;
+ }
+
+ // Ensure the bytes before boundary are "[LF]--": boundary should be
+ // at the beginning of a line, and should start with "--"
+ if (pos < 3) {
+ continue;
+ }
+ parser->seek(pos - 3);
+ if (!parser->matchBytes("\n--", 3)) {
+ continue;
+ }
+
+ parser->seek(pos + boundary.length());
+
+ const byte_t next = parser->peekByte();
+
+ // Boundary should be followed by a new line or a dash
+ if (!isspace(next) && next != '-') {
+ continue;
+ }
+
+ // Get rid of the "[CR]" just before "[LF]--", if any
+ size_t backwards = 0;
+ if (pos >= 4) {
+ parser->seek(pos - 4);
+ if (parser->peekByte() == '\r') {
+ ++backwards;
+ }
+ }
+
+ *boundaryStart = pos - backwards - 3;
+ *boundaryEnd = pos + boundary.length();
+
+ return pos;
+ }
+
+ return pos;
+}
+
+
+void body::parseImpl(
+ const parsingContext& ctx,
+ const shared_ptr <utility::parserInputStreamAdapter>& parser,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition
+) {
+
+ removeAllParts();
+
+ m_prologText.clear();
+ m_epilogText.clear();
+
+ if (end == position) {
+
+ setParsedBounds(position, end);
+
+ if (newPosition) {
+ *newPosition = end;
+ }
+
+ return;
+ }
+
+ // Check whether the body is a MIME-multipart.
+ // If it is, also get (or try to guess) the boundary separator.
+ bool isMultipart = false;
+ string boundary;
+
+ shared_ptr <const contentTypeField> ctf =
+ m_part->getHeader()->findField <contentTypeField>(fields::CONTENT_TYPE);
+
+ if (ctf) {
+
+ const mediaType type = *ctf->getValue <mediaType>();
+
+ if (type.getType() == mediaTypes::MULTIPART) {
+
+ isMultipart = true;
+
+ if (ctf->hasBoundary()) {
+
+ boundary = ctf->getBoundary();
+
+ } else {
+
+ // No "boundary" parameter specified: we can try to
+ // guess it by scanning the body contents...
+ size_t pos = position;
+
+ parser->seek(pos);
+
+ if (pos + 2 < end && parser->matchBytes("--", 2)) {
+
+ pos += 2;
+
+ } else {
+
+ pos = parser->findNext("\n--", position);
+
+ if ((pos != npos) && (pos + 3 < end)) {
+ pos += 3; // skip \n--
+ }
+ }
+
+ if ((pos != npos) && (pos < end)) {
+
+ parser->seek(pos);
+
+ // Read some bytes after boundary separator
+ byte_t buffer[256];
+ const size_t bufferLen =
+ parser->read(buffer, std::min(end - pos, sizeof(buffer) / sizeof(buffer[0])));
+
+ buffer[sizeof(buffer) / sizeof(buffer[0]) - 1] = '\0';
+
+ // Skip transport padding bytes (SPACE or HTAB), if any
+ size_t boundarySkip = 0;
+
+ while (boundarySkip < bufferLen && parserHelpers::isSpace(buffer[boundarySkip])) {
+ ++boundarySkip;
+ }
+
+ // Extract boundary from buffer (stop at first CR or LF).
+ // We have to stop after a reasonnably long boundary length (100)
+ // not to take the whole body contents for a boundary...
+ byte_t boundaryBytes[100];
+ size_t boundaryLen = 0;
+
+ for (byte_t c = buffer[boundarySkip] ;
+ boundaryLen < bufferLen && boundaryLen < 100 && !(c == '\r' || c == '\n') ;
+ ++boundaryLen, c = buffer[boundarySkip + boundaryLen]) {
+
+ boundaryBytes[boundaryLen] = c;
+ }
+
+ if (boundaryLen >= 1 && boundaryLen < 100) {
+
+ // RFC #1521, Page 31:
+ // "...the boundary parameter, which consists of 1 to 70
+ // characters from a set of characters known to be very
+ // robust through email gateways, and NOT ending with
+ // white space..."
+ while (boundaryLen != 0 &&
+ parserHelpers::isSpace(boundaryBytes[boundaryLen - 1])) {
+
+ boundaryLen--;
+ }
+
+ if (boundaryLen >= 1) {
+ boundary = string(boundaryBytes, boundaryBytes + boundaryLen);
+ }
+ }
+ }
+ }
+ }
+ }
+
+ // This is a multi-part body
+ if (isMultipart && !boundary.empty()) {
+
+ size_t partStart = position;
+ size_t pos = position;
+
+ bool lastPart = false;
+
+ // Find the first boundary
+ size_t boundaryStart, boundaryEnd;
+ pos = findNextBoundaryPosition(parser, boundary, pos, end, &boundaryStart, &boundaryEnd);
+
+ for (int index = 0 ; !lastPart && (pos != npos) && (pos < end) ; ++index) {
+
+ size_t partEnd = boundaryStart;
+
+ // Check whether it is the last part (boundary terminated by "--")
+ parser->seek(boundaryEnd);
+
+ if (boundaryEnd + 1 < end && parser->matchBytes("--", 2)) {
+
+ lastPart = true;
+ boundaryEnd += 2;
+ }
+
+ // RFC 2046 §5.1.1 page 22: """If a boundary delimiter
+ // line appears to end with white space, the white
+ // space must be presumed to have been added by a
+ // gateway, and must be deleted."""
+ parser->seek(boundaryEnd);
+ boundaryEnd += parser->skipIf(parserHelpers::isSpaceOrTab, end);
+
+ // End of boundary line
+ if (boundaryEnd + 1 < end && parser->matchBytes("\r\n", 2)) {
+ boundaryEnd += 2;
+ } else if (boundaryEnd < end && parser->peekByte() == '\n') {
+ ++boundaryEnd;
+ } else if (boundaryEnd == end) {
+ } else {
+ /*
+ * RFC 2046 §5.1.1 page 19: """[...] optional
+ * linear whitespace, and a terminating
+ * CRLF.""" — junk handling is left
+ * unspecified, so we might as well skip it to
+ * facilitate broken mails.
+ */
+ boundaryEnd += parser->skipIf([](char_t c) { return c != '\n'; }, end);
+ pos = findNextBoundaryPosition(parser, boundary, boundaryEnd, end, &boundaryStart, &boundaryEnd);
+ --index;
+ continue;
+ }
+
+ if (index == 0) {
+
+ if (partEnd > partStart) {
+
+ vmime::text text;
+ text.parse(ctx, parser, partStart, partEnd);
+
+ m_prologText = text.getWholeBuffer();
+
+ } else {
+
+ m_prologText = "";
+ }
+
+ } else { // index > 0
+
+ shared_ptr <bodyPart> part = m_part->createChildPart();
+
+ // End before start may happen on empty bodyparts (directly
+ // successive boundaries without even a line-break)
+ if (partEnd < partStart) {
+ std::swap(partStart, partEnd);
+ }
+
+ part->parse(ctx, parser, partStart, partEnd, NULL);
+
+ m_parts.push_back(part);
+ }
+
+ partStart = boundaryEnd;
+
+ // Find the next boundary
+ pos = findNextBoundaryPosition(
+ parser, boundary, boundaryEnd, end, &boundaryStart, &boundaryEnd
+ );
+ }
+
+ m_contents = make_shared <emptyContentHandler>();
+
+ // Last part was not found: recover from missing boundary
+ if (!lastPart && pos == npos) {
+
+ shared_ptr <bodyPart> part = m_part->createChildPart();
+
+ try {
+ part->parse(ctx, parser, partStart, end);
+ } catch (std::exception&) {
+ throw;
+ }
+
+ m_parts.push_back(part);
+
+ // Treat remaining text as epilog
+ } else if (partStart < end) {
+
+ vmime::text text;
+ text.parse(ctx, parser, partStart, end);
+
+ m_epilogText = text.getWholeBuffer();
+ }
+
+ // Treat the contents as 'simple' data
+ } else {
+
+ encoding enc;
+
+ shared_ptr <const headerField> cef =
+ m_part->getHeader()->findField(fields::CONTENT_TRANSFER_ENCODING);
+
+ if (cef) {
+
+ enc = *cef->getValue <encoding>();
+
+ } else {
+
+ // Defaults to "7bit" (RFC-1521)
+ enc = vmime::encoding(encodingTypes::SEVEN_BIT);
+ }
+
+ // Extract the (encoded) contents
+ const size_t length = end - position;
+
+ shared_ptr <utility::inputStream> contentStream =
+ make_shared <utility::seekableInputStreamRegionAdapter>(
+ parser->getUnderlyingStream(), position, length
+ );
+
+ m_contents = make_shared <streamContentHandler>(contentStream, length, enc);
+ }
+
+ setParsedBounds(position, end);
+
+ if (newPosition) {
+ *newPosition = end;
+ }
+}
+
+
+text body::getActualPrologText(const generationContext& ctx) const {
+
+ const string& prologText =
+ m_prologText.empty()
+ ? (isRootPart()
+ ? ctx.getPrologText()
+ : NULL_STRING
+ )
+ : m_prologText;
+
+ if (prologText.empty()) {
+ return text();
+ } else {
+ return text(prologText, vmime::charset("us-ascii"));
+ }
+}
+
+
+text body::getActualEpilogText(const generationContext& ctx) const {
+
+ const string& epilogText =
+ m_epilogText.empty()
+ ? (isRootPart()
+ ? ctx.getEpilogText()
+ : NULL_STRING
+ )
+ : m_epilogText;
+
+ if (epilogText.empty()) {
+ return text();
+ } else {
+ return text(epilogText, vmime::charset("us-ascii"));
+ }
+}
+
+
+void body::generateImpl(
+ const generationContext& ctx,
+ utility::outputStream& os,
+ const size_t /* curLinePos */,
+ size_t* newLinePos
+) const {
+
+ // MIME-Multipart
+ if (getPartCount() != 0) {
+
+ string boundary;
+
+ if (!m_part) {
+
+ boundary = generateRandomBoundaryString();
+
+ } else {
+
+ // Use current boundary string, if specified. If no "Content-Type" field is
+ // present, or the boundary is not specified, generate a random one
+ shared_ptr <contentTypeField> ctf =
+ m_part->getHeader()->findField <contentTypeField>(fields::CONTENT_TYPE);
+
+ if (ctf) {
+
+ if (ctf->hasBoundary()) {
+
+ boundary = ctf->getBoundary();
+
+ } else {
+
+ // No boundary string specified
+ boundary = generateRandomBoundaryString();
+ }
+
+ } else {
+
+ // No Content-Type (and no boundary string specified)
+ boundary = generateRandomBoundaryString();
+ }
+ }
+
+ const text prologText = getActualPrologText(ctx);
+ const text epilogText = getActualEpilogText(ctx);
+
+ if (!prologText.isEmpty()) {
+
+ prologText.encodeAndFold(
+ ctx, os, 0, NULL,
+ text::FORCE_NO_ENCODING | text::NO_NEW_LINE_SEQUENCE
+ );
+
+ os << CRLF;
+ }
+
+ os << "--" << boundary;
+
+ for (size_t p = 0 ; p < getPartCount() ; ++p) {
+
+ os << CRLF;
+
+ getPartAt(p)->generate(ctx, os, 0);
+
+ os << CRLF << "--" << boundary;
+ }
+
+ os << "--" << CRLF;
+
+ if (!epilogText.isEmpty()) {
+
+ epilogText.encodeAndFold(
+ ctx, os, 0, NULL,
+ text::FORCE_NO_ENCODING | text::NO_NEW_LINE_SEQUENCE
+ );
+
+ os << CRLF;
+ }
+
+ if (newLinePos) {
+ *newLinePos = 0;
+ }
+
+ // Simple body
+ } else {
+
+ // Generate the contents
+ shared_ptr <contentHandler> contents = m_contents->clone();
+ contents->setContentTypeHint(getContentType());
+
+ contents->generate(os, getEncoding(), ctx.getMaxLineLength());
+ }
+}
+
+
+size_t body::getGeneratedSize(const generationContext& ctx) {
+
+ // MIME-Multipart
+ if (getPartCount() != 0) {
+
+ size_t size = 0;
+
+ // Size of parts and boundaries
+ for (size_t p = 0 ; p < getPartCount() ; ++p) {
+ size += 100; // boundary, CRLF...
+ size += getPartAt(p)->getGeneratedSize(ctx);
+ }
+
+ // Size of prolog/epilog text
+ const text prologText = getActualPrologText(ctx);
+
+ if (!prologText.isEmpty()) {
+
+ std::ostringstream oss;
+ utility::outputStreamAdapter osa(oss);
+
+ prologText.encodeAndFold(
+ ctx, osa, 0, NULL,
+ text::FORCE_NO_ENCODING | text::NO_NEW_LINE_SEQUENCE
+ );
+
+ size += oss.str().size();
+ }
+
+ const text epilogText = getActualEpilogText(ctx);
+
+ if (!epilogText.isEmpty()) {
+
+ std::ostringstream oss;
+ utility::outputStreamAdapter osa(oss);
+
+ epilogText.encodeAndFold(
+ ctx, osa, 0, NULL,
+ text::FORCE_NO_ENCODING | text::NO_NEW_LINE_SEQUENCE
+ );
+
+ size += oss.str().size();
+ }
+
+ return size;
+
+ // Simple body
+ } else {
+
+ if (getEncoding() == m_contents->getEncoding()) {
+
+ // No re-encoding has to be performed
+ return m_contents->getLength();
+
+ } else {
+
+ shared_ptr <utility::encoder::encoder> srcEncoder = m_contents->getEncoding().getEncoder();
+ shared_ptr <utility::encoder::encoder> dstEncoder = getEncoding().getEncoder();
+
+ return dstEncoder->getEncodedSize(srcEncoder->getDecodedSize(m_contents->getLength()));
+ }
+ }
+}
+
+
+/*
+ RFC #1521, Page 32:
+ 7.2.1. Multipart: The common syntax
+
+ "...Encapsulation boundaries must not appear within the
+ encapsulations, and must be no longer than 70 characters..."
+
+
+ boundary := 0*69<bchars> bcharsnospace
+
+ bchars := bcharsnospace / " "
+
+ bcharsnospace := DIGIT / ALPHA / "'" / "(" / ")" / "+" /"_"
+ / "," / "-" / "." / "/" / ":" / "=" / "?"
+*/
+
+const string body::generateRandomBoundaryString() {
+
+ // 64 characters that can be _safely_ used in a boundary string
+ static const char bchars[] = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-+";
+
+ /*
+ RFC #1521, Page 19:
+
+ Since the hyphen character ("-") is represented as itself in the
+ Quoted-Printable encoding, care must be taken, when encapsulating a
+ quoted-printable encoded body in a multipart entity, to ensure that
+ the encapsulation boundary does not appear anywhere in the encoded
+ body. (A good strategy is to choose a boundary that includes a
+ character sequence such as "=_" which can never appear in a quoted-
+ printable body. See the definition of multipart messages later in
+ this document.)
+ */
+
+ char boundary[2 + 48 + 1] = { 0 };
+
+ boundary[0] = '=';
+ boundary[1] = '_';
+
+ // Generate a string of random characters
+ unsigned int r = utility::random::getTime();
+ unsigned int m = static_cast <unsigned int>(sizeof(unsigned int));
+
+ for (size_t i = 2 ; i < (sizeof(boundary) / sizeof(boundary[0]) - 1) ; ++i) {
+
+ boundary[i] = bchars[r & 63];
+ r >>= 6;
+
+ if (--m == 0) {
+ r = utility::random::getNext();
+ m = static_cast <unsigned int>(sizeof(unsigned int));
+ }
+ }
+
+ return string(boundary);
+}
+
+
+bool body::isValidBoundary(const string& boundary) {
+
+ static const string validChars("0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'()+_,-./:=?");
+
+ const string::const_iterator end = boundary.end();
+ bool valid = false;
+
+ if (boundary.length() > 0 && boundary.length() < 70) {
+
+ const char last = *(end - 1);
+
+ if (!(last == ' ' || last == '\t' || last == '\n')) {
+
+ valid = true;
+
+ for (string::const_iterator i = boundary.begin() ; valid && i != end ; ++i) {
+ valid = (validChars.find_first_of(*i) != string::npos);
+ }
+ }
+ }
+
+ return valid;
+}
+
+
+//
+// Quick-access functions
+//
+
+
+void body::setContentType(const mediaType& type, const charset& chset) {
+
+ shared_ptr <contentTypeField> ctf =
+ dynamicCast <contentTypeField>(m_part->getHeader()->ContentType());
+
+ ctf->setValue(type);
+ ctf->setCharset(chset);
+}
+
+
+void body::setContentType(const mediaType& type) {
+
+ m_part->getHeader()->ContentType()->setValue(type);
+}
+
+
+const mediaType body::getContentType() const {
+
+ shared_ptr <const contentTypeField> ctf =
+ m_part->getHeader()->findField <contentTypeField>(fields::CONTENT_TYPE);
+
+ if (ctf) {
+
+ return *ctf->getValue <mediaType>();
+
+ } else {
+
+ // Defaults to "text/plain" (RFC-1521)
+ return mediaType(mediaTypes::TEXT, mediaTypes::TEXT_PLAIN);
+ }
+}
+
+
+void body::setCharset(const charset& chset) {
+
+ shared_ptr <contentTypeField> ctf =
+ m_part->getHeader()->findField <contentTypeField>(fields::CONTENT_TYPE);
+
+ // If a Content-Type field exists, set charset
+ if (ctf) {
+
+ ctf->setCharset(chset);
+
+ // Else, create a new Content-Type field of default type "text/plain"
+ // and set charset on it
+ } else {
+
+ setContentType(mediaType(mediaTypes::TEXT, mediaTypes::TEXT_PLAIN), chset);
+ }
+}
+
+
+const charset body::getCharset() const {
+
+ const shared_ptr <const contentTypeField> ctf =
+ m_part->getHeader()->findField <contentTypeField>(fields::CONTENT_TYPE);
+
+ if (ctf) {
+
+ if (ctf->hasCharset()) {
+
+ return ctf->getCharset();
+
+ } else {
+
+ // Defaults to "us-ascii" (RFC-1521)
+ return vmime::charset(charsets::US_ASCII);
+ }
+
+ } else {
+
+ // Defaults to "us-ascii" (RFC-1521)
+ return vmime::charset(charsets::US_ASCII);
+ }
+}
+
+
+void body::setEncoding(const encoding& enc) {
+
+ m_part->getHeader()->ContentTransferEncoding()->setValue(enc);
+}
+
+
+const encoding body::getEncoding() const {
+
+ shared_ptr <const headerField> cef =
+ m_part->getHeader()->findField(fields::CONTENT_TRANSFER_ENCODING);
+
+ if (cef) {
+
+ return *cef->getValue <encoding>();
+
+ } else {
+
+ if (m_contents->isEncoded()) {
+ return m_contents->getEncoding();
+ }
+ }
+
+ // Defaults to "7bit" (RFC-1521)
+ return vmime::encoding(encodingTypes::SEVEN_BIT);
+}
+
+
+void body::setParentPart(bodyPart* parent) {
+
+ m_part = parent;
+
+ for (std::vector <shared_ptr <bodyPart> >::iterator it = m_parts.begin() ;
+ it != m_parts.end() ; ++it) {
+
+ shared_ptr <bodyPart> childPart = *it;
+ parent->importChildPart(childPart);
+ }
+}
+
+
+bool body::isRootPart() const {
+
+ return !m_part || !m_part->getParentPart();
+}
+
+
+shared_ptr <component> body::clone() const {
+
+ shared_ptr <body> bdy = make_shared <body>();
+
+ bdy->copyFrom(*this);
+
+ return bdy;
+}
+
+
+void body::copyFrom(const component& other) {
+
+ const body& bdy = dynamic_cast <const body&>(other);
+
+ m_prologText = bdy.m_prologText;
+ m_epilogText = bdy.m_epilogText;
+
+ m_contents = bdy.m_contents;
+
+ removeAllParts();
+
+ for (size_t p = 0 ; p < bdy.getPartCount() ; ++p) {
+
+ shared_ptr <bodyPart> part = m_part->createChildPart();
+
+ part->copyFrom(*bdy.getPartAt(p));
+
+ m_parts.push_back(part);
+ }
+}
+
+
+body& body::operator=(const body& other) {
+
+ copyFrom(other);
+ return *this;
+}
+
+
+const string& body::getPrologText() const {
+
+ return m_prologText;
+}
+
+
+void body::setPrologText(const string& prologText) {
+
+ m_prologText = prologText;
+}
+
+
+const string& body::getEpilogText() const {
+
+ return m_epilogText;
+}
+
+
+void body::setEpilogText(const string& epilogText) {
+
+ m_epilogText = epilogText;
+}
+
+
+const shared_ptr <const contentHandler> body::getContents() const {
+
+ return m_contents;
+}
+
+
+void body::setContents(const shared_ptr <const contentHandler>& contents) {
+
+ m_contents = contents;
+}
+
+
+void body::setContents(
+ const shared_ptr <const contentHandler>& contents,
+ const mediaType& type
+) {
+
+ m_contents = contents;
+
+ setContentType(type);
+}
+
+
+void body::setContents(
+ const shared_ptr <const contentHandler>& contents,
+ const mediaType& type,
+ const charset& chset
+) {
+
+ m_contents = contents;
+
+ setContentType(type, chset);
+}
+
+
+void body::setContents(
+ const shared_ptr <const contentHandler>& contents,
+ const mediaType& type,
+ const charset& chset,
+ const encoding& enc
+) {
+
+ m_contents = contents;
+
+ setContentType(type, chset);
+ setEncoding(enc);
+}
+
+
+void body::initNewPart(const shared_ptr <bodyPart>& part) {
+
+ // A part can be in only one body at the same time: if part is
+ // already attached to a parent part, remove it from the current
+ // parent part
+ if (part->getParentPart()) {
+ part->getParentPart()->getBody()->removePart(part);
+ }
+
+ if (m_part) {
+
+ m_part->importChildPart(part);
+
+ shared_ptr <header> hdr = m_part->getHeader();
+
+ // Check whether we have a boundary string
+ shared_ptr <contentTypeField> ctf =
+ hdr->findField <contentTypeField>(fields::CONTENT_TYPE);
+
+ if (ctf) {
+
+ if (ctf->hasBoundary()) {
+
+ const string boundary = ctf->getBoundary();
+
+ if (boundary.empty() || !isValidBoundary(boundary)) {
+ ctf->setBoundary(generateRandomBoundaryString());
+ }
+
+ } else {
+
+ // No "boundary" parameter: generate a random one.
+ ctf->setBoundary(generateRandomBoundaryString());
+ }
+
+ if (ctf->getValue <mediaType>()->getType() != mediaTypes::MULTIPART) {
+
+ // Warning: multi-part body but the Content-Type is
+ // not specified as "multipart/..."
+ }
+
+ } else {
+
+ // No "Content-Type" field: create a new one and generate
+ // a random boundary string.
+ ctf = hdr->getField <contentTypeField>(fields::CONTENT_TYPE);
+
+ ctf->setValue(mediaType(mediaTypes::MULTIPART, mediaTypes::MULTIPART_MIXED));
+ ctf->setBoundary(generateRandomBoundaryString());
+ }
+ }
+}
+
+
+void body::appendPart(const shared_ptr <bodyPart>& part) {
+
+ initNewPart(part);
+
+ m_parts.push_back(part);
+}
+
+
+void body::insertPartBefore(
+ const shared_ptr <bodyPart>& beforePart,
+ const shared_ptr <bodyPart>& part
+) {
+
+ initNewPart(part);
+
+ const std::vector <shared_ptr <bodyPart> >::iterator it = std::find(
+ m_parts.begin(), m_parts.end(), beforePart
+ );
+
+ if (it == m_parts.end()) {
+ throw exceptions::no_such_part();
+ }
+
+ m_parts.insert(it, part);
+}
+
+
+void body::insertPartBefore(
+ const size_t pos,
+ const shared_ptr <bodyPart>& part
+) {
+
+ initNewPart(part);
+
+ m_parts.insert(m_parts.begin() + pos, part);
+}
+
+
+void body::insertPartAfter(
+ const shared_ptr <bodyPart>& afterPart,
+ const shared_ptr <bodyPart>& part
+) {
+
+ initNewPart(part);
+
+ const std::vector <shared_ptr <bodyPart> >::iterator it = std::find(
+ m_parts.begin(), m_parts.end(), afterPart
+ );
+
+ if (it == m_parts.end()) {
+ throw exceptions::no_such_part();
+ }
+
+ m_parts.insert(it + 1, part);
+}
+
+
+void body::insertPartAfter(const size_t pos, const shared_ptr <bodyPart>& part) {
+
+ initNewPart(part);
+
+ m_parts.insert(m_parts.begin() + pos + 1, part);
+}
+
+
+void body::removePart(const shared_ptr <bodyPart>& part) {
+
+ const std::vector <shared_ptr <bodyPart> >::iterator it = std::find(
+ m_parts.begin(), m_parts.end(), part
+ );
+
+ if (it == m_parts.end()) {
+ throw exceptions::no_such_part();
+ }
+
+ m_parts.erase(it);
+}
+
+
+void body::removePart(const size_t pos) {
+
+ m_parts.erase(m_parts.begin() + pos);
+}
+
+
+void body::removeAllParts() {
+
+ m_parts.clear();
+}
+
+
+size_t body::getPartCount() const {
+
+ return m_parts.size();
+}
+
+
+bool body::isEmpty() const {
+
+ return m_parts.size() == 0;
+}
+
+
+shared_ptr <bodyPart> body::getPartAt(const size_t pos) {
+
+ return m_parts[pos];
+}
+
+
+const shared_ptr <const bodyPart> body::getPartAt(const size_t pos) const {
+
+ return m_parts[pos];
+}
+
+
+const std::vector <shared_ptr <const bodyPart> > body::getPartList() const {
+
+ std::vector <shared_ptr <const bodyPart> > list;
+
+ list.reserve(m_parts.size());
+
+ for (std::vector <shared_ptr <bodyPart> >::const_iterator it = m_parts.begin() ;
+ it != m_parts.end() ; ++it) {
+
+ list.push_back(*it);
+ }
+
+ return list;
+}
+
+
+const std::vector <shared_ptr <bodyPart> > body::getPartList() {
+
+ return m_parts;
+}
+
+
+const std::vector <shared_ptr <component> > body::getChildComponents() {
+
+ std::vector <shared_ptr <component> > list;
+
+ copy_vector(m_parts, list);
+
+ return list;
+}
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/body.hpp b/vmime-master/src/vmime/body.hpp
new file mode 100644
index 0000000..7ece000
--- /dev/null
+++ b/vmime-master/src/vmime/body.hpp
@@ -0,0 +1,365 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_BODY_HPP_INCLUDED
+#define VMIME_BODY_HPP_INCLUDED
+
+
+#include "vmime/base.hpp"
+#include "vmime/component.hpp"
+
+#include "vmime/header.hpp"
+
+#include "vmime/mediaType.hpp"
+#include "vmime/charset.hpp"
+#include "vmime/encoding.hpp"
+
+#include "vmime/contentHandler.hpp"
+
+
+namespace vmime {
+
+
+class bodyPart;
+
+
+/** Body section of a MIME part.
+ */
+class VMIME_EXPORT body : public component {
+
+ friend class bodyPart;
+
+public:
+
+ body();
+ ~body();
+
+ /** Add a part at the end of the list.
+ *
+ * @param part part to append
+ */
+ void appendPart(const shared_ptr <bodyPart>& part);
+
+ /** Insert a new part before the specified part.
+ *
+ * @param beforePart part before which the new part will be inserted
+ * @param part part to insert
+ * @throw exceptions::no_such_part if the part is not in the list
+ */
+ void insertPartBefore(
+ const shared_ptr <bodyPart>& beforePart,
+ const shared_ptr <bodyPart>& part
+ );
+
+ /** Insert a new part before the specified position.
+ *
+ * @param pos position at which to insert the new part (0 to insert at
+ * the beginning of the list)
+ * @param part part to insert
+ */
+ void insertPartBefore(const size_t pos, const shared_ptr <bodyPart>& part);
+
+ /** Insert a new part after the specified part.
+ *
+ * @param afterPart part after which the new part will be inserted
+ * @param part part to insert
+ * @throw exceptions::no_such_part if the part is not in the list
+ */
+ void insertPartAfter(
+ const shared_ptr <bodyPart>& afterPart,
+ const shared_ptr <bodyPart>& part
+ );
+
+ /** Insert a new part after the specified position.
+ *
+ * @param pos position of the part before the new part
+ * @param part part to insert
+ */
+ void insertPartAfter(const size_t pos, const shared_ptr <bodyPart>& part);
+
+ /** Remove the specified part from the list.
+ *
+ * @param part part to remove
+ * @throw exceptions::no_such_part if the part is not in the list
+ */
+ void removePart(const shared_ptr <bodyPart>& part);
+
+ /** Remove the part at the specified position.
+ *
+ * @param pos position of the part to remove
+ */
+ void removePart(const size_t pos);
+
+ /** Remove all parts from the list.
+ */
+ void removeAllParts();
+
+ /** Return the number of parts in the list.
+ *
+ * @return number of parts
+ */
+ size_t getPartCount() const;
+
+ /** Tests whether the list of parts is empty.
+ *
+ * @return true if there is no part, false otherwise
+ */
+ bool isEmpty() const;
+
+ /** Return the part at the specified position.
+ *
+ * @param pos position
+ * @return part at position 'pos'
+ */
+ shared_ptr <bodyPart> getPartAt(const size_t pos);
+
+ /** Return the part at the specified position.
+ *
+ * @param pos position
+ * @return part at position 'pos'
+ */
+ const shared_ptr <const bodyPart> getPartAt(const size_t pos) const;
+
+ /** Return the part list.
+ *
+ * @return list of parts
+ */
+ const std::vector <shared_ptr <const bodyPart> > getPartList() const;
+
+ /** Return the part list.
+ *
+ * @return list of parts
+ */
+ const std::vector <shared_ptr <bodyPart> > getPartList();
+
+ /** Return the prolog text.
+ *
+ * @return prolog text
+ */
+ const string& getPrologText() const;
+
+ /** Set the prolog text.
+ *
+ * @param prologText new prolog text
+ */
+ void setPrologText(const string& prologText);
+
+ /** Return the epilog text.
+ *
+ * @return epilog text
+ */
+ const string& getEpilogText() const;
+
+ /** Set the epilog text.
+ *
+ * @param epilogText new epilog text
+ */
+ void setEpilogText(const string& epilogText);
+
+ /** Return a read-only reference to body contents.
+ *
+ * @return read-only body contents
+ */
+ const shared_ptr <const contentHandler> getContents() const;
+
+ /** Set the body contents.
+ *
+ * @param contents new body contents
+ */
+ void setContents(const shared_ptr <const contentHandler>& contents);
+
+ /** Set the body contents and type.
+ *
+ * @param contents new body contents
+ * @param type type of contents
+ */
+ void setContents(
+ const shared_ptr <const contentHandler>& contents,
+ const mediaType& type
+ );
+
+ /** Set the body contents, type and charset.
+ *
+ * @param contents new body contents
+ * @param type type of contents
+ * @param chset charset of contents
+ */
+ void setContents(
+ const shared_ptr <const contentHandler>& contents,
+ const mediaType& type,
+ const charset& chset
+ );
+
+ /** Set the body contents, type, charset and encoding.
+ *
+ * @param contents new body contents
+ * @param type type of contents
+ * @param chset charset of contents
+ * @param enc contents encoding
+ */
+ void setContents(
+ const shared_ptr <const contentHandler>& contents,
+ const mediaType& type,
+ const charset& chset,
+ const encoding& enc
+ );
+
+ /** Set the MIME type and charset of contents.
+ * If a charset is defined, it will not be modified.
+ *
+ * @param type MIME media type of contents
+ * @param chset charset of contents
+ */
+ void setContentType(const mediaType& type, const charset& chset);
+
+ /** Set the MIME type of contents.
+ *
+ * @param type MIME media type of contents
+ */
+ void setContentType(const mediaType& type);
+
+ /** Return the media type of the data contained in the body contents.
+ * This is a shortcut for getHeader()->ContentType()->getValue()
+ * on the parent part.
+ *
+ * @return media type of body contents
+ */
+ const mediaType getContentType() const;
+
+ /** Set the charset of contents.
+ * If the type is not set, it will be set to default "text/plain" type.
+ *
+ * @param chset charset of contents
+ */
+ void setCharset(const charset& chset);
+
+ /** Return the charset of the data contained in the body contents.
+ * This is a shortcut for getHeader()->ContentType()->getCharset()
+ * on the parent part.
+ *
+ * @return charset of body contents
+ */
+ const charset getCharset() const;
+
+ /** Set the output encoding of contents.
+ * Contents will be encoded (or re-encoded) when this node is being generated.
+ *
+ * @param enc encoding of contents
+ */
+ void setEncoding(const encoding& enc);
+
+ /** Return the encoding used to encode the body contents.
+ * This is a shortcut for getHeader()->ContentTransferEncoding()->getValue()
+ * on the parent part.
+ *
+ * @return encoding of body contents
+ */
+ const encoding getEncoding() const;
+
+ /** Generate a new random boundary string.
+ *
+ * @return randomly generated boundary string
+ */
+ static const string generateRandomBoundaryString();
+
+ /** Test a boundary string for validity (as defined in RFC #1521, page 19).
+ *
+ * @param boundary boundary string to test
+ * @return true if the boundary string is valid, false otherwise
+ */
+ static bool isValidBoundary(const string& boundary);
+
+ shared_ptr <component> clone() const;
+ void copyFrom(const component& other);
+ body& operator=(const body& other);
+
+ const std::vector <shared_ptr <component> > getChildComponents();
+
+ size_t getGeneratedSize(const generationContext& ctx);
+
+private:
+
+ text getActualPrologText(const generationContext& ctx) const;
+ text getActualEpilogText(const generationContext& ctx) const;
+
+ void setParentPart(bodyPart* parent);
+
+
+ string m_prologText;
+ string m_epilogText;
+
+ shared_ptr <const contentHandler> m_contents;
+
+ bodyPart* m_part;
+
+ std::vector <shared_ptr <bodyPart> > m_parts;
+
+ bool isRootPart() const;
+
+ void initNewPart(const shared_ptr <bodyPart>& part);
+
+protected:
+
+ /** Finds the next boundary position in the parsing buffer.
+ *
+ * @param parser parser object
+ * @param boundary boundary string (without "--" nor CR/LF)
+ * @param position start position
+ * @param end end position
+ * @param boundaryStart will hold the start position of the boundary (including any
+ * CR/LF and "--" before the boundary)
+ * @param boundaryEnd will hold the end position of the boundary (position just
+ * before the CRLF or "--" which follows)
+ * @return the position of the boundary string, or npos if not found
+ */
+ size_t findNextBoundaryPosition(
+ const shared_ptr <utility::parserInputStreamAdapter>& parser,
+ const string& boundary,
+ const size_t position,
+ const size_t end,
+ size_t* boundaryStart,
+ size_t* boundaryEnd
+ );
+
+ // Component parsing & assembling
+ void parseImpl(
+ const parsingContext& ctx,
+ const shared_ptr <utility::parserInputStreamAdapter>& parser,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition = NULL
+ );
+
+ void generateImpl(
+ const generationContext& ctx,
+ utility::outputStream& os,
+ const size_t curLinePos = 0,
+ size_t* newLinePos = NULL
+ ) const;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_BODY_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/bodyPart.cpp b/vmime-master/src/vmime/bodyPart.cpp
new file mode 100644
index 0000000..ff81994
--- /dev/null
+++ b/vmime-master/src/vmime/bodyPart.cpp
@@ -0,0 +1,198 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/bodyPart.hpp"
+
+
+namespace vmime {
+
+
+bodyPart::bodyPart()
+ : m_header(make_shared <header>()),
+ m_body(make_shared <body>()),
+ m_parent() {
+
+ m_body->setParentPart(this);
+}
+
+
+void bodyPart::parseImpl(
+ const parsingContext& ctx,
+ const shared_ptr <utility::parserInputStreamAdapter>& parser,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition
+) {
+
+ // Parse the headers
+ size_t pos = position;
+ m_header->parse(ctx, parser, pos, end, &pos);
+
+ // Parse the body contents
+ m_body->parse(ctx, parser, pos, end, NULL);
+
+ setParsedBounds(position, end);
+
+ if (newPosition) {
+ *newPosition = end;
+ }
+}
+
+
+void bodyPart::generateImpl(
+ const generationContext& ctx,
+ utility::outputStream& os,
+ const size_t /* curLinePos */,
+ size_t* newLinePos
+) const {
+
+ m_header->generate(ctx, os);
+
+ os << CRLF;
+
+ m_body->generate(ctx, os);
+
+ if (newLinePos) {
+ *newLinePos = 0;
+ }
+}
+
+
+size_t bodyPart::getGeneratedSize(const generationContext& ctx) {
+
+ return m_header->getGeneratedSize(ctx) + 2 /* CRLF */ + m_body->getGeneratedSize(ctx);
+}
+
+
+shared_ptr <component> bodyPart::clone() const {
+
+ shared_ptr <bodyPart> p = make_shared <bodyPart>();
+
+ p->m_parent = NULL;
+
+ p->m_header->copyFrom(*m_header);
+ p->m_body->copyFrom(*m_body);
+
+ return p;
+}
+
+
+void bodyPart::copyFrom(const component& other) {
+
+ const bodyPart& bp = dynamic_cast <const bodyPart&>(other);
+
+ m_header->copyFrom(*(bp.m_header));
+ m_body->copyFrom(*(bp.m_body));
+}
+
+
+bodyPart& bodyPart::operator=(const bodyPart& other) {
+
+ copyFrom(other);
+ return *this;
+}
+
+
+const shared_ptr <const header> bodyPart::getHeader() const {
+
+ return m_header;
+}
+
+
+shared_ptr <header> bodyPart::getHeader() {
+
+ return m_header;
+}
+
+
+void bodyPart::setHeader(const shared_ptr <header>& h) {
+
+ m_header = h;
+}
+
+
+const shared_ptr <const body> bodyPart::getBody() const {
+
+ return m_body;
+}
+
+
+shared_ptr <body> bodyPart::getBody() {
+
+ return m_body;
+}
+
+
+void bodyPart::setBody(const shared_ptr <body>& b) {
+
+ bodyPart* oldPart = b->m_part;
+
+ m_body = b;
+ m_body->setParentPart(this);
+
+ // A body is associated to one and only one part
+ if (oldPart) {
+ oldPart->setBody(make_shared <body>());
+ }
+}
+
+
+bodyPart* bodyPart::getParentPart() {
+
+ return m_parent;
+}
+
+
+const bodyPart* bodyPart::getParentPart() const {
+
+ return m_parent;
+}
+
+
+shared_ptr <bodyPart> bodyPart::createChildPart() {
+
+ shared_ptr <bodyPart> part = make_shared <bodyPart>();
+ part->m_parent = this;
+
+ return part;
+}
+
+
+void bodyPart::importChildPart(const shared_ptr <bodyPart>& part) {
+
+ part->m_parent = this;
+}
+
+
+const std::vector <shared_ptr <component> > bodyPart::getChildComponents() {
+
+ std::vector <shared_ptr <component> > list;
+
+ list.push_back(m_header);
+ list.push_back(m_body);
+
+ return list;
+}
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/bodyPart.hpp b/vmime-master/src/vmime/bodyPart.hpp
new file mode 100644
index 0000000..f63b367
--- /dev/null
+++ b/vmime-master/src/vmime/bodyPart.hpp
@@ -0,0 +1,155 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_BODYPART_HPP_INCLUDED
+#define VMIME_BODYPART_HPP_INCLUDED
+
+
+#include "vmime/base.hpp"
+#include "vmime/component.hpp"
+
+#include "vmime/header.hpp"
+#include "vmime/body.hpp"
+
+
+namespace vmime {
+
+
+/** A MIME part.
+ */
+class VMIME_EXPORT bodyPart : public component {
+
+ friend class body;
+
+public:
+
+ bodyPart();
+
+ /** Return the header section of this part.
+ *
+ * @return header section
+ */
+ const shared_ptr <const header> getHeader() const;
+
+ /** Return the header section of this part.
+ *
+ * @return header section
+ */
+ shared_ptr <header> getHeader();
+
+ /** Replaces the header section of this part.
+ *
+ * @param header the new header of this part
+ */
+ void setHeader(const shared_ptr <header>& header);
+
+ /** Return the body section of this part.
+ *
+ * @return body section
+ */
+ const shared_ptr <const body> getBody() const;
+
+ /** Return the body section of this part.
+ *
+ * @return body section
+ */
+ shared_ptr <body> getBody();
+
+ /** Replaces the body section of this part.
+ *
+ * @param body new body section
+ */
+ void setBody(const shared_ptr <body>& body);
+
+ /** Return the parent part of this part.
+ *
+ * @return parent part or NULL if not known
+ */
+ bodyPart* getParentPart();
+
+ /** Return the parent part of this part (const version).
+ *
+ * @return parent part or NULL if not known
+ */
+ const bodyPart* getParentPart() const;
+
+
+ shared_ptr <component> clone() const;
+ void copyFrom(const component& other);
+ bodyPart& operator=(const bodyPart& other);
+
+ const std::vector <shared_ptr <component> > getChildComponents();
+
+ size_t getGeneratedSize(const generationContext& ctx);
+
+private:
+
+ shared_ptr <header> m_header;
+ mutable shared_ptr <body> m_body;
+
+ // We can't use a weak_ptr<> here as the parent part may
+ // have been allocated on the stack
+ bodyPart* m_parent;
+
+protected:
+
+ /** Creates and returns a new part and set this part as its
+ * parent. The newly created sub-part should then be added
+ * to this part by calling getBody()->appendPart(). Called
+ * by the body class.
+ *
+ * @return child part
+ */
+ shared_ptr <bodyPart> createChildPart();
+
+ /** Detach the specified part from its current parent part (if
+ * any) and attach it to this part by setting this part as its
+ * new parent. The sub-part should then be added to this part
+ * by calling getBody()->appendPart(). Called by body class.
+ *
+ * @param part child part to attach
+ */
+ void importChildPart(const shared_ptr <bodyPart>& part);
+
+ // Component parsing & assembling
+ void parseImpl(
+ const parsingContext& ctx,
+ const shared_ptr <utility::parserInputStreamAdapter>& parser,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition = NULL
+ );
+
+ void generateImpl(
+ const generationContext& ctx,
+ utility::outputStream& os,
+ const size_t curLinePos = 0,
+ size_t* newLinePos = NULL
+ ) const;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_BODYPART_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/bodyPartAttachment.cpp b/vmime-master/src/vmime/bodyPartAttachment.cpp
new file mode 100644
index 0000000..01b306e
--- /dev/null
+++ b/vmime-master/src/vmime/bodyPartAttachment.cpp
@@ -0,0 +1,147 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/bodyPartAttachment.hpp"
+
+
+namespace vmime {
+
+
+bodyPartAttachment::bodyPartAttachment(const shared_ptr <const bodyPart>& part)
+ : m_part(part) {
+
+}
+
+
+const mediaType bodyPartAttachment::getType() const {
+
+ shared_ptr <const contentTypeField> ctf = getContentType();
+
+ if (ctf) {
+
+ return *ctf->getValue <mediaType>();
+
+ } else {
+
+ // No "Content-type" field: assume "application/octet-stream".
+ return mediaType(
+ mediaTypes::APPLICATION,
+ mediaTypes::APPLICATION_OCTET_STREAM
+ );
+ }
+}
+
+
+const word bodyPartAttachment::getName() const {
+
+ word name;
+
+ // Try the 'filename' parameter of 'Content-Disposition' field
+ shared_ptr <const contentDispositionField> cdf = getContentDisposition();
+
+ if (cdf && cdf->hasFilename()) {
+
+ name = cdf->getFilename();
+
+ // Try the 'name' parameter of 'Content-Type' field
+ } else {
+
+ shared_ptr <const contentTypeField> ctf = getContentType();
+
+ if (ctf) {
+
+ shared_ptr <const parameter> prm = ctf->findParameter("name");
+
+ if (prm) {
+ name = prm->getValue();
+ }
+ }
+ }
+
+ return name;
+}
+
+
+const text bodyPartAttachment::getDescription() const {
+
+ text description;
+
+ shared_ptr <const headerField> cd =
+ getHeader()->findField(fields::CONTENT_DESCRIPTION);
+
+ if (cd) {
+
+ description = *cd->getValue <text>();
+
+ } else {
+
+ // No description available.
+ }
+
+ return description;
+}
+
+
+const encoding bodyPartAttachment::getEncoding() const {
+
+ return m_part->getBody()->getEncoding();
+}
+
+
+const shared_ptr <const contentHandler> bodyPartAttachment::getData() const {
+
+ return m_part->getBody()->getContents();
+}
+
+
+shared_ptr <const object> bodyPartAttachment::getPart() const {
+
+ return m_part;
+}
+
+
+shared_ptr <const header> bodyPartAttachment::getHeader() const {
+
+ return m_part->getHeader();
+}
+
+
+shared_ptr <const contentDispositionField> bodyPartAttachment::getContentDisposition() const {
+
+ return getHeader()->findField <contentDispositionField>(fields::CONTENT_DISPOSITION);
+}
+
+
+shared_ptr <const contentTypeField> bodyPartAttachment::getContentType() const {
+
+ return getHeader()->findField <contentTypeField>(fields::CONTENT_TYPE);
+}
+
+
+void bodyPartAttachment::generateIn(const shared_ptr <bodyPart>& /* parent */) const {
+
+ // Not used
+}
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/bodyPartAttachment.hpp b/vmime-master/src/vmime/bodyPartAttachment.hpp
new file mode 100644
index 0000000..974e2f8
--- /dev/null
+++ b/vmime-master/src/vmime/bodyPartAttachment.hpp
@@ -0,0 +1,76 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_BODYPARTATTACHMENT_HPP_INCLUDED
+#define VMIME_BODYPARTATTACHMENT_HPP_INCLUDED
+
+
+#ifndef VMIME_BUILDING_DOC // implementation detail
+
+
+#include "vmime/attachment.hpp"
+
+#include "vmime/contentDispositionField.hpp"
+#include "vmime/contentTypeField.hpp"
+
+
+namespace vmime {
+
+
+/** An attachment related to a local body part.
+ */
+class VMIME_EXPORT bodyPartAttachment : public attachment {
+
+public:
+
+ bodyPartAttachment(const shared_ptr <const bodyPart>& part);
+
+ const mediaType getType() const;
+ const word getName() const;
+ const text getDescription() const;
+ const encoding getEncoding() const;
+
+ const shared_ptr <const contentHandler> getData() const;
+
+ shared_ptr <const object> getPart() const;
+ shared_ptr <const header> getHeader() const;
+
+private:
+
+ void generateIn(const shared_ptr <bodyPart>& parent) const;
+
+ shared_ptr <const contentDispositionField> getContentDisposition() const;
+ shared_ptr <const contentTypeField> getContentType() const;
+
+
+ shared_ptr <const bodyPart> m_part;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_BUILDING_DOC
+
+
+#endif // VMIME_BODYPARTATTACHMENT_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/charset.cpp b/vmime-master/src/vmime/charset.cpp
new file mode 100644
index 0000000..8828c56
--- /dev/null
+++ b/vmime-master/src/vmime/charset.cpp
@@ -0,0 +1,268 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/charset.hpp"
+#include "vmime/exception.hpp"
+#include "vmime/platform.hpp"
+#include "vmime/encoding.hpp"
+
+#include "vmime/utility/stringUtils.hpp"
+
+#include "vmime/charsetConverter.hpp"
+
+
+
+namespace vmime {
+
+
+charset::charset()
+ : m_name(charsets::US_ASCII) {
+
+}
+
+
+charset::charset(const string& name)
+ : m_name(name) {
+
+ // If we receive this rfc-1642 valid MIME charset, convert it to something usefull for iconv
+ if (utility::stringUtils::isStringEqualNoCase(m_name, "unicode-1-1-utf-7")) {
+ m_name = "utf-7";
+ }
+}
+
+
+charset::charset(const char* name)
+ : m_name(name) {
+
+}
+
+
+void charset::parseImpl(
+ const parsingContext& /* ctx */,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition
+) {
+
+ m_name = utility::stringUtils::trim(
+ string(buffer.begin() + position, buffer.begin() + end)
+ );
+
+ // If we parsed this rfc-1642 valid MIME charset, convert it to something usefull for iconv
+ if (utility::stringUtils::isStringEqualNoCase(m_name, "unicode-1-1-utf-7")) {
+ m_name = "utf-7";
+ }
+
+ setParsedBounds(position, end);
+
+ if (newPosition) {
+ *newPosition = end;
+ }
+}
+
+
+void charset::generateImpl(
+ const generationContext& /* ctx */,
+ utility::outputStream& os,
+ const size_t curLinePos,
+ size_t* newLinePos
+) const {
+
+ os << m_name;
+
+ if (newLinePos) {
+ *newLinePos = curLinePos + m_name.length();
+ }
+}
+
+
+void charset::convert(
+ utility::inputStream& in,
+ utility::outputStream& out,
+ const charset& source,
+ const charset& dest,
+ const charsetConverterOptions& opts
+) {
+
+ shared_ptr <charsetConverter> conv = charsetConverter::create(source, dest, opts);
+ conv->convert(in, out);
+}
+
+
+void charset::convert(
+ const string& in,
+ string& out,
+ const charset& source,
+ const charset& dest,
+ const charsetConverterOptions& opts
+) {
+
+ if (source == dest) {
+ out = in;
+ return;
+ }
+
+ shared_ptr <charsetConverter> conv = charsetConverter::create(source, dest, opts);
+ conv->convert(in, out);
+}
+
+
+bool charset::isValidText(const string& text, string::size_type* firstInvalidByte) const {
+
+ charsetConverterOptions opts;
+ opts.silentlyReplaceInvalidSequences = false;
+
+ charsetConverter::status st;
+
+ try {
+
+ std::string out;
+
+ // Try converting to UTF-8
+ shared_ptr <charsetConverter> conv = charsetConverter::create(*this, vmime::charset("utf-8"), opts);
+ conv->convert(text, out, &st);
+
+ } catch (exceptions::illegal_byte_sequence_for_charset& e) {
+
+ // An illegal byte sequence was found in the input buffer
+ if (firstInvalidByte) {
+
+ if (st.inputBytesRead < text.length())
+ *firstInvalidByte = st.inputBytesRead;
+ else
+ *firstInvalidByte = text.length();
+ }
+
+ return false;
+ }
+
+ if (firstInvalidByte) {
+ *firstInvalidByte = text.length();
+ }
+
+ return true;
+}
+
+
+const charset charset::getLocalCharset() {
+
+ return platform::getHandler()->getLocalCharset();
+}
+
+
+charset& charset::operator=(const charset& other) {
+
+ copyFrom(other);
+ return *this;
+}
+
+
+bool charset::operator==(const charset& value) const {
+
+ return utility::stringUtils::isStringEqualNoCase(m_name, value.m_name);
+}
+
+
+bool charset::operator!=(const charset& value) const {
+
+ return !(*this == value);
+}
+
+
+shared_ptr <component> charset::clone() const {
+
+ return make_shared <charset>(m_name);
+}
+
+
+const string& charset::getName() const {
+
+ return m_name;
+}
+
+
+void charset::copyFrom(const component& other) {
+
+ m_name = dynamic_cast <const charset&>(other).m_name;
+}
+
+
+const std::vector <shared_ptr <component> > charset::getChildComponents() {
+
+ return std::vector <shared_ptr <component> >();
+}
+
+
+
+// Explicitly force encoding for some charsets
+struct CharsetEncodingEntry {
+
+ CharsetEncodingEntry(const string& charset_, const string& encoding_)
+ : charset(charset_), encoding(encoding_) {
+
+ }
+
+ const string charset;
+ const string encoding;
+};
+
+
+CharsetEncodingEntry g_charsetEncodingMap[] = {
+
+ // Use QP encoding for ISO-8859-x charsets
+ CharsetEncodingEntry("iso-8859", encodingTypes::QUOTED_PRINTABLE),
+ CharsetEncodingEntry("iso8859", encodingTypes::QUOTED_PRINTABLE),
+
+ // RFC-1468 states:
+ // " ISO-2022-JP may also be used in MIME Part 2 headers. The "B"
+ // encoding should be used with ISO-2022-JP text. "
+ // Use Base64 encoding for all ISO-2022 charsets.
+ CharsetEncodingEntry("iso-2022", encodingTypes::BASE64),
+ CharsetEncodingEntry("iso2022", encodingTypes::BASE64),
+
+ // Last entry is not used
+ CharsetEncodingEntry("", "")
+};
+
+
+bool charset::getRecommendedEncoding(encoding& enc) const {
+
+ // Special treatment for some charsets
+ const string cset = utility::stringUtils::toLower(getName());
+
+ for (unsigned int i = 0 ;
+ i < (sizeof(g_charsetEncodingMap) / sizeof(g_charsetEncodingMap[0])) - 1 ;
+ ++i) {
+
+ if (cset.find(g_charsetEncodingMap[i].charset) != string::npos) {
+ enc = g_charsetEncodingMap[i].encoding;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/charset.hpp b/vmime-master/src/vmime/charset.hpp
new file mode 100644
index 0000000..61f9bd6
--- /dev/null
+++ b/vmime-master/src/vmime/charset.hpp
@@ -0,0 +1,176 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_CHARSET_HPP_INCLUDED
+#define VMIME_CHARSET_HPP_INCLUDED
+
+
+#include "vmime/base.hpp"
+#include "vmime/utility/inputStream.hpp"
+#include "vmime/utility/outputStream.hpp"
+#include "vmime/charsetConverterOptions.hpp"
+#include "vmime/component.hpp"
+
+
+namespace vmime {
+
+
+class encoding; // forward reference
+
+
+/** Charset description (basic type).
+ */
+class VMIME_EXPORT charset : public component {
+
+public:
+
+ charset();
+ charset(const string& name);
+ charset(const char* name); // to allow creation from vmime::charsets constants
+
+public:
+
+ /** Return the ISO name of the charset.
+ *
+ * @return charset name
+ */
+ const string& getName() const;
+
+ charset& operator=(const charset& other);
+
+ bool operator==(const charset& value) const;
+ bool operator!=(const charset& value) const;
+
+ const std::vector <shared_ptr <component> > getChildComponents();
+
+ /** Gets the recommended encoding for this charset.
+ * Note: there may be no recommended encoding.
+ *
+ * @param enc output parameter that will hold recommended encoding
+ * @return true if an encoding is recommended (the encoding is stored
+ * in the enc parameter), false otherwise (in this case, the enc
+ * parameter is not modified)
+ */
+ bool getRecommendedEncoding(encoding& enc) const;
+
+ /** Returns the default charset used on the system.
+ *
+ * This function simply calls <code>platformHandler::getLocalCharset()</code>
+ * and is provided for convenience.
+ *
+ * @return system default charset
+ */
+ static const charset getLocalCharset();
+
+ /** Convert a string buffer from one charset to another
+ * charset (in-memory conversion)
+ *
+ * \deprecated Use the new convert() method, which takes
+ * an outputStream parameter.
+ *
+ * @param in input buffer
+ * @param out output buffer
+ * @param source input charset
+ * @param dest output charset
+ * @param opts conversion options
+ * @throws exceptions::illegal_byte_sequence_for_charset if an illegal
+ * byte sequence was found in the input bytes, and the
+ * 'silentlyReplaceInvalidSequences' flag is set to false in
+ * the charsetConverterOptions
+ * @throws exceptions::charset_conv_error if an unexpected error occurred
+ * during the conversion
+ */
+ static void convert(
+ const string& in,
+ string& out,
+ const charset& source,
+ const charset& dest,
+ const charsetConverterOptions& opts = charsetConverterOptions()
+ );
+
+ /** Convert the contents of an input stream in a specified charset
+ * to another charset and write the result to an output stream.
+ *
+ * @param in input stream to read data from
+ * @param out output stream to write the converted data
+ * @param source input charset
+ * @param dest output charset
+ * @param opts conversion options
+ * @throws exceptions::illegal_byte_sequence_for_charset if an illegal
+ * byte sequence was found in the input bytes, and the
+ * 'silentlyReplaceInvalidSequences' flag is set to false in
+ * the charsetConverterOptions
+ * @throws exceptions::charset_conv_error if an unexpected error occurred
+ * during the conversion
+ */
+ static void convert(
+ utility::inputStream& in,
+ utility::outputStream& out,
+ const charset& source,
+ const charset& dest,
+ const charsetConverterOptions& opts = charsetConverterOptions()
+ );
+
+ /** Checks whether the specified text is valid in this charset.
+ *
+ * @param text input text
+ * @param firstInvalidByte if the function returns false, will contain
+ * the index of the first invalid byte in the string. Can be NULL if
+ * not used.
+ * @return true if the text is perfectly valid in this charset,
+ * or false otherwise (eg. it contains illegal sequences)
+ */
+ bool isValidText(const string& text, string::size_type* firstInvalidByte) const;
+
+
+ shared_ptr <component> clone() const;
+ void copyFrom(const component& other);
+
+private:
+
+ string m_name;
+
+protected:
+
+ // Component parsing & assembling
+ void parseImpl(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition = NULL
+ );
+
+ void generateImpl(
+ const generationContext& ctx,
+ utility::outputStream& os,
+ const size_t curLinePos = 0,
+ size_t* newLinePos = NULL
+ ) const;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_CHARSET_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/charsetConverter.cpp b/vmime-master/src/vmime/charsetConverter.cpp
new file mode 100644
index 0000000..96bc3b8
--- /dev/null
+++ b/vmime-master/src/vmime/charsetConverter.cpp
@@ -0,0 +1,53 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/charsetConverter.hpp"
+
+#include "vmime/charsetConverter_idna.hpp"
+
+
+namespace vmime {
+
+
+// static
+shared_ptr <charsetConverter> charsetConverter::create(
+ const charset& source,
+ const charset& dest,
+ const charsetConverterOptions& opts
+) {
+
+ if (source == "idna" || dest == "idna") {
+ return make_shared <charsetConverter_idna>(source, dest, opts);
+ } else {
+ return createGenericConverter(source, dest, opts);
+ }
+}
+
+
+charsetConverter::status::status()
+ : inputBytesRead(0), outputBytesWritten(0) {
+
+}
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/charsetConverter.hpp b/vmime-master/src/vmime/charsetConverter.hpp
new file mode 100644
index 0000000..2cde4b5
--- /dev/null
+++ b/vmime-master/src/vmime/charsetConverter.hpp
@@ -0,0 +1,162 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_CHARSETCONVERTER_HPP_INCLUDED
+#define VMIME_CHARSETCONVERTER_HPP_INCLUDED
+
+
+#include "vmime/base.hpp"
+#include "vmime/component.hpp"
+
+#include "vmime/charset.hpp"
+#include "vmime/charsetConverterOptions.hpp"
+#include "vmime/utility/filteredStream.hpp"
+
+
+namespace vmime {
+
+
+namespace utility {
+
+
+/** A filtered output stream which applies a charset conversion
+ * to input bytes.
+ *
+ * May throw a exceptions::charset_conv_error if an unexpected error
+ * occurred when initializing convert, or during charset conversion.
+ *
+ * May also throw a exceptions::illegal_byte_sequence_for_charset
+ * if an illegal byte sequence was found in the input bytes, and the
+ * 'silentlyReplaceInvalidSequences' flag is set to false in
+ * the charsetConverterOptions.
+ */
+class VMIME_EXPORT charsetFilteredOutputStream : public filteredOutputStream {
+
+};
+
+
+} // utility
+
+
+/** Convert between charsets.
+ */
+class VMIME_EXPORT charsetConverter : public object {
+
+public:
+
+ /** Holds information about a conversion.
+ */
+ struct status {
+
+ status();
+
+
+ /** Number of bytes read from input buffer and successfully converted.
+ */
+ size_t inputBytesRead;
+
+ /** Number of bytes written to output buffer.
+ */
+ size_t outputBytesWritten;
+ };
+
+
+ /** Construct and initialize an iconv charset converter.
+ *
+ * @param source input charset
+ * @param dest output charset
+ * @param opts conversion options
+ */
+ static shared_ptr <charsetConverter> create(
+ const charset& source,
+ const charset& dest,
+ const charsetConverterOptions& opts = charsetConverterOptions()
+ );
+
+ /** Convert a string buffer from one charset to another
+ * charset (in-memory conversion)
+ *
+ * \deprecated Use the new convert() method, which takes
+ * an outputStream parameter.
+ *
+ * @param in input buffer
+ * @param out output buffer
+ * @param st will receive some extra infos when conversion is finished
+ * or stopped by an error (can be NULL)
+ * @throws exceptions::illegal_byte_sequence_for_charset if an illegal
+ * byte sequence was found in the input bytes, and the
+ * 'silentlyReplaceInvalidSequences' flag is set to false in
+ * the charsetConverterOptions
+ * @throws exceptions::charset_conv_error if an unexpected error occurred
+ * during the conversion
+ */
+ virtual void convert(const string& in, string& out, status* st = NULL) = 0;
+
+ /** Convert the contents of an input stream in a specified charset
+ * to another charset and write the result to an output stream.
+ *
+ * @param in input stream to read data from
+ * @param out output stream to write the converted data
+ * @param st will receive some extra infos when conversion is finished
+ * or stopped by an error (can be NULL)
+ * @throws exceptions::illegal_byte_sequence_for_charset if an illegal
+ * byte sequence was found in the input bytes, and the
+ * 'silentlyReplaceInvalidSequences' flag is set to false in
+ * the charsetConverterOptions
+ * @throws exceptions::charset_conv_error if an unexpected error occurred
+ * during the conversion
+ */
+ virtual void convert(
+ utility::inputStream& in,
+ utility::outputStream& out,
+ status* st = NULL
+ ) = 0;
+
+ /** Returns a filtered output stream which applies a charset
+ * conversion to input bytes. Please note that it may not be
+ * supported by the converter.
+ *
+ * @param os stream into which filtered data will be written
+ * @param opts conversion options
+ * @return a filtered output stream, or NULL if not supported
+ */
+ virtual shared_ptr <utility::charsetFilteredOutputStream>
+ getFilteredOutputStream(
+ utility::outputStream& os,
+ const charsetConverterOptions& opts = charsetConverterOptions()
+ ) = 0;
+
+private:
+
+ static shared_ptr <charsetConverter> createGenericConverter(
+ const charset& source,
+ const charset& dest,
+ const charsetConverterOptions& opts
+ );
+};
+
+
+} // vmime
+
+
+#endif // VMIME_CHARSETCONVERTER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/charsetConverterOptions.cpp b/vmime-master/src/vmime/charsetConverterOptions.cpp
new file mode 100644
index 0000000..a18a928
--- /dev/null
+++ b/vmime-master/src/vmime/charsetConverterOptions.cpp
@@ -0,0 +1,37 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/charsetConverterOptions.hpp"
+
+
+namespace vmime {
+
+
+charsetConverterOptions::charsetConverterOptions()
+ : silentlyReplaceInvalidSequences(true),
+ invalidSequence("?") {
+
+}
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/charsetConverterOptions.hpp b/vmime-master/src/vmime/charsetConverterOptions.hpp
new file mode 100644
index 0000000..567e004
--- /dev/null
+++ b/vmime-master/src/vmime/charsetConverterOptions.hpp
@@ -0,0 +1,59 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_CHARSETCONVERTEROPTIONS_HPP_INCLUDED
+#define VMIME_CHARSETCONVERTEROPTIONS_HPP_INCLUDED
+
+
+#include "vmime/base.hpp"
+
+
+namespace vmime {
+
+
+/** Options for charset conversion.
+ */
+class VMIME_EXPORT charsetConverterOptions : public object {
+
+public:
+
+ charsetConverterOptions();
+
+
+ /** If true, invalid sequences will be silently replaced with
+ * a string when possible (see 'invalidSequence').
+ * Default is true.
+ */
+ bool silentlyReplaceInvalidSequences;
+
+ /** Replace invalid sequences with this string.
+ * Default is '?'.
+ */
+ string invalidSequence;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_CHARSETCONVERTEROPTIONS_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/charsetConverter_iconv.cpp b/vmime-master/src/vmime/charsetConverter_iconv.cpp
new file mode 100644
index 0000000..5c4cc17
--- /dev/null
+++ b/vmime-master/src/vmime/charsetConverter_iconv.cpp
@@ -0,0 +1,537 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_CHARSETCONV_LIB_IS_ICONV
+
+
+#include "vmime/charsetConverter_iconv.hpp"
+
+#include "vmime/exception.hpp"
+#include "vmime/utility/inputStreamStringAdapter.hpp"
+#include "vmime/utility/outputStreamStringAdapter.hpp"
+
+
+extern "C" {
+
+#ifndef VMIME_BUILDING_DOC
+
+ #include <iconv.h>
+ #include <errno.h>
+
+ // HACK: prototypes may differ depending on the compiler and/or system (the
+ // second parameter may or may not be 'const'). This relies on the compiler
+ // for choosing the right type.
+
+ class ICONV_IN_TYPE {
+
+ public:
+
+ ICONV_IN_TYPE(const char** ptr) : m_ptr(ptr) { }
+
+ ICONV_IN_TYPE(const vmime::byte_t** ptr)
+ : m_ptr(reinterpret_cast <const char**>(ptr)) { }
+
+ operator const char**() { return m_ptr; }
+ operator char**() { return const_cast <char**>(m_ptr); }
+
+ private:
+
+ const char** m_ptr;
+ };
+
+ class ICONV_OUT_TYPE {
+
+ public:
+
+ ICONV_OUT_TYPE(char** ptr) : m_ptr(ptr) { }
+
+ ICONV_OUT_TYPE(vmime::byte_t** ptr)
+ : m_ptr(reinterpret_cast <char**>(ptr)) { }
+
+ operator char**() { return m_ptr; }
+
+ private:
+
+ char** m_ptr;
+ };
+
+#endif // VMIME_BUILDING_DOC
+}
+
+
+
+// Output replacement char when an invalid sequence is encountered
+template <typename OUTPUT_CLASS, typename ICONV_DESC>
+void outputInvalidChar(
+ OUTPUT_CLASS& out,
+ ICONV_DESC cd,
+ const vmime::charsetConverterOptions& opts = vmime::charsetConverterOptions()
+) {
+
+ const char* invalidCharIn = opts.invalidSequence.c_str();
+ vmime::size_t invalidCharInLen = opts.invalidSequence.length();
+
+ vmime::byte_t invalidCharOutBuffer[16];
+ vmime::byte_t* invalidCharOutPtr = invalidCharOutBuffer;
+ vmime::size_t invalidCharOutLen = 16;
+
+ if (iconv(cd, ICONV_IN_TYPE(&invalidCharIn), &invalidCharInLen,
+ ICONV_OUT_TYPE(&invalidCharOutPtr), &invalidCharOutLen) != static_cast <size_t>(-1)) {
+
+ out.write(invalidCharOutBuffer, 16 - invalidCharOutLen);
+ }
+}
+
+
+
+namespace vmime {
+
+
+// static
+shared_ptr <charsetConverter> charsetConverter::createGenericConverter(
+ const charset& source,
+ const charset& dest,
+ const charsetConverterOptions& opts
+) {
+
+ return make_shared <charsetConverter_iconv>(source, dest, opts);
+}
+
+
+charsetConverter_iconv::charsetConverter_iconv(
+ const charset& source,
+ const charset& dest,
+ const charsetConverterOptions& opts
+)
+ : m_desc(NULL),
+ m_source(source),
+ m_dest(dest),
+ m_options(opts) {
+
+ // Get an iconv descriptor
+ const iconv_t cd = iconv_open(dest.getName().c_str(), source.getName().c_str());
+
+ if (cd != reinterpret_cast <iconv_t>(-1)) {
+
+ iconv_t* p = new iconv_t;
+ *p= cd;
+
+ m_desc = p;
+ }
+}
+
+
+charsetConverter_iconv::~charsetConverter_iconv() {
+
+ if (m_desc) {
+
+ // Close iconv handle
+ iconv_close(*static_cast <iconv_t*>(m_desc));
+
+ delete static_cast <iconv_t*>(m_desc);
+ m_desc = NULL;
+ }
+}
+
+
+void charsetConverter_iconv::convert(
+ utility::inputStream& in,
+ utility::outputStream& out,
+ status* st
+) {
+
+ if (st) {
+ new (st) status();
+ }
+
+ if (!m_desc) {
+ throw exceptions::charset_conv_error("Cannot initialize converter.");
+ }
+
+ const iconv_t cd = *static_cast <iconv_t*>(m_desc);
+
+ byte_t inBuffer[32768];
+ byte_t outBuffer[32768];
+ size_t inPos = 0;
+
+ bool prevIsInvalid = false;
+ bool breakAfterNext = false;
+
+ while (true) {
+
+ // Fullfill the buffer
+ size_t inLength = static_cast <size_t>(in.read(inBuffer + inPos, sizeof(inBuffer) - inPos) + inPos);
+ size_t outLength = sizeof(outBuffer);
+
+ const byte_t* inPtr = breakAfterNext ? NULL : inBuffer;
+ size_t *ptrLength = breakAfterNext ? NULL : &inLength;
+ byte_t* outPtr = outBuffer;
+
+ // Convert input bytes
+ if (iconv(cd, ICONV_IN_TYPE(&inPtr), ptrLength,
+ ICONV_OUT_TYPE(&outPtr), &outLength) == static_cast <size_t>(-1)) {
+
+ if (st && inPtr) {
+ st->inputBytesRead += (inPtr - inBuffer);
+ st->outputBytesWritten += (outPtr - outBuffer);
+ }
+
+ // Illegal input sequence or input sequence has no equivalent
+ // sequence in the destination charset.
+ if (prevIsInvalid) {
+
+ // Write successfully converted bytes
+ out.write(outBuffer, sizeof(outBuffer) - outLength);
+
+ if (!m_options.silentlyReplaceInvalidSequences) {
+ throw exceptions::illegal_byte_sequence_for_charset();
+ }
+
+ // Output a special character to indicate we don't known how to
+ // convert the sequence at this position
+ outputInvalidChar(out, cd, m_options);
+
+ // Skip a byte and leave unconverted bytes in the input buffer
+ std::copy(const_cast <byte_t*>(inPtr + 1), inBuffer + sizeof(inBuffer), inBuffer);
+ inPos = inLength - 1;
+
+ } else {
+
+ // Write successfully converted bytes
+ out.write(outBuffer, sizeof(outBuffer) - outLength);
+
+ // Leave unconverted bytes in the input buffer
+ std::copy(const_cast <byte_t*>(inPtr), inBuffer + sizeof(inBuffer), inBuffer);
+ inPos = inLength;
+
+ if (errno != E2BIG) {
+ prevIsInvalid = true;
+ }
+ }
+
+ } else {
+
+ // Write successfully converted bytes
+ out.write(outBuffer, sizeof(outBuffer) - outLength);
+
+ if (st && inPtr) {
+ st->inputBytesRead += (inPtr - inBuffer);
+ st->outputBytesWritten += (outPtr - outBuffer);
+ }
+
+ inPos = 0;
+ prevIsInvalid = false;
+ }
+
+ if (breakAfterNext) {
+ break;
+ }
+
+ // Check for end of data, loop again to flush stateful data from iconv
+ if (in.eof() && inPos == 0) {
+ breakAfterNext = true;
+ }
+ }
+}
+
+
+void charsetConverter_iconv::convert(const string& in, string& out, status* st) {
+
+ if (st) {
+ new (st) status();
+ }
+
+ out.clear();
+
+ utility::inputStreamStringAdapter is(in);
+ utility::outputStreamStringAdapter os(out);
+
+ convert(is, os, st);
+
+ os.flush();
+}
+
+
+shared_ptr <utility::charsetFilteredOutputStream>
+ charsetConverter_iconv::getFilteredOutputStream(
+ utility::outputStream& os,
+ const charsetConverterOptions& opts
+ ) {
+
+ return make_shared <utility::charsetFilteredOutputStream_iconv>(m_source, m_dest, &os, opts);
+}
+
+
+
+// charsetFilteredOutputStream_iconv
+
+namespace utility {
+
+
+charsetFilteredOutputStream_iconv::charsetFilteredOutputStream_iconv(
+ const charset& source,
+ const charset& dest, outputStream* os,
+ const charsetConverterOptions& opts
+)
+ : m_desc(NULL),
+ m_sourceCharset(source),
+ m_destCharset(dest),
+ m_stream(*os),
+ m_unconvCount(0),
+ m_options(opts) {
+
+ // Get an iconv descriptor
+ const iconv_t cd = iconv_open(dest.getName().c_str(), source.getName().c_str());
+
+ if (cd != reinterpret_cast <iconv_t>(-1)) {
+
+ iconv_t* p = new iconv_t;
+ *p= cd;
+
+ m_desc = p;
+ }
+}
+
+
+charsetFilteredOutputStream_iconv::~charsetFilteredOutputStream_iconv() {
+
+ if (m_desc) {
+
+ // Close iconv handle
+ iconv_close(*static_cast <iconv_t*>(m_desc));
+
+ delete static_cast <iconv_t*>(m_desc);
+ m_desc = NULL;
+ }
+}
+
+
+outputStream& charsetFilteredOutputStream_iconv::getNextOutputStream() {
+
+ return m_stream;
+}
+
+
+void charsetFilteredOutputStream_iconv::writeImpl(
+ const byte_t* const data,
+ const size_t count
+) {
+
+ if (!m_desc) {
+ throw exceptions::charset_conv_error("Cannot initialize converter.");
+ }
+
+ const iconv_t cd = *static_cast <iconv_t*>(m_desc);
+
+ const byte_t* curData = data;
+ size_t curDataLen = count;
+
+ // If there is some unconverted bytes left, add more data from this
+ // chunk to see if it can now be converted.
+ while (m_unconvCount != 0 || curDataLen != 0) {
+
+ if (m_unconvCount != 0) {
+
+ // Check if an incomplete input sequence is larger than the
+ // input buffer size: should not happen except if something
+ // in the input sequence is invalid. If so, output a special
+ // character and skip one byte in the invalid sequence.
+ if (m_unconvCount >= sizeof(m_unconvBuffer)) {
+
+ if (!m_options.silentlyReplaceInvalidSequences) {
+ throw exceptions::illegal_byte_sequence_for_charset();
+ }
+
+ outputInvalidChar(m_stream, cd);
+
+ std::copy(
+ m_unconvBuffer + 1,
+ m_unconvBuffer + m_unconvCount, m_unconvBuffer
+ );
+
+ m_unconvCount--;
+ }
+
+ // Get more data
+ const size_t remaining =
+ std::min(curDataLen, sizeof(m_unconvBuffer) - m_unconvCount);
+
+ std::copy(curData, curData + remaining, m_unconvBuffer + m_unconvCount);
+
+ m_unconvCount += remaining;
+ curDataLen -= remaining;
+ curData += remaining;
+
+ if (remaining == 0)
+ return; // no more data
+
+ // Try a conversion
+ const byte_t* inPtr = m_unconvBuffer;
+ size_t inLength = m_unconvCount;
+ byte_t* outPtr = m_outputBuffer;
+ size_t outLength = sizeof(m_outputBuffer);
+
+ const size_t inLength0 = inLength;
+
+ if (iconv(cd, ICONV_IN_TYPE(&inPtr), &inLength,
+ ICONV_OUT_TYPE(&outPtr), &outLength) == static_cast <size_t>(-1)) {
+
+ const size_t inputConverted = inLength0 - inLength;
+
+ // Write successfully converted bytes
+ m_stream.write(m_outputBuffer, sizeof(m_outputBuffer) - outLength);
+
+ // Shift unconverted bytes
+ std::copy(
+ m_unconvBuffer + inputConverted,
+ m_unconvBuffer + m_unconvCount, m_unconvBuffer
+ );
+
+ m_unconvCount -= inputConverted;
+
+ continue;
+ }
+
+ // Write successfully converted bytes
+ m_stream.write(m_outputBuffer, sizeof(m_outputBuffer) - outLength);
+
+ // Empty the unconverted buffer
+ m_unconvCount = 0;
+ }
+
+ if (curDataLen == 0) {
+ return; // no more data
+ }
+
+ // Now, convert the current data buffer
+ const byte_t* inPtr = curData;
+ size_t inLength = std::min(curDataLen, sizeof(m_outputBuffer) / MAX_CHARACTER_WIDTH);
+ byte_t* outPtr = m_outputBuffer;
+ size_t outLength = sizeof(m_outputBuffer);
+
+ const size_t inLength0 = inLength;
+
+ if (iconv(cd, ICONV_IN_TYPE(&inPtr), &inLength,
+ ICONV_OUT_TYPE(&outPtr), &outLength) == static_cast <size_t>(-1)) {
+
+ // Write successfully converted bytes
+ m_stream.write(m_outputBuffer, sizeof(m_outputBuffer) - outLength);
+
+ const size_t inputConverted = inLength0 - inLength;
+
+ curData += inputConverted;
+ curDataLen -= inputConverted;
+
+ // Put one byte byte into the unconverted buffer so
+ // that the next iteration fill it
+ if (curDataLen != 0) {
+
+ m_unconvCount = 1;
+ m_unconvBuffer[0] = *curData;
+
+ curData++;
+ curDataLen--;
+ }
+
+ } else {
+
+ // Write successfully converted bytes
+ m_stream.write(m_outputBuffer, sizeof(m_outputBuffer) - outLength);
+
+ curData += inLength0;
+ curDataLen -= inLength0;
+ }
+ }
+}
+
+
+void charsetFilteredOutputStream_iconv::flush() {
+
+ if (!m_desc) {
+ throw exceptions::charset_conv_error("Cannot initialize converter.");
+ }
+
+ const iconv_t cd = *static_cast <iconv_t*>(m_desc);
+
+ size_t offset = 0;
+
+ // Process unconverted bytes
+ while (m_unconvCount != 0) {
+
+ // Try a conversion
+ const byte_t* inPtr = m_unconvBuffer + offset;
+ size_t inLength = m_unconvCount;
+ byte_t* outPtr = m_outputBuffer;
+ size_t outLength = sizeof(m_outputBuffer);
+
+ const size_t inLength0 = inLength;
+
+ if (iconv(cd, ICONV_IN_TYPE(&inPtr), &inLength,
+ ICONV_OUT_TYPE(&outPtr), &outLength) == static_cast <size_t>(-1)) {
+
+ const size_t inputConverted = inLength0 - inLength;
+
+ // Skip a "blocking" character
+ if (inputConverted == 0) {
+
+ if (!m_options.silentlyReplaceInvalidSequences) {
+ throw exceptions::illegal_byte_sequence_for_charset();
+ }
+
+ outputInvalidChar(m_stream, cd);
+
+ offset++;
+ m_unconvCount--;
+
+ } else {
+
+ // Write successfully converted bytes
+ m_stream.write(m_outputBuffer, sizeof(m_outputBuffer) - outLength);
+
+ offset += inputConverted;
+ m_unconvCount -= inputConverted;
+ }
+
+ } else {
+
+ // Write successfully converted bytes
+ m_stream.write(m_outputBuffer, sizeof(m_outputBuffer) - outLength);
+
+ m_unconvCount = 0;
+ }
+ }
+
+ m_stream.flush();
+}
+
+
+} // utility
+
+
+} // vmime
+
+
+#endif // VMIME_CHARSETCONV_LIB_IS_ICONV
diff --git a/vmime-master/src/vmime/charsetConverter_iconv.hpp b/vmime-master/src/vmime/charsetConverter_iconv.hpp
new file mode 100644
index 0000000..c64813c
--- /dev/null
+++ b/vmime-master/src/vmime/charsetConverter_iconv.hpp
@@ -0,0 +1,145 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_CHARSETCONVERTER_ICONV_HPP_INCLUDED
+#define VMIME_CHARSETCONVERTER_ICONV_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_CHARSETCONV_LIB_IS_ICONV
+
+
+#include "vmime/charsetConverter.hpp"
+
+
+namespace vmime {
+
+
+/** A generic charset converter which uses iconv library.
+ */
+class charsetConverter_iconv : public charsetConverter {
+
+public:
+
+ /** Construct and initialize an iconv charset converter.
+ *
+ * @param source input charset
+ * @param dest output charset
+ * @param opts conversion options
+ */
+ charsetConverter_iconv(
+ const charset& source,
+ const charset& dest,
+ const charsetConverterOptions& opts = charsetConverterOptions()
+ );
+
+ ~charsetConverter_iconv();
+
+ void convert(const string& in, string& out, status* st = NULL);
+ void convert(utility::inputStream& in, utility::outputStream& out, status* st = NULL);
+
+ shared_ptr <utility::charsetFilteredOutputStream> getFilteredOutputStream(
+ utility::outputStream& os,
+ const charsetConverterOptions& opts = charsetConverterOptions()
+ );
+
+private:
+
+ void* m_desc;
+
+ charset m_source;
+ charset m_dest;
+
+ charsetConverterOptions m_options;
+};
+
+
+namespace utility {
+
+
+class charsetFilteredOutputStream_iconv : public charsetFilteredOutputStream {
+
+public:
+
+ /** Construct a new filter for the specified output stream.
+ *
+ * @param source input charset
+ * @param dest output charset
+ * @param os stream into which write filtered data
+ * @param opts conversion options
+ */
+ charsetFilteredOutputStream_iconv(
+ const charset& source,
+ const charset& dest, outputStream* os,
+ const charsetConverterOptions& opts = charsetConverterOptions()
+ );
+
+ ~charsetFilteredOutputStream_iconv();
+
+
+ outputStream& getNextOutputStream();
+
+ void flush();
+
+protected:
+
+ void writeImpl(const byte_t* const data, const size_t count);
+
+private:
+
+ // Maximum character width in any charset
+ enum { MAX_CHARACTER_WIDTH = 128 };
+
+
+ void* m_desc;
+
+ const charset m_sourceCharset;
+ const charset m_destCharset;
+
+ outputStream& m_stream;
+
+ // Buffer in which unconverted bytes are left until they can
+ // be converted (when more data arrives). The length should be
+ // large enough to contain any character in any charset.
+ byte_t m_unconvBuffer[MAX_CHARACTER_WIDTH];
+ size_t m_unconvCount;
+
+ // Buffer used for conversion. Avoids declaring it in write().
+ // Should be at least MAX_CHARACTER_WIDTH * MAX_CHARACTER_WIDTH.
+ byte_t m_outputBuffer[32768];
+
+ charsetConverterOptions m_options;
+};
+
+
+} // utility
+
+
+} // vmime
+
+
+#endif // VMIME_CHARSETCONV_LIB_IS_ICONV
+
+#endif // VMIME_CHARSETCONVERTER_ICONV_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/charsetConverter_icu.cpp b/vmime-master/src/vmime/charsetConverter_icu.cpp
new file mode 100644
index 0000000..55195b7
--- /dev/null
+++ b/vmime-master/src/vmime/charsetConverter_icu.cpp
@@ -0,0 +1,572 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_CHARSETCONV_LIB_IS_ICU
+
+
+#include "vmime/charsetConverter_icu.hpp"
+
+#include "vmime/exception.hpp"
+#include "vmime/utility/inputStreamStringAdapter.hpp"
+#include "vmime/utility/outputStreamStringAdapter.hpp"
+
+
+#ifndef VMIME_BUILDING_DOC
+
+ #include <unicode/ucnv.h>
+ #include <unicode/ucnv_err.h>
+
+#endif // VMIME_BUILDING_DOC
+
+
+#include <unicode/unistr.h>
+
+
+namespace vmime {
+
+
+// static
+shared_ptr <charsetConverter> charsetConverter::createGenericConverter(
+ const charset& source,
+ const charset& dest,
+ const charsetConverterOptions& opts
+) {
+
+ return make_shared <charsetConverter_icu>(source, dest, opts);
+}
+
+
+charsetConverter_icu::charsetConverter_icu(
+ const charset& source,
+ const charset& dest,
+ const charsetConverterOptions& opts
+)
+ : m_from(NULL),
+ m_to(NULL),
+ m_source(source),
+ m_dest(dest),
+ m_options(opts) {
+
+ UErrorCode err = U_ZERO_ERROR;
+ m_from = ucnv_open(source.getName().c_str(), &err);
+
+ if (!U_SUCCESS(err)) {
+
+ throw exceptions::charset_conv_error(
+ "Cannot initialize ICU converter for source charset '" + source.getName()
+ + "' (error code: " + u_errorName(err) + "."
+ );
+ }
+
+ m_to = ucnv_open(dest.getName().c_str(), &err);
+
+ if (!U_SUCCESS(err)) {
+
+ throw exceptions::charset_conv_error(
+ "Cannot initialize ICU converter for destination charset '" + dest.getName()
+ + "' (error code: " + u_errorName(err) + "."
+ );
+ }
+}
+
+
+charsetConverter_icu::~charsetConverter_icu() {
+
+ if (m_from) ucnv_close(m_from);
+ if (m_to) ucnv_close(m_to);
+}
+
+
+void charsetConverter_icu::convert(
+ utility::inputStream& in,
+ utility::outputStream& out,
+ status* st
+) {
+
+ UErrorCode err = U_ZERO_ERROR;
+
+ ucnv_reset(m_from);
+ ucnv_reset(m_to);
+
+ if (st) {
+ new (st) status();
+ }
+
+ // From buffers
+ byte_t cpInBuffer[16]; // stream data put here
+ const size_t outSize = ucnv_getMinCharSize(m_from) * sizeof(cpInBuffer) * sizeof(UChar);
+ std::vector <UChar> uOutBuffer(outSize); // Unicode chars end up here
+
+ // To buffers
+ // converted (char) data end up here
+ const size_t cpOutBufferSz = ucnv_getMaxCharSize(m_to) * outSize;
+ std::vector <char> cpOutBuffer(cpOutBufferSz);
+
+ // Tell ICU what to do when encountering an illegal byte sequence
+ if (m_options.silentlyReplaceInvalidSequences) {
+
+ // Set replacement chars for when converting from Unicode to codepage
+ icu::UnicodeString substString(m_options.invalidSequence.c_str());
+ ucnv_setSubstString(m_to, substString.getTerminatedBuffer(), -1, &err);
+
+ if (U_FAILURE(err)) {
+ throw exceptions::charset_conv_error("[ICU] Error when setting substitution string.");
+ }
+
+ } else {
+
+ // Tell ICU top stop (and return an error) on illegal byte sequences
+ ucnv_setToUCallBack(
+ m_from, UCNV_TO_U_CALLBACK_STOP, UCNV_SUB_STOP_ON_ILLEGAL, NULL, NULL, &err
+ );
+
+ if (U_FAILURE(err)) {
+ throw exceptions::charset_conv_error("[ICU] Error when setting ToU callback.");
+ }
+
+ ucnv_setFromUCallBack(
+ m_to, UCNV_FROM_U_CALLBACK_STOP, UCNV_SUB_STOP_ON_ILLEGAL, NULL, NULL, &err
+ );
+
+ if (U_FAILURE(err)) {
+ throw exceptions::charset_conv_error("[ICU] Error when setting FromU callback.");
+ }
+ }
+
+ // Input data available
+ while (!in.eof()) {
+
+ // Read input data into buffer
+ size_t inLength = in.read(cpInBuffer, sizeof(cpInBuffer));
+
+ // Beginning of read data
+ const char* source = reinterpret_cast <const char*>(&cpInBuffer[0]);
+ const char* sourceLimit = source + inLength; // end + 1
+
+ UBool flush = in.eof(); // is this last run?
+
+ UErrorCode toErr;
+
+ // Loop until all source has been processed
+ do {
+
+ // Set up target pointers
+ UChar* target = &uOutBuffer[0];
+ UChar* targetLimit = &target[0] + outSize;
+
+ toErr = U_ZERO_ERROR;
+
+ ucnv_toUnicode(
+ m_from, &target, targetLimit,
+ &source, sourceLimit, NULL, flush, &toErr
+ );
+
+ if (st) {
+ st->inputBytesRead += (source - reinterpret_cast <const char*>(&cpInBuffer[0]));
+ }
+
+ if (toErr != U_BUFFER_OVERFLOW_ERROR && U_FAILURE(toErr)) {
+
+ if (toErr == U_INVALID_CHAR_FOUND ||
+ toErr == U_TRUNCATED_CHAR_FOUND ||
+ toErr == U_ILLEGAL_CHAR_FOUND) {
+
+ // Error will be thrown later (*)
+
+ } else {
+
+ throw exceptions::charset_conv_error(
+ "[ICU] Error converting to Unicode from " + m_source.getName()
+ );
+ }
+ }
+
+ // The Unicode source is the buffer just written and the limit
+ // is where the previous conversion stopped (target is moved in the conversion)
+ const UChar* uSource = &uOutBuffer[0];
+ UChar* uSourceLimit = &target[0];
+ UErrorCode fromErr;
+
+ // Loop until converted chars are fully written
+ do {
+
+ char* cpTarget = &cpOutBuffer[0];
+ const char* cpTargetLimit = &cpOutBuffer[0] + cpOutBufferSz;
+
+ fromErr = U_ZERO_ERROR;
+
+ // Write converted bytes (Unicode) to destination codepage
+ ucnv_fromUnicode(
+ m_to, &cpTarget, cpTargetLimit,
+ &uSource, uSourceLimit, NULL, flush, &fromErr
+ );
+
+ if (st) {
+
+ // Decrement input bytes count by the number of input bytes in error
+ char errBytes[16];
+ int8_t errBytesLen = sizeof(errBytes);
+ UErrorCode errBytesErr = U_ZERO_ERROR;
+
+ ucnv_getInvalidChars(m_from, errBytes, &errBytesLen, &errBytesErr);
+
+ st->inputBytesRead -= errBytesLen;
+ st->outputBytesWritten += cpTarget - &cpOutBuffer[0];
+ }
+
+ // (*) If an error occurred while converting from input charset, throw it now
+ if (toErr == U_INVALID_CHAR_FOUND ||
+ toErr == U_TRUNCATED_CHAR_FOUND ||
+ toErr == U_ILLEGAL_CHAR_FOUND) {
+
+ throw exceptions::illegal_byte_sequence_for_charset();
+ }
+
+ if (fromErr != U_BUFFER_OVERFLOW_ERROR && U_FAILURE(fromErr)) {
+
+ if (fromErr == U_INVALID_CHAR_FOUND ||
+ fromErr == U_TRUNCATED_CHAR_FOUND ||
+ fromErr == U_ILLEGAL_CHAR_FOUND) {
+
+ throw exceptions::illegal_byte_sequence_for_charset();
+
+ } else {
+
+ throw exceptions::charset_conv_error(
+ "[ICU] Error converting from Unicode to " + m_dest.getName()
+ );
+ }
+ }
+
+ // Write to destination stream
+ out.write(&cpOutBuffer[0], (cpTarget - &cpOutBuffer[0]));
+
+ } while (fromErr == U_BUFFER_OVERFLOW_ERROR);
+
+ } while (toErr == U_BUFFER_OVERFLOW_ERROR);
+ }
+}
+
+
+void charsetConverter_icu::convert(const string& in, string& out, status* st) {
+
+ if (st) {
+ new (st) status();
+ }
+
+ out.clear();
+
+ utility::inputStreamStringAdapter is(in);
+ utility::outputStreamStringAdapter os(out);
+
+ convert(is, os, st);
+
+ os.flush();
+}
+
+
+shared_ptr <utility::charsetFilteredOutputStream>
+ charsetConverter_icu::getFilteredOutputStream(
+ utility::outputStream& os,
+ const charsetConverterOptions& opts
+ ) {
+
+ return make_shared <utility::charsetFilteredOutputStream_icu>(m_source, m_dest, &os, opts);
+}
+
+
+
+// charsetFilteredOutputStream_icu
+
+namespace utility {
+
+
+charsetFilteredOutputStream_icu::charsetFilteredOutputStream_icu(
+ const charset& source,
+ const charset& dest,
+ outputStream* os,
+ const charsetConverterOptions& opts
+)
+ : m_from(NULL),
+ m_to(NULL),
+ m_sourceCharset(source),
+ m_destCharset(dest),
+ m_stream(*os),
+ m_options(opts) {
+
+ UErrorCode err = U_ZERO_ERROR;
+ m_from = ucnv_open(source.getName().c_str(), &err);
+
+ if (!U_SUCCESS(err)) {
+
+ throw exceptions::charset_conv_error(
+ "Cannot initialize ICU converter for source charset '" + source.getName()
+ + "' (error code: " + u_errorName(err) + "."
+ );
+ }
+
+ m_to = ucnv_open(dest.getName().c_str(), &err);
+
+ if (!U_SUCCESS(err)) {
+
+ throw exceptions::charset_conv_error(
+ "Cannot initialize ICU converter for destination charset '" + dest.getName()
+ + "' (error code: " + u_errorName(err) + "."
+ );
+ }
+
+ // Tell ICU what to do when encountering an illegal byte sequence
+ if (m_options.silentlyReplaceInvalidSequences) {
+
+ // Set replacement chars for when converting from Unicode to codepage
+ icu::UnicodeString substString(m_options.invalidSequence.c_str());
+ ucnv_setSubstString(m_to, substString.getTerminatedBuffer(), -1, &err);
+
+ if (U_FAILURE(err)) {
+ throw exceptions::charset_conv_error("[ICU] Error when setting substitution string.");
+ }
+
+ } else {
+
+ // Tell ICU top stop (and return an error) on illegal byte sequences
+ ucnv_setToUCallBack(
+ m_to, UCNV_TO_U_CALLBACK_STOP, UCNV_SUB_STOP_ON_ILLEGAL, NULL, NULL, &err
+ );
+
+ if (U_FAILURE(err)) {
+ throw exceptions::charset_conv_error("[ICU] Error when setting ToU callback.");
+ }
+
+ ucnv_setFromUCallBack(
+ m_to, UCNV_FROM_U_CALLBACK_STOP, UCNV_SUB_STOP_ON_ILLEGAL, NULL, NULL, &err
+ );
+
+ if (U_FAILURE(err)) {
+ throw exceptions::charset_conv_error("[ICU] Error when setting FromU callback.");
+ }
+ }
+}
+
+
+charsetFilteredOutputStream_icu::~charsetFilteredOutputStream_icu() {
+
+ if (m_from) ucnv_close(m_from);
+ if (m_to) ucnv_close(m_to);
+}
+
+
+outputStream& charsetFilteredOutputStream_icu::getNextOutputStream() {
+
+ return m_stream;
+}
+
+
+void charsetFilteredOutputStream_icu::writeImpl(
+ const byte_t* const data,
+ const size_t count
+) {
+
+ if (!m_from || !m_to) {
+ throw exceptions::charset_conv_error("Cannot initialize converters.");
+ }
+
+ // Allocate buffer for Unicode chars
+ const size_t uniSize = ucnv_getMinCharSize(m_from) * count * sizeof(UChar);
+ std::vector <UChar> uniBuffer(uniSize);
+
+ // Conversion loop
+ UErrorCode toErr = U_ZERO_ERROR;
+
+ const char* uniSource = reinterpret_cast <const char*>(data);
+ const char* uniSourceLimit = uniSource + count;
+
+ do {
+
+ // Convert from source charset to Unicode
+ UChar* uniTarget = &uniBuffer[0];
+ UChar* uniTargetLimit = &uniBuffer[0] + uniSize;
+
+ toErr = U_ZERO_ERROR;
+
+ ucnv_toUnicode(
+ m_from, &uniTarget, uniTargetLimit,
+ &uniSource, uniSourceLimit, NULL, /* flush */ FALSE, &toErr
+ );
+
+ if (U_FAILURE(toErr) && toErr != U_BUFFER_OVERFLOW_ERROR) {
+
+ if (toErr == U_INVALID_CHAR_FOUND ||
+ toErr == U_TRUNCATED_CHAR_FOUND ||
+ toErr == U_ILLEGAL_CHAR_FOUND) {
+
+ throw exceptions::illegal_byte_sequence_for_charset();
+
+ } else {
+
+ throw exceptions::charset_conv_error(
+ "[ICU] Error converting to Unicode from '" + m_sourceCharset.getName() + "'."
+ );
+ }
+ }
+
+ const size_t uniLength = uniTarget - &uniBuffer[0];
+
+ // Allocate buffer for destination charset
+ const size_t cpSize = ucnv_getMinCharSize(m_to) * uniLength;
+ std::vector <char> cpBuffer(cpSize);
+
+ // Convert from Unicode to destination charset
+ UErrorCode fromErr = U_ZERO_ERROR;
+
+ const UChar* cpSource = &uniBuffer[0];
+ const UChar* cpSourceLimit = &uniBuffer[0] + uniLength;
+
+ do {
+
+ char* cpTarget = &cpBuffer[0];
+ char* cpTargetLimit = &cpBuffer[0] + cpSize;
+
+ fromErr = U_ZERO_ERROR;
+
+ ucnv_fromUnicode(
+ m_to, &cpTarget, cpTargetLimit,
+ &cpSource, cpSourceLimit, NULL, /* flush */ FALSE, &fromErr
+ );
+
+ if (fromErr != U_BUFFER_OVERFLOW_ERROR && U_FAILURE(fromErr)) {
+
+ if (fromErr == U_INVALID_CHAR_FOUND ||
+ fromErr == U_TRUNCATED_CHAR_FOUND ||
+ fromErr == U_ILLEGAL_CHAR_FOUND) {
+
+ throw exceptions::illegal_byte_sequence_for_charset();
+
+ } else {
+
+ throw exceptions::charset_conv_error(
+ "[ICU] Error converting from Unicode to '" + m_destCharset.getName() + "'."
+ );
+ }
+ }
+
+ const size_t cpLength = cpTarget - &cpBuffer[0];
+
+ // Write successfully converted bytes
+ m_stream.write(&cpBuffer[0], cpLength);
+
+ } while (fromErr == U_BUFFER_OVERFLOW_ERROR);
+
+ } while (toErr == U_BUFFER_OVERFLOW_ERROR);
+}
+
+
+void charsetFilteredOutputStream_icu::flush() {
+
+ if (!m_from || !m_to) {
+ throw exceptions::charset_conv_error("Cannot initialize converters.");
+ }
+
+ // Allocate buffer for Unicode chars
+ const size_t uniSize = ucnv_getMinCharSize(m_from) * 1024 * sizeof(UChar);
+ std::vector <UChar> uniBuffer(uniSize);
+
+ // Conversion loop (with flushing)
+ UErrorCode toErr = U_ZERO_ERROR;
+
+ const char* uniSource = 0;
+ const char* uniSourceLimit = 0;
+
+ do {
+
+ // Convert from source charset to Unicode
+ UChar* uniTarget = &uniBuffer[0];
+ UChar* uniTargetLimit = &uniBuffer[0] + uniSize;
+
+ toErr = U_ZERO_ERROR;
+
+ ucnv_toUnicode(
+ m_from, &uniTarget, uniTargetLimit,
+ &uniSource, uniSourceLimit, NULL, /* flush */ TRUE, &toErr
+ );
+
+ if (U_FAILURE(toErr) && toErr != U_BUFFER_OVERFLOW_ERROR) {
+
+ throw exceptions::charset_conv_error(
+ "[ICU] Error converting to Unicode from '" + m_sourceCharset.getName() + "'."
+ );
+ }
+
+ const size_t uniLength = uniTarget - &uniBuffer[0];
+
+ // Allocate buffer for destination charset
+ const size_t cpSize = ucnv_getMinCharSize(m_to) * uniLength;
+ std::vector <char> cpBuffer(cpSize);
+
+ // Convert from Unicode to destination charset
+ UErrorCode fromErr = U_ZERO_ERROR;
+
+ const UChar* cpSource = &uniBuffer[0];
+ const UChar* cpSourceLimit = &uniBuffer[0] + uniLength;
+
+ do {
+
+ char* cpTarget = &cpBuffer[0];
+ char* cpTargetLimit = &cpBuffer[0] + cpSize;
+
+ fromErr = U_ZERO_ERROR;
+
+ ucnv_fromUnicode(
+ m_to, &cpTarget, cpTargetLimit,
+ &cpSource, cpSourceLimit, NULL, /* flush */ TRUE, &fromErr
+ );
+
+ if (fromErr != U_BUFFER_OVERFLOW_ERROR && U_FAILURE(fromErr)) {
+
+ throw exceptions::charset_conv_error(
+ "[ICU] Error converting from Unicode to '" + m_destCharset.getName() + "'."
+ );
+ }
+
+ const size_t cpLength = cpTarget - &cpBuffer[0];
+
+ // Write successfully converted bytes
+ m_stream.write(&cpBuffer[0], cpLength);
+
+ } while (fromErr == U_BUFFER_OVERFLOW_ERROR);
+
+ } while (toErr == U_BUFFER_OVERFLOW_ERROR);
+
+ m_stream.flush();
+}
+
+
+} // utility
+
+
+} // vmime
+
+
+#endif // VMIME_CHARSETCONV_LIB_IS_ICU
diff --git a/vmime-master/src/vmime/charsetConverter_icu.hpp b/vmime-master/src/vmime/charsetConverter_icu.hpp
new file mode 100644
index 0000000..cf5eb6b
--- /dev/null
+++ b/vmime-master/src/vmime/charsetConverter_icu.hpp
@@ -0,0 +1,137 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_CHARSETCONVERTER_ICU_HPP_INCLUDED
+#define VMIME_CHARSETCONVERTER_ICU_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_CHARSETCONV_LIB_IS_ICU
+
+
+#include "vmime/charsetConverter.hpp"
+
+
+struct UConverter;
+
+
+namespace vmime {
+
+
+/** A generic charset converter which uses ICU library.
+ */
+class charsetConverter_icu : public charsetConverter {
+
+public:
+
+ /** Construct and initialize an ICU charset converter.
+ *
+ * @param source input charset
+ * @param dest output charset
+ * @param opts conversion options
+ */
+ charsetConverter_icu(
+ const charset& source,
+ const charset& dest,
+ const charsetConverterOptions& opts = charsetConverterOptions()
+ );
+
+ ~charsetConverter_icu();
+
+ void convert(const string& in, string& out, status* st = NULL);
+ void convert(utility::inputStream& in, utility::outputStream& out, status* st = NULL);
+
+ shared_ptr <utility::charsetFilteredOutputStream> getFilteredOutputStream(
+ utility::outputStream& os,
+ const charsetConverterOptions& opts = charsetConverterOptions()
+ );
+
+private:
+
+ UConverter* m_from;
+ UConverter* m_to;
+
+ charset m_source;
+ charset m_dest;
+
+ charsetConverterOptions m_options;
+};
+
+
+namespace utility {
+
+
+class charsetFilteredOutputStream_icu : public charsetFilteredOutputStream {
+
+public:
+
+ /** Construct a new filter for the specified output stream.
+ *
+ * @param source input charset
+ * @param dest output charset
+ * @param os stream into which write filtered data
+ * @param opts conversion options
+ */
+ charsetFilteredOutputStream_icu(
+ const charset& source,
+ const charset& dest,
+ outputStream* os,
+ const charsetConverterOptions& opts = charsetConverterOptions()
+ );
+
+ ~charsetFilteredOutputStream_icu();
+
+
+ outputStream& getNextOutputStream();
+
+ void flush();
+
+protected:
+
+ void writeImpl(const byte_t* const data, const size_t count);
+
+private:
+
+ UConverter* m_from;
+ UConverter* m_to;
+
+ const charset m_sourceCharset;
+ const charset m_destCharset;
+
+ outputStream& m_stream;
+
+ charsetConverterOptions m_options;
+};
+
+
+} // utility
+
+
+} // vmime
+
+
+#endif // VMIME_CHARSETCONV_LIB_IS_ICU
+
+#endif // VMIME_CHARSETCONVERTER_ICU_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/charsetConverter_idna.cpp b/vmime-master/src/vmime/charsetConverter_idna.cpp
new file mode 100644
index 0000000..eb8764f
--- /dev/null
+++ b/vmime-master/src/vmime/charsetConverter_idna.cpp
@@ -0,0 +1,208 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/charsetConverter_idna.hpp"
+
+#include "vmime/exception.hpp"
+
+#include "vmime/utility/stringUtils.hpp"
+#include "vmime/utility/streamUtils.hpp"
+#include "vmime/utility/outputStreamStringAdapter.hpp"
+
+
+extern "C" {
+
+#include "contrib/punycode/punycode.h"
+#include "contrib/punycode/punycode.c"
+
+}
+
+#include "contrib/utf8/utf8.h"
+
+
+namespace vmime {
+
+
+charsetConverter_idna::charsetConverter_idna(
+ const charset& source,
+ const charset& dest,
+ const charsetConverterOptions& opts
+)
+ : m_source(source),
+ m_dest(dest),
+ m_options(opts) {
+
+}
+
+
+charsetConverter_idna::~charsetConverter_idna() {
+
+}
+
+
+void charsetConverter_idna::convert(utility::inputStream& in, utility::outputStream& out, status* st) {
+
+ if (st) {
+ new (st) status();
+ }
+
+ // IDNA should be used for short strings, so it does not matter if we
+ // do not work directly on the stream
+ string inStr;
+ vmime::utility::outputStreamStringAdapter os(inStr);
+ vmime::utility::bufferedStreamCopy(in, os);
+
+ string outStr;
+ convert(inStr, outStr, st);
+
+ out << outStr;
+}
+
+
+void charsetConverter_idna::convert(const string& in, string& out, status* st) {
+
+ if (st) {
+ new (st) status();
+ }
+
+ out.clear();
+
+ if (m_dest == "idna") {
+
+ if (utility::stringUtils::is7bit(in)) {
+
+ if (st) {
+ st->inputBytesRead = in.length();
+ st->outputBytesWritten = in.length();
+ }
+
+ // No need to encode as Punycode
+ out = in;
+ return;
+ }
+
+ string inUTF8;
+ charset::convert(in, inUTF8, m_source, vmime::charsets::UTF_8);
+
+ const char* ch = inUTF8.c_str();
+ const char* end = inUTF8.c_str() + inUTF8.length();
+
+ std::vector <punycode_uint> unichars;
+ unichars.reserve(inUTF8.length());
+
+ while (ch < end) {
+ const utf8::uint32_t uc = utf8::unchecked::next(ch);
+ unichars.push_back(uc);
+ }
+
+ if (st) {
+ st->inputBytesRead = in.length();
+ }
+
+ punycode_uint inputLen = static_cast <punycode_uint>(unichars.size());
+
+ std::vector <char> output(inUTF8.length() * 2);
+ punycode_uint outputLen = static_cast <punycode_uint>(output.size());
+
+ const punycode_status status = punycode_encode(
+ inputLen, &unichars[0], /* case_flags */ NULL, &outputLen, &output[0]
+ );
+
+ if (status == punycode_success) {
+
+ out = string("xn--") + string(output.begin(), output.begin() + outputLen);
+
+ if (st) {
+ st->outputBytesWritten = out.length();
+ }
+
+ } else {
+
+ // TODO
+ }
+
+ } else if (m_source == "idna") {
+
+ if (in.length() < 5 || in.substr(0, 4) != "xn--") {
+
+ if (st) {
+ st->inputBytesRead = in.length();
+ st->outputBytesWritten = in.length();
+ }
+
+ // Not an IDNA string
+ out = in;
+ return;
+ }
+
+ punycode_uint inputLen = static_cast <punycode_uint>(in.length() - 4);
+
+ std::vector <punycode_uint> output(in.length() - 4);
+ punycode_uint outputLen = static_cast <punycode_uint>(output.size());
+
+ const punycode_status status = punycode_decode(
+ inputLen, &in[4], &outputLen, &output[0], /* case_flags */ NULL
+ );
+
+ if (st) {
+ st->inputBytesRead = in.length();
+ }
+
+ if (status == punycode_success) {
+
+ std::vector <char> outUTF8Bytes(outputLen * 4);
+ char* p = &outUTF8Bytes[0];
+
+ for (std::vector <punycode_uint>::const_iterator it = output.begin() ;
+ it != output.begin() + outputLen ; ++it) {
+
+ p = utf8::unchecked::append(*it, p);
+ }
+
+ string outUTF8(&outUTF8Bytes[0], p);
+ charset::convert(outUTF8, out, vmime::charsets::UTF_8, m_dest);
+
+ if (st) {
+ st->outputBytesWritten = out.length();
+ }
+
+ } else {
+
+ // TODO
+ }
+ }
+}
+
+
+shared_ptr <utility::charsetFilteredOutputStream>
+ charsetConverter_idna::getFilteredOutputStream(
+ utility::outputStream& /* os */,
+ const charsetConverterOptions& /* opts */
+ ) {
+
+ // Not supported
+ return null;
+}
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/charsetConverter_idna.hpp b/vmime-master/src/vmime/charsetConverter_idna.hpp
new file mode 100644
index 0000000..aaf547d
--- /dev/null
+++ b/vmime-master/src/vmime/charsetConverter_idna.hpp
@@ -0,0 +1,74 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_CHARSETCONVERTER_IDNA_HPP_INCLUDED
+#define VMIME_CHARSETCONVERTER_IDNA_HPP_INCLUDED
+
+
+#include "vmime/charsetConverter.hpp"
+
+
+namespace vmime {
+
+
+/** A charset converter which can convert to and from Punycode (for IDNA).
+ */
+class charsetConverter_idna : public charsetConverter {
+
+public:
+
+ /** Construct and initialize an IDNA charset converter.
+ *
+ * @param source input charset
+ * @param dest output charset
+ * @param opts conversion options
+ */
+ charsetConverter_idna(
+ const charset& source,
+ const charset& dest,
+ const charsetConverterOptions& opts = charsetConverterOptions()
+ );
+
+ ~charsetConverter_idna();
+
+ void convert(const string& in, string& out, status* st = NULL);
+ void convert(utility::inputStream& in, utility::outputStream& out, status* st = NULL);
+
+ shared_ptr <utility::charsetFilteredOutputStream> getFilteredOutputStream(
+ utility::outputStream& os,
+ const charsetConverterOptions& opts = charsetConverterOptions()
+ );
+
+private:
+
+ charset m_source;
+ charset m_dest;
+
+ charsetConverterOptions m_options;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_CHARSETCONVERTER_IDNA_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/charsetConverter_win.cpp b/vmime-master/src/vmime/charsetConverter_win.cpp
new file mode 100644
index 0000000..eab1829
--- /dev/null
+++ b/vmime-master/src/vmime/charsetConverter_win.cpp
@@ -0,0 +1,227 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_CHARSETCONV_LIB_IS_WIN
+
+
+#include "vmime/charsetConverter_win.hpp"
+
+#include "vmime/exception.hpp"
+#include "vmime/utility/stringUtils.hpp"
+#include "vmime/utility/inputStreamStringAdapter.hpp"
+#include "vmime/utility/outputStreamStringAdapter.hpp"
+
+#include <string.h>
+#include <stdlib.h>
+
+
+#if (_WIN32 || _WIN64 || WIN32 || WIN64)
+ #include <windows.h>
+ #include "vmime/platforms/windows/windowsCodepages.hpp"
+#else
+ #error Please use VMIME_CHARSETCONV_LIB_IS_WIN only on Windows!
+#endif
+
+
+#define CP_UNICODE 1200
+
+
+namespace vmime {
+
+
+// static
+shared_ptr <charsetConverter> charsetConverter::createGenericConverter(
+ const charset& source,
+ const charset& dest,
+ const charsetConverterOptions& opts
+) {
+
+ return make_shared <charsetConverter_win>(source, dest, opts);
+}
+
+
+charsetConverter_win::charsetConverter_win(
+ const charset& source,
+ const charset& dest,
+ const charsetConverterOptions& opts
+)
+ : m_source(source),
+ m_dest(dest),
+ m_options(opts) {
+
+}
+
+
+void charsetConverter_win::convert(
+ utility::inputStream& in,
+ utility::outputStream& out,
+ status* st
+) {
+
+ if (st) {
+ new (st) status();
+ }
+
+ byte_t buffer[32768];
+ string inStr, outStr;
+
+ while (!in.eof()) {
+ const size_t len = in.read(buffer, sizeof(buffer));
+ utility::stringUtils::appendBytesToString(inStr, buffer, len);
+ }
+
+ convert(inStr, outStr, st);
+
+ out.write(outStr.data(), outStr.length());
+}
+
+
+void charsetConverter_win::convert(const string& in, string& out, status* st) {
+
+ if (st) {
+ new (st) status();
+ }
+
+ const int sourceCodePage = getCodePage(m_source.getName().c_str());
+ const int destCodePage = getCodePage(m_dest.getName().c_str());
+
+ // Convert from source charset to Unicode
+ std::vector <char> unicodeBuffer;
+ const WCHAR* unicodePtr = NULL;
+ size_t unicodeLen = 0;
+
+ if (sourceCodePage == CP_UNICODE) {
+
+ unicodePtr = reinterpret_cast <const WCHAR*>(in.c_str());
+ unicodeLen = in.length() / 2;
+
+ } else {
+
+ const size_t bufferSize = MultiByteToWideChar(
+ sourceCodePage, 0, in.c_str(), static_cast <int>(in.length()), NULL, 0
+ ) * sizeof(WCHAR); // in wide characters
+
+ unicodeBuffer.resize(bufferSize);
+
+ DWORD flags = 0;
+
+ if (!m_options.silentlyReplaceInvalidSequences) {
+ flags |= MB_ERR_INVALID_CHARS;
+ }
+
+ unicodePtr = reinterpret_cast <const WCHAR*>(&unicodeBuffer[0]);
+ unicodeLen = MultiByteToWideChar(
+ sourceCodePage, 0, in.c_str(), static_cast <int>(in.length()),
+ reinterpret_cast <WCHAR*>(&unicodeBuffer[0]), static_cast <int>(bufferSize)
+ );
+
+ if (unicodeLen == 0) {
+
+ if (GetLastError() == ERROR_NO_UNICODE_TRANSLATION) {
+
+ throw exceptions::illegal_byte_sequence_for_charset();
+
+ } else {
+
+ throw exceptions::charset_conv_error(
+ "MultiByteToWideChar() failed when converting to Unicode from " + m_source.getName()
+ );
+ }
+ }
+ }
+
+ // Convert from Unicode to destination charset
+ if (destCodePage == CP_UNICODE) {
+
+ out.assign(reinterpret_cast <const char*>(unicodePtr), unicodeLen * 2);
+
+ } else {
+
+ const size_t bufferSize = WideCharToMultiByte(
+ destCodePage, 0, unicodePtr, static_cast <int>(unicodeLen),
+ NULL, 0, 0, NULL
+ ); // in multibyte characters
+
+ std::vector <char> buffer;
+ buffer.resize(bufferSize);
+
+ const size_t len = WideCharToMultiByte(
+ destCodePage, 0, unicodePtr, static_cast <int>(unicodeLen),
+ &buffer[0], static_cast <int>(bufferSize), 0, NULL
+ );
+
+ if (len == 0) {
+
+ if (GetLastError() == ERROR_NO_UNICODE_TRANSLATION) {
+
+ throw exceptions::illegal_byte_sequence_for_charset();
+
+ } else {
+
+ throw exceptions::charset_conv_error(
+ "WideCharToMultiByte() failed when converting from Unicode to " + m_source.getName()
+ );
+ }
+ }
+
+ out.assign(&buffer[0], len);
+ }
+}
+
+
+// static
+int charsetConverter_win::getCodePage(const char* name) {
+
+ if (_stricmp(name, charsets::UTF_16) == 0) { // wchar_t is UTF-16 on Windows
+ return CP_UNICODE;
+ }
+
+ // "cp1252" --> return 1252
+ if ((name[0] == 'c' || name[0] == 'C') &&
+ (name[1] == 'p' || name[1] == 'P')) {
+
+ return atoi(name + 2);
+ }
+
+ return vmime::platforms::windows::windowsCodepages::getByName(name); // throws
+}
+
+
+shared_ptr <utility::charsetFilteredOutputStream>
+ charsetConverter_win::getFilteredOutputStream(
+ utility::outputStream& /* os */,
+ const charsetConverterOptions& /* opts */
+ ) {
+
+ // TODO: implement me!
+ return null;
+}
+
+
+} // vmime
+
+
+#endif // VMIME_CHARSETCONV_LIB_IS_WIN
diff --git a/vmime-master/src/vmime/charsetConverter_win.hpp b/vmime-master/src/vmime/charsetConverter_win.hpp
new file mode 100644
index 0000000..d20970b
--- /dev/null
+++ b/vmime-master/src/vmime/charsetConverter_win.hpp
@@ -0,0 +1,91 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_CHARSETCONVERTER_WIN_HPP_INCLUDED
+#define VMIME_CHARSETCONVERTER_WIN_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_CHARSETCONV_LIB_IS_WIN
+
+
+#include "vmime/charsetConverter.hpp"
+
+
+namespace vmime {
+
+
+/** A generic charset converter which uses Windows MultiByteToWideChar
+ * and WideCharToMultiByte API functions.
+ *
+ * ICU or iconv library should always be preferred over this one, even
+ * on Windows platform, as MultiByteToWideChar() and WideCharToMultiByte()
+ * functions cannot be used easily with streams (no context). Moreover,
+ * error handling is very poor, in particular when an invalid sequence
+ * is found...
+ *
+ * Also, "status" is not supported by this converter for the same reason.
+ */
+class charsetConverter_win : public charsetConverter {
+
+public:
+
+ /** Construct and initialize a Windows charset converter.
+ *
+ * @param source input charset
+ * @param dest output charset
+ * @param opts conversion options
+ */
+ charsetConverter_win(
+ const charset& source,
+ const charset& dest,
+ const charsetConverterOptions& opts = charsetConverterOptions()
+ );
+
+ void convert(const string& in, string& out, status* st);
+ void convert(utility::inputStream& in, utility::outputStream& out, status* st);
+
+ shared_ptr <utility::charsetFilteredOutputStream> getFilteredOutputStream(
+ utility::outputStream& os,
+ const charsetConverterOptions& opts
+ );
+
+private:
+
+ static int getCodePage(const char* name);
+
+ charset m_source;
+ charset m_dest;
+
+ charsetConverterOptions m_options;
+};
+
+
+} // namespace
+
+
+#endif // VMIME_CHARSETCONV_LIB_IS_WIN
+
+#endif // VMIME_CHARSETCONVERTER_WIN_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/component.cpp b/vmime-master/src/vmime/component.cpp
new file mode 100644
index 0000000..7adf8f7
--- /dev/null
+++ b/vmime-master/src/vmime/component.cpp
@@ -0,0 +1,275 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/component.hpp"
+#include "vmime/base.hpp"
+
+#include "vmime/utility/streamUtils.hpp"
+#include "vmime/utility/inputStreamStringAdapter.hpp"
+#include "vmime/utility/outputStreamAdapter.hpp"
+
+#include <sstream>
+
+
+namespace vmime {
+
+
+component::component()
+ : m_parsedOffset(0), m_parsedLength(0) {
+
+}
+
+
+component::~component() {
+
+}
+
+
+void component::parse(
+ const shared_ptr <utility::inputStream>& inputStream,
+ const size_t length
+) {
+
+ parse(inputStream, 0, length, NULL);
+}
+
+
+void component::parse(
+ const shared_ptr <utility::inputStream>& inputStream,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition) {
+
+ parse(parsingContext::getDefaultContext(), inputStream, position, end, newPosition);
+}
+
+
+void component::parse(
+ const parsingContext& ctx,
+ const shared_ptr <utility::inputStream>& inputStream,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition
+) {
+
+ m_parsedOffset = m_parsedLength = 0;
+
+ shared_ptr <utility::seekableInputStream> seekableStream =
+ dynamicCast <utility::seekableInputStream>(inputStream);
+
+ if (!seekableStream || end == 0) {
+
+ // Read the whole stream into a buffer
+ std::ostringstream oss;
+ utility::outputStreamAdapter ossAdapter(oss);
+
+ utility::bufferedStreamCopyRange(*inputStream, ossAdapter, position, end - position);
+
+ const string buffer = oss.str();
+ parseImpl(ctx, buffer, 0, buffer.length(), NULL);
+
+ } else {
+
+ shared_ptr <utility::parserInputStreamAdapter> parser =
+ make_shared <utility::parserInputStreamAdapter>(seekableStream);
+
+ parseImpl(ctx, parser, position, end, newPosition);
+ }
+}
+
+
+void component::parse(const string& buffer) {
+
+ m_parsedOffset = m_parsedLength = 0;
+
+ parseImpl(parsingContext::getDefaultContext(), buffer, 0, buffer.length(), NULL);
+}
+
+
+void component::parse(const parsingContext& ctx, const string& buffer) {
+
+ m_parsedOffset = m_parsedLength = 0;
+
+ parseImpl(ctx, buffer, 0, buffer.length(), NULL);
+}
+
+
+void component::parse(
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition
+) {
+
+ m_parsedOffset = m_parsedLength = 0;
+
+ parseImpl(parsingContext::getDefaultContext(), buffer, position, end, newPosition);
+}
+
+
+void component::parse(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end, size_t* newPosition
+) {
+
+ m_parsedOffset = m_parsedLength = 0;
+
+ parseImpl(ctx, buffer, position, end, newPosition);
+}
+
+
+void component::offsetParsedBounds(const size_t offset) {
+
+ // Offset parsed bounds of this component
+ if (m_parsedLength != 0) {
+ m_parsedOffset += offset;
+ }
+
+ // Offset parsed bounds of our children
+ std::vector <shared_ptr <component> > children = getChildComponents();
+
+ for (size_t i = 0, n = children.size() ; i < n ; ++i) {
+ children[i]->offsetParsedBounds(offset);
+ }
+}
+
+
+void component::parseImpl(
+ const parsingContext& ctx,
+ const shared_ptr <utility::parserInputStreamAdapter>& parser,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition
+) {
+
+ // This is the default implementation for parsing from an input stream:
+ // actually, we extract the substring and use the "parse from string" implementation
+ const string buffer = parser->extract(position, end);
+ parseImpl(ctx, buffer, 0, buffer.length(), newPosition);
+
+ // Recursivey offset parsed bounds on children
+ if (position != 0) {
+ offsetParsedBounds(position);
+ }
+
+ if (newPosition) {
+ *newPosition += position;
+ }
+}
+
+
+void component::parseImpl(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition) {
+
+ // This is the default implementation for parsing from a string:
+ // actually, we encapsulate the string buffer in an input stream, then use
+ // the "parse from input stream" implementation
+ shared_ptr <utility::seekableInputStream> stream =
+ make_shared <utility::inputStreamStringAdapter>(buffer);
+
+ shared_ptr <utility::parserInputStreamAdapter> parser =
+ make_shared <utility::parserInputStreamAdapter>(stream);
+
+ parseImpl(ctx, parser, position, end, newPosition);
+}
+
+
+const string component::generate(
+ const size_t maxLineLength,
+ const size_t curLinePos
+) const {
+
+ std::ostringstream oss;
+ utility::outputStreamAdapter adapter(oss);
+
+ generationContext ctx(generationContext::getDefaultContext());
+ ctx.setMaxLineLength(maxLineLength);
+
+ generateImpl(ctx, adapter, curLinePos, NULL);
+
+ return oss.str();
+}
+
+
+void component::generate(
+ utility::outputStream& os,
+ const size_t curLinePos,
+ size_t* newLinePos
+) const {
+
+ generateImpl(generationContext::getDefaultContext(), os, curLinePos, newLinePos);
+}
+
+
+void component::generate(
+ const generationContext& ctx,
+ utility::outputStream& outputStream,
+ const size_t curLinePos,
+ size_t* newLinePos
+) const {
+
+ generateImpl(ctx, outputStream, curLinePos, newLinePos);
+}
+
+
+size_t component::getParsedOffset() const {
+
+ return m_parsedOffset;
+}
+
+
+size_t component::getParsedLength() const {
+
+ return m_parsedLength;
+}
+
+
+void component::setParsedBounds(const size_t start, const size_t end) {
+
+ m_parsedOffset = start;
+ m_parsedLength = end - start;
+}
+
+
+size_t component::getGeneratedSize(const generationContext& ctx) {
+
+ std::vector <shared_ptr <component> > children = getChildComponents();
+ size_t totalSize = 0;
+
+ for (std::vector <shared_ptr <component> >::iterator it = children.begin() ;
+ it != children.end() ; ++it) {
+
+ totalSize += (*it)->getGeneratedSize(ctx);
+ }
+
+ return totalSize;
+}
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/component.hpp b/vmime-master/src/vmime/component.hpp
new file mode 100644
index 0000000..91164c3
--- /dev/null
+++ b/vmime-master/src/vmime/component.hpp
@@ -0,0 +1,265 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_COMPONENT_HPP_INCLUDED
+#define VMIME_COMPONENT_HPP_INCLUDED
+
+
+#include "vmime/base.hpp"
+#include "vmime/utility/inputStream.hpp"
+#include "vmime/utility/seekableInputStream.hpp"
+#include "vmime/utility/parserInputStreamAdapter.hpp"
+#include "vmime/utility/outputStream.hpp"
+#include "vmime/generationContext.hpp"
+#include "vmime/parsingContext.hpp"
+
+
+namespace vmime {
+
+
+/** This abstract class is the base class for all the components of a message.
+ * It defines methods for parsing and generating a component.
+ */
+class VMIME_EXPORT component : public object {
+
+public:
+
+ component();
+ virtual ~component();
+
+ /** Parse RFC-822/MIME data for this component, using the default
+ * parsing context.
+ *
+ * @param buffer input buffer
+ */
+ void parse(const string& buffer);
+
+ /** Parse RFC-822/MIME data for this component.
+ *
+ * @param ctx parsing context
+ * @param buffer input buffer
+ */
+ void parse(const parsingContext& ctx, const string& buffer);
+
+ /** Parse RFC-822/MIME data for this component. If stream is not seekable,
+ * or if length is not specified, entire contents of the stream will
+ * be loaded into memory before parsing.
+ *
+ * @param inputStream stream from which to read data
+ * @param length data length, in bytes (0 = unknown/not specified)
+ */
+ void parse(const shared_ptr <utility::inputStream>& inputStream, const size_t length);
+
+ /** Parse RFC-822/MIME data for this component, using the default
+ * parsing context.
+ *
+ * @param buffer input buffer
+ * @param position current position in the input buffer
+ * @param end end position in the input buffer
+ * @param newPosition will receive the new position in the input buffer
+ */
+ void parse(
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition = NULL
+ );
+
+ /** Parse RFC-822/MIME data for this component.
+ *
+ * @param ctx parsing context
+ * @param buffer input buffer
+ * @param position current position in the input buffer
+ * @param end end position in the input buffer
+ * @param newPosition will receive the new position in the input buffer
+ */
+ void parse(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition = NULL
+ );
+
+ /** Parse RFC-822/MIME data for this component. If stream is not seekable,
+ * or if end position is not specified, entire contents of the stream will
+ * be loaded into memory before parsing. The default parsing context
+ * will be used.
+ *
+ * @param inputStream stream from which to read data
+ * @param position current position in the input stream
+ * @param end end position in the input stream
+ * @param newPosition will receive the new position in the input stream
+ */
+ void parse(
+ const shared_ptr <utility::inputStream>& inputStream,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition = NULL
+ );
+
+ /** Parse RFC-822/MIME data for this component. If stream is not seekable,
+ * or if end position is not specified, entire contents of the stream will
+ * be loaded into memory before parsing.
+ *
+ * @param ctx parsing context
+ * @param inputStream stream from which to read data
+ * @param position current position in the input stream
+ * @param end end position in the input stream
+ * @param newPosition will receive the new position in the input stream
+ */
+ void parse(
+ const parsingContext& ctx,
+ const shared_ptr <utility::inputStream>& inputStream,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition = NULL
+ );
+
+ /** Generate RFC-2822/MIME data for this component.
+ *
+ * \deprecated Use the new generate() method, which takes an outputStream parameter.
+ *
+ * @param maxLineLength maximum line length for output
+ * @param curLinePos length of the current line in the output buffer
+ * @return generated data
+ */
+ virtual const string generate(
+ const size_t maxLineLength = lineLengthLimits::infinite,
+ const size_t curLinePos = 0
+ ) const;
+
+ /** Generate RFC-2822/MIME data for this component, using the default generation context.
+ *
+ * @param outputStream output stream
+ * @param curLinePos length of the current line in the output buffer
+ * @param newLinePos will receive the new line position (length of the last line written)
+ */
+ virtual void generate(
+ utility::outputStream& outputStream,
+ const size_t curLinePos = 0,
+ size_t* newLinePos = NULL
+ ) const;
+
+ /** Generate RFC-2822/MIME data for this component, using the default generation context.
+ *
+ * @param ctx generation context
+ * @param outputStream output stream
+ * @param curLinePos length of the current line in the output buffer
+ * @param newLinePos will receive the new line position (length of the last line written)
+ */
+ virtual void generate(
+ const generationContext& ctx,
+ utility::outputStream& outputStream,
+ const size_t curLinePos = 0,
+ size_t* newLinePos = NULL
+ ) const;
+
+ /** Clone this component.
+ *
+ * @return a copy of this component
+ */
+ virtual shared_ptr <component> clone() const = 0;
+
+ /** Replace data in this component by data in other component.
+ * Both components must be of the same type.
+ *
+ * @throw std::bad_cast_exception if the components are not
+ * of the same (dynamic) type
+ * @param other other component to copy data from
+ */
+ virtual void copyFrom(const component& other) = 0;
+
+ /** Return the start position of this component in the
+ * parsed message contents. Use for debugging only.
+ *
+ * @return start position in parsed buffer
+ * or 0 if this component has not been parsed
+ */
+ size_t getParsedOffset() const;
+
+ /** Return the length of this component in the
+ * parsed message contents. Use for debugging only.
+ *
+ * @return length of the component in parsed buffer
+ * or 0 if this component has not been parsed
+ */
+ size_t getParsedLength() const;
+
+ /** Return the list of children of this component.
+ *
+ * @return list of child components
+ */
+ virtual const std::vector <shared_ptr <component> > getChildComponents() = 0;
+
+ /** Get the number of bytes that will be used by this component when
+ * it is generated. This may be a heuristically-derived estimate,
+ * but such an estimated size should always be larger than the actual
+ * generated size.
+ *
+ * @param ctx generation context
+ * @return component size when generated
+ */
+ virtual size_t getGeneratedSize(const generationContext& ctx);
+
+protected:
+
+ void setParsedBounds(const size_t start, const size_t end);
+
+ // AT LEAST ONE of these parseImpl() functions MUST be implemented in derived class
+ virtual void parseImpl(
+ const parsingContext& ctx,
+ const shared_ptr <utility::parserInputStreamAdapter>& parser,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition = NULL
+ );
+
+ virtual void parseImpl(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition = NULL
+ );
+
+ virtual void generateImpl(
+ const generationContext& ctx,
+ utility::outputStream& os,
+ const size_t curLinePos = 0,
+ size_t* newLinePos = NULL
+ ) const = 0;
+
+private:
+
+ void offsetParsedBounds(const size_t offset);
+
+ size_t m_parsedOffset;
+ size_t m_parsedLength;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_COMPONENT_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/constants.cpp b/vmime-master/src/vmime/constants.cpp
new file mode 100644
index 0000000..445c012
--- /dev/null
+++ b/vmime-master/src/vmime/constants.cpp
@@ -0,0 +1,251 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/constants.hpp"
+
+
+namespace vmime {
+
+
+// Media Types
+namespace mediaTypes {
+
+ // Types
+ const char* const TEXT = "text";
+ const char* const MULTIPART = "multipart";
+ const char* const MESSAGE = "message";
+ const char* const APPLICATION = "application";
+ const char* const IMAGE = "image";
+ const char* const AUDIO = "audio";
+ const char* const VIDEO = "video";
+
+ // Sub-types
+ const char* const TEXT_PLAIN = "plain";
+ const char* const TEXT_HTML = "html";
+ const char* const TEXT_RICHTEXT = "richtext";
+ const char* const TEXT_ENRICHED = "enriched";
+ const char* const TEXT_RFC822_HEADERS = "rfc822-headers"; // RFC-1892
+ const char* const TEXT_DIRECTORY = "directory"; // RFC-2426
+
+ const char* const MULTIPART_MIXED = "mixed";
+ const char* const MULTIPART_RELATED = "related";
+ const char* const MULTIPART_ALTERNATIVE = "alternative";
+ const char* const MULTIPART_PARALLEL = "parallel";
+ const char* const MULTIPART_DIGEST = "digest";
+ const char* const MULTIPART_REPORT = "report"; // RFC-1892
+
+ const char* const MESSAGE_RFC822 = "rfc822";
+ const char* const MESSAGE_PARTIAL = "partial";
+ const char* const MESSAGE_EXTERNAL_BODY = "external-body";
+ const char* const MESSAGE_DISPOSITION_NOTIFICATION = "disposition-notification";
+ const char* const MESSAGE_DELIVERY_STATUS = "delivery-status";
+
+ const char* const APPLICATION_OCTET_STREAM = "octet-stream";
+
+ const char* const IMAGE_JPEG = "jpeg";
+ const char* const IMAGE_GIF = "gif";
+
+ const char* const AUDIO_BASIC = "basic";
+
+ const char* const VIDEO_MPEG = "mpeg";
+}
+
+
+// Encoding types
+namespace encodingTypes {
+
+ const char* const SEVEN_BIT = "7bit";
+ const char* const EIGHT_BIT = "8bit";
+ const char* const BASE64 = "base64";
+ const char* const QUOTED_PRINTABLE = "quoted-printable";
+ const char* const BINARY = "binary";
+ const char* const UUENCODE = "uuencode";
+}
+
+
+// Content disposition types
+namespace contentDispositionTypes {
+
+ const char* const INLINE = "inline";
+ const char* const ATTACHMENT = "attachment";
+}
+
+
+// Charsets
+namespace charsets {
+
+ const char* const ISO8859_1 = "iso-8859-1";
+ const char* const ISO8859_2 = "iso-8859-2";
+ const char* const ISO8859_3 = "iso-8859-3";
+ const char* const ISO8859_4 = "iso-8859-4";
+ const char* const ISO8859_5 = "iso-8859-5";
+ const char* const ISO8859_6 = "iso-8859-6";
+ const char* const ISO8859_7 = "iso-8859-7";
+ const char* const ISO8859_8 = "iso-8859-8";
+ const char* const ISO8859_9 = "iso-8859-9";
+ const char* const ISO8859_10 = "iso-8859-10";
+ const char* const ISO8859_13 = "iso-8859-13";
+ const char* const ISO8859_14 = "iso-8859-14";
+ const char* const ISO8859_15 = "iso-8859-15";
+ const char* const ISO8859_16 = "iso-8859-16";
+
+ const char* const CP_437 = "cp437";
+ const char* const CP_737 = "cp737";
+ const char* const CP_775 = "cp775";
+ const char* const CP_850 = "cp850";
+ const char* const CP_852 = "cp852";
+ const char* const CP_853 = "cp853";
+ const char* const CP_855 = "cp855";
+ const char* const CP_857 = "cp857";
+ const char* const CP_858 = "cp858";
+ const char* const CP_860 = "cp860";
+ const char* const CP_861 = "cp861";
+ const char* const CP_862 = "cp862";
+ const char* const CP_863 = "cp863";
+ const char* const CP_864 = "cp864";
+ const char* const CP_865 = "cp865";
+ const char* const CP_866 = "cp866";
+ const char* const CP_869 = "cp869";
+ const char* const CP_874 = "cp874";
+ const char* const CP_1125 = "cp1125";
+ const char* const CP_1250 = "cp1250";
+ const char* const CP_1251 = "cp1251";
+ const char* const CP_1252 = "cp1252";
+ const char* const CP_1253 = "cp1253";
+ const char* const CP_1254 = "cp1254";
+ const char* const CP_1255 = "cp1255";
+ const char* const CP_1256 = "cp1256";
+ const char* const CP_1257 = "cp1257";
+
+ const char* const US_ASCII = "us-ascii";
+
+ const char* const UTF_7 = "utf-7";
+ const char* const UTF_8 = "utf-8";
+ const char* const UTF_16 = "utf-16";
+ const char* const UTF_32 = "utf-32";
+
+ const char* const WINDOWS_1250 = "windows-1250";
+ const char* const WINDOWS_1251 = "windows-1251";
+ const char* const WINDOWS_1252 = "windows-1252";
+ const char* const WINDOWS_1253 = "windows-1253";
+ const char* const WINDOWS_1254 = "windows-1254";
+ const char* const WINDOWS_1255 = "windows-1255";
+ const char* const WINDOWS_1256 = "windows-1256";
+ const char* const WINDOWS_1257 = "windows-1257";
+ const char* const WINDOWS_1258 = "windows-1258";
+
+ const char* const IDNA = "idna";
+}
+
+
+// Fields
+namespace fields {
+
+ const char* const RECEIVED = "Received";
+ const char* const FROM = "From";
+ const char* const SENDER = "Sender";
+ const char* const REPLY_TO = "Reply-To";
+ const char* const TO = "To";
+ const char* const CC = "Cc";
+ const char* const BCC = "Bcc";
+ const char* const DATE = "Date";
+ const char* const SUBJECT = "Subject";
+ const char* const ORGANIZATION = "Organization";
+ const char* const USER_AGENT = "User-Agent";
+ const char* const DELIVERED_TO = "Delivered-To";
+ const char* const RETURN_PATH = "Return-Path";
+ const char* const MIME_VERSION = "Mime-Version";
+ const char* const MESSAGE_ID = "Message-Id";
+ const char* const CONTENT_TYPE = "Content-Type";
+ const char* const CONTENT_TRANSFER_ENCODING = "Content-Transfer-Encoding";
+ const char* const CONTENT_DESCRIPTION = "Content-Description";
+ const char* const CONTENT_DISPOSITION = "Content-Disposition";
+ const char* const CONTENT_ID = "Content-Id";
+ const char* const CONTENT_LOCATION = "Content-Location";
+ const char* const IN_REPLY_TO = "In-Reply-To";
+ const char* const REFERENCES = "References";
+
+ const char* const X_MAILER = "X-Mailer";
+ const char* const X_PRIORITY = "X-Priority";
+
+ // RFC-3798: Message Disposition
+ const char* const ORIGINAL_MESSAGE_ID = "Original-Message-ID";
+ const char* const DISPOSITION_NOTIFICATION_TO = "Disposition-Notification-To";
+ const char* const DISPOSITION_NOTIFICATION_OPTIONS = "Disposition-Notification-Options";
+ const char* const DISPOSITION = "Disposition";
+ const char* const FAILURE = "Failure";
+ const char* const ERROR = "Error";
+ const char* const WARNING = "Warning";
+ const char* const ORIGINAL_RECIPIENT = "Original-Recipient";
+ const char* const FINAL_RECIPIENT = "Final-Recipient";
+ const char* const REPORTING_UA = "Reporting-UA";
+ const char* const MDN_GATEWAY = "MDN-Gateway";
+}
+
+
+// Constants for disposition action modes (RFC-3978).
+namespace dispositionActionModes {
+
+ const char* const MANUAL = "manual";
+ const char* const AUTOMATIC = "automatic";
+}
+
+
+// Constants for disposition sending modes (RFC-3798).
+namespace dispositionSendingModes {
+
+ const char* const SENT_MANUALLY = "MDN-sent-manually";
+ const char* const SENT_AUTOMATICALLY ="MDN-sent-automatically";
+}
+
+
+// Constants for disposition types (RFC-3798).
+namespace dispositionTypes {
+
+ const char* const DISPLAYED = "displayed";
+ const char* const DELETED = "deleted";
+}
+
+
+// Constants for disposition modifiers (RFC-3798).
+namespace dispositionModifiers {
+
+ const char* const ERROR = "error";
+}
+
+// Constants for DSN (delivery status notification)
+namespace dsn {
+
+ const char* const NOTIFY = "NOTIFY";
+ const char* const NEVER = "NEVER";
+ const char* const SUCCESS = "SUCCESS";
+ const char* const FAILURE = "FAILURE";
+ const char* const DELAY = "DELAY";
+ const char* const ORCPT = "ORCPT";
+ const char* const RET = "RET";
+ const char* const FULL = "FULL";
+ const char* const HDRS = "HDRS";
+ const char* const ENVID = "ENVID";
+}
+
+} // vmime
diff --git a/vmime-master/src/vmime/constants.hpp b/vmime-master/src/vmime/constants.hpp
new file mode 100644
index 0000000..9d25383
--- /dev/null
+++ b/vmime-master/src/vmime/constants.hpp
@@ -0,0 +1,272 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free SOFTWARE; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software FOUNDATION; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// along with this PROGRAM; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_CONSTANTS_HPP_INCLUDED
+#define VMIME_CONSTANTS_HPP_INCLUDED
+
+
+#include <string>
+
+#include "vmime/types.hpp"
+
+
+// Remove Windows defines of ERROR and WARNING
+#ifdef _WIN32
+ #undef ERROR
+ #undef WARNING
+#endif
+
+
+namespace vmime {
+
+ /** Constants for media types. */
+ namespace mediaTypes {
+
+ // Types
+ extern VMIME_EXPORT const char* const TEXT;
+ extern VMIME_EXPORT const char* const MULTIPART;
+ extern VMIME_EXPORT const char* const MESSAGE;
+ extern VMIME_EXPORT const char* const APPLICATION;
+ extern VMIME_EXPORT const char* const IMAGE;
+ extern VMIME_EXPORT const char* const AUDIO;
+ extern VMIME_EXPORT const char* const VIDEO;
+
+ // Sub-types
+ extern VMIME_EXPORT const char* const TEXT_PLAIN;
+ extern VMIME_EXPORT const char* const TEXT_HTML;
+ extern VMIME_EXPORT const char* const TEXT_RICHTEXT;
+ extern VMIME_EXPORT const char* const TEXT_ENRICHED;
+ extern VMIME_EXPORT const char* const TEXT_RFC822_HEADERS; // RFC-1892
+ extern VMIME_EXPORT const char* const TEXT_DIRECTORY; // RFC-2426
+
+ extern VMIME_EXPORT const char* const MULTIPART_MIXED;
+ extern VMIME_EXPORT const char* const MULTIPART_RELATED;
+ extern VMIME_EXPORT const char* const MULTIPART_ALTERNATIVE;
+ extern VMIME_EXPORT const char* const MULTIPART_PARALLEL;
+ extern VMIME_EXPORT const char* const MULTIPART_DIGEST;
+ extern VMIME_EXPORT const char* const MULTIPART_REPORT; // RFC-1892
+
+ extern VMIME_EXPORT const char* const MESSAGE_RFC822;
+ extern VMIME_EXPORT const char* const MESSAGE_PARTIAL;
+ extern VMIME_EXPORT const char* const MESSAGE_EXTERNAL_BODY;
+ extern VMIME_EXPORT const char* const MESSAGE_DISPOSITION_NOTIFICATION;
+ extern VMIME_EXPORT const char* const MESSAGE_DELIVERY_STATUS;
+
+ extern VMIME_EXPORT const char* const APPLICATION_OCTET_STREAM;
+
+ extern VMIME_EXPORT const char* const IMAGE_JPEG;
+ extern VMIME_EXPORT const char* const IMAGE_GIF;
+
+ extern VMIME_EXPORT const char* const AUDIO_BASIC;
+
+ extern VMIME_EXPORT const char* const VIDEO_MPEG;
+ }
+
+
+ /** Constants for encoding types. */
+ namespace encodingTypes {
+
+ extern VMIME_EXPORT const char* const SEVEN_BIT;
+ extern VMIME_EXPORT const char* const EIGHT_BIT;
+ extern VMIME_EXPORT const char* const BASE64;
+ extern VMIME_EXPORT const char* const QUOTED_PRINTABLE;
+ extern VMIME_EXPORT const char* const BINARY;
+ extern VMIME_EXPORT const char* const UUENCODE;
+ }
+
+
+ /** Constants for content disposition types (RFC-2183). */
+ namespace contentDispositionTypes {
+
+ extern VMIME_EXPORT const char* const INLINE;
+ extern VMIME_EXPORT const char* const ATTACHMENT;
+ }
+
+
+ /** Constants for charsets. */
+ namespace charsets {
+
+ extern VMIME_EXPORT const char* const ISO8859_1;
+ extern VMIME_EXPORT const char* const ISO8859_2;
+ extern VMIME_EXPORT const char* const ISO8859_3;
+ extern VMIME_EXPORT const char* const ISO8859_4;
+ extern VMIME_EXPORT const char* const ISO8859_5;
+ extern VMIME_EXPORT const char* const ISO8859_6;
+ extern VMIME_EXPORT const char* const ISO8859_7;
+ extern VMIME_EXPORT const char* const ISO8859_8;
+ extern VMIME_EXPORT const char* const ISO8859_9;
+ extern VMIME_EXPORT const char* const ISO8859_10;
+ extern VMIME_EXPORT const char* const ISO8859_13;
+ extern VMIME_EXPORT const char* const ISO8859_14;
+ extern VMIME_EXPORT const char* const ISO8859_15;
+ extern VMIME_EXPORT const char* const ISO8859_16;
+
+ extern VMIME_EXPORT const char* const CP_437;
+ extern VMIME_EXPORT const char* const CP_737;
+ extern VMIME_EXPORT const char* const CP_775;
+ extern VMIME_EXPORT const char* const CP_850;
+ extern VMIME_EXPORT const char* const CP_852;
+ extern VMIME_EXPORT const char* const CP_853;
+ extern VMIME_EXPORT const char* const CP_855;
+ extern VMIME_EXPORT const char* const CP_857;
+ extern VMIME_EXPORT const char* const CP_858;
+ extern VMIME_EXPORT const char* const CP_860;
+ extern VMIME_EXPORT const char* const CP_861;
+ extern VMIME_EXPORT const char* const CP_862;
+ extern VMIME_EXPORT const char* const CP_863;
+ extern VMIME_EXPORT const char* const CP_864;
+ extern VMIME_EXPORT const char* const CP_865;
+ extern VMIME_EXPORT const char* const CP_866;
+ extern VMIME_EXPORT const char* const CP_869;
+ extern VMIME_EXPORT const char* const CP_874;
+ extern VMIME_EXPORT const char* const CP_1125;
+ extern VMIME_EXPORT const char* const CP_1250;
+ extern VMIME_EXPORT const char* const CP_1251;
+ extern VMIME_EXPORT const char* const CP_1252;
+ extern VMIME_EXPORT const char* const CP_1253;
+ extern VMIME_EXPORT const char* const CP_1254;
+ extern VMIME_EXPORT const char* const CP_1255;
+ extern VMIME_EXPORT const char* const CP_1256;
+ extern VMIME_EXPORT const char* const CP_1257;
+
+ extern VMIME_EXPORT const char* const US_ASCII;
+
+ extern VMIME_EXPORT const char* const UTF_7;
+ extern VMIME_EXPORT const char* const UTF_8;
+ extern VMIME_EXPORT const char* const UTF_16;
+ extern VMIME_EXPORT const char* const UTF_32;
+
+ extern VMIME_EXPORT const char* const WINDOWS_1250;
+ extern VMIME_EXPORT const char* const WINDOWS_1251;
+ extern VMIME_EXPORT const char* const WINDOWS_1252;
+ extern VMIME_EXPORT const char* const WINDOWS_1253;
+ extern VMIME_EXPORT const char* const WINDOWS_1254;
+ extern VMIME_EXPORT const char* const WINDOWS_1255;
+ extern VMIME_EXPORT const char* const WINDOWS_1256;
+ extern VMIME_EXPORT const char* const WINDOWS_1257;
+ extern VMIME_EXPORT const char* const WINDOWS_1258;
+
+ extern VMIME_EXPORT const char* const IDNA;
+ }
+
+ /** Constants for standard field names. */
+ namespace fields {
+
+ extern VMIME_EXPORT const char* const RECEIVED;
+ extern VMIME_EXPORT const char* const FROM;
+ extern VMIME_EXPORT const char* const SENDER;
+ extern VMIME_EXPORT const char* const REPLY_TO;
+ extern VMIME_EXPORT const char* const TO;
+ extern VMIME_EXPORT const char* const CC;
+ extern VMIME_EXPORT const char* const BCC;
+ extern VMIME_EXPORT const char* const DATE;
+ extern VMIME_EXPORT const char* const SUBJECT;
+ extern VMIME_EXPORT const char* const ORGANIZATION;
+ extern VMIME_EXPORT const char* const USER_AGENT;
+ extern VMIME_EXPORT const char* const DELIVERED_TO;
+ extern VMIME_EXPORT const char* const RETURN_PATH;
+ extern VMIME_EXPORT const char* const MIME_VERSION;
+ extern VMIME_EXPORT const char* const MESSAGE_ID;
+ extern VMIME_EXPORT const char* const CONTENT_TYPE;
+ extern VMIME_EXPORT const char* const CONTENT_TRANSFER_ENCODING;
+ extern VMIME_EXPORT const char* const CONTENT_DESCRIPTION;
+ extern VMIME_EXPORT const char* const CONTENT_DISPOSITION;
+ extern VMIME_EXPORT const char* const CONTENT_ID;
+ extern VMIME_EXPORT const char* const CONTENT_LOCATION;
+ extern VMIME_EXPORT const char* const IN_REPLY_TO;
+ extern VMIME_EXPORT const char* const REFERENCES;
+
+ extern VMIME_EXPORT const char* const X_MAILER;
+ extern VMIME_EXPORT const char* const X_PRIORITY;
+
+ // RFC-3798: Message Disposition Notification
+ extern VMIME_EXPORT const char* const ORIGINAL_MESSAGE_ID;
+ extern VMIME_EXPORT const char* const DISPOSITION_NOTIFICATION_TO;
+ extern VMIME_EXPORT const char* const DISPOSITION_NOTIFICATION_OPTIONS;
+ extern VMIME_EXPORT const char* const DISPOSITION;
+ extern VMIME_EXPORT const char* const FAILURE;
+ extern VMIME_EXPORT const char* const ERROR;
+ extern VMIME_EXPORT const char* const WARNING;
+ extern VMIME_EXPORT const char* const ORIGINAL_RECIPIENT;
+ extern VMIME_EXPORT const char* const FINAL_RECIPIENT;
+ extern VMIME_EXPORT const char* const REPORTING_UA;
+ extern VMIME_EXPORT const char* const MDN_GATEWAY;
+ }
+
+ /** Constants for disposition action modes (RFC-3978). */
+ namespace dispositionActionModes {
+
+ /** User implicitely displayed or deleted the message (filter or
+ * any other automatic action). */
+ extern VMIME_EXPORT const char* const AUTOMATIC;
+
+ /** User explicitely displayed or deleted the message (manual action). */
+ extern VMIME_EXPORT const char* const MANUAL;
+ }
+
+ /** Constants for disposition sending modes (RFC-3798). */
+ namespace dispositionSendingModes {
+
+ /** The MDN was sent because the MUA had previously been configured
+ * to do so automatically. */
+ extern VMIME_EXPORT const char* const SENT_AUTOMATICALLY;
+
+ /** User explicitly gave permission for this particular MDN to be sent. */
+ extern VMIME_EXPORT const char* const SENT_MANUALLY;
+ }
+
+ /** Constants for disposition types (RFC-3798). */
+ namespace dispositionTypes {
+
+ /** Message has been displayed to the user. */
+ extern VMIME_EXPORT const char* const DISPLAYED;
+ /** Message has been deleted without being displayed. */
+ extern VMIME_EXPORT const char* const DELETED;
+ /** Message has been denied. */
+ extern VMIME_EXPORT const char* const DENIED;
+ }
+
+ /** Constants for disposition modifiers (RFC-3798). */
+ namespace dispositionModifiers {
+
+ extern VMIME_EXPORT const char* const ERROR;
+ }
+
+ /** Constants for DSN (delivery status notification) */
+ namespace dsn {
+
+ extern VMIME_EXPORT const char* const NOTIFY;
+ extern VMIME_EXPORT const char* const NEVER;
+ extern VMIME_EXPORT const char* const SUCCESS;
+ extern VMIME_EXPORT const char* const FAILURE;
+ extern VMIME_EXPORT const char* const DELAY;
+ extern VMIME_EXPORT const char* const ORCPT;
+ extern VMIME_EXPORT const char* const RET;
+ extern VMIME_EXPORT const char* const FULL;
+ extern VMIME_EXPORT const char* const HDRS;
+ extern VMIME_EXPORT const char* const ENVID;
+ }
+}
+
+
+#endif // VMIME_CONSTANTS_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/contentDisposition.cpp b/vmime-master/src/vmime/contentDisposition.cpp
new file mode 100644
index 0000000..1602273
--- /dev/null
+++ b/vmime-master/src/vmime/contentDisposition.cpp
@@ -0,0 +1,144 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/contentDisposition.hpp"
+#include "vmime/utility/stringUtils.hpp"
+
+
+namespace vmime {
+
+
+contentDisposition::contentDisposition()
+ : m_name(contentDispositionTypes::INLINE) {
+
+}
+
+
+contentDisposition::contentDisposition(const string& name)
+ : m_name(utility::stringUtils::toLower(name)) {
+
+}
+
+
+contentDisposition::contentDisposition(const contentDisposition& type)
+ : headerFieldValue(), m_name(type.m_name) {
+
+}
+
+
+void contentDisposition::parseImpl(
+ const parsingContext& /* ctx */,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition
+) {
+
+ m_name = utility::stringUtils::trim(
+ utility::stringUtils::toLower(
+ string(buffer.begin() + position, buffer.begin() + end)
+ )
+ );
+
+ setParsedBounds(position, end);
+
+ if (newPosition) {
+ *newPosition = end;
+ }
+}
+
+
+void contentDisposition::generateImpl(
+ const generationContext& /* ctx */,
+ utility::outputStream& os,
+ const size_t curLinePos,
+ size_t* newLinePos
+) const {
+
+ os << m_name;
+
+ if (newLinePos) {
+ *newLinePos = curLinePos + m_name.length();
+ }
+}
+
+
+contentDisposition& contentDisposition::operator=(const string& name) {
+
+ m_name = utility::stringUtils::toLower(name);
+ return *this;
+}
+
+
+bool contentDisposition::operator==(const contentDisposition& value) const {
+
+ return utility::stringUtils::toLower(m_name) == value.m_name;
+}
+
+
+bool contentDisposition::operator!=(const contentDisposition& value) const {
+
+ return !(*this == value);
+}
+
+
+shared_ptr <component> contentDisposition::clone() const {
+
+ return make_shared <contentDisposition>(*this);
+}
+
+
+void contentDisposition::copyFrom(const component& other) {
+
+ const contentDisposition& d = dynamic_cast <const contentDisposition&>(other);
+
+ m_name = d.m_name;
+}
+
+
+contentDisposition& contentDisposition::operator=(const contentDisposition& other) {
+
+ copyFrom(other);
+ return *this;
+}
+
+
+const string& contentDisposition::getName() const {
+
+ return m_name;
+}
+
+
+void contentDisposition::setName(const string& name) {
+
+ m_name = name;
+}
+
+
+const std::vector <shared_ptr <component> > contentDisposition::getChildComponents() {
+
+ return std::vector <shared_ptr <component> >();
+}
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/contentDisposition.hpp b/vmime-master/src/vmime/contentDisposition.hpp
new file mode 100644
index 0000000..636c0fb
--- /dev/null
+++ b/vmime-master/src/vmime/contentDisposition.hpp
@@ -0,0 +1,99 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_CONTENTDISPOSITION_HPP_INCLUDED
+#define VMIME_CONTENTDISPOSITION_HPP_INCLUDED
+
+
+#include "vmime/base.hpp"
+#include "vmime/headerFieldValue.hpp"
+
+
+namespace vmime {
+
+
+/** Content disposition (basic type).
+ */
+class VMIME_EXPORT contentDisposition : public headerFieldValue {
+
+public:
+
+ contentDisposition();
+ contentDisposition(const string& name);
+ contentDisposition(const contentDisposition& disp);
+
+
+ /** Return the content disposition type.
+ * See the constants in vmime::dispositionTypes.
+ *
+ * @return name of the disposition type (eg. "inline")
+ */
+ const string& getName() const;
+
+ /** Set the content disposition type.
+ * See the constants in vmime::dispositionTypes.
+ *
+ * @param name name of the disposition type
+ */
+ void setName(const string& name);
+
+ shared_ptr <component> clone() const;
+ void copyFrom(const component& other);
+ contentDisposition& operator=(const contentDisposition& other);
+
+ const std::vector <shared_ptr <component> > getChildComponents();
+
+
+ contentDisposition& operator=(const string& name);
+
+ bool operator==(const contentDisposition& value) const;
+ bool operator!=(const contentDisposition& value) const;
+
+private:
+
+ string m_name;
+
+protected:
+
+ // Component parsing & assembling
+ void parseImpl(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition = NULL
+ );
+
+ void generateImpl(
+ const generationContext& ctx,
+ utility::outputStream& os,
+ const size_t curLinePos = 0,
+ size_t* newLinePos = NULL
+ ) const;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_CONTENTDISPOSITION_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/contentDispositionField.cpp b/vmime-master/src/vmime/contentDispositionField.cpp
new file mode 100644
index 0000000..7e50680
--- /dev/null
+++ b/vmime-master/src/vmime/contentDispositionField.cpp
@@ -0,0 +1,162 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/contentDispositionField.hpp"
+#include "vmime/exception.hpp"
+
+
+namespace vmime {
+
+
+contentDispositionField::contentDispositionField() {
+
+}
+
+
+contentDispositionField::contentDispositionField(contentDispositionField&)
+ : parameterizedHeaderField() {
+
+}
+
+
+bool contentDispositionField::hasCreationDate() const {
+
+ return hasParameter("creation-date");
+}
+
+
+const datetime contentDispositionField::getCreationDate() const {
+
+ shared_ptr <parameter> param = findParameter("creation-date");
+
+ if (param) {
+ return param->getValueAs <datetime>();
+ } else {
+ return datetime::now();
+ }
+}
+
+
+void contentDispositionField::setCreationDate(const datetime& creationDate) {
+
+ getParameter("creation-date")->setValue(creationDate);
+}
+
+
+bool contentDispositionField::hasModificationDate() const {
+
+ return hasParameter("modification-date");
+}
+
+
+const datetime contentDispositionField::getModificationDate() const {
+
+ shared_ptr <parameter> param = findParameter("modification-date");
+
+ if (param) {
+ return param->getValueAs <datetime>();
+ } else {
+ return datetime::now();
+ }
+}
+
+
+void contentDispositionField::setModificationDate(const datetime& modificationDate) {
+
+ getParameter("modification-date")->setValue(modificationDate);
+}
+
+
+bool contentDispositionField::hasReadDate() const {
+
+ return hasParameter("read-date");
+}
+
+
+const datetime contentDispositionField::getReadDate() const {
+
+ shared_ptr <parameter> param = findParameter("read-date");
+
+ if (param) {
+ return param->getValueAs <datetime>();
+ } else {
+ return datetime::now();
+ }
+}
+
+
+void contentDispositionField::setReadDate(const datetime& readDate) {
+
+ getParameter("read-date")->setValue(readDate);
+}
+
+
+bool contentDispositionField::hasFilename() const {
+
+ return hasParameter("filename");
+}
+
+
+const word contentDispositionField::getFilename() const {
+
+ shared_ptr <parameter> param = findParameter("filename");
+
+ if (param) {
+ return param->getValue();
+ } else {
+ return word();
+ }
+}
+
+
+void contentDispositionField::setFilename(const word& filename) {
+
+ getParameter("filename")->setValue(filename);
+}
+
+
+bool contentDispositionField::hasSize() const {
+
+ return hasParameter("size");
+}
+
+
+const string contentDispositionField::getSize() const {
+
+ shared_ptr <parameter> param = findParameter("size");
+
+ if (param) {
+ return param->getValue().getBuffer();
+ } else {
+ return "";
+ }
+}
+
+
+void contentDispositionField::setSize(const string& size) {
+
+ getParameter("size")->setValue(word(size, vmime::charsets::US_ASCII));
+}
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/contentDispositionField.hpp b/vmime-master/src/vmime/contentDispositionField.hpp
new file mode 100644
index 0000000..89eb907
--- /dev/null
+++ b/vmime-master/src/vmime/contentDispositionField.hpp
@@ -0,0 +1,146 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_CONTENTDISPOSITIONFIELD_HPP_INCLUDED
+#define VMIME_CONTENTDISPOSITIONFIELD_HPP_INCLUDED
+
+
+#include "vmime/parameterizedHeaderField.hpp"
+
+#include "vmime/contentDisposition.hpp"
+#include "vmime/dateTime.hpp"
+#include "vmime/word.hpp"
+
+
+namespace vmime {
+
+
+/** Describes presentation information, as per RFC-2183.
+ */
+class VMIME_EXPORT contentDispositionField : public parameterizedHeaderField {
+
+ friend class headerFieldFactory;
+
+protected:
+
+ contentDispositionField();
+ contentDispositionField(contentDispositionField&);
+
+public:
+
+ /** Test whether the "creation-date" parameter is set.
+ *
+ * @return true if the "creation-date" parameter is set, or false otherwise
+ */
+ bool hasCreationDate() const;
+
+ /** Return the value of the "creation-date" parameter.
+ *
+ * @return value of the "creation-date" parameter
+ */
+ const datetime getCreationDate() const;
+
+ /** Set the value of the "creation-date" parameter.
+ *
+ * @param creationDate new value for the "creation-date" parameter
+ */
+ void setCreationDate(const datetime& creationDate);
+
+ /** Test whether the "modification-date" parameter is set.
+ *
+ * @return true if the "modification-date" parameter is set, or false otherwise
+ */
+ bool hasModificationDate() const;
+
+ /** Return the value of the "modification-date" parameter.
+ *
+ * @return value of the "modification-date" parameter
+ */
+ const datetime getModificationDate() const;
+
+ /** Set the value of the "modification-date" parameter.
+ *
+ * @param modificationDate new value for the "modification-date" parameter
+ */
+ void setModificationDate(const datetime& modificationDate);
+
+ /** Test whether the "read-date" parameter is set.
+ *
+ * @return true if the "read-date" parameter is set, or false otherwise
+ */
+ bool hasReadDate() const;
+
+ /** Return the value of the "read-date" parameter.
+ *
+ * @return value of the "read-date" parameter
+ */
+ const datetime getReadDate() const;
+
+ /** Set the value of the "read-date" parameter.
+ *
+ * @param readDate new value for the "read-date" parameter
+ */
+ void setReadDate(const datetime& readDate);
+
+ /** Test whether the "filename" parameter is set.
+ *
+ * @return true if the "filename" parameter is set, or false otherwise
+ */
+ bool hasFilename() const;
+
+ /** Return the value of the "filename" parameter.
+ *
+ * @return value of the "filename" parameter
+ */
+ const word getFilename() const;
+
+ /** Set the value of the "filename" parameter.
+ *
+ * @param filename new value for the "filename" parameter
+ */
+ void setFilename(const word& filename);
+
+ /** Test whether the "size" parameter is set.
+ *
+ * @return true if the "size" parameter is set, or false otherwise
+ */
+ bool hasSize() const;
+
+ /** Return the value of the "size" parameter.
+ *
+ * @return value of the "size" parameter
+ */
+ const string getSize() const;
+
+ /** Set the value of the "size" parameter.
+ *
+ * @param size new value for the "size" parameter
+ */
+ void setSize(const string& size);
+};
+
+
+} // vmime
+
+
+#endif // VMIME_CONTENTDISPOSITIONFIELD_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/contentHandler.cpp b/vmime-master/src/vmime/contentHandler.cpp
new file mode 100644
index 0000000..0a0e6ad
--- /dev/null
+++ b/vmime-master/src/vmime/contentHandler.cpp
@@ -0,0 +1,39 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/contentHandler.hpp"
+
+
+namespace vmime {
+
+
+// No encoding = "binary" encoding
+const encoding contentHandler::NO_ENCODING(encodingTypes::BINARY);
+
+
+contentHandler::~contentHandler() {
+
+}
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/contentHandler.hpp b/vmime-master/src/vmime/contentHandler.hpp
new file mode 100644
index 0000000..2d344ee
--- /dev/null
+++ b/vmime-master/src/vmime/contentHandler.hpp
@@ -0,0 +1,147 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_CONTENTHANDLER_HPP_INCLUDED
+#define VMIME_CONTENTHANDLER_HPP_INCLUDED
+
+
+#include <limits>
+
+#include "vmime/base.hpp"
+#include "vmime/utility/progressListener.hpp"
+#include "vmime/encoding.hpp"
+#include "vmime/mediaType.hpp"
+
+
+namespace vmime {
+
+
+class VMIME_EXPORT contentHandler : public object {
+
+public:
+
+ /** Used to specify that enclosed data is not encoded. */
+ static const vmime::encoding NO_ENCODING;
+
+
+ virtual ~contentHandler();
+
+ /** Return a copy of this object.
+ *
+ * @return copy of this object
+ */
+ virtual shared_ptr <contentHandler> clone() const = 0;
+
+ /** Output the contents into the specified stream. Data will be
+ * encoded before being written into the stream. This is used internally
+ * by the body object to generate the message, you may not need to use
+ * this (see contentHandler::extract() if you want to get the contents).
+ *
+ * @param os output stream
+ * @param enc encoding for output
+ * @param maxLineLength maximum line length for output
+ */
+ virtual void generate(
+ utility::outputStream& os,
+ const vmime::encoding& enc,
+ const size_t maxLineLength = lineLengthLimits::infinite
+ ) const = 0;
+
+ /** Extract the contents into the specified stream. If needed, data
+ * will be decoded before being written into the stream.
+ *
+ * @throw exceptions::no_encoder_available if the encoding is
+ * not supported
+ * @param os output stream
+ * @param progress progress listener, or NULL if you do not
+ * want to receive progress notifications
+ */
+ virtual void extract(
+ utility::outputStream& os,
+ utility::progressListener* progress = NULL
+ ) const = 0;
+
+ /** Extract the contents into the specified stream, without
+ * decoding it. It may be useful in case the encoding is not
+ * supported and you want to extract raw data.
+ *
+ * @param os output stream
+ * @param progress progress listener, or NULL if you do not
+ * want to receive progress notifications
+ */
+ virtual void extractRaw(
+ utility::outputStream& os,
+ utility::progressListener* progress = NULL
+ ) const = 0;
+
+ /** Returns the actual length of data. WARNING: this can return 0 if no
+ * length was specified when setting data of this object, or if the
+ * length is not known).
+ *
+ * @return length of data
+ */
+ virtual size_t getLength() const = 0;
+
+ /** Returns 'true' if data managed by this object is encoded.
+ *
+ * @return true if data is encoded, false otherwise
+ */
+ virtual bool isEncoded() const = 0;
+
+ /** Returns the encoding used for data (or "binary" if not encoded).
+ *
+ * @return encoding used for data
+ */
+ virtual const vmime::encoding& getEncoding() const = 0;
+
+ /** Returns 'true' if there is no data set.
+ *
+ * @return true if no data is managed by this object, false otherwise
+ */
+ virtual bool isEmpty() const = 0;
+
+ /** Indicates whether the extract() method can be called multiple times.
+ *
+ * @return true if the data can be extracted multiple times, or false
+ * if not (ie. streamed data from socket)
+ */
+ virtual bool isBuffered() const = 0;
+
+ /** Gives a hint about the kind of data managed by this object.
+ *
+ * @param type content media type
+ */
+ virtual void setContentTypeHint(const mediaType& type) = 0;
+
+ /** Returns a hint about the kind of data managed by this object.
+ *
+ * @return type content media type
+ */
+ virtual const mediaType getContentTypeHint() const = 0;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_CONTENTHANDLER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/contentTypeField.cpp b/vmime-master/src/vmime/contentTypeField.cpp
new file mode 100644
index 0000000..ec4971d
--- /dev/null
+++ b/vmime-master/src/vmime/contentTypeField.cpp
@@ -0,0 +1,114 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/contentTypeField.hpp"
+#include "vmime/exception.hpp"
+
+
+namespace vmime {
+
+
+contentTypeField::contentTypeField() {
+
+}
+
+
+contentTypeField::contentTypeField(contentTypeField&)
+ : parameterizedHeaderField() {
+
+}
+
+
+bool contentTypeField::hasBoundary() const {
+
+ return hasParameter("boundary");
+}
+
+
+const string contentTypeField::getBoundary() const {
+
+ shared_ptr <parameter> param = findParameter("boundary");
+
+ if (param) {
+ return param->getValue().getBuffer();
+ } else {
+ return "";
+ }
+}
+
+
+void contentTypeField::setBoundary(const string& boundary) {
+
+ getParameter("boundary")->setValue(word(boundary, vmime::charsets::US_ASCII));
+}
+
+
+bool contentTypeField::hasCharset() const {
+
+ return hasParameter("charset");
+}
+
+
+const charset contentTypeField::getCharset() const {
+
+ shared_ptr <parameter> param = findParameter("charset");
+
+ if (param) {
+ return param->getValueAs <charset>();
+ } else {
+ return charset();
+ }
+}
+
+
+void contentTypeField::setCharset(const charset& ch) {
+
+ getParameter("charset")->setValue(ch);
+}
+
+
+bool contentTypeField::hasReportType() const {
+
+ return hasParameter("report-type");
+}
+
+
+const string contentTypeField::getReportType() const {
+
+ shared_ptr <parameter> param = findParameter("report-type");
+
+ if (param) {
+ return param->getValue().getBuffer();
+ } else {
+ return "";
+ }
+}
+
+
+void contentTypeField::setReportType(const string& reportType) {
+
+ getParameter("report-type")->setValue(word(reportType, vmime::charsets::US_ASCII));
+}
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/contentTypeField.hpp b/vmime-master/src/vmime/contentTypeField.hpp
new file mode 100644
index 0000000..a63e7da
--- /dev/null
+++ b/vmime-master/src/vmime/contentTypeField.hpp
@@ -0,0 +1,113 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_CONTENTTYPEFIELD_HPP_INCLUDED
+#define VMIME_CONTENTTYPEFIELD_HPP_INCLUDED
+
+
+#include "vmime/parameterizedHeaderField.hpp"
+
+#include "vmime/mediaType.hpp"
+#include "vmime/charset.hpp"
+
+
+namespace vmime {
+
+
+class VMIME_EXPORT contentTypeField : public parameterizedHeaderField {
+
+ friend class headerFieldFactory;
+
+protected:
+
+ contentTypeField();
+ contentTypeField(contentTypeField&);
+
+public:
+
+ /** Test whether the "boundary" parameter is set.
+ *
+ * @return true if the "boundary" parameter is set, or false otherwise
+ */
+ bool hasBoundary() const;
+
+ /** Return the value of the "boundary" parameter. Boundary is a
+ * random string used to separate body parts.
+ *
+ * @return value of the "boundary" parameter
+ */
+ const string getBoundary() const;
+
+ /** Set the value of the "boundary" parameter. Boundary is a
+ * random string used to separate body parts. Normally, the
+ * boundary is generated automatically by VMime, you should
+ * not need to call this.
+ *
+ * @param boundary new value for the "boundary" parameter
+ */
+ void setBoundary(const string& boundary);
+
+ /** Test whether the "charset" parameter is set.
+ *
+ * @return true if the "charset" parameter is set, or false otherwise
+ */
+ bool hasCharset() const;
+
+ /** Return the value of the "charset" parameter. It specifies the
+ * charset used in the body part contents.
+ *
+ * @return value of the "charset" parameter
+ */
+ const charset getCharset() const;
+
+ /** Set the value of the "charset" parameter. It specifies the
+ * charset used in the body part contents.
+ *
+ * @param ch new value for the "charset" parameter
+ */
+ void setCharset(const charset& ch);
+
+ /** Test whether the "report-type" parameter is set.
+ *
+ * @return true if the "report-type" parameter is set, or false otherwise
+ */
+ bool hasReportType() const;
+
+ /** Return the value of the "report-type" parameter (RFC-1892).
+ *
+ * @return value of the "report-type" parameter
+ */
+ const string getReportType() const;
+
+ /** Set the value of the "report-type" parameter (RFC-1892).
+ *
+ * @param reportType new value for the "report-type" parameter
+ */
+ void setReportType(const string& reportType);
+};
+
+
+} // vmime
+
+
+#endif // VMIME_CONTENTTYPEFIELD_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/context.cpp b/vmime-master/src/vmime/context.cpp
new file mode 100644
index 0000000..3fc4941
--- /dev/null
+++ b/vmime-master/src/vmime/context.cpp
@@ -0,0 +1,86 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/context.hpp"
+
+
+namespace vmime {
+
+
+context::context()
+ : m_internationalizedEmail(false) {
+
+}
+
+
+context::context(const context& ctx)
+ : object(),
+ m_internationalizedEmail(ctx.m_internationalizedEmail) {
+
+}
+
+
+context::~context() {
+
+}
+
+
+bool context::getInternationalizedEmailSupport() const {
+
+ return m_internationalizedEmail;
+}
+
+
+void context::setInternationalizedEmailSupport(const bool support) {
+
+ m_internationalizedEmail = support;
+}
+
+
+const charsetConverterOptions& context::getCharsetConversionOptions() const {
+
+ return m_charsetConvOptions;
+}
+
+
+void context::setCharsetConversionOptions(const charsetConverterOptions& opts) {
+
+ m_charsetConvOptions = opts;
+}
+
+
+context& context::operator=(const context& ctx) {
+
+ copyFrom(ctx);
+ return *this;
+}
+
+
+void context::copyFrom(const context& ctx) {
+
+ m_internationalizedEmail = ctx.m_internationalizedEmail;
+ m_charsetConvOptions = ctx.m_charsetConvOptions;
+}
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/context.hpp b/vmime-master/src/vmime/context.hpp
new file mode 100644
index 0000000..1d00950
--- /dev/null
+++ b/vmime-master/src/vmime/context.hpp
@@ -0,0 +1,120 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_CONTEXT_HPP_INCLUDED
+#define VMIME_CONTEXT_HPP_INCLUDED
+
+
+#include "vmime/base.hpp"
+#include "vmime/charsetConverterOptions.hpp"
+
+
+namespace vmime {
+
+
+/** Holds configuration parameters used either for parsing or generating messages.
+ */
+class VMIME_EXPORT context : public object {
+
+public:
+
+ virtual ~context();
+
+ /** Returns whether support for Internationalized Email Headers (RFC-6532)
+ * is enabled.
+ *
+ * @return true if RFC-6532 support is enabled, false otherwise
+ */
+ bool getInternationalizedEmailSupport() const;
+
+ /** Enables or disables support for Internationalized Email Headers (RFC-6532).
+ * This is disabled by default, and should be used only with servers
+ * which support it (eg. SMTP servers with SMTPUTF8 extension).
+ *
+ * @param support true if RFC-6532 support is enabled, false otherwise
+ */
+ void setInternationalizedEmailSupport(const bool support);
+
+ /** Returns options used currently for charset conversions by the parser and/or
+ * the generator. See charsetConverterOptions class for more information.
+ *
+ * @return current charset conversion options
+ */
+ const charsetConverterOptions& getCharsetConversionOptions() const;
+
+ /** Sets the options used currently for charset conversions by the parser and/or
+ * the generator. See charsetConverterOptions class for more information.
+ *
+ * @param opts new charset conversion options
+ */
+ void setCharsetConversionOptions(const charsetConverterOptions& opts);
+
+ /** Switches between contexts temporarily.
+ */
+ template <typename CTX_CLASS>
+ class switcher {
+
+ public:
+
+ /** Switches to the specified context.
+ * Default context will temporarily use the data of the specified
+ * new context during the lifetime of this object.
+ *
+ * @param newCtx new context
+ */
+ switcher(CTX_CLASS& newCtx)
+ : m_oldCtxData(CTX_CLASS::getDefaultContext()), m_newCtx(&newCtx) {
+
+ CTX_CLASS::getDefaultContext().copyFrom(newCtx);
+ }
+
+ /** Restores back saved context.
+ */
+ ~switcher() {
+
+ CTX_CLASS::getDefaultContext().copyFrom(m_oldCtxData);
+ }
+
+ private:
+
+ CTX_CLASS m_oldCtxData;
+ CTX_CLASS* m_newCtx;
+ };
+
+protected:
+
+ context();
+ context(const context& ctx);
+
+ virtual context& operator=(const context& ctx);
+ void copyFrom(const context& ctx);
+
+ bool m_internationalizedEmail;
+ charsetConverterOptions m_charsetConvOptions;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_CONTEXT_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/dateTime.cpp b/vmime-master/src/vmime/dateTime.cpp
new file mode 100644
index 0000000..fd44303
--- /dev/null
+++ b/vmime-master/src/vmime/dateTime.cpp
@@ -0,0 +1,925 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include <iomanip>
+
+#include "vmime/config.hpp"
+#include "vmime/dateTime.hpp"
+#include "vmime/platform.hpp"
+#include "vmime/parserHelpers.hpp"
+
+#include "vmime/utility/datetimeUtils.hpp"
+
+
+namespace vmime {
+
+/*
+
+ RFC #822:
+ 5. DATE AND TIME SPECIFICATION
+
+date-time = [ day "," ] date time ; dd mm yy
+ ; hh:mm:ss zzz
+day = "Mon" / "Tue" / "Wed" / "Thu" /
+ "Fri" / "Sat" / "Sun"
+
+date = 1*2DIGIT month 2DIGIT ; day month year
+ ; e.g. 20 Jun 82
+month = "Jan" / "Feb" / "Mar" / "Apr" /
+ "May" / "Jun" / "Jul" / "Aug" /
+ "Sep" / "Oct" / "Nov" / "Dec"
+
+time = hour zone ; ANSI and Military
+
+hour = 2DIGIT ":" 2DIGIT [":" 2DIGIT] ; 00:00:00 - 23:59:59
+
+zone = "UT" / "GMT" ; Universal Time
+ ; North American : UT
+ / "EST" / "EDT" ; Eastern: - 5/ - 4
+ / "CST" / "CDT" ; Central: - 6/ - 5
+ / "MST" / "MDT" ; Mountain: - 7/ - 6
+ / "PST" / "PDT" ; Pacific: - 8/ - 7
+ / 1ALPHA ; Military: Z = UT;
+ ; A:-1; (J not used)
+ ; M:-12; N:+1; Y:+12
+ / ( ("+" / "-") 4DIGIT ) ; Local differential
+ ; hours+min. (HHMM)
+*/
+
+
+void datetime::parseImpl(
+ const parsingContext& /* ctx */,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition
+) {
+
+ const char* const pend = buffer.data() + end;
+ const char* p = buffer.data() + position;
+
+ // Parse the date and time value
+ while (p < pend && parserHelpers::isSpace(*p)) ++p;
+
+ if (p < pend) {
+
+ if (parserHelpers::isAlpha(*p)) {
+
+ // Ignore week day
+ while (p < pend && parserHelpers::isAlpha(*p)) ++p;
+ while (p < pend && parserHelpers::isSpace(*p)) ++p;
+ if (p < pend && *p == ',') ++p;
+ while (p < pend && parserHelpers::isSpace(*p)) ++p;
+ }
+
+ bool dayParsed = false;
+
+ if (parserHelpers::isAlpha(*p)) {
+
+ // Ill-formed date/time, this may be the month,
+ // so we skip day parsing (will be done later)
+
+ } else {
+
+ while (p < pend && !parserHelpers::isDigit(*p)) ++p;
+
+ if (p < pend && parserHelpers::isDigit(*p)) {
+
+ // Month day
+ int day = 0;
+
+ do {
+ day = day * 10 + (*p - '0');
+ ++p;
+ } while (p < pend && parserHelpers::isDigit(*p));
+
+ m_day = (day >= 1 && day <= 31) ? day : 1;
+
+ while (p < pend && !parserHelpers::isSpace(*p)) ++p;
+ while (p < pend && parserHelpers::isSpace(*p)) ++p;
+
+ } else {
+
+ m_day = 1;
+
+ // Skip everything to the next field
+ while (p < pend && !parserHelpers::isSpace(*p)) ++p;
+ while (p < pend && parserHelpers::isSpace(*p)) ++p;
+ }
+
+ dayParsed = true;
+ }
+
+ if (p < pend && parserHelpers::isAlpha(*p)) {
+
+ // Month
+ char_t month[4] = { 0 };
+ int monthLength = 0;
+
+ do {
+ month[monthLength++] = *p;
+ ++p;
+ } while (monthLength < 3 && p < pend && parserHelpers::isAlpha(*p));
+
+ while (p < pend && parserHelpers::isAlpha(*p)) ++p;
+
+ switch (month[0]) {
+
+ case 'a':
+ case 'A': {
+
+ if (month[1] == 'u' || month[1] == 'U')
+ m_month = AUGUST;
+ else
+ m_month = APRIL; // by default
+
+ break;
+ }
+ case 'd':
+ case 'D': {
+
+ m_month = DECEMBER;
+ break;
+ }
+ case 'f':
+ case 'F': {
+
+ m_month = FEBRUARY;
+ break;
+ }
+ case 'j':
+ case 'J': {
+
+ if (month[1] == 'u' || month[1] == 'U') {
+
+ if (month[2] == 'l' || month[2] == 'L') {
+ m_month = JULY;
+ } else { // if (month[2] == 'n' || month[2] == 'N')
+ m_month = JUNE;
+ }
+
+ } else {
+
+ m_month = JANUARY; // by default
+ }
+
+ break;
+ }
+ case 'm':
+ case 'M': {
+
+ if ((month[1] == 'a' || month[1] == 'A') &&
+ (month[2] == 'y' || month[2] == 'Y')) {
+
+ m_month = MAY;
+
+ } else {
+
+ m_month = MARCH; // by default
+ }
+
+ break;
+ }
+ case 'n':
+ case 'N': {
+
+ m_month = NOVEMBER;
+ break;
+ }
+ case 'o':
+ case 'O': {
+
+ m_month = OCTOBER;
+ break;
+ }
+ case 's':
+ case 'S': {
+
+ m_month = SEPTEMBER;
+ break;
+ }
+ default: {
+
+ m_month = JANUARY; // by default
+ break;
+ }
+ }
+
+ while (p < pend && !parserHelpers::isSpace(*p)) ++p;
+ while (p < pend && parserHelpers::isSpace(*p)) ++p;
+
+ } else {
+
+ m_month = JANUARY;
+
+ if (parserHelpers::isDigit(*p)) {
+
+ // Here, we expected a month, but it maybe
+ // a ill-formed date, so try to parse a year
+ // (we don't skip anything).
+
+ } else {
+
+ // Skip everything to the next field
+ while (p < pend && !parserHelpers::isSpace(*p)) ++p;
+ while (p < pend && parserHelpers::isSpace(*p)) ++p;
+ }
+ }
+
+ if (!dayParsed && p < pend && parserHelpers::isDigit(*p)) {
+
+ // Month day
+ int day = 0;
+
+ do {
+ day = day * 10 + (*p - '0');
+ ++p;
+ } while (p < pend && parserHelpers::isDigit(*p));
+
+ m_day = (day >= 1 && day <= 31) ? day : 1;
+
+ while (p < pend && !parserHelpers::isSpace(*p)) ++p;
+ while (p < pend && parserHelpers::isSpace(*p)) ++p;
+ }
+
+ if (p < pend && parserHelpers::isDigit(*p)) {
+
+ // Check for ill-formed date/time and try to recover
+ if (p + 2 < pend && *(p + 2) == ':') {
+
+ // Skip year (default to current), and advance
+ // to time parsing
+ m_year = now().getYear();
+
+ } else {
+
+ // Year
+ int year = 0;
+
+ do {
+ year = year * 10 + (*p - '0');
+ ++p;
+ } while (p < pend && parserHelpers::isDigit(*p));
+
+ if (year < 70) m_year = year + 2000;
+ else if (year < 1000) m_year = year + 1900;
+ else m_year = year;
+
+ while (p < pend && !parserHelpers::isSpace(*p)) ++p;
+ while (p < pend && parserHelpers::isSpace(*p)) ++p;
+ }
+
+ } else {
+
+ m_year = 1970;
+
+ // Skip everything to the next field
+ while (p < pend && !parserHelpers::isSpace(*p)) ++p;
+ while (p < pend && parserHelpers::isSpace(*p)) ++p;
+ }
+
+ if (p < pend && parserHelpers::isDigit(*p)) {
+
+ // Hour
+ int hour = 0;
+
+ do {
+ hour = hour * 10 + (*p - '0');
+ ++p;
+ } while (p < pend && parserHelpers::isDigit(*p));
+
+ m_hour = (hour >= 0 && hour <= 23) ? hour : 0;
+
+ while (p < pend && parserHelpers::isSpace(*p)) ++p;
+
+ if (p < pend && *p == ':') {
+
+ ++p;
+
+ while (p < pend && parserHelpers::isSpace(*p)) ++p;
+
+ if (p < pend && parserHelpers::isDigit(*p)) {
+
+ // Minute
+ int minute = 0;
+
+ do {
+ minute = minute * 10 + (*p - '0');
+ ++p;
+ } while (p < pend && parserHelpers::isDigit(*p));
+
+ m_minute = (minute >= 0 && minute <= 59) ? minute : 0;
+
+ while (p < pend && parserHelpers::isSpace(*p)) ++p;
+
+ if (p < pend && *p == ':') {
+
+ ++p;
+
+ while (p < pend && parserHelpers::isSpace(*p)) ++p;
+
+ if (p < pend && parserHelpers::isDigit(*p)) {
+
+ // Second
+ int second = 0;
+
+ do {
+ second = second * 10 + (*p - '0');
+ ++p;
+ } while (p < pend && parserHelpers::isDigit(*p));
+
+ m_second = (second >= 0 && second <= 59) ? second : 0;
+
+ while (p < pend && !parserHelpers::isSpace(*p)) ++p;
+ while (p < pend && parserHelpers::isSpace(*p)) ++p;
+
+ } else {
+
+ m_second = 0;
+ }
+
+ } else {
+
+ m_second = 0;
+ }
+
+ } else {
+
+ m_minute = 0;
+ }
+
+ } else {
+
+ m_minute = 0;
+ }
+
+ } else {
+
+ m_hour = 0;
+
+ // Skip everything to the next field
+ while (p < pend && !parserHelpers::isSpace(*p)) ++p;
+ while (p < pend && parserHelpers::isSpace(*p)) ++p;
+ }
+
+ if (p + 1 < pend && (*p == '+' || *p == '-') && parserHelpers::isDigit(*(p + 1))) {
+
+ const char_t sign = *p;
+ ++p;
+
+ // Zone offset (in hour/minutes)
+ int offset = 0;
+
+ do {
+ offset = offset * 10 + (*p - '0');
+ ++p;
+ } while (p < pend && parserHelpers::isDigit(*p));
+
+ const int hourOff = offset / 100;
+ const int minOff = offset % 100;
+
+ if (sign == '+') {
+ m_zone = hourOff * 60 + minOff;
+ } else {
+ m_zone = -(hourOff * 60 + minOff);
+ }
+
+ } else if (p < pend && isalpha(*p)) {
+
+ bool done = false;
+
+ // Zone offset (Time zone name)
+ char_t zone[4] = { 0 };
+ int zoneLength = 0;
+
+ do {
+ zone[zoneLength++] = *p;
+ ++p;
+ } while (zoneLength < 3 && p < pend);
+
+ switch (zone[0])
+ {
+ case 'c':
+ case 'C':
+ {
+ if (zoneLength >= 2)
+ {
+ if (zone[1] == 's' || zone[1] == 'S')
+ m_zone = CST;
+ else
+ m_zone = CDT;
+
+ done = true;
+ }
+
+ break;
+ }
+ case 'e':
+ case 'E':
+ {
+ if (zoneLength >= 2) {
+
+ if (zone[1] == 's' || zone[1] == 'S') {
+ m_zone = EST;
+ } else {
+ m_zone = EDT;
+ }
+
+ done = true;
+ }
+
+ break;
+ }
+ case 'm':
+ case 'M': {
+
+ if (zoneLength >= 2) {
+
+ if (zone[1] == 's' || zone[1] == 'S') {
+ m_zone = MST;
+ } else {
+ m_zone = MDT;
+ }
+
+ done = true;
+ }
+
+ break;
+ }
+ case 'p':
+ case 'P': {
+
+ if (zoneLength >= 2) {
+
+ if (zone[1] == 's' || zone[1] == 'S') {
+ m_zone = PST;
+ } else {
+ m_zone = PDT;
+ }
+
+ done = true;
+ }
+
+ break;
+ }
+ case 'g':
+ case 'G':
+ case 'u':
+ case 'U': {
+
+ if (zoneLength >= 2) {
+
+ m_zone = GMT; // = UTC
+ done = true;
+ }
+
+ break;
+ }
+
+ }
+
+ if (!done) {
+
+ const char_t z = zone[0];
+
+ // Military time zone
+ if (z != 'j' && z != 'J') {
+
+ typedef std::map <char_t, int> Map;
+ static const Map::value_type offsetMapInit[] = {
+
+ Map::value_type('a', -60),
+ Map::value_type('b', -120),
+ Map::value_type('c', -180),
+ Map::value_type('d', -240),
+ Map::value_type('e', -300),
+ Map::value_type('f', -360),
+ Map::value_type('g', -420),
+ Map::value_type('h', -480),
+ Map::value_type('i', -540),
+ Map::value_type('k', -600),
+ Map::value_type('l', -660),
+ Map::value_type('m', -720),
+
+ Map::value_type('n', 60),
+ Map::value_type('o', 120),
+ Map::value_type('p', 180),
+ Map::value_type('q', 240),
+ Map::value_type('r', 300),
+ Map::value_type('s', 360),
+ Map::value_type('t', 420),
+ Map::value_type('u', 480),
+ Map::value_type('v', 540),
+ Map::value_type('w', 600),
+ Map::value_type('x', 660),
+ Map::value_type('y', 720),
+
+ Map::value_type('z', 0),
+ };
+
+ static const Map offsetMap(
+ ::vmime::begin(offsetMapInit),
+ ::vmime::end(offsetMapInit)
+ );
+
+ Map::const_iterator pos =
+ offsetMap.find(parserHelpers::toLower(z));
+
+ if (pos != offsetMap.end()) {
+ m_zone = (*pos).second;
+ } else {
+ m_zone = GMT;
+ }
+
+ } else {
+
+ m_zone = GMT;
+ }
+ }
+
+ } else {
+
+ m_zone = 0;
+ }
+
+ } else {
+
+ m_year = 1970;
+ m_month = JANUARY;
+ m_day = 1;
+
+ m_hour = 0;
+ m_minute = 0;
+ m_second = 0;
+
+ m_zone = 0;
+ }
+
+ setParsedBounds(position, end);
+
+ if (newPosition) {
+ *newPosition = end;
+ }
+}
+
+
+void datetime::generateImpl(
+ const generationContext& /* ctx */,
+ utility::outputStream& os,
+ const size_t curLinePos,
+ size_t* newLinePos
+) const {
+
+ static const char* dayNames[] = {
+ "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
+ };
+ static const char* monthNames[] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+ };
+
+ const int z = ((m_zone < 0) ? -m_zone : m_zone);
+ const int zh = z / 60;
+ const int zm = z % 60;
+
+ std::ostringstream oss;
+ oss.imbue(std::locale::classic());
+
+ oss << dayNames[getWeekDay()] << ", "
+ << m_day << " " << monthNames[m_month - 1] << " " << m_year
+ << " " << std::setfill('0') << std::setw(2) << m_hour << ":"
+ << std::setfill('0') << std::setw(2) << m_minute << ":"
+ << std::setfill('0') << std::setw(2) << m_second
+ << " " << ((m_zone < 0) ? '-' : '+') << std::setfill('0') << std::setw(2) << zh
+ << std::setfill('0') << std::setw(2) << zm;
+
+ const string& str = oss.str();
+ os << str;
+
+ if (newLinePos) {
+ *newLinePos = curLinePos + str.length();
+ }
+}
+
+
+datetime::datetime()
+ : m_year(1970), m_month(1), m_day(1),
+ m_hour(0), m_minute(0), m_second(0), m_zone(0) {
+
+}
+
+
+datetime::datetime(const int year, const int month, const int day)
+ : m_year(year), m_month(month), m_day(day),
+ m_hour(0), m_minute(0), m_second(0), m_zone(0) {
+
+}
+
+
+datetime::datetime(
+ const int year,
+ const int month,
+ const int day,
+ const int hour,
+ const int minute,
+ const int second,
+ const int zone
+)
+ : m_year(year),
+ m_month(month),
+ m_day(day),
+ m_hour(hour),
+ m_minute(minute),
+ m_second(second),
+ m_zone(zone) {
+
+}
+
+
+datetime::datetime(const datetime& d)
+ : headerFieldValue(),
+ m_year(d.m_year),
+ m_month(d.m_month),
+ m_day(d.m_day),
+ m_hour(d.m_hour),
+ m_minute(d.m_minute),
+ m_second(d.m_second),
+ m_zone(d.m_zone) {
+
+}
+
+
+datetime::datetime(const time_t t, const int zone) {
+
+#if VMIME_HAVE_LOCALTIME_S
+
+ struct tm tms;
+
+ if (!gmtime_s(&tms, &t)) {
+ localtime_s(&tms, &t);
+ }
+
+#elif VMIME_HAVE_LOCALTIME_R
+ struct tm tms;
+
+ if (!gmtime_r(&t, &tms)) {
+ localtime_r(&t, &tms);
+ }
+
+#else
+
+ struct tm* gtm = gmtime(&t);
+ struct tm* ltm = localtime(&t);
+
+ struct tm tms;
+
+ if (gtm) {
+ tms = *gtm;
+ } else if (ltm) {
+ tms = *ltm;
+ }
+
+#endif
+
+ m_year = tms.tm_year + 1900;
+ m_month = tms.tm_mon + 1;
+ m_day = tms.tm_mday;
+ m_hour = tms.tm_hour;
+ m_minute = tms.tm_min;
+ m_second = tms.tm_sec;
+ m_zone = zone;
+}
+
+
+datetime::datetime(const string& date) {
+
+ parse(date);
+}
+
+
+datetime::~datetime() {
+
+}
+
+
+void datetime::copyFrom(const component& other) {
+
+ const datetime& d = dynamic_cast <const datetime&>(other);
+
+ m_year = d.m_year;
+ m_month = d.m_month;
+ m_day = d.m_day;
+ m_hour = d.m_hour;
+ m_minute = d.m_minute;
+ m_second = d.m_second;
+ m_zone = d.m_zone;
+}
+
+
+datetime& datetime::operator=(const datetime& other) {
+
+ copyFrom(other);
+ return *this;
+}
+
+
+datetime& datetime::operator=(const string& s) {
+
+ parse(s);
+ return *this;
+}
+
+
+void datetime::getTime(int& hour, int& minute, int& second, int& zone) const {
+
+ hour = m_hour;
+ minute = m_minute;
+ second = m_second;
+ zone = m_zone;
+}
+
+
+void datetime::getTime(int& hour, int& minute, int& second) const {
+
+ hour = m_hour;
+ minute = m_minute;
+ second = m_second;
+}
+
+
+void datetime::getDate(int& year, int& month, int& day) const {
+
+ year = m_year;
+ month = m_month;
+ day = m_day;
+}
+
+
+void datetime::setTime(
+ const int hour,
+ const int minute,
+ const int second,
+ const int zone
+) {
+
+ m_hour = hour;
+ m_minute = minute;
+ m_second = second;
+ m_zone = zone;
+}
+
+
+void datetime::setDate(
+ const int year,
+ const int month,
+ const int day
+) {
+
+ m_year = year;
+ m_month = month;
+ m_day = day;
+}
+
+
+const datetime datetime::now() {
+
+ return platform::getHandler()->getCurrentLocalTime();
+}
+
+
+shared_ptr <component> datetime::clone() const {
+
+ return make_shared <datetime>(*this);
+}
+
+
+const std::vector <shared_ptr <component> > datetime::getChildComponents() {
+
+ return std::vector <shared_ptr <component> >();
+}
+
+
+int datetime::getYear() const { return m_year; }
+int datetime::getMonth() const { return m_month; }
+int datetime::getDay() const { return m_day; }
+int datetime::getHour() const { return m_hour; }
+int datetime::getMinute() const { return m_minute; }
+int datetime::getSecond() const { return m_second; }
+int datetime::getZone() const { return m_zone; }
+int datetime::getWeekDay() const { return utility::datetimeUtils::getDayOfWeek(m_year, m_month, m_day); }
+int datetime::getWeek() const { return utility::datetimeUtils::getWeekOfYear(m_year, m_month, m_day); }
+
+void datetime::setYear(const int year) { m_year = year; }
+void datetime::setMonth(const int month) { m_month = std::min(std::max(month, 1), 12); }
+void datetime::setDay(const int day) { m_day = day; }
+void datetime::setHour(const int hour) { m_hour = hour; }
+void datetime::setMinute(const int minute) { m_minute = minute; }
+void datetime::setSecond(const int second) { m_second = second; }
+void datetime::setZone(const int zone) { m_zone = zone; }
+
+
+bool datetime::operator==(const datetime& other) const {
+
+ const datetime ut1 = utility::datetimeUtils::toUniversalTime(*this);
+ const datetime ut2 = utility::datetimeUtils::toUniversalTime(other);
+
+ return ut1.m_year == ut2.m_year &&
+ ut1.m_month == ut2.m_month &&
+ ut1.m_day == ut2.m_day &&
+ ut1.m_hour == ut2.m_hour &&
+ ut1.m_minute == ut2.m_minute &&
+ ut1.m_second == ut2.m_second;
+}
+
+
+bool datetime::operator!=(const datetime& other) const {
+
+ const datetime ut1 = utility::datetimeUtils::toUniversalTime(*this);
+ const datetime ut2 = utility::datetimeUtils::toUniversalTime(other);
+
+ return ut1.m_year != ut2.m_year ||
+ ut1.m_month != ut2.m_month ||
+ ut1.m_day != ut2.m_day ||
+ ut1.m_hour != ut2.m_hour ||
+ ut1.m_minute != ut2.m_minute ||
+ ut1.m_second != ut2.m_second;
+}
+
+
+bool datetime::operator<(const datetime& other) const {
+
+ const datetime ut1 = utility::datetimeUtils::toUniversalTime(*this);
+ const datetime ut2 = utility::datetimeUtils::toUniversalTime(other);
+
+ return (ut1.m_year < ut2.m_year) ||
+ ((ut1.m_year == ut2.m_year) && ((ut1.m_month < ut2.m_month) ||
+ ((ut1.m_month == ut2.m_month) && ((ut1.m_day < ut2.m_day) ||
+ ((ut1.m_day == ut2.m_day) && ((ut1.m_hour < ut2.m_hour) ||
+ ((ut1.m_hour == ut2.m_hour) && ((ut1.m_minute < ut2.m_minute) ||
+ ((ut1.m_minute == ut2.m_minute) && ((ut1.m_second < ut2.m_second)))))))))));
+}
+
+
+bool datetime::operator<=(const datetime& other) const {
+
+ const datetime ut1 = utility::datetimeUtils::toUniversalTime(*this);
+ const datetime ut2 = utility::datetimeUtils::toUniversalTime(other);
+
+ return (ut1.m_year < ut2.m_year) ||
+ ((ut1.m_year == ut2.m_year) && ((ut1.m_month < ut2.m_month) ||
+ ((ut1.m_month == ut2.m_month) && ((ut1.m_day < ut2.m_day) ||
+ ((ut1.m_day == ut2.m_day) && ((ut1.m_hour < ut2.m_hour) ||
+ ((ut1.m_hour == ut2.m_hour) && ((ut1.m_minute < ut2.m_minute) ||
+ ((ut1.m_minute == ut2.m_minute) && ((ut1.m_second <= ut2.m_second)))))))))));
+}
+
+
+bool datetime::operator>(const datetime& other) const {
+
+ const datetime ut1 = utility::datetimeUtils::toUniversalTime(*this);
+ const datetime ut2 = utility::datetimeUtils::toUniversalTime(other);
+
+ return (ut1.m_year > ut2.m_year) ||
+ ((ut1.m_year == ut2.m_year) && ((ut1.m_month > ut2.m_month) ||
+ ((ut1.m_month == ut2.m_month) && ((ut1.m_day > ut2.m_day) ||
+ ((ut1.m_day == ut2.m_day) && ((ut1.m_hour > ut2.m_hour) ||
+ ((ut1.m_hour == ut2.m_hour) && ((ut1.m_minute > ut2.m_minute) ||
+ ((ut1.m_minute == ut2.m_minute) && (ut1.m_second > ut2.m_second))))))))));
+}
+
+
+bool datetime::operator>=(const datetime& other) const {
+
+ const datetime ut1 = utility::datetimeUtils::toUniversalTime(*this);
+ const datetime ut2 = utility::datetimeUtils::toUniversalTime(other);
+
+ return (ut1.m_year > ut2.m_year) ||
+ ((ut1.m_year == ut2.m_year) && ((ut1.m_month > ut2.m_month) ||
+ ((ut1.m_month == ut2.m_month) && ((ut1.m_day > ut2.m_day) ||
+ ((ut1.m_day == ut2.m_day) && ((ut1.m_hour > ut2.m_hour) ||
+ ((ut1.m_hour == ut2.m_hour) && ((ut1.m_minute > ut2.m_minute) ||
+ ((ut1.m_minute == ut2.m_minute) && (ut1.m_second >= ut2.m_second))))))))));
+}
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/dateTime.hpp b/vmime-master/src/vmime/dateTime.hpp
new file mode 100644
index 0000000..64e8dad
--- /dev/null
+++ b/vmime-master/src/vmime/dateTime.hpp
@@ -0,0 +1,275 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_DATETIME_HPP_INCLUDED
+#define VMIME_DATETIME_HPP_INCLUDED
+
+
+#include "vmime/base.hpp"
+#include "vmime/headerFieldValue.hpp"
+
+#include <ctime>
+
+
+namespace vmime {
+
+
+/** Date and time (basic type).
+ */
+class VMIME_EXPORT datetime : public headerFieldValue {
+
+public:
+
+ // Constructors
+ datetime();
+ datetime(
+ const int year,
+ const int month,
+ const int day
+ );
+ datetime(
+ const int year,
+ const int month,
+ const int day,
+ const int hour,
+ const int minute,
+ const int second,
+ const int zone = GMT
+ );
+ datetime(const datetime& d);
+ datetime(const string& date);
+ datetime(const time_t t, const int zone = GMT);
+
+ // Destructor
+ ~datetime();
+
+ // Some time zones (in minutes)
+ enum TimeZones {
+
+ GMT_12 = -720, // GMT-12h
+ GMT_11 = -660, // GMT-11h
+ GMT_10 = -600, // GMT-10h
+ GMT_9 = -540, // GMT-9h
+ GMT_8 = -480, // GMT-8h
+ GMT_7 = -420, // GMT-7h
+ GMT_6 = -360, // GMT-6h
+ GMT_5 = -300, // GMT-5h
+ GMT_4 = -240, // GMT-4h
+ GMT_3 = -180, // GMT-3h
+ GMT_2 = -120, // GMT-2h
+ GMT_1 = -60, // GMT-1h
+ GMT = 0, // GMT
+ GMT1 = 60, // GMT+1h
+ GMT2 = 120, // GMT+2h
+ GMT3 = 180, // GMT+3h
+ GMT4 = 240, // GMT+4h
+ GMT5 = 300, // GMT+5h
+ GMT6 = 360, // GMT+6h
+ GMT7 = 420, // GMT+7h
+ GMT8 = 480, // GMT+8h
+ GMT9 = 540, // GMT+9h
+ GMT10 = 600, // GMT+10h
+ GMT11 = 660, // GMT+11h
+ GMT12 = 720, // GMT+12h
+
+ UT = GMT, // Universal Time
+
+ EST = GMT_5, // Eastern
+ EDT = GMT_4,
+ CST = GMT_6, // Central
+ CDT = GMT_5,
+ MST = GMT_7, // Mountain
+ MDT = GMT_6,
+ PST = GMT_8, // Pacific
+ PDT = GMT_7,
+
+ // Military time zones
+ A = GMT_1,
+ B = GMT_2,
+ C = GMT_3,
+ D = GMT_4,
+ E = GMT_5,
+ F = GMT_6,
+ G = GMT_7,
+ H = GMT_8,
+ I = GMT_9, // J not used
+ K = GMT_10,
+ L = GMT_11,
+ M = GMT_12,
+
+ N = GMT1,
+ O = GMT2,
+ P = GMT3,
+ Q = GMT4,
+ R = GMT5,
+ S = GMT6,
+ T = GMT7,
+ U = GMT8,
+ V = GMT9,
+ W = GMT10,
+ X = GMT11,
+ Y = GMT12,
+
+ Z = GMT
+ };
+
+ // Months list
+ enum Months {
+
+ // Long
+ JANUARY = 1,
+ FEBRUARY = 2,
+ MARCH = 3,
+ APRIL = 4,
+ MAY = 5,
+ JUNE = 6,
+ JULY = 7,
+ AUGUST = 8,
+ SEPTEMBER = 9,
+ OCTOBER = 10,
+ NOVEMBER = 11,
+ DECEMBER = 12,
+
+ // Short
+ JAN = 1,
+ FEB = 2,
+ MAR = 3,
+ APR = 4,
+ JUN = 6,
+ JUL = 7,
+ AUG = 8,
+ SEP = 9,
+ OCT = 10,
+ NOV = 11,
+ DEC = 12
+ };
+
+ // Days of week list
+ enum DaysOfWeek {
+
+ // Long
+ SUNDAY = 0,
+ MONDAY = 1,
+ TUESDAY = 2,
+ WEDNESDAY = 3,
+ THURSDAY = 4,
+ FRIDAY = 5,
+ SATURDAY = 6,
+
+ // Short
+ SUN = 0,
+ MON = 1,
+ TUE = 2,
+ WED = 3,
+ THU = 4,
+ FRI = 5,
+ SAT = 6
+ };
+
+private:
+
+ // Date components
+ int m_year;
+ int m_month;
+ int m_day;
+
+ // Time components
+ int m_hour;
+ int m_minute;
+ int m_second;
+ int m_zone;
+
+public:
+
+ // Get
+ int getYear() const;
+ int getMonth() const;
+ int getDay() const;
+ int getHour() const;
+ int getMinute() const;
+ int getSecond() const;
+ int getZone() const;
+ int getWeekDay() const;
+ int getWeek() const;
+
+ void getTime(int& hour, int& minute, int& second, int& zone) const;
+ void getTime(int& hour, int& minute, int& second) const;
+ void getDate(int& year, int& month, int& day) const;
+
+ // Set
+ void setYear(const int year);
+ void setMonth(const int month);
+ void setDay(const int day);
+ void setHour(const int hour);
+ void setMinute(const int minute);
+ void setSecond(const int second);
+ void setZone(const int zone);
+
+ void setTime(const int hour = 0, const int minute = 0, const int second = 0, const int zone = GMT);
+ void setDate(const int year, const int month, const int day);
+
+ // Assignment
+ datetime& operator=(const datetime& other);
+ datetime& operator=(const string& s);
+
+ void copyFrom(const component& other);
+
+ shared_ptr <component> clone() const;
+
+ // Comparison
+ bool operator==(const datetime& other) const;
+ bool operator!=(const datetime& other) const;
+ bool operator<(const datetime& other) const;
+ bool operator<=(const datetime& other) const;
+ bool operator>(const datetime& other) const;
+ bool operator>=(const datetime& other) const;
+
+ // Current date and time
+ static const datetime now();
+
+ const std::vector <shared_ptr <component> > getChildComponents();
+
+protected:
+
+ // Component parsing & assembling
+ void parseImpl(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition = NULL
+ );
+
+ void generateImpl(
+ const generationContext& ctx,
+ utility::outputStream& os,
+ const size_t curLinePos = 0,
+ size_t* newLinePos = NULL
+ ) const;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_DATETIME_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/defaultAttachment.cpp b/vmime-master/src/vmime/defaultAttachment.cpp
new file mode 100644
index 0000000..36eaa3c
--- /dev/null
+++ b/vmime-master/src/vmime/defaultAttachment.cpp
@@ -0,0 +1,164 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/defaultAttachment.hpp"
+
+#include "vmime/contentDisposition.hpp"
+#include "vmime/contentDispositionField.hpp"
+#include "vmime/encoding.hpp"
+
+
+namespace vmime {
+
+
+defaultAttachment::defaultAttachment() {
+
+}
+
+
+defaultAttachment::defaultAttachment(
+ const shared_ptr <const contentHandler>& data,
+ const encoding& enc,
+ const mediaType& type,
+ const text& desc,
+ const word& name
+)
+ : m_type(type),
+ m_desc(desc),
+ m_data(data),
+ m_encoding(enc),
+ m_name(name) {
+
+}
+
+
+defaultAttachment::defaultAttachment(
+ const shared_ptr <const contentHandler>& data,
+ const mediaType& type,
+ const text& desc,
+ const word& name
+)
+ : m_type(type),
+ m_desc(desc),
+ m_data(data),
+ m_encoding(encoding::decide(data)),
+ m_name(name) {
+
+}
+
+
+defaultAttachment::defaultAttachment(const defaultAttachment& attach)
+ : attachment(),
+ m_type(attach.m_type),
+ m_desc(attach.m_desc),
+ m_data(vmime::clone(attach.m_data)),
+ m_encoding(attach.m_encoding),
+ m_name(attach.m_name) {
+
+}
+
+
+defaultAttachment::~defaultAttachment() {
+
+}
+
+
+defaultAttachment& defaultAttachment::operator=(const defaultAttachment& attach) {
+
+ m_type = attach.m_type;
+ m_desc = attach.m_desc;
+ m_name = attach.m_name;
+ m_data = vmime::clone(attach.m_data);
+ m_encoding = attach.m_encoding;
+
+ return *this;
+}
+
+
+void defaultAttachment::generateIn(const shared_ptr <bodyPart>& parent) const {
+
+ // Create and append a new part for this attachment
+ shared_ptr <bodyPart> part = make_shared <bodyPart>();
+ parent->getBody()->appendPart(part);
+
+ generatePart(part);
+}
+
+
+void defaultAttachment::generatePart(const shared_ptr <bodyPart>& part) const {
+
+ // Set header fields
+ part->getHeader()->ContentType()->setValue(m_type);
+ if (!m_desc.isEmpty()) part->getHeader()->ContentDescription()->setValue(m_desc);
+ part->getHeader()->ContentTransferEncoding()->setValue(m_encoding);
+ part->getHeader()->ContentDisposition()->setValue(contentDisposition(contentDispositionTypes::ATTACHMENT));
+ dynamicCast <contentDispositionField>(part->getHeader()->ContentDisposition())->setFilename(m_name);
+
+ // Set contents
+ part->getBody()->setContents(m_data);
+}
+
+
+const mediaType defaultAttachment::getType() const {
+
+ return m_type;
+}
+
+
+const text defaultAttachment::getDescription() const {
+
+ return m_desc;
+}
+
+
+const word defaultAttachment::getName() const {
+
+ return m_name;
+}
+
+
+const shared_ptr <const contentHandler> defaultAttachment::getData() const {
+
+ return m_data;
+}
+
+
+const encoding defaultAttachment::getEncoding() const {
+
+ return m_encoding;
+}
+
+
+shared_ptr <const object> defaultAttachment::getPart() const {
+
+ return null;
+}
+
+
+shared_ptr <const header> defaultAttachment::getHeader() const {
+
+ return null;
+}
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/defaultAttachment.hpp b/vmime-master/src/vmime/defaultAttachment.hpp
new file mode 100644
index 0000000..ce1c603
--- /dev/null
+++ b/vmime-master/src/vmime/defaultAttachment.hpp
@@ -0,0 +1,99 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_DEFAULTATTACHMENT_HPP_INCLUDED
+#define VMIME_DEFAULTATTACHMENT_HPP_INCLUDED
+
+
+#include "vmime/attachment.hpp"
+#include "vmime/encoding.hpp"
+
+
+namespace vmime {
+
+
+/** Default implementation for attachments.
+ */
+class VMIME_EXPORT defaultAttachment : public attachment {
+
+protected:
+
+ // For use in derived classes.
+ defaultAttachment();
+
+public:
+
+ defaultAttachment(
+ const shared_ptr <const contentHandler>& data,
+ const encoding& enc,
+ const mediaType& type,
+ const text& desc = NULL_TEXT,
+ const word& name = NULL_WORD
+ );
+
+ defaultAttachment(
+ const shared_ptr <const contentHandler>& data,
+ const mediaType& type,
+ const text& desc = NULL_TEXT,
+ const word& name = NULL_WORD
+ );
+
+ defaultAttachment(const defaultAttachment& attach);
+
+ ~defaultAttachment();
+
+ defaultAttachment& operator=(const defaultAttachment& attach);
+
+ const mediaType getType() const;
+ const text getDescription() const;
+ const word getName() const;
+ const shared_ptr <const contentHandler> getData() const;
+ const encoding getEncoding() const;
+
+ shared_ptr <const object> getPart() const;
+
+ shared_ptr <const header> getHeader() const;
+
+protected:
+
+ mediaType m_type; /**< Media type (eg. "application/octet-stream") */
+ text m_desc; /**< Description (eg. "The image you requested") */
+ shared_ptr <const contentHandler> m_data; /**< Attachment data (eg. the file contents) */
+ encoding m_encoding; /**< Encoding */
+ word m_name; /**< Name/filename (eg. "sunset.jpg") */
+
+private:
+
+ // No need to override "generateIn", use "generatePart" instead (see below).
+ void generateIn(const shared_ptr <bodyPart>& parent) const;
+
+protected:
+
+ virtual void generatePart(const shared_ptr <bodyPart>& part) const;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_DEFAULTATTACHMENT_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/disposition.cpp b/vmime-master/src/vmime/disposition.cpp
new file mode 100644
index 0000000..6e10cb9
--- /dev/null
+++ b/vmime-master/src/vmime/disposition.cpp
@@ -0,0 +1,351 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/disposition.hpp"
+
+#include "vmime/parserHelpers.hpp"
+#include "vmime/utility/stringUtils.hpp"
+
+
+namespace vmime {
+
+
+disposition::disposition() {
+
+}
+
+
+disposition::disposition(
+ const string& actionMode,
+ const string& sendingMode,
+ const string& type,
+ const string& modifier
+)
+ : m_actionMode(actionMode),
+ m_sendingMode(sendingMode),
+ m_type(type) {
+
+ m_modifiers.push_back(modifier);
+}
+
+
+shared_ptr <component> disposition::clone() const {
+
+ shared_ptr <disposition> disp = make_shared <disposition>();
+
+ disp->m_actionMode = m_actionMode;
+ disp->m_sendingMode = m_sendingMode;
+ disp->m_type = m_type;
+ disp->m_modifiers.resize(m_modifiers.size());
+
+ std::copy(m_modifiers.begin(), m_modifiers.end(), disp->m_modifiers.begin());
+
+ return disp;
+}
+
+
+void disposition::copyFrom(const component& other) {
+
+ const disposition& disp = dynamic_cast <const disposition&>(other);
+
+ m_actionMode = disp.m_actionMode;
+ m_sendingMode = disp.m_sendingMode;
+ m_type = disp.m_type;
+ m_modifiers.resize(disp.m_modifiers.size());
+
+ std::copy(disp.m_modifiers.begin(), disp.m_modifiers.end(), m_modifiers.begin());
+}
+
+
+disposition& disposition::operator=(const disposition& other) {
+
+ copyFrom(other);
+ return *this;
+}
+
+
+const std::vector <shared_ptr <component> > disposition::getChildComponents() {
+
+ return std::vector <shared_ptr <component> >();
+}
+
+
+void disposition::setActionMode(const string& mode) {
+
+ m_actionMode = mode;
+}
+
+
+const string& disposition::getActionMode() const {
+
+ return m_actionMode;
+}
+
+
+void disposition::setSendingMode(const string& mode) {
+
+ m_sendingMode = mode;
+}
+
+
+const string& disposition::getSendingMode() const {
+
+ return m_sendingMode;
+}
+
+
+void disposition::setType(const string& type) {
+
+ m_type = type;
+}
+
+
+const string& disposition::getType() const {
+
+ return m_type;
+}
+
+
+void disposition::addModifier(const string& modifier) {
+
+ if (!hasModifier(modifier)) {
+ m_modifiers.push_back(utility::stringUtils::toLower(modifier));
+ }
+}
+
+
+void disposition::removeModifier(const string& modifier) {
+
+ const string modifierLC = utility::stringUtils::toLower(modifier);
+
+ for (std::vector <string>::iterator it = m_modifiers.begin() ;
+ it != m_modifiers.end() ; ++it) {
+
+ if (*it == modifierLC) {
+ m_modifiers.erase(it);
+ break;
+ }
+ }
+}
+
+
+void disposition::removeAllModifiers() {
+
+ m_modifiers.clear();
+}
+
+
+bool disposition::hasModifier(const string& modifier) const {
+
+ const string modifierLC = utility::stringUtils::toLower(modifier);
+
+ for (std::vector <string>::const_iterator it = m_modifiers.begin() ;
+ it != m_modifiers.end() ; ++it) {
+
+ if (*it == modifierLC) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+const std::vector <string> disposition::getModifierList() const {
+
+ return m_modifiers;
+}
+
+
+void disposition::parseImpl(
+ const parsingContext& /* ctx */,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition
+) {
+
+ // disposition-mode ";" disposition-type
+ // [ "/" disposition-modifier *( "," disposition-modifier ) ]
+ //
+ // disposition-mode = action-mode "/" sending-mode
+
+ size_t pos = position;
+
+ while (pos < end && parserHelpers::isSpace(buffer[pos])) {
+ ++pos;
+ }
+
+ // -- disposition-mode
+ const size_t modeStart = pos;
+ size_t modeEnd = pos;
+
+ while (pos < end && buffer[pos] != ';') {
+ ++modeEnd;
+ ++pos;
+ }
+
+ while (modeEnd > modeStart && parserHelpers::isSpace(buffer[modeEnd - 1])) {
+ --modeEnd;
+ }
+
+ const string mode = string(buffer.begin() + modeStart, buffer.begin() + modeEnd);
+ const size_t slash = mode.find('/');
+
+ if (slash != string::npos) {
+
+ m_actionMode = string(mode.begin(), mode.begin() + slash);
+ m_sendingMode = string(mode.begin() + slash + 1, mode.end());
+
+ } else {
+
+ m_actionMode = mode;
+ m_sendingMode.clear();
+ }
+
+ if (pos < end) {
+ // Skip ';'
+ ++pos;
+ }
+
+ while (pos < end && parserHelpers::isSpace(buffer[pos])) {
+ ++pos;
+ }
+
+ // -- disposition-type
+ const size_t typeStart = pos;
+ size_t typeEnd = pos;
+
+ while (pos < end && buffer[pos] != '/') {
+ ++typeEnd;
+ ++pos;
+ }
+
+ while (typeEnd > typeStart && parserHelpers::isSpace(buffer[typeEnd - 1])) {
+ --typeEnd;
+ }
+
+ m_type = string(buffer.begin() + typeStart, buffer.begin() + typeEnd);
+
+ m_modifiers.clear();
+
+ if (pos < end) { // modifiers follow
+
+ // Skip '/'
+ ++pos;
+
+ while (pos < end) {
+
+ while (pos < end && parserHelpers::isSpace(buffer[pos])) {
+ ++pos;
+ }
+
+ const size_t modifierStart = pos;
+ size_t modifierEnd = pos;
+
+ while (pos < end && buffer[pos] != ',') {
+ ++modifierEnd;
+ ++pos;
+ }
+
+ while (modifierEnd > modifierStart && parserHelpers::isSpace(buffer[modifierEnd - 1])) {
+ --modifierEnd;
+ }
+
+ if (modifierEnd > modifierStart) {
+
+ m_modifiers.push_back(
+ string(
+ buffer.begin() + modifierStart,
+ buffer.begin() + modifierEnd
+ )
+ );
+ }
+
+ // Skip ','
+ if (pos < end) {
+ ++pos;
+ }
+ }
+ }
+
+ if (newPosition) {
+ *newPosition = pos;
+ }
+}
+
+
+void disposition::generateImpl(
+ const generationContext& ctx,
+ utility::outputStream& os,
+ const size_t curLinePos,
+ size_t* newLinePos
+) const {
+
+ size_t pos = curLinePos;
+
+ const string actionMode = (m_actionMode.empty() ? "automatic-action" : m_actionMode);
+ const string sendingMode = (m_sendingMode.empty() ? "MDN-sent-automatically" : m_sendingMode);
+
+ os << actionMode << "/" << sendingMode << ";";
+ pos += actionMode.length() + 1 + sendingMode.length() + 1;
+
+ if (pos > ctx.getMaxLineLength()) {
+ os << NEW_LINE_SEQUENCE;
+ pos = NEW_LINE_SEQUENCE_LENGTH;
+ }
+
+ const string type = (m_type.empty() ? "displayed" : m_type);
+
+ os << type;
+ pos += type.length();
+
+ if (m_modifiers.size() >= 1) {
+
+ for (std::vector <string>::size_type i = 0, n = 0 ; i < m_modifiers.size() ; ++i) {
+
+ const string mod = utility::stringUtils::trim(m_modifiers[i]);
+
+ if (!mod.empty()) {
+
+ if (n == 0) {
+ os << "/";
+ } else {
+ os << ",";
+ }
+
+ os << mod;
+ pos += 1 + mod.length();
+
+ ++n;
+ }
+ }
+ }
+
+ if (newLinePos) {
+ *newLinePos = pos;
+ }
+}
+
+
+}
diff --git a/vmime-master/src/vmime/disposition.hpp b/vmime-master/src/vmime/disposition.hpp
new file mode 100644
index 0000000..d4b023b
--- /dev/null
+++ b/vmime-master/src/vmime/disposition.hpp
@@ -0,0 +1,163 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_DISPOSITION_HPP_INCLUDED
+#define VMIME_DISPOSITION_HPP_INCLUDED
+
+
+#include "vmime/base.hpp"
+#include "vmime/headerFieldValue.hpp"
+
+#include <vector>
+
+
+namespace vmime {
+
+
+/** Disposition - from RFC-3798 (basic type).
+ */
+class VMIME_EXPORT disposition : public headerFieldValue {
+
+public:
+
+ disposition();
+ disposition(
+ const string& actionMode,
+ const string& sendingMode,
+ const string& type,
+ const string& modifier
+ );
+
+
+ shared_ptr <component> clone() const;
+ void copyFrom(const component& other);
+ disposition& operator=(const disposition& other);
+
+ const std::vector <shared_ptr <component> > getChildComponents();
+
+
+ /** Set the disposition action mode.
+ * See the constants in vmime::dispositionActionModes.
+ *
+ * @param mode disposition action mode
+ */
+ void setActionMode(const string& mode);
+
+ /** Return the disposition action mode.
+ * See the constants in vmime::dispositionActionModes.
+ *
+ * @return disposition action mode
+ */
+ const string& getActionMode() const;
+
+ /** Set the disposition sending mode.
+ * See the constants in vmime::dispositionSendingModes.
+ *
+ * @param mode disposition sending mode
+ */
+ void setSendingMode(const string& mode);
+
+ /** Return the disposition sending mode.
+ * See the constants in vmime::dispositionSendingModes.
+ *
+ * @return disposition sending mode
+ */
+ const string& getSendingMode() const;
+
+ /** Set the disposition type.
+ * See the constants in vmime::dispositionTypes.
+ *
+ * @param type disposition type
+ */
+ void setType(const string& type);
+
+ /** Return the disposition type.
+ * See the constants in vmime::dispositionTypes.
+ *
+ * @return disposition type
+ */
+ const string& getType() const;
+
+ /** Add a disposition modifier if it does not exist.
+ * See the constants in vmime::dispositionModifiers.
+ *
+ * @param modifier modifier to add
+ */
+ void addModifier(const string& modifier);
+
+ /** Remove the specified disposition modifier.
+ * See the constants in vmime::dispositionModifiers.
+ *
+ * @param modifier modifier to remove
+ */
+ void removeModifier(const string& modifier);
+
+ /** Remove all disposition modifiers.
+ */
+ void removeAllModifiers();
+
+ /** Test whether a disposition modifier is set.
+ *
+ * @param modifier modifier to test
+ * @return true if the specified modifier is set, false otherwise
+ */
+ bool hasModifier(const string& modifier) const;
+
+ /** Return the list of modifiers.
+ *
+ * @return list of modifiers
+ */
+ const std::vector <string> getModifierList() const;
+
+private:
+
+ string m_actionMode;
+ string m_sendingMode;
+ string m_type;
+
+ std::vector <string> m_modifiers;
+
+protected:
+
+ // Component parsing & assembling
+ void parseImpl(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition = NULL
+ );
+
+ void generateImpl(
+ const generationContext& ctx,
+ utility::outputStream& os,
+ const size_t curLinePos = 0,
+ size_t* newLinePos = NULL
+ ) const;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_DISPOSITION_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/emailAddress.cpp b/vmime-master/src/vmime/emailAddress.cpp
new file mode 100644
index 0000000..1be678a
--- /dev/null
+++ b/vmime-master/src/vmime/emailAddress.cpp
@@ -0,0 +1,708 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/emailAddress.hpp"
+
+#include "vmime/platform.hpp"
+
+#include "vmime/parserHelpers.hpp"
+#include "vmime/utility/outputStreamAdapter.hpp"
+#include "vmime/utility/outputStreamStringAdapter.hpp"
+#include "vmime/utility/stringUtils.hpp"
+
+
+namespace vmime {
+
+
+/** Decode an IDNA-encoded domain name ("xn--5rtw95l.xn--wgv71a")
+ * to a fully decoded domain name in UTF-8 ("黒川.日本").
+ *
+ * @param idnaDomain domain name encoded with IDNA
+ * @return decoded domain name in UTF-8
+ */
+static const string domainNameFromIDNA(const string& idnaDomain) {
+
+ std::ostringstream domainName;
+ size_t p = 0;
+
+ for (size_t n = idnaDomain.find('.', p) ;
+ (n = idnaDomain.find('.', p)) != string::npos ; p = n + 1) {
+
+ const string encodedPart(idnaDomain.begin() + p, idnaDomain.begin() + n);
+
+ if (encodedPart.length() > 4 &&
+ encodedPart[0] == 'x' && encodedPart[1] == 'n' &&
+ encodedPart[2] == '-' && encodedPart[3] == '-') {
+
+ string decodedPart;
+ charset::convert(
+ encodedPart, decodedPart,
+ vmime::charsets::IDNA, vmime::charsets::UTF_8
+ );
+
+ domainName << decodedPart << '.';
+
+ } else {
+
+ domainName << encodedPart << '.'; // not encoded
+ }
+ }
+
+ if (p < idnaDomain.length()) {
+
+ const string encodedPart(idnaDomain.begin() + p, idnaDomain.end());
+
+ if (encodedPart.length() > 4 &&
+ encodedPart[0] == 'x' && encodedPart[1] == 'n' &&
+ encodedPart[2] == '-' && encodedPart[3] == '-') {
+
+ string decodedPart;
+ charset::convert(
+ encodedPart, decodedPart,
+ vmime::charsets::IDNA, vmime::charsets::UTF_8
+ );
+
+ domainName << decodedPart;
+
+ } else {
+
+ domainName << encodedPart; // not encoded
+ }
+ }
+
+ return domainName.str();
+}
+
+
+/** Encode an UTF-8 domain name ("黒川.日本") to an IDNA-encoded
+ * domain name ("xn--5rtw95l.xn--wgv71a").
+ *
+ * @param domainName domain name in UTF-8
+ * @return domain name encoded with IDNA
+ */
+static const string domainNameToIDNA(const string& domainName) {
+
+ std::ostringstream idnaDomain;
+ size_t p = 0;
+
+ for (size_t n = domainName.find('.', p) ;
+ (n = domainName.find('.', p)) != string::npos ; p = n + 1) {
+
+ string idnaPart;
+ charset::convert(
+ string(domainName.begin() + p, domainName.begin() + n), idnaPart,
+ vmime::charsets::UTF_8, vmime::charsets::IDNA
+ );
+
+ idnaDomain << idnaPart << '.';
+ }
+
+ if (p < domainName.length()) {
+
+ string idnaPart;
+ charset::convert(
+ string(domainName.begin() + p, domainName.end()), idnaPart,
+ vmime::charsets::UTF_8, vmime::charsets::IDNA
+ );
+
+ idnaDomain << idnaPart;
+ }
+
+ return idnaDomain.str();
+}
+
+
+
+
+emailAddress::emailAddress() {
+
+}
+
+
+emailAddress::emailAddress(const emailAddress& eml)
+ : component(),
+ m_localName(eml.m_localName),
+ m_domainName(eml.m_domainName) {
+
+}
+
+
+emailAddress::emailAddress(const string& email) {
+
+ parse(email);
+}
+
+
+emailAddress::emailAddress(const char* email) {
+
+ parse(email);
+}
+
+
+emailAddress::emailAddress(const string& localName, const string& domainName)
+ : component(),
+ m_localName(word(localName, vmime::charsets::UTF_8)),
+ m_domainName(word(domainName, vmime::charsets::UTF_8)) {
+
+}
+
+
+emailAddress::emailAddress(const word& localName, const word& domainName)
+ : component(),
+ m_localName(localName),
+ m_domainName(domainName) {
+
+}
+
+
+void emailAddress::parseImpl(
+ const parsingContext& /* ctx */,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition
+) {
+
+ const char* const pend = buffer.data() + end;
+ const char* const pstart = buffer.data() + position;
+ const char* p = pstart;
+
+ enum ParserStates {
+ State_Before,
+ State_LocalPartStart,
+ State_LocalPartMiddle,
+ State_LocalPartComment,
+ State_LocalPartQuoted,
+ State_LocalPartRFC2047Start,
+ State_LocalPartRFC2047Middle,
+ State_LocalPartRFC2047MiddleQM,
+ State_LocalPartRFC2047End,
+ State_DomainPartStart,
+ State_DomainPartMiddle,
+ State_DomainPartComment,
+ State_End,
+ State_Error
+ } state = State_Before;
+
+ std::ostringstream localPart;
+ std::ostringstream domainPart;
+
+ bool escapeNext = false; // for quoting
+ bool prevIsDot = false;
+ bool atFound = false;
+ bool stop = false;
+ int commentLevel = 0;
+ bool localPartIsRFC2047 = false;
+
+ while (p < pend && !stop) {
+
+ const char c = *p;
+
+ if ((localPart.str().length() + domainPart.str().length()) >= 256) {
+ state = State_Error;
+ break;
+ }
+
+ switch (state) {
+
+ case State_Before:
+
+ if (parserHelpers::isSpace(c)) {
+ ++p;
+ } else {
+ state = State_LocalPartStart;
+ }
+
+ break;
+
+ case State_LocalPartStart:
+
+ if (c == '"') {
+
+ state = State_LocalPartQuoted;
+ ++p;
+
+ } else if (c == '=') {
+
+ state = State_LocalPartRFC2047Start;
+ ++p;
+
+ } else if (c == '(') {
+
+ state = State_LocalPartComment;
+ ++commentLevel;
+ ++p;
+
+ } else {
+
+ state = State_LocalPartMiddle;
+ localPart << c;
+ ++p;
+ }
+
+ break;
+
+ case State_LocalPartComment:
+
+ if (escapeNext) {
+
+ escapeNext = false;
+ ++p;
+
+ } else if (c == '\\') {
+
+ escapeNext = true;
+ ++p;
+
+ } else if (c == '(') {
+
+ ++commentLevel;
+ ++p;
+
+ } else if (c == ')') {
+
+ if (--commentLevel == 0) {
+ // End of comment
+ state = State_LocalPartMiddle;
+ }
+
+ ++p;
+
+ } else {
+
+ // Comment continues
+ ++p;
+ }
+
+ break;
+
+ case State_LocalPartQuoted:
+
+ if (escapeNext) {
+
+ escapeNext = false;
+
+ if (c == '"' || c == '\\') {
+
+ localPart << c;
+ ++p;
+
+ } else {
+
+ // This char cannot be escaped
+ state = State_Error;
+ }
+
+ } else if (c == '"') {
+
+ // End of quoted string
+ state = State_LocalPartMiddle;
+ ++p;
+
+ } else if (c == '\\') {
+
+ escapeNext = true;
+ ++p;
+
+ } else {
+
+ localPart << c;
+ ++p;
+ }
+
+ break;
+
+ case State_LocalPartRFC2047Start:
+
+ if (c == '?') {
+
+ state = State_LocalPartRFC2047Middle;
+ localPart << "=?";
+ localPartIsRFC2047 = true;
+ ++p;
+
+ } else {
+
+ state = State_LocalPartMiddle;
+ localPart << '=';
+ localPart << c;
+ ++p;
+ }
+
+ break;
+
+ case State_LocalPartMiddle:
+
+ if (c == '.') {
+
+ prevIsDot = true;
+ localPart << c;
+ ++p;
+
+ } else if (c == '"' && prevIsDot) {
+
+ prevIsDot = false;
+ state = State_LocalPartQuoted;
+ ++p;
+
+ } else if (c == '(') {
+
+ // By allowing comments anywhere in the local part,
+ // we are more permissive than RFC-2822
+ state = State_LocalPartComment;
+ ++commentLevel;
+ ++p;
+
+ } else if (c == '@') {
+
+ atFound = true;
+ state = State_DomainPartStart;
+ ++p;
+
+ } else if (parserHelpers::isSpace(c)) {
+
+ // Allow not specifying domain part
+ state = State_End;
+
+ } else {
+
+ prevIsDot = false;
+ localPart << c;
+ ++p;
+ }
+
+ break;
+
+ case State_LocalPartRFC2047Middle:
+
+ if (c == '?') {
+
+ state = State_LocalPartRFC2047MiddleQM;
+ ++p;
+
+ } else {
+
+ localPart << c;
+ ++p;
+ }
+
+ break;
+
+ case State_LocalPartRFC2047MiddleQM:
+
+ if (c == '=') {
+
+ // End of RFC-2047 encoded word
+ state = State_LocalPartRFC2047End;
+ localPart << "?=";
+ ++p;
+
+ } else {
+
+ state = State_LocalPartRFC2047Middle;
+ localPart << '?';
+ localPart << c;
+ ++p;
+ }
+
+ break;
+
+ case State_LocalPartRFC2047End:
+
+ if (c == '@') {
+
+ atFound = true;
+ state = State_DomainPartStart;
+ ++p;
+
+ } else {
+
+ state = State_End;
+ }
+
+ break;
+
+ case State_DomainPartStart:
+
+ if (c == '(') {
+
+ state = State_DomainPartComment;
+ ++commentLevel;
+ ++p;
+
+ } else {
+
+ state = State_DomainPartMiddle;
+ domainPart << c;
+ ++p;
+ }
+
+ break;
+
+ case State_DomainPartMiddle:
+
+ if (parserHelpers::isSpace(c)) {
+
+ state = State_End;
+
+ } else if (c == '(') {
+
+ // By allowing comments anywhere in the domain part,
+ // we are more permissive than RFC-2822
+ state = State_DomainPartComment;
+ ++commentLevel;
+ ++p;
+
+ } else {
+
+ domainPart << c;
+ ++p;
+ }
+
+ break;
+
+ case State_DomainPartComment:
+
+ if (escapeNext) {
+
+ escapeNext = false;
+ ++p;
+
+ } else if (c == '\\') {
+
+ escapeNext = true;
+ ++p;
+
+ } else if (c == '(') {
+
+ ++commentLevel;
+ ++p;
+
+ } else if (c == ')') {
+
+ if (--commentLevel == 0) {
+
+ // End of comment
+ state = State_DomainPartMiddle;
+ }
+
+ ++p;
+
+ } else {
+
+ // Comment continues
+ ++p;
+ }
+
+ break;
+
+ case State_End:
+ case State_Error:
+
+ stop = true;
+ break;
+ }
+ }
+
+ if (p == pend && state != State_Error) {
+
+ if (state == State_DomainPartMiddle) {
+ state = State_End;
+ } else if (state == State_LocalPartMiddle) {
+ state = State_End; // allow not specifying domain part
+ }
+ }
+
+ if (state != State_End) {
+
+ m_localName = word("invalid", vmime::charsets::UTF_8);
+ m_domainName = word("invalid", vmime::charsets::UTF_8);
+
+ } else {
+
+ // If the domain part is missing, use local host name
+ if (domainPart.str().empty() && !atFound) {
+ domainPart << platform::getHandler()->getHostName();
+ }
+
+ if (localPartIsRFC2047) {
+ m_localName.parse(localPart.str());
+ } else {
+ m_localName = word(localPart.str(), vmime::charsets::UTF_8);
+ }
+
+ m_domainName = word(domainNameFromIDNA(domainPart.str()), vmime::charsets::UTF_8);
+ }
+
+ setParsedBounds(position, p - pend);
+
+ if (newPosition) {
+ *newPosition = p - pend;
+ }
+}
+
+
+void emailAddress::generateImpl(
+ const generationContext& ctx,
+ utility::outputStream& os,
+ const size_t curLinePos,
+ size_t* newLinePos
+) const {
+
+ string localPart, domainPart;
+
+ if (ctx.getInternationalizedEmailSupport() &&
+ (!utility::stringUtils::is7bit(m_localName.getBuffer()) ||
+ !utility::stringUtils::is7bit(m_domainName.getBuffer()))) {
+
+ // Local part
+ string localPartUTF8(m_localName.getConvertedText(vmime::charsets::UTF_8));
+ word localPartWord(localPartUTF8, vmime::charsets::UTF_8);
+
+ vmime::utility::outputStreamStringAdapter os(localPart);
+ localPartWord.generate(ctx, os, 0, NULL, text::FORCE_NO_ENCODING | text::QUOTE_IF_NEEDED, NULL);
+
+ // Domain part
+ domainPart = m_domainName.getConvertedText(vmime::charsets::UTF_8);
+
+ } else {
+
+ // Local part
+ vmime::utility::outputStreamStringAdapter os(localPart);
+ m_localName.generate(ctx, os, 0, NULL, text::QUOTE_IF_NEEDED, NULL);
+
+ // Domain part as IDNA
+ domainPart = domainNameToIDNA(m_domainName.getConvertedText(vmime::charsets::UTF_8));
+ }
+
+ os << localPart
+ << "@"
+ << domainPart;
+
+ if (newLinePos) {
+
+ *newLinePos = curLinePos
+ + localPart.length()
+ + 1 // @
+ + domainPart.length();
+ }
+}
+
+
+bool emailAddress::operator==(const class emailAddress& eml) const {
+
+ return m_localName == eml.m_localName &&
+ m_domainName == eml.m_domainName;
+}
+
+
+bool emailAddress::operator!=(const class emailAddress& eml) const {
+
+ return !(*this == eml);
+}
+
+
+void emailAddress::copyFrom(const component& other) {
+
+ const emailAddress& source = dynamic_cast <const emailAddress&>(other);
+
+ m_localName = source.m_localName;
+ m_domainName = source.m_domainName;
+}
+
+
+emailAddress& emailAddress::operator=(const emailAddress& other) {
+
+ copyFrom(other);
+ return *this;
+}
+
+
+shared_ptr <component>emailAddress::clone() const {
+
+ return make_shared <emailAddress>(*this);
+}
+
+
+const word& emailAddress::getLocalName() const {
+
+ return m_localName;
+}
+
+
+void emailAddress::setLocalName(const word& localName) {
+
+ m_localName = localName;
+}
+
+
+const word& emailAddress::getDomainName() const {
+
+ return m_domainName;
+}
+
+
+void emailAddress::setDomainName(const word& domainName) {
+
+ m_domainName = domainName;
+}
+
+
+const std::vector <shared_ptr <component> > emailAddress::getChildComponents() {
+
+ return std::vector <shared_ptr <component> >();
+}
+
+
+bool emailAddress::isEmpty() const {
+
+ return m_localName.isEmpty();
+}
+
+
+const string emailAddress::toString() const {
+
+ std::ostringstream oss;
+ utility::outputStreamAdapter adapter(oss);
+
+ generationContext ctx(generationContext::getDefaultContext());
+ ctx.setMaxLineLength(lineLengthLimits::infinite);
+
+ generateImpl(ctx, adapter, 0, NULL);
+
+ return oss.str();
+}
+
+
+const text emailAddress::toText() const {
+
+ text txt;
+ txt.appendWord(make_shared <vmime::word>(m_localName));
+ txt.appendWord(make_shared <vmime::word>("@", vmime::charsets::US_ASCII));
+ txt.appendWord(make_shared <vmime::word>(m_domainName));
+
+ return txt;
+}
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/emailAddress.hpp b/vmime-master/src/vmime/emailAddress.hpp
new file mode 100644
index 0000000..7824996
--- /dev/null
+++ b/vmime-master/src/vmime/emailAddress.hpp
@@ -0,0 +1,135 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_EMAILADDRESS_HPP_INCLUDED
+#define VMIME_EMAILADDRESS_HPP_INCLUDED
+
+
+#include "vmime/component.hpp"
+#include "vmime/text.hpp"
+
+
+namespace vmime {
+
+
+/** An email address: local name and domain name (basic type).
+ */
+class VMIME_EXPORT emailAddress : public component {
+
+public:
+
+ emailAddress();
+ emailAddress(const emailAddress& eml);
+ emailAddress(const string& email);
+ emailAddress(const char* email);
+ emailAddress(const string& localName, const string& domainName);
+ emailAddress(const word& localName, const word& domainName);
+
+ /** Return the local name of the address.
+ *
+ * @return local name of the address
+ */
+ const word& getLocalName() const;
+
+ /** Set the local name of the address.
+ *
+ * @param localName local name of the address
+ */
+ void setLocalName(const word& localName);
+
+ /** Return the domain name of the address.
+ *
+ * @return domain name of the address
+ */
+ const word& getDomainName() const;
+
+ /** Set the domain name of the address.
+ *
+ * @param domainName domain name of the address
+ */
+ void setDomainName(const word& domainName);
+
+ /** Returns whether this email address is empty.
+ * Address is considered as empty if the local part is not specified.
+ *
+ * @return true if the address is empty, false otherwise
+ */
+ bool isEmpty() const;
+
+ /** Returns the email address as a string, by joining components.
+ * (ie. the local name, followed by a @ then the domain name.)
+ *
+ * @return email address as a string
+ */
+ const string toString() const;
+
+ /** Returns the email address as multibyte text, by joining components.
+ * (ie. the local name, followed by a @ then the domain name.)
+ *
+ * @return email address as multibyte text
+ */
+ const text toText() const;
+
+ // Comparison
+ bool operator==(const class emailAddress& eml) const;
+ bool operator!=(const class emailAddress& eml) const;
+
+ // Assignment
+ void copyFrom(const component& other);
+ shared_ptr <component> clone() const;
+ emailAddress& operator=(const emailAddress& other);
+
+ const std::vector <shared_ptr <component> > getChildComponents();
+
+protected:
+
+ word m_localName;
+ word m_domainName;
+
+public:
+
+ using component::parse;
+ using component::generate;
+
+ // Component parsing & assembling
+ void parseImpl(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition = NULL
+ );
+
+ void generateImpl(
+ const generationContext& ctx,
+ utility::outputStream& os,
+ const size_t curLinePos = 0,
+ size_t* newLinePos = NULL
+ ) const;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_EMAILADDRESS_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/emptyContentHandler.cpp b/vmime-master/src/vmime/emptyContentHandler.cpp
new file mode 100644
index 0000000..3cf7965
--- /dev/null
+++ b/vmime-master/src/vmime/emptyContentHandler.cpp
@@ -0,0 +1,126 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/emptyContentHandler.hpp"
+
+
+namespace vmime {
+
+
+emptyContentHandler::emptyContentHandler() {
+
+}
+
+
+shared_ptr <contentHandler> emptyContentHandler::clone() const {
+
+ return make_shared <emptyContentHandler>();
+}
+
+
+void emptyContentHandler::generate(
+ utility::outputStream& /* os */,
+ const vmime::encoding& /* enc */,
+ const size_t /* maxLineLength */
+) const {
+
+ // Nothing to do.
+}
+
+
+void emptyContentHandler::extract(
+ utility::outputStream& /* os */,
+ utility::progressListener* progress) const
+{
+ if (progress) {
+ progress->start(0);
+ }
+
+ // Nothing to do.
+
+ if (progress) {
+ progress->stop(0);
+ }
+}
+
+
+void emptyContentHandler::extractRaw(
+ utility::outputStream& /* os */,
+ utility::progressListener* progress
+) const {
+
+ if (progress) {
+ progress->start(0);
+ }
+
+ // Nothing to do.
+
+ if (progress) {
+ progress->stop(0);
+ }
+}
+
+
+size_t emptyContentHandler::getLength() const {
+
+ return 0;
+}
+
+
+bool emptyContentHandler::isEmpty() const {
+
+ return true;
+}
+
+
+bool emptyContentHandler::isEncoded() const {
+
+ return false;
+}
+
+
+const vmime::encoding& emptyContentHandler::getEncoding() const {
+
+ return NO_ENCODING;
+}
+
+
+bool emptyContentHandler::isBuffered() const {
+
+ return true;
+}
+
+
+void emptyContentHandler::setContentTypeHint(const mediaType& type) {
+
+ m_contentType = type;
+}
+
+
+const mediaType emptyContentHandler::getContentTypeHint() const {
+
+ return m_contentType;
+}
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/emptyContentHandler.hpp b/vmime-master/src/vmime/emptyContentHandler.hpp
new file mode 100644
index 0000000..b7e0897
--- /dev/null
+++ b/vmime-master/src/vmime/emptyContentHandler.hpp
@@ -0,0 +1,80 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_EMPTYCONTENTHANDLER_HPP_INCLUDED
+#define VMIME_EMPTYCONTENTHANDLER_HPP_INCLUDED
+
+
+#include "vmime/contentHandler.hpp"
+
+
+namespace vmime {
+
+
+class VMIME_EXPORT emptyContentHandler : public contentHandler {
+
+public:
+
+ emptyContentHandler();
+
+ shared_ptr <contentHandler> clone() const;
+
+ void generate(
+ utility::outputStream& os,
+ const vmime::encoding& enc,
+ const size_t maxLineLength = lineLengthLimits::infinite
+ ) const;
+
+ void extract(
+ utility::outputStream& os,
+ utility::progressListener* progress = NULL
+ ) const;
+
+ void extractRaw(
+ utility::outputStream& os,
+ utility::progressListener* progress = NULL
+ ) const;
+
+ size_t getLength() const;
+
+ bool isEncoded() const;
+
+ const vmime::encoding& getEncoding() const;
+
+ bool isEmpty() const;
+
+ bool isBuffered() const;
+
+ void setContentTypeHint(const mediaType& type);
+ const mediaType getContentTypeHint() const;
+
+private:
+
+ mediaType m_contentType;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_EMPTYCONTENTHANDLER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/encoding.cpp b/vmime-master/src/vmime/encoding.cpp
new file mode 100644
index 0000000..23814a6
--- /dev/null
+++ b/vmime-master/src/vmime/encoding.cpp
@@ -0,0 +1,331 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/encoding.hpp"
+#include "vmime/contentHandler.hpp"
+
+#include "vmime/utility/outputStreamStringAdapter.hpp"
+#include "vmime/utility/encoder/encoderFactory.hpp"
+
+#include <algorithm>
+
+
+namespace vmime {
+
+
+encoding::encoding()
+ : m_name(encodingTypes::SEVEN_BIT),
+ m_usage(USAGE_UNKNOWN) {
+
+}
+
+
+encoding::encoding(const string& name)
+ : m_name(utility::stringUtils::toLower(name)),
+ m_usage(USAGE_UNKNOWN) {
+
+}
+
+
+encoding::encoding(const string& name, const EncodingUsage usage)
+ : m_name(utility::stringUtils::toLower(name)),
+ m_usage(usage) {
+
+}
+
+
+encoding::encoding(const encoding& enc)
+ : headerFieldValue(),
+ m_name(enc.m_name),
+ m_usage(enc.m_usage) {
+}
+
+
+void encoding::parseImpl(
+ const parsingContext& /* ctx */,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition
+) {
+
+ m_usage = USAGE_UNKNOWN;
+
+ m_name = utility::stringUtils::toLower(
+ utility::stringUtils::trim(
+ utility::stringUtils::unquote(
+ utility::stringUtils::trim(
+ string(buffer.begin() + position, buffer.begin() + end)
+ )
+ )
+ )
+ );
+
+ if (m_name.empty()) {
+ m_name = encodingTypes::SEVEN_BIT; // assume default "7-bit"
+ }
+
+ setParsedBounds(position, end);
+
+ if (newPosition) {
+ *newPosition = end;
+ }
+}
+
+
+void encoding::generateImpl(
+ const generationContext& /* ctx */,
+ utility::outputStream& os,
+ const size_t curLinePos,
+ size_t* newLinePos
+) const {
+
+ os << m_name;
+
+ if (newLinePos) {
+ *newLinePos = curLinePos + m_name.length();
+ }
+}
+
+
+shared_ptr <utility::encoder::encoder> encoding::getEncoder() const {
+
+ shared_ptr <utility::encoder::encoder> encoder =
+ utility::encoder::encoderFactory::getInstance()->create(generate());
+
+ // FIXME: this should not be here (move me into QP encoder instead?)
+ if (m_usage == USAGE_TEXT && m_name == encodingTypes::QUOTED_PRINTABLE) {
+ encoder->getProperties()["text"] = true;
+ }
+
+ return encoder;
+}
+
+
+encoding& encoding::operator=(const encoding& other) {
+
+ copyFrom(other);
+ return (*this);
+}
+
+
+encoding& encoding::operator=(const string& name) {
+
+ m_name = utility::stringUtils::toLower(name);
+ m_usage = USAGE_UNKNOWN;
+
+ return *this;
+}
+
+
+bool encoding::operator==(const encoding& value) const {
+
+ return utility::stringUtils::toLower(m_name) == value.m_name;
+}
+
+
+bool encoding::operator!=(const encoding& value) const {
+
+ return !(*this == value);
+}
+
+
+const encoding encoding::decideImpl(
+ const string::const_iterator begin,
+ const string::const_iterator end
+) {
+
+ const string::difference_type length = end - begin;
+ const string::difference_type count = std::count_if(
+ begin, end,
+ std::bind2nd(std::less<unsigned char>(), 127)
+ );
+
+ // All is in 7-bit US-ASCII --> 7-bit (or Quoted-Printable...)
+ if (length == count) {
+
+ // Now, we check if there is any line with more than
+ // "lineLengthLimits::convenient" characters (7-bit requires that)
+ string::const_iterator p = begin;
+
+ const size_t maxLen = lineLengthLimits::convenient;
+ size_t len = 0;
+
+ for ( ; p != end && len <= maxLen ; ) {
+
+ if (*p == '\n') {
+
+ len = 0;
+ ++p;
+
+ // May or may not need to be encoded, we don't take
+ // any risk (avoid problems with SMTP)
+ if (p != end && *p == '.') {
+ len = maxLen + 1;
+ }
+
+ } else {
+
+ ++len;
+ ++p;
+ }
+ }
+
+ if (len > maxLen) {
+ return encoding(encodingTypes::QUOTED_PRINTABLE);
+ } else {
+ return encoding(encodingTypes::SEVEN_BIT);
+ }
+
+ // Less than 20% non US-ASCII --> Quoted-Printable
+ } else if ((length - count) <= length / 5) {
+
+ return encoding(encodingTypes::QUOTED_PRINTABLE);
+
+ // Otherwise --> Base64
+ } else {
+
+ return encoding(encodingTypes::BASE64);
+ }
+}
+
+
+bool encoding::shouldReencode() const {
+
+ if (m_name == encodingTypes::BASE64 ||
+ m_name == encodingTypes::QUOTED_PRINTABLE ||
+ m_name == encodingTypes::UUENCODE) {
+
+ return false;
+ }
+
+ return true;
+}
+
+
+const encoding encoding::decide(
+ const shared_ptr <const contentHandler>& data,
+ const EncodingUsage usage
+) {
+
+ // Do not re-encode data if it is already encoded
+ if (data->isEncoded() && !data->getEncoding().shouldReencode()) {
+ return data->getEncoding();
+ }
+
+ encoding enc;
+
+ if (usage == USAGE_TEXT && data->isBuffered() &&
+ data->getLength() > 0 && data->getLength() < 32768) {
+
+ // Extract data into temporary buffer
+ string buffer;
+ utility::outputStreamStringAdapter os(buffer);
+
+ data->extract(os);
+ os.flush();
+
+ enc = decideImpl(buffer.begin(), buffer.end());
+
+ } else {
+
+ enc = encoding(encodingTypes::BASE64);
+ }
+
+ enc.setUsage(usage);
+
+ return enc;
+}
+
+
+const encoding encoding::decide(
+ const shared_ptr <const contentHandler>& data,
+ const charset& chset,
+ const EncodingUsage usage
+) {
+
+ // Do not re-encode data if it is already encoded
+ if (data->isEncoded() && !data->getEncoding().shouldReencode()) {
+ return data->getEncoding();
+ }
+
+ if (usage == USAGE_TEXT) {
+
+ encoding recEncoding;
+
+ if (chset.getRecommendedEncoding(recEncoding)) {
+
+ recEncoding.setUsage(usage);
+ return recEncoding;
+ }
+ }
+
+ return decide(data, usage);
+}
+
+
+shared_ptr <component> encoding::clone() const {
+
+ return make_shared <encoding>(*this);
+}
+
+
+void encoding::copyFrom(const component& other) {
+
+ const encoding& e = dynamic_cast <const encoding&>(other);
+
+ m_name = e.m_name;
+}
+
+
+const string& encoding::getName() const {
+
+ return m_name;
+}
+
+
+void encoding::setName(const string& name) {
+
+ m_name = name;
+}
+
+
+encoding::EncodingUsage encoding::getUsage() const {
+
+ return m_usage;
+}
+
+
+void encoding::setUsage(const EncodingUsage usage) {
+
+ m_usage = usage;
+}
+
+
+const std::vector <shared_ptr <component> > encoding::getChildComponents() {
+
+ return std::vector <shared_ptr <component> >();
+}
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/encoding.hpp b/vmime-master/src/vmime/encoding.hpp
new file mode 100644
index 0000000..2ff17ef
--- /dev/null
+++ b/vmime-master/src/vmime/encoding.hpp
@@ -0,0 +1,180 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_ENCODING_HPP_INCLUDED
+#define VMIME_ENCODING_HPP_INCLUDED
+
+
+#include "vmime/base.hpp"
+#include "vmime/headerFieldValue.hpp"
+
+#include "vmime/utility/encoder/encoder.hpp"
+
+
+namespace vmime {
+
+
+class contentHandler;
+
+
+/** Content encoding (basic type).
+ */
+class VMIME_EXPORT encoding : public headerFieldValue {
+
+public:
+
+ enum EncodingUsage {
+
+ USAGE_UNKNOWN,
+ USAGE_TEXT, /**< Use for body text. */
+ USAGE_BINARY_DATA /**< Use for attachment, image... */
+ };
+
+
+ encoding();
+ explicit encoding(const string& name);
+ encoding(const string& name, const EncodingUsage usage);
+ encoding(const encoding& enc);
+
+ /** Return the name of the encoding.
+ * See the constants in vmime::encodingTypes.
+ *
+ * @return name of the encoding (eg. "quoted-printable")
+ */
+ const string& getName() const;
+
+ /** Set the name of the encoding.
+ * See the constants in vmime::encodingTypes.
+ *
+ * @param name name of the encoding
+ */
+ void setName(const string& name);
+
+ /** Return the type of contents this encoding is used for.
+ * See the EncodingUsage enum.
+ */
+ EncodingUsage getUsage() const;
+
+ /** Set the type of contents this encoding is used for.
+ * See the EncodingUsage enum.
+ *
+ * @param usage type of contents
+ */
+ void setUsage(const EncodingUsage usage);
+
+
+ encoding& operator=(const encoding& other);
+ encoding& operator=(const string& name);
+
+ bool operator==(const encoding& value) const;
+ bool operator!=(const encoding& value) const;
+
+ const std::vector <shared_ptr <component> > getChildComponents();
+
+ /** Decide which encoding to use based on the specified data.
+ *
+ * @param data data used to determine encoding
+ * @param usage context of use of data
+ * @return suitable encoding for specified data
+ */
+ static const encoding decide(
+ const shared_ptr <const contentHandler>& data,
+ const EncodingUsage usage = USAGE_BINARY_DATA
+ );
+
+ /** Decide which encoding to use based on the specified data and charset.
+ *
+ * @param data data used to determine encoding
+ * @param chset charset of data
+ * @param usage context of use of data
+ * @return suitable encoding for specified data and charset
+ */
+ static const encoding decide(
+ const shared_ptr <const contentHandler>& data,
+ const charset& chset,
+ const EncodingUsage usage = USAGE_BINARY_DATA
+ );
+
+
+ shared_ptr <component> clone() const;
+ void copyFrom(const component& other);
+
+ /** Use encoderFactory to obtain an encoder/decoder object
+ * for the current encoding type.
+ *
+ * @throw exceptions::no_encoder_available if no encoder
+ * is registered for the encoding
+ * @return a new encoder object for the encoding type
+ */
+ shared_ptr <utility::encoder::encoder> getEncoder() const;
+
+private:
+
+ string m_name;
+ EncodingUsage m_usage;
+
+ /** Determine whether data encoded using this encoding should
+ * be re-encoded if needed.
+ *
+ * @return true if data should be re-encoded, false otherwise
+ */
+ bool shouldReencode() const;
+
+ /** Decide which encoding to use based on the specified data.
+ *
+ * Please note: this will read the whole buffer, so it should be used only
+ * for small amount of data (eg. text), and not large binary attachments.
+ *
+ * @param begin start iterator in buffer
+ * @param end end iterator in buffer
+ * @return suitable encoding for specified data
+ */
+ static const encoding decideImpl(
+ const string::const_iterator begin,
+ const string::const_iterator end
+ );
+
+protected:
+
+ // Component parsing & assembling
+ void parseImpl(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition = NULL
+ );
+
+ void generateImpl(
+ const generationContext& ctx,
+ utility::outputStream& os,
+ const size_t curLinePos = 0,
+ size_t* newLinePos = NULL
+ ) const;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_ENCODING_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/exception.cpp b/vmime-master/src/vmime/exception.cpp
new file mode 100644
index 0000000..fb9dea9
--- /dev/null
+++ b/vmime-master/src/vmime/exception.cpp
@@ -0,0 +1,735 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/exception.hpp"
+
+
+namespace vmime {
+
+
+//
+// exception
+//
+
+const exception exception::NO_EXCEPTION;
+
+
+exception::exception()
+ : std::runtime_error(""), m_other(NULL) {
+
+}
+
+
+exception::exception(const string& what, const exception& other)
+ : std::runtime_error(what), m_other(&other != &NO_EXCEPTION ? other.clone() : NULL) {
+
+}
+
+
+exception::exception(const exception& e)
+ : std::runtime_error(e.what()), m_other(e.m_other == NULL ? NULL : e.m_other->clone()) {
+
+}
+
+
+exception::~exception() throw() {
+
+ delete m_other;
+}
+
+
+void exception::chainException(const exception& other) {
+
+ exception* e = other.clone();
+
+ delete m_other;
+ m_other = e;
+}
+
+
+const exception* exception::other() const throw() {
+
+ return m_other;
+}
+
+
+const char* exception::name() const throw() {
+
+ return "exception";
+}
+
+
+exception* exception::clone() const {
+
+ return new exception(*this);
+}
+
+
+
+namespace exceptions {
+
+
+//
+// bad_field_value_type
+//
+
+bad_field_value_type::~bad_field_value_type() throw() {}
+bad_field_value_type::bad_field_value_type(const string& fieldName, const exception& other)
+ : exception("Bad value type for field '" + fieldName + "'.", other) {}
+
+exception* bad_field_value_type::clone() const { return new bad_field_value_type(*this); }
+const char* bad_field_value_type::name() const throw() { return "bad_field_value_type"; }
+
+
+
+//
+// charset_conv_error
+//
+
+charset_conv_error::~charset_conv_error() throw() {}
+charset_conv_error::charset_conv_error(const string& what, const exception& other)
+ : exception(what.empty() ? "Charset conversion error." : what, other) {}
+
+exception* charset_conv_error::clone() const { return new charset_conv_error(*this); }
+const char* charset_conv_error::name() const throw() { return "charset_conv_error"; }
+
+
+
+//
+// illegal_byte_sequence_for_charset
+//
+
+illegal_byte_sequence_for_charset::~illegal_byte_sequence_for_charset() throw() {}
+illegal_byte_sequence_for_charset::illegal_byte_sequence_for_charset(const string& what, const exception& other)
+ : exception(what.empty() ? "Found illegal byte sequence for this charset." : what, other) {}
+
+exception* illegal_byte_sequence_for_charset::clone() const { return new illegal_byte_sequence_for_charset(*this); }
+const char* illegal_byte_sequence_for_charset::name() const throw() { return "illegal_byte_sequence_for_charset"; }
+
+
+
+//
+// no_encoder_available
+//
+
+no_encoder_available::~no_encoder_available() throw() {}
+no_encoder_available::no_encoder_available(const string& name, const exception& other)
+ : exception("No encoder available: '" + name + "'.", other) {}
+
+exception* no_encoder_available::clone() const { return new no_encoder_available(*this); }
+const char* no_encoder_available::name() const throw() { return "no_encoder_available"; }
+
+
+//
+// no_digest_algorithm_available
+//
+
+no_digest_algorithm_available::~no_digest_algorithm_available() throw() {}
+no_digest_algorithm_available::no_digest_algorithm_available(const string& name, const exception& other)
+ : exception("No algorithm available: '" + name + "'.", other) {}
+
+exception* no_digest_algorithm_available::clone() const { return new no_digest_algorithm_available(*this); }
+const char* no_digest_algorithm_available::name() const throw() { return "no_digest_algorithm_available"; }
+
+
+//
+// no_such_field
+//
+
+no_such_field::~no_such_field() throw() {}
+no_such_field::no_such_field(const exception& other)
+ : exception("Field not found.", other) {}
+
+exception* no_such_field::clone() const { return new no_such_field(*this); }
+const char* no_such_field::name() const throw() { return "no_such_field"; }
+
+
+//
+// no_such_part
+//
+
+no_such_part::~no_such_part() throw() {}
+no_such_part::no_such_part(const exception& other)
+ : exception("Part not found.", other) {}
+
+exception* no_such_part::clone() const { return new no_such_part(*this); }
+const char* no_such_part::name() const throw() { return "no_such_part"; }
+
+
+//
+// no_such_message_id
+//
+
+no_such_message_id::~no_such_message_id() throw() {}
+no_such_message_id::no_such_message_id(const exception& other)
+ : exception("Message-Id not found.", other) {}
+
+exception* no_such_message_id::clone() const { return new no_such_message_id(*this); }
+const char* no_such_message_id::name() const throw() { return "no_such_message_id"; }
+
+
+//
+// open_file_error
+//
+
+open_file_error::~open_file_error() throw() {}
+open_file_error::open_file_error(const exception& other)
+ : exception("Error opening file.", other) {}
+
+exception* open_file_error::clone() const { return new open_file_error(*this); }
+const char* open_file_error::name() const throw() { return "open_file_error"; }
+
+
+//
+// no_factory_available
+//
+
+no_factory_available::~no_factory_available() throw() {}
+no_factory_available::no_factory_available(const exception& other)
+ : exception("No factory available.", other) {}
+
+exception* no_factory_available::clone() const { return new no_factory_available(*this); }
+const char* no_factory_available::name() const throw() { return "no_factory_available"; }
+
+
+//
+// no_platform_handler
+//
+
+no_platform_handler::~no_platform_handler() throw() {}
+no_platform_handler::no_platform_handler(const exception& other)
+ : exception("No platform handler installed.", other) {}
+
+exception* no_platform_handler::clone() const { return new no_platform_handler(*this); }
+const char* no_platform_handler::name() const throw() { return "no_platform_handler"; }
+
+
+//
+// no_expeditor
+//
+
+no_expeditor::~no_expeditor() throw() {}
+no_expeditor::no_expeditor(const exception& other)
+ : exception("No expeditor specified.", other) {}
+
+exception* no_expeditor::clone() const { return new no_expeditor(*this); }
+const char* no_expeditor::name() const throw() { return "no_expeditor"; }
+
+
+//
+// no_recipient
+//
+
+no_recipient::~no_recipient() throw() {}
+no_recipient::no_recipient(const exception& other)
+ : exception("No recipient specified.", other) {}
+
+exception* no_recipient::clone() const { return new no_recipient(*this); }
+const char* no_recipient::name() const throw() { return "no_recipient"; }
+
+
+//
+// no_such_property
+//
+
+no_such_property::~no_such_property() throw() {}
+no_such_property::no_such_property(const string& name, const exception& other)
+ : exception(string("No such property: '") + name + string("'."), other) { }
+
+exception* no_such_property::clone() const { return new no_such_property(*this); }
+const char* no_such_property::name() const throw() { return "no_such_property"; }
+
+
+//
+// invalid_property_type
+//
+
+invalid_property_type::~invalid_property_type() throw() {}
+invalid_property_type::invalid_property_type(const exception& other)
+ : exception("Invalid property type.", other) {}
+
+exception* invalid_property_type::clone() const { return new invalid_property_type(*this); }
+const char* invalid_property_type::name() const throw() { return "invalid_property_type"; }
+
+
+//
+// invalid_argument
+//
+
+invalid_argument::~invalid_argument() throw() {}
+invalid_argument::invalid_argument(const exception& other)
+ : exception("Invalid argument.", other) {}
+
+exception* invalid_argument::clone() const { return new invalid_argument(*this); }
+const char* invalid_argument::name() const throw() { return "invalid_argument"; }
+
+
+//
+// system_error
+//
+
+system_error::~system_error() throw() { }
+system_error::system_error(const string& what, const exception& other)
+ : exception(what, other) {}
+
+exception* system_error::clone() const { return new system_error(*this); }
+const char* system_error::name() const throw() { return "system_error"; }
+
+
+//
+// malformed_url
+//
+
+malformed_url::~malformed_url() throw() {}
+malformed_url::malformed_url(const string& error, const exception& other)
+ : exception("Malformed URL: " + error + ".", other) {}
+
+exception* malformed_url::clone() const { return new malformed_url(*this); }
+const char* malformed_url::name() const throw() { return "malformed_url"; }
+
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+//
+// net_exception
+//
+
+net_exception::~net_exception() throw() {}
+net_exception::net_exception(const string& what, const exception& other)
+ : exception(what, other) {}
+
+exception* net_exception::clone() const { return new net_exception(*this); }
+const char* net_exception::name() const throw() { return "net_exception"; }
+
+
+//
+// socket_exception
+//
+
+socket_exception::~socket_exception() throw() {}
+socket_exception::socket_exception(const string& what, const exception& other)
+ : net_exception(what.empty()
+ ? "Socket error." : what, other) {}
+
+exception* socket_exception::clone() const { return new socket_exception(*this); }
+const char* socket_exception::name() const throw() { return "socket_exception"; }
+
+
+//
+// socket_not_connected_exception
+//
+
+socket_not_connected_exception::~socket_not_connected_exception() throw() {}
+socket_not_connected_exception::socket_not_connected_exception(const string& what, const exception& other)
+ : socket_exception(what.empty()
+ ? "Socket is not connected." : what, other) {}
+
+exception* socket_not_connected_exception::clone() const { return new socket_not_connected_exception(*this); }
+const char* socket_not_connected_exception::name() const throw() { return "socket_not_connected_exception"; }
+
+
+//
+// connection_error
+//
+
+connection_error::~connection_error() throw() {}
+connection_error::connection_error(const string& what, const exception& other)
+ : socket_exception(what.empty()
+ ? "Connection error." : what, other) {}
+
+exception* connection_error::clone() const { return new connection_error(*this); }
+const char* connection_error::name() const throw() { return "connection_error"; }
+
+
+//
+// connection_greeting_error
+//
+
+connection_greeting_error::~connection_greeting_error() throw() {}
+connection_greeting_error::connection_greeting_error(const string& response, const exception& other)
+ : net_exception("Greeting error.", other), m_response(response) {}
+
+const string& connection_greeting_error::response() const { return (m_response); }
+
+exception* connection_greeting_error::clone() const { return new connection_greeting_error(*this); }
+const char* connection_greeting_error::name() const throw() { return "connection_greeting_error"; }
+
+
+//
+// authentication_error
+//
+
+authentication_error::~authentication_error() throw() {}
+authentication_error::authentication_error(const string& response, const exception& other)
+ : net_exception("Authentication error.", other), m_response(response) {}
+
+const string& authentication_error::response() const { return (m_response); }
+
+exception* authentication_error::clone() const { return new authentication_error(*this); }
+const char* authentication_error::name() const throw() { return "authentication_error"; }
+
+
+//
+// unsupported_option
+//
+
+unsupported_option::~unsupported_option() throw() {}
+unsupported_option::unsupported_option(const exception& other)
+ : net_exception("Unsupported option.", other) {}
+
+exception* unsupported_option::clone() const { return new unsupported_option(*this); }
+const char* unsupported_option::name() const throw() { return "unsupported_option"; }
+
+
+//
+// illegal_state
+//
+
+illegal_state::~illegal_state() throw() {}
+illegal_state::illegal_state(const string& state, const exception& other)
+ : net_exception("Illegal state to accomplish the operation: '" + state + "'.", other) {}
+
+exception* illegal_state::clone() const { return new illegal_state(*this); }
+const char* illegal_state::name() const throw() { return "illegal_state"; }
+
+
+//
+// folder_not_found
+//
+
+folder_not_found::~folder_not_found() throw() {}
+folder_not_found::folder_not_found(const exception& other)
+ : net_exception("Folder not found.", other) {}
+
+exception* folder_not_found::clone() const { return new folder_not_found(*this); }
+const char* folder_not_found::name() const throw() { return "folder_not_found"; }
+
+
+//
+// folder_already_open
+//
+
+folder_already_open::~folder_already_open() throw() {}
+folder_already_open::folder_already_open(const exception& other)
+ : net_exception("Folder is already open in the same session.", other) {}
+
+exception* folder_already_open::clone() const { return new folder_already_open(*this); }
+const char* folder_already_open::name() const throw() { return "folder_already_open"; }
+
+
+//
+// message_not_found
+//
+
+message_not_found::~message_not_found() throw() {}
+message_not_found::message_not_found(const exception& other)
+ : net_exception("Message not found.", other) {}
+
+exception* message_not_found::clone() const { return new message_not_found(*this); }
+const char* message_not_found::name() const throw() { return "message_not_found"; }
+
+
+//
+// operation_not_supported
+//
+
+operation_not_supported::~operation_not_supported() throw() {}
+operation_not_supported::operation_not_supported(const exception& other)
+ : net_exception("Operation not supported.", other) {}
+
+exception* operation_not_supported::clone() const { return new operation_not_supported(*this); }
+const char* operation_not_supported::name() const throw() { return "operation_not_supported"; }
+
+
+//
+// operation_timed_out
+//
+
+operation_timed_out::~operation_timed_out() throw() {}
+operation_timed_out::operation_timed_out(const exception& other)
+ : net_exception("Operation timed out.", other) {}
+
+exception* operation_timed_out::clone() const { return new operation_timed_out(*this); }
+const char* operation_timed_out::name() const throw() { return "operation_timed_out"; }
+
+
+//
+// operation_cancelled
+//
+
+operation_cancelled::~operation_cancelled() throw() {}
+operation_cancelled::operation_cancelled(const exception& other)
+ : net_exception("Operation cancelled by the user.", other) {}
+
+exception* operation_cancelled::clone() const { return new operation_cancelled(*this); }
+const char* operation_cancelled::name() const throw() { return "operation_cancelled"; }
+
+
+//
+// unfetched_object
+//
+
+unfetched_object::~unfetched_object() throw() {}
+unfetched_object::unfetched_object(const exception& other)
+ : net_exception("Object not fetched.", other) {}
+
+exception* unfetched_object::clone() const { return new unfetched_object(*this); }
+const char* unfetched_object::name() const throw() { return "unfetched_object"; }
+
+
+//
+// not_connected
+//
+
+not_connected::~not_connected() throw() {}
+not_connected::not_connected(const exception& other)
+ : net_exception("Not connected to a service.", other) {}
+
+exception* not_connected::clone() const { return new not_connected(*this); }
+const char* not_connected::name() const throw() { return "not_connected"; }
+
+
+//
+// already_connected
+//
+
+already_connected::~already_connected() throw() {}
+already_connected::already_connected(const exception& other)
+ : net_exception("Already connected to a service. Disconnect and retry.", other) {}
+
+exception* already_connected::clone() const { return new already_connected(*this); }
+const char* already_connected::name() const throw() { return "already_connected"; }
+
+
+//
+// illegal_operation
+//
+
+illegal_operation::~illegal_operation() throw() {}
+illegal_operation::illegal_operation(const string& msg, const exception& other)
+ : net_exception(msg.empty()
+ ? "Illegal operation."
+ : "Illegal operation: " + msg + ".",
+ other
+ ) {}
+
+exception* illegal_operation::clone() const { return new illegal_operation(*this); }
+const char* illegal_operation::name() const throw() { return "illegal_operation"; }
+
+
+//
+// command_error
+//
+
+command_error::~command_error() throw() {}
+command_error::command_error(const string& command, const string& response,
+ const string& desc, const exception& other)
+ : net_exception(desc.empty()
+ ? "Error while executing command '" + command + "'."
+ : "Error while executing command '" + command + "': " + desc + ".",
+ other
+ ),
+ m_command(command), m_response(response) {}
+
+const string& command_error::command() const { return (m_command); }
+
+const string& command_error::response() const { return (m_response); }
+
+exception* command_error::clone() const { return new command_error(*this); }
+const char* command_error::name() const throw() { return "command_error"; }
+
+
+//
+// invalid_response
+//
+
+invalid_response::~invalid_response() throw() {}
+invalid_response::invalid_response(const string& command, const string& response, const exception& other)
+ : net_exception(command.empty()
+ ? "Received invalid response."
+ : "Received invalid response for command '" + command + "'.",
+ other
+ ),
+ m_command(command), m_response(response) {}
+
+const string& invalid_response::command() const { return (m_command); }
+
+const string& invalid_response::response() const { return (m_response); }
+
+exception* invalid_response::clone() const { return new invalid_response(*this); }
+const char* invalid_response::name() const throw() { return "invalid_response"; }
+
+
+//
+// partial_fetch_not_supported
+//
+
+partial_fetch_not_supported::~partial_fetch_not_supported() throw() {}
+partial_fetch_not_supported::partial_fetch_not_supported(const exception& other)
+ : net_exception("Partial fetch not supported.", other) {}
+
+exception* partial_fetch_not_supported::clone() const { return new partial_fetch_not_supported(*this); }
+const char* partial_fetch_not_supported::name() const throw() { return "partial_fetch_not_supported"; }
+
+
+//
+// invalid_folder_name
+//
+
+invalid_folder_name::~invalid_folder_name() throw() {}
+invalid_folder_name::invalid_folder_name(const string& error, const exception& other)
+ : net_exception(error.empty()
+ ? "Invalid folder name: " + error + "."
+ : "Invalid folder name.",
+ other) {}
+
+exception* invalid_folder_name::clone() const { return new invalid_folder_name(*this); }
+const char* invalid_folder_name::name() const throw() { return "invalid_folder_name"; }
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+
+#if VMIME_HAVE_FILESYSTEM_FEATURES
+
+
+//
+// filesystem_exception
+//
+
+filesystem_exception::~filesystem_exception() throw() {}
+filesystem_exception::filesystem_exception(const string& what, const utility::path& path, const exception& other)
+ : exception(what, other), m_path(path) {}
+
+const utility::path& filesystem_exception::path() const { return (m_path); }
+
+exception* filesystem_exception::clone() const { return new filesystem_exception(*this); }
+const char* filesystem_exception::name() const throw() { return "filesystem_exception"; }
+
+
+//
+// not_a_directory
+//
+
+not_a_directory::~not_a_directory() throw() {}
+not_a_directory::not_a_directory(const utility::path& path, const exception& other)
+ : filesystem_exception("Operation failed: this is not a directory.", path, other) {}
+
+exception* not_a_directory::clone() const { return new not_a_directory(*this); }
+const char* not_a_directory::name() const throw() { return "not_a_directory"; }
+
+
+//
+// file_not_found
+//
+
+file_not_found::~file_not_found() throw() {}
+file_not_found::file_not_found(const utility::path& path, const exception& other)
+ : filesystem_exception("File not found.", path, other) {}
+
+exception* file_not_found::clone() const { return new file_not_found(*this); }
+const char* file_not_found::name() const throw() { return "file_not_found"; }
+
+
+#endif // VMIME_HAVE_FILESYSTEM_FEATURES
+
+
+//
+// authentication_exception
+//
+
+authentication_exception::~authentication_exception() throw() {}
+authentication_exception::authentication_exception(const string& what, const exception& other)
+ : exception(what, other) {}
+
+exception* authentication_exception::clone() const { return new authentication_exception(*this); }
+const char* authentication_exception::name() const throw() { return "authentication_exception"; }
+
+
+//
+// no_auth_information
+//
+
+no_auth_information::~no_auth_information() throw() {}
+no_auth_information::no_auth_information(const exception& other)
+ : authentication_exception("Information cannot be provided.", other) {}
+
+exception* no_auth_information::clone() const { return new no_auth_information(*this); }
+const char* no_auth_information::name() const throw() { return "no_auth_information"; }
+
+
+#if VMIME_HAVE_SASL_SUPPORT
+
+
+//
+// sasl_exception
+//
+
+sasl_exception::~sasl_exception() throw() {}
+sasl_exception::sasl_exception(const string& what, const exception& other)
+ : authentication_exception(what, other) {}
+
+exception* sasl_exception::clone() const { return new sasl_exception(*this); }
+const char* sasl_exception::name() const throw() { return "sasl_exception"; }
+
+
+//
+// no_such_mechanism
+//
+
+no_such_mechanism::~no_such_mechanism() throw() {}
+no_such_mechanism::no_such_mechanism(const string& name, const exception& other)
+ : sasl_exception("No such SASL mechanism: '" + name + "'.", other) {}
+
+exception* no_such_mechanism::clone() const { return new no_such_mechanism(*this); }
+const char* no_such_mechanism::name() const throw() { return "no_such_mechanism"; }
+
+
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+
+#if VMIME_HAVE_TLS_SUPPORT
+
+
+//
+// tls_exception
+//
+
+tls_exception::~tls_exception() throw() {}
+tls_exception::tls_exception(const string& what, const exception& other)
+ : exception(what, other) {}
+
+exception* tls_exception::clone() const { return new tls_exception(*this); }
+const char* tls_exception::name() const throw() { return "tls_exception"; }
+
+
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+
+} // exceptions
+
+
+} // vmime
+
diff --git a/vmime-master/src/vmime/exception.hpp b/vmime-master/src/vmime/exception.hpp
new file mode 100644
index 0000000..da0ec24
--- /dev/null
+++ b/vmime-master/src/vmime/exception.hpp
@@ -0,0 +1,865 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_EXCEPTION_HPP_INCLUDED
+#define VMIME_EXCEPTION_HPP_INCLUDED
+
+
+#include <stdexcept>
+
+#include "vmime/config.hpp"
+#include "vmime/base.hpp"
+#include "vmime/utility/path.hpp"
+
+
+namespace vmime {
+
+
+/** Base class for VMime exceptions.
+ */
+class VMIME_EXPORT exception : public std::runtime_error {
+
+private:
+
+ exception* m_other;
+
+ exception();
+
+public:
+
+ exception(const string& what, const exception& other = NO_EXCEPTION);
+ exception(const exception& e);
+
+ virtual ~exception() throw();
+
+ /** Chain the specified exception with this exception.
+ *
+ * @param other next exception in the chain
+ */
+ void chainException(const exception& other);
+
+ /** Return the next exception in the chain, that is the exception
+ * that caused this exception. This permits nesting exceptions.
+ *
+ * @return next exception in the chain
+ */
+ const exception* other() const throw();
+
+ /** Return a name identifying the exception.
+ *
+ * @return exception name
+ */
+ virtual const char* name() const throw();
+
+ /** Clone this object.
+ *
+ * @return a new copy of this object
+ */
+ virtual exception* clone() const;
+
+protected:
+
+ static const exception NO_EXCEPTION;
+};
+
+
+
+/** List of all VMime exceptions. */
+namespace exceptions {
+
+
+class VMIME_EXPORT bad_field_value_type : public vmime::exception {
+
+public:
+
+ bad_field_value_type(const string& fieldName, const exception& other = NO_EXCEPTION);
+ ~bad_field_value_type() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+};
+
+
+class VMIME_EXPORT charset_conv_error : public vmime::exception {
+
+public:
+
+ charset_conv_error(const string& what = "", const exception& other = NO_EXCEPTION);
+ ~charset_conv_error() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+};
+
+
+class VMIME_EXPORT illegal_byte_sequence_for_charset : public vmime::exception {
+
+public:
+
+ illegal_byte_sequence_for_charset(const string& what = "", const exception& other = NO_EXCEPTION);
+ ~illegal_byte_sequence_for_charset() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+};
+
+
+/** No encoder has been found for the specified encoding name.
+ */
+class VMIME_EXPORT no_encoder_available : public vmime::exception {
+
+public:
+
+ no_encoder_available(const string& name, const exception& other = NO_EXCEPTION);
+ ~no_encoder_available() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+};
+
+
+/** No algorithm has been found for the specified name.
+ */
+class VMIME_EXPORT no_digest_algorithm_available : public vmime::exception {
+
+public:
+
+ no_digest_algorithm_available(const string& name, const exception& other = NO_EXCEPTION);
+ ~no_digest_algorithm_available() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+};
+
+
+class VMIME_EXPORT no_such_field : public vmime::exception {
+
+public:
+
+ no_such_field(const exception& other = NO_EXCEPTION);
+ ~no_such_field() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+};
+
+
+class VMIME_EXPORT no_such_part : public vmime::exception {
+
+public:
+
+ no_such_part(const exception& other = NO_EXCEPTION);
+ ~no_such_part() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+};
+
+
+class VMIME_EXPORT no_such_message_id : public vmime::exception {
+
+public:
+
+ no_such_message_id(const exception& other = NO_EXCEPTION);
+ ~no_such_message_id() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+};
+
+
+class VMIME_EXPORT open_file_error : public vmime::exception {
+
+public:
+
+ open_file_error(const exception& other = NO_EXCEPTION);
+ ~open_file_error() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+};
+
+
+class VMIME_EXPORT no_factory_available : public vmime::exception {
+
+public:
+
+ no_factory_available(const exception& other = NO_EXCEPTION);
+ ~no_factory_available() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+};
+
+
+class VMIME_EXPORT no_platform_handler : public vmime::exception {
+
+public:
+
+ no_platform_handler(const exception& other = NO_EXCEPTION);
+ ~no_platform_handler() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+};
+
+
+/** No expeditor specified.
+ */
+class VMIME_EXPORT no_expeditor : public vmime::exception {
+
+public:
+
+ no_expeditor(const exception& other = NO_EXCEPTION);
+ ~no_expeditor() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+};
+
+
+/** No recipient specified.
+ */
+class VMIME_EXPORT no_recipient : public vmime::exception {
+
+public:
+
+ no_recipient(const exception& other = NO_EXCEPTION);
+ ~no_recipient() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+};
+
+
+/** There is no property with that name in the set.
+ */
+class VMIME_EXPORT no_such_property : public vmime::exception {
+
+public:
+
+ no_such_property(const string& name, const exception& other = NO_EXCEPTION);
+ ~no_such_property() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+};
+
+
+/** Bad type specified when reading property.
+ */
+class VMIME_EXPORT invalid_property_type : public vmime::exception {
+
+public:
+
+ invalid_property_type(const exception& other = NO_EXCEPTION);
+ ~invalid_property_type() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+};
+
+
+/** Bad argument was passed to the function.
+ */
+class VMIME_EXPORT invalid_argument : public vmime::exception {
+
+public:
+
+ invalid_argument(const exception& other = NO_EXCEPTION);
+ ~invalid_argument() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+};
+
+
+/** Underlying operating system error.
+ */
+class VMIME_EXPORT system_error : public vmime::exception {
+
+public:
+
+ system_error(const string& what, const exception& other = NO_EXCEPTION);
+ ~system_error() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+};
+
+
+/** The URL is malformed.
+ */
+class VMIME_EXPORT malformed_url : public vmime::exception {
+
+public:
+
+ malformed_url(const string& error, const exception& other = NO_EXCEPTION);
+ ~malformed_url() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+};
+
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+/** Base class for exceptions thrown by the networking module.
+ */
+class VMIME_EXPORT net_exception : public vmime::exception {
+
+public:
+
+ net_exception(const string& what, const exception& other = NO_EXCEPTION);
+ ~net_exception() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+};
+
+
+/** Alias for 'net_exception' (compatibility with version <= 0.7.1);
+ * this is deprecated.
+ */
+typedef net_exception messaging_exception;
+
+
+/** Socket error.
+ */
+class VMIME_EXPORT socket_exception : public net_exception {
+
+public:
+
+ socket_exception(const string& what = "", const exception& other = NO_EXCEPTION);
+ ~socket_exception() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+
+};
+
+
+/** Socket not connected: you are trying to write to/read from a socket which
+ * is not connected to a peer.
+ */
+class VMIME_EXPORT socket_not_connected_exception : public socket_exception {
+
+public:
+
+ socket_not_connected_exception(const string& what = "", const exception& other = NO_EXCEPTION);
+ ~socket_not_connected_exception() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+
+};
+
+
+/** Error while connecting to the server: this may be a DNS resolution error
+ * or a connection error (for example, time-out while connecting).
+ */
+class VMIME_EXPORT connection_error : public socket_exception {
+
+public:
+
+ connection_error(const string& what = "", const exception& other = NO_EXCEPTION);
+ ~connection_error() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+};
+
+
+/** Server did not initiated the connection correctly.
+ */
+class VMIME_EXPORT connection_greeting_error : public net_exception {
+
+public:
+
+ connection_greeting_error(const string& response, const exception& other = NO_EXCEPTION);
+ ~connection_greeting_error() throw();
+
+ const string& response() const;
+
+ exception* clone() const;
+ const char* name() const throw();
+
+private:
+
+ string m_response;
+};
+
+
+/** Error while giving credentials to the server (wrong username
+ * or password, or wrong authentication method).
+ */
+class VMIME_EXPORT authentication_error : public net_exception {
+
+public:
+
+ authentication_error(const string& response, const exception& other = NO_EXCEPTION);
+ ~authentication_error() throw();
+
+ const string& response() const;
+
+ exception* clone() const;
+ const char* name() const throw();
+
+private:
+
+ string m_response;
+};
+
+
+/** Option not supported.
+ */
+class VMIME_EXPORT unsupported_option : public net_exception {
+
+public:
+
+ unsupported_option(const exception& other = NO_EXCEPTION);
+ ~unsupported_option() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+};
+
+
+/** The current state of the object does not permit to execute the
+ * operation (for example, you try to close a folder which is not open).
+ */
+class VMIME_EXPORT illegal_state : public net_exception {
+
+public:
+
+ illegal_state(const string& state, const exception& other = NO_EXCEPTION);
+ ~illegal_state() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+};
+
+
+/** Folder not found (does not exist).
+ */
+class VMIME_EXPORT folder_not_found : public net_exception {
+
+public:
+
+ folder_not_found(const exception& other = NO_EXCEPTION);
+ ~folder_not_found() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+};
+
+
+/** Folder is already open in the same session.
+ */
+class VMIME_EXPORT folder_already_open : public net_exception {
+
+public:
+
+ folder_already_open(const exception& other = NO_EXCEPTION);
+ ~folder_already_open() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+};
+
+
+/** Message not found (does not exist).
+ */
+class VMIME_EXPORT message_not_found : public net_exception {
+
+public:
+
+ message_not_found(const exception& other = NO_EXCEPTION);
+ ~message_not_found() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+};
+
+
+/** Operation not supported by the underlying protocol.
+ */
+class VMIME_EXPORT operation_not_supported : public net_exception {
+
+public:
+
+ operation_not_supported(const exception& other = NO_EXCEPTION);
+ ~operation_not_supported() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+};
+
+
+/** The operation timed out (time-out delay is elapsed).
+ */
+class VMIME_EXPORT operation_timed_out : public net_exception {
+
+public:
+
+ operation_timed_out(const exception& other = NO_EXCEPTION);
+ ~operation_timed_out() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+};
+
+
+/** The operation has been cancelled.
+ */
+class VMIME_EXPORT operation_cancelled : public net_exception {
+
+public:
+
+ operation_cancelled(const exception& other = NO_EXCEPTION);
+ ~operation_cancelled() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+};
+
+
+/** Must call fetchMessage() or fetchHeader() before accessing
+ * the requested object.
+ */
+class VMIME_EXPORT unfetched_object : public net_exception {
+
+public:
+
+ unfetched_object(const exception& other = NO_EXCEPTION);
+ ~unfetched_object() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+};
+
+
+/** The service is not currently connected.
+ */
+class VMIME_EXPORT not_connected : public net_exception {
+
+public:
+
+ not_connected(const exception& other = NO_EXCEPTION);
+ ~not_connected() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+};
+
+
+/** The service is already connected (must disconnect before).
+ */
+class VMIME_EXPORT already_connected : public net_exception {
+
+public:
+
+ already_connected(const exception& other = NO_EXCEPTION);
+ ~already_connected() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+};
+
+
+/** Illegal operation: cannot run this operation on the object.
+ */
+class VMIME_EXPORT illegal_operation : public net_exception {
+
+public:
+
+ illegal_operation(const string& msg = "", const exception& other = NO_EXCEPTION);
+ ~illegal_operation() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+};
+
+
+/** Command error: operation failed (this is specific to the underlying protocol).
+ */
+class VMIME_EXPORT command_error : public net_exception {
+
+public:
+
+ command_error(
+ const string& command,
+ const string& response,
+ const string& desc = "",
+ const exception& other = NO_EXCEPTION
+ );
+
+ ~command_error() throw();
+
+ /** Return the name of the command which have thrown the exception.
+ * This is protocol-dependent.
+ *
+ * @return command name (protocol-dependent)
+ */
+ const string& command() const;
+
+ /** Return the invalid response line.
+ * The meaning is protocol-dependent.
+ *
+ * @return response line (protocol-dependent)
+ */
+ const string& response() const;
+
+ exception* clone() const;
+ const char* name() const throw();
+
+private:
+
+ string m_command;
+ string m_response;
+};
+
+
+/** The server returned an invalid response.
+ */
+class VMIME_EXPORT invalid_response : public net_exception {
+
+public:
+
+ invalid_response(
+ const string& command,
+ const string& response,
+ const exception& other = NO_EXCEPTION
+ );
+
+ ~invalid_response() throw();
+
+ /** Return the name of the command which have thrown the exception.
+ * This is protocol-dependent.
+ *
+ * @return command name (protocol-dependent)
+ */
+ const string& command() const;
+
+ /** Return the invalid response line.
+ * The meaning is protocol-dependent.
+ *
+ * @return response line (protocol-dependent)
+ */
+ const string& response() const;
+
+ exception* clone() const;
+ const char* name() const throw();
+
+private:
+
+ string m_command;
+ string m_response;
+};
+
+
+/** Partial fetch is not supported by the underlying protocol.
+ */
+class VMIME_EXPORT partial_fetch_not_supported : public net_exception {
+
+public:
+
+ partial_fetch_not_supported(const exception& other = NO_EXCEPTION);
+ ~partial_fetch_not_supported() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+};
+
+
+/** Folder name is invalid.
+ */
+class VMIME_EXPORT invalid_folder_name : public net_exception {
+
+public:
+
+ invalid_folder_name(const string& error = "", const exception& other = NO_EXCEPTION);
+ ~invalid_folder_name() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+};
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+
+#if VMIME_HAVE_FILESYSTEM_FEATURES
+
+
+/** Base class for exceptions thrown by the filesystem features.
+ */
+class VMIME_EXPORT filesystem_exception : public vmime::exception {
+
+public:
+
+ filesystem_exception(
+ const string& what,
+ const utility::path& path,
+ const exception& other = NO_EXCEPTION
+ );
+
+ ~filesystem_exception() throw();
+
+ /** Return the full path of the file have thrown the exception.
+ *
+ * @return full path of the file/directory
+ */
+ const utility::path& path() const;
+
+ exception* clone() const;
+ const char* name() const throw();
+
+private:
+
+ const utility::path m_path;
+};
+
+
+/** File is not a directory.
+ */
+class VMIME_EXPORT not_a_directory : public filesystem_exception {
+
+public:
+
+ not_a_directory(const utility::path& path, const exception& other = NO_EXCEPTION);
+ ~not_a_directory() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+};
+
+
+/** File not found.
+ */
+class VMIME_EXPORT file_not_found : public filesystem_exception {
+
+public:
+
+ file_not_found(const utility::path& path, const exception& other = NO_EXCEPTION);
+ ~file_not_found() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+};
+
+
+#endif // VMIME_HAVE_FILESYSTEM_FEATURES
+
+
+/** Authentication exception.
+ */
+class VMIME_EXPORT authentication_exception : public vmime::exception {
+
+public:
+
+ authentication_exception(const string& what, const exception& other = NO_EXCEPTION);
+ ~authentication_exception() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+};
+
+
+/** The requested information cannot be provided.
+ */
+class VMIME_EXPORT no_auth_information : public authentication_exception {
+
+public:
+
+ no_auth_information(const exception& other = NO_EXCEPTION);
+ ~no_auth_information() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+};
+
+
+#if VMIME_HAVE_SASL_SUPPORT
+
+
+/** Base class for exceptions thrown by SASL module.
+ */
+class VMIME_EXPORT sasl_exception : public authentication_exception {
+
+public:
+
+ sasl_exception(const string& what, const exception& other = NO_EXCEPTION);
+ ~sasl_exception() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+};
+
+
+/** No mechanism is registered with the specified name.
+ */
+class VMIME_EXPORT no_such_mechanism : public sasl_exception {
+
+public:
+
+ no_such_mechanism(const string& name, const exception& other = NO_EXCEPTION);
+ ~no_such_mechanism() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+};
+
+
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+
+#if VMIME_HAVE_TLS_SUPPORT
+
+
+/** Base class for exceptions thrown by TLS module.
+ */
+class VMIME_EXPORT tls_exception : public vmime::exception {
+
+public:
+
+ tls_exception(const string& what, const exception& other = NO_EXCEPTION);
+ ~tls_exception() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+};
+
+
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+
+} // exceptions
+
+
+} // vmime
+
+
+#endif // VMIME_EXCEPTION_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/export.hpp b/vmime-master/src/vmime/export.hpp
new file mode 100644
index 0000000..a3b4dfb
--- /dev/null
+++ b/vmime-master/src/vmime/export.hpp
@@ -0,0 +1,36 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_EXPORT_HPP_INCLUDED
+#define VMIME_EXPORT_HPP_INCLUDED
+
+
+// Define VMIME_STATIC if you are linking with the static library
+#ifdef VMIME_STATIC
+# include "vmime/export-static.hpp"
+#else
+# include "vmime/export-shared.hpp"
+#endif
+
+
+#endif // VMIME_EXPORT_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/fileAttachment.cpp b/vmime-master/src/vmime/fileAttachment.cpp
new file mode 100644
index 0000000..ac75570
--- /dev/null
+++ b/vmime-master/src/vmime/fileAttachment.cpp
@@ -0,0 +1,253 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_FILESYSTEM_FEATURES
+
+
+#include <fstream>
+#include <sstream>
+
+#include "vmime/fileAttachment.hpp"
+#include "vmime/exception.hpp"
+
+#include "vmime/streamContentHandler.hpp"
+#include "vmime/utility/inputStreamPointerAdapter.hpp"
+
+#include "vmime/contentDispositionField.hpp"
+
+#include "vmime/platform.hpp"
+#include "vmime/utility/file.hpp"
+
+
+namespace vmime {
+
+
+fileAttachment::fileAttachment(
+ const string& filepath,
+ const mediaType& type
+) {
+
+ m_type = type;
+
+ setData(filepath);
+
+ m_encoding = encoding::decide(m_data);
+}
+
+
+fileAttachment::fileAttachment(
+ const string& filepath,
+ const mediaType& type,
+ const text& desc
+) {
+
+ m_type = type;
+ m_desc = desc;
+
+ setData(filepath);
+
+ m_encoding = encoding::decide(m_data);
+}
+
+
+fileAttachment::fileAttachment(
+ const string& filepath,
+ const mediaType& type,
+ const text& desc,
+ const encoding& enc
+) {
+
+ m_type = type;
+ m_desc = desc;
+
+ setData(filepath);
+
+ m_encoding = enc;
+}
+
+
+fileAttachment::fileAttachment(
+ const shared_ptr <contentHandler>& cts,
+ const word& filename,
+ const mediaType& type) {
+
+ if (!filename.isEmpty()) {
+ m_fileInfo.setFilename(filename);
+ }
+
+ m_type = type;
+
+ setData(cts);
+
+ m_encoding = encoding::decide(m_data);
+}
+
+
+fileAttachment::fileAttachment(
+ const shared_ptr <contentHandler>& cts,
+ const word& filename,
+ const mediaType& type,
+ const text& desc
+) {
+
+ if (!filename.isEmpty()) {
+ m_fileInfo.setFilename(filename);
+ }
+
+ m_type = type;
+ m_desc = desc;
+
+ setData(cts);
+
+ m_encoding = encoding::decide(m_data);
+}
+
+
+fileAttachment::fileAttachment(
+ const shared_ptr <contentHandler>& cts,
+ const word& filename,
+ const mediaType& type,
+ const text& desc,
+ const encoding& enc
+) {
+
+ if (!filename.isEmpty()) {
+ m_fileInfo.setFilename(filename);
+ }
+
+ m_type = type;
+ m_desc = desc;
+ m_encoding = enc;
+
+ setData(cts);
+}
+
+
+void fileAttachment::setData(const string& filepath) {
+
+ shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory();
+ utility::file::path path = fsf->stringToPath(filepath);
+
+ shared_ptr <utility::file> file = fsf->create(path);
+
+ if (!file->isFile()) {
+ throw exceptions::open_file_error();
+ }
+
+ m_data = make_shared <streamContentHandler>(
+ file->getFileReader()->getInputStream(), file->getLength()
+ );
+
+ m_fileInfo.setFilename(path.getLastComponent());
+ m_fileInfo.setSize(file->getLength());
+}
+
+
+void fileAttachment::setData(const shared_ptr <contentHandler>& cts) {
+
+ m_data = cts;
+
+ m_fileInfo.setSize(cts->getLength());
+}
+
+
+void fileAttachment::generatePart(const shared_ptr <bodyPart>& part) const {
+
+ defaultAttachment::generatePart(part);
+
+ shared_ptr <contentDispositionField> cdf =
+ dynamicCast <contentDispositionField>(part->getHeader()->ContentDisposition());
+
+ if (m_fileInfo.hasSize()) cdf->setSize(utility::stringUtils::toString(m_fileInfo.getSize()));
+ if (m_fileInfo.hasFilename() && !m_fileInfo.getFilename().isEmpty()) cdf->setFilename(m_fileInfo.getFilename());
+ if (m_fileInfo.hasCreationDate()) cdf->setCreationDate(m_fileInfo.getCreationDate());
+ if (m_fileInfo.hasModificationDate()) cdf->setModificationDate(m_fileInfo.getModificationDate());
+ if (m_fileInfo.hasReadDate()) cdf->setReadDate(m_fileInfo.getReadDate());
+}
+
+
+const fileAttachment::fileInfo& fileAttachment::getFileInfo() const {
+
+ return m_fileInfo;
+}
+
+
+fileAttachment::fileInfo& fileAttachment::getFileInfo() {
+
+ return m_fileInfo;
+}
+
+
+
+//
+// fileAttachment::fileInfo
+//
+
+fileAttachment::fileInfo::fileInfo()
+ : m_filename(NULL),
+ m_size(NULL),
+ m_creationDate(NULL),
+ m_modifDate(NULL),
+ m_readDate(NULL) {
+
+}
+
+
+fileAttachment::fileInfo::~fileInfo()
+{
+ delete m_filename;
+ delete m_size;
+ delete m_creationDate;
+ delete m_modifDate;
+ delete m_readDate;
+}
+
+bool fileAttachment::fileInfo::hasFilename() const { return m_filename; }
+const word& fileAttachment::fileInfo::getFilename() const { return *m_filename; }
+void fileAttachment::fileInfo::setFilename(const string& name) { if (m_filename) { *m_filename = name; } else { m_filename = new word(name); } }
+void fileAttachment::fileInfo::setFilename(const word& name) { if (m_filename) { *m_filename = name; } else { m_filename = new word(name); } }
+
+bool fileAttachment::fileInfo::hasCreationDate() const { return m_creationDate; }
+const datetime& fileAttachment::fileInfo::getCreationDate() const { return *m_creationDate; }
+void fileAttachment::fileInfo::setCreationDate(const datetime& date) { if (m_creationDate) { *m_creationDate = date; } else { m_creationDate = new datetime(date); } }
+
+bool fileAttachment::fileInfo::hasModificationDate() const { return m_modifDate; }
+const datetime& fileAttachment::fileInfo::getModificationDate() const { return *m_modifDate; }
+void fileAttachment::fileInfo::setModificationDate(const datetime& date) { if (m_modifDate) { *m_modifDate = date; } else { m_modifDate = new datetime(date); } }
+
+bool fileAttachment::fileInfo::hasReadDate() const { return m_readDate; }
+const datetime& fileAttachment::fileInfo::getReadDate() const { return *m_readDate; }
+void fileAttachment::fileInfo::setReadDate(const datetime& date) { if (m_readDate) { *m_readDate = date; } else { m_readDate = new datetime(date); } }
+
+bool fileAttachment::fileInfo::hasSize() const { return m_size; }
+size_t fileAttachment::fileInfo::getSize() const { return *m_size; }
+void fileAttachment::fileInfo::setSize(const size_t size) { if (m_size) { *m_size = size; } else { m_size = new size_t(size); } }
+
+
+} // vmime
+
+
+#endif // VMIME_HAVE_FILESYSTEM_FEATURES
diff --git a/vmime-master/src/vmime/fileAttachment.hpp b/vmime-master/src/vmime/fileAttachment.hpp
new file mode 100644
index 0000000..c77662f
--- /dev/null
+++ b/vmime-master/src/vmime/fileAttachment.hpp
@@ -0,0 +1,226 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_FILEATTACHMENT_HPP_INCLUDED
+#define VMIME_FILEATTACHMENT_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_FILESYSTEM_FEATURES
+
+
+#include "vmime/defaultAttachment.hpp"
+#include "vmime/dateTime.hpp"
+#include "vmime/contentHandler.hpp"
+#include "vmime/utility/stream.hpp"
+
+
+namespace vmime {
+
+
+/** Attachment of type 'file'.
+ */
+class VMIME_EXPORT fileAttachment : public defaultAttachment {
+
+public:
+
+ fileAttachment(
+ const string& filepath,
+ const mediaType& type
+ );
+
+ fileAttachment(
+ const string& filepath,
+ const mediaType& type,
+ const text& desc
+ );
+
+ fileAttachment(
+ const string& filepath,
+ const mediaType& type,
+ const text& desc,
+ const encoding& enc
+ );
+
+ fileAttachment(
+ const shared_ptr <contentHandler>& cts,
+ const word& filename,
+ const mediaType& type
+ );
+
+ fileAttachment(
+ const shared_ptr <contentHandler>& cts,
+ const word& filename,
+ const mediaType& type,
+ const text& desc
+ );
+
+ fileAttachment(
+ const shared_ptr <contentHandler>& cts,
+ const word& filename,
+ const mediaType& type,
+ const text& desc,
+ const encoding& enc
+ );
+
+ /** Stores information about a file attachment.
+ */
+ class VMIME_EXPORT fileInfo {
+
+ public:
+
+ fileInfo();
+ ~fileInfo();
+
+ /** Check whether the 'filename' property is present.
+ *
+ * @return true if the 'filename' property is set,
+ * false otherwise
+ */
+ bool hasFilename() const;
+
+ /** Return the value of the 'filename' property.
+ *
+ * @return file name
+ */
+ const word& getFilename() const;
+
+ /** Set the value of the 'filename' property.
+ *
+ * @param name file name
+ */
+ void setFilename(const string& name);
+
+ /** Set the value of the 'filename' property.
+ *
+ * @param name file name
+ */
+ void setFilename(const word& name);
+
+ /** Check whether the 'creation-date' property is present.
+ *
+ * @return true if the 'creation-date' property is set,
+ * false otherwise
+ */
+ bool hasCreationDate() const;
+
+ /** Return the value of the 'creation-date' property.
+ *
+ * @return file creation time
+ */
+ const datetime& getCreationDate() const;
+
+ /** Set the value of the 'creation-date' property.
+ *
+ * @param date file creation time
+ */
+ void setCreationDate(const datetime& date);
+
+ /** Check whether the 'modification-date' property is present.
+ *
+ * @return true if the 'modification-date' property is set,
+ * false otherwise
+ */
+ bool hasModificationDate() const;
+
+ /** Return the value of the 'modification-date' property.
+ *
+ * @return file modification time
+ */
+ const datetime& getModificationDate() const;
+
+ /** Set the value of the 'modification-date' property.
+ *
+ * @param date file modification time
+ */
+ void setModificationDate(const datetime& date);
+
+ /** Check whether the 'read-date' property is set.
+ *
+ * @return true if the 'read-date' property is set,
+ * false otherwise
+ */
+ bool hasReadDate() const;
+
+ /** Return the value of the 'read-date' property.
+ *
+ * @return file access time
+ */
+ const datetime& getReadDate() const;
+
+ /** Set the value of the 'read-date' property.
+ *
+ * @param date file access time
+ */
+ void setReadDate(const datetime& date);
+
+ /** Check whether the value of the 'size' property is set.
+ *
+ * @return true if the 'size' property is set,
+ * false otherwise
+ */
+ bool hasSize() const;
+
+ /** Return the value of the 'size' property.
+ *
+ * @return file size
+ */
+ size_t getSize() const;
+
+ /** Set the value of the 'size' property.
+ *
+ * @param size file size
+ */
+ void setSize(const size_t size);
+
+ private:
+
+ word* m_filename;
+ size_t * m_size;
+ datetime* m_creationDate;
+ datetime* m_modifDate;
+ datetime* m_readDate;
+ };
+
+ const fileInfo& getFileInfo() const;
+ fileInfo& getFileInfo();
+
+private:
+
+ void setData(const string& filepath);
+ void setData(const shared_ptr <contentHandler>& cts);
+
+ fileInfo m_fileInfo;
+
+ void generatePart(const shared_ptr <bodyPart>& part) const;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_HAVE_FILESYSTEM_FEATURES
+
+#endif // VMIME_FILEATTACHMENT_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/fileContentHandler.cpp b/vmime-master/src/vmime/fileContentHandler.cpp
new file mode 100644
index 0000000..baedf69
--- /dev/null
+++ b/vmime-master/src/vmime/fileContentHandler.cpp
@@ -0,0 +1,94 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_FILESYSTEM_FEATURES
+
+
+#include "vmime/fileContentHandler.hpp"
+
+
+namespace vmime {
+
+
+fileContentHandler::fileContentHandler()
+ : streamContentHandler() {
+
+}
+
+
+fileContentHandler::fileContentHandler(
+ const shared_ptr <utility::file>& file,
+ const vmime::encoding& enc
+) {
+
+ setData(file, enc);
+}
+
+
+fileContentHandler::~fileContentHandler() {
+
+}
+
+
+fileContentHandler::fileContentHandler(const fileContentHandler& cts)
+ : streamContentHandler() {
+
+ setData(cts.m_file, cts.m_encoding);
+}
+
+
+fileContentHandler& fileContentHandler::operator=(const fileContentHandler& cts) {
+
+ setData(cts.m_file, cts.m_encoding);
+
+ return *this;
+}
+
+
+shared_ptr <contentHandler> fileContentHandler::clone() const {
+
+ return make_shared <fileContentHandler>(*this);
+}
+
+
+void fileContentHandler::setData(
+ const shared_ptr <utility::file>& file,
+ const vmime::encoding& enc
+) {
+
+ m_file = file;
+ m_encoding = enc;
+
+ streamContentHandler::setData(
+ file->getFileReader()->getInputStream(), file->getLength(), enc
+ );
+}
+
+
+} // vmime
+
+
+#endif // VMIME_HAVE_FILESYSTEM_FEATURES
diff --git a/vmime-master/src/vmime/fileContentHandler.hpp b/vmime-master/src/vmime/fileContentHandler.hpp
new file mode 100644
index 0000000..80df069
--- /dev/null
+++ b/vmime-master/src/vmime/fileContentHandler.hpp
@@ -0,0 +1,102 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_FILECONTENTHANDLER_HPP_INCLUDED
+#define VMIME_FILECONTENTHANDLER_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_FILESYSTEM_FEATURES
+
+
+#include "vmime/streamContentHandler.hpp"
+#include "vmime/utility/file.hpp"
+
+
+namespace vmime {
+
+
+/** A content handler which obtains its data from a file.
+ */
+class VMIME_EXPORT fileContentHandler : public streamContentHandler {
+
+public:
+
+ /** Creates a new empty content handler. No data can be extracted until
+ * a file is attached using setData() function.
+ *
+ * @return a reference to a new content handler
+ */
+ fileContentHandler();
+
+ /** Creates a new content handler using a file.
+ *
+ * @param file file from which data will be obtained
+ * @param enc set to anything other than NO_ENCODING if the data contained
+ * in the file is already encoded with the specified encoding
+ *
+ * @return a reference to a new content handler
+ */
+ fileContentHandler(
+ const shared_ptr <utility::file>& file,
+ const vmime::encoding& enc = NO_ENCODING
+ );
+
+ ~fileContentHandler();
+
+ fileContentHandler(const fileContentHandler& cts);
+ fileContentHandler& operator=(const fileContentHandler& cts);
+
+ shared_ptr <contentHandler> clone() const;
+
+ /** Sets the data managed by this content handler.
+ *
+ * @param file file from which data will be obtained
+ * @param enc set to anything other than NO_ENCODING if the data contained
+ * in the file is already encoded with the specified encoding
+ */
+ void setData(
+ const shared_ptr <utility::file>& file,
+ const vmime::encoding& enc = NO_ENCODING
+ );
+
+private:
+
+ // Equals to NO_ENCODING if data is not encoded, otherwise this
+ // specifies the encoding that have been used to encode the data.
+ vmime::encoding m_encoding;
+
+ // Actual data
+ shared_ptr <utility::file> m_file;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_HAVE_FILESYSTEM_FEATURES
+
+
+#endif // VMIME_FILECONTENTHANDLER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/generatedMessageAttachment.cpp b/vmime-master/src/vmime/generatedMessageAttachment.cpp
new file mode 100644
index 0000000..ad9e678
--- /dev/null
+++ b/vmime-master/src/vmime/generatedMessageAttachment.cpp
@@ -0,0 +1,108 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/generatedMessageAttachment.hpp"
+
+#include "vmime/utility/outputStreamAdapter.hpp"
+
+
+namespace vmime {
+
+
+generatedMessageAttachment::generatedMessageAttachment(
+ const shared_ptr <const bodyPart>& part
+)
+ : m_bpa(make_shared <bodyPartAttachment>(part)) {
+
+}
+
+
+const mediaType generatedMessageAttachment::getType() const {
+
+ return mediaType(mediaTypes::MESSAGE, mediaTypes::MESSAGE_RFC822);
+}
+
+
+const text generatedMessageAttachment::getDescription() const {
+
+ return m_bpa->getDescription();
+}
+
+
+const word generatedMessageAttachment::getName() const {
+
+ return m_bpa->getName();
+}
+
+
+const shared_ptr <const contentHandler> generatedMessageAttachment::getData() const {
+
+ return m_bpa->getData();
+}
+
+
+const encoding generatedMessageAttachment::getEncoding() const {
+
+ return m_bpa->getEncoding();
+}
+
+
+shared_ptr <const object> generatedMessageAttachment::getPart() const {
+
+ return m_bpa->getPart();
+}
+
+
+shared_ptr <const header> generatedMessageAttachment::getHeader() const {
+
+ return m_bpa->getHeader();
+}
+
+
+shared_ptr <message> generatedMessageAttachment::getMessage() const {
+
+ if (!m_msg) {
+
+ // Extract data
+ std::ostringstream oss;
+ utility::outputStreamAdapter os(oss);
+
+ getData()->extract(os);
+
+ // Parse message
+ m_msg = make_shared <message>();
+ m_msg->parse(oss.str());
+ }
+
+ return m_msg;
+}
+
+
+void generatedMessageAttachment::generateIn(const shared_ptr <bodyPart>& /* parent */) const {
+
+ // Not used (see 'parsedMessageAttachment')
+}
+
+
+} // vmime
+
diff --git a/vmime-master/src/vmime/generatedMessageAttachment.hpp b/vmime-master/src/vmime/generatedMessageAttachment.hpp
new file mode 100644
index 0000000..b65fcc1
--- /dev/null
+++ b/vmime-master/src/vmime/generatedMessageAttachment.hpp
@@ -0,0 +1,77 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_GENERATEDMESSAGEATTACHMENT_HPP_INCLUDED
+#define VMIME_GENERATEDMESSAGEATTACHMENT_HPP_INCLUDED
+
+
+#ifndef VMIME_BUILDING_DOC // implementation detail
+
+
+#include "vmime/messageAttachment.hpp"
+#include "vmime/bodyPartAttachment.hpp"
+
+
+namespace vmime {
+
+
+/** A message attachment that can be extracted from a message.
+ */
+class VMIME_EXPORT generatedMessageAttachment : public messageAttachment {
+
+public:
+
+ generatedMessageAttachment(const shared_ptr <const bodyPart>& part);
+
+ const mediaType getType() const;
+ const text getDescription() const;
+ const word getName() const;
+
+ const shared_ptr <const contentHandler> getData() const;
+
+ const encoding getEncoding() const;
+
+ shared_ptr <const object> getPart() const;
+
+ shared_ptr <const header> getHeader() const;
+
+ shared_ptr <message> getMessage() const;
+
+protected:
+
+ void generateIn(const shared_ptr <bodyPart>& parent) const;
+
+private:
+
+ shared_ptr <bodyPartAttachment> m_bpa;
+ mutable shared_ptr <message> m_msg;
+};
+
+
+} // vmime
+
+
+#endif // !VMIME_BUILDING_DOC
+
+
+#endif // VMIME_GENERATEDMESSAGEATTACHMENT_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/generationContext.cpp b/vmime-master/src/vmime/generationContext.cpp
new file mode 100644
index 0000000..24757c7
--- /dev/null
+++ b/vmime-master/src/vmime/generationContext.cpp
@@ -0,0 +1,139 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/generationContext.hpp"
+
+
+namespace vmime {
+
+
+generationContext::generationContext()
+ : m_maxLineLength(lineLengthLimits::convenient),
+ m_prologText("This is a multi-part message in MIME format. Your mail reader " \
+ "does not understand MIME message format."),
+ m_epilogText(""),
+ m_wrapMessageId(true),
+ m_paramValueMode(PARAMETER_VALUE_RFC2231_ONLY) {
+
+}
+
+
+generationContext::generationContext(const generationContext& ctx)
+ : context(ctx),
+ m_maxLineLength(ctx.m_maxLineLength),
+ m_prologText(ctx.m_prologText),
+ m_epilogText(ctx.m_epilogText),
+ m_wrapMessageId(ctx.m_wrapMessageId),
+ m_paramValueMode(ctx.m_paramValueMode) {
+
+}
+
+
+generationContext& generationContext::getDefaultContext() {
+
+ static generationContext ctx;
+ return ctx;
+}
+
+
+size_t generationContext::getMaxLineLength() const {
+
+ return m_maxLineLength;
+}
+
+
+void generationContext::setMaxLineLength(const size_t maxLineLength) {
+
+ m_maxLineLength = maxLineLength;
+}
+
+
+
+const string generationContext::getPrologText() const {
+
+ return m_prologText;
+}
+
+
+void generationContext::setPrologText(const string& prologText) {
+
+ m_prologText = prologText;
+}
+
+
+const string generationContext::getEpilogText() const {
+
+ return m_epilogText;
+}
+
+
+void generationContext::setEpilogText(const string& epilogText) {
+
+ m_epilogText = epilogText;
+}
+
+
+bool generationContext::getWrapMessageId() const {
+
+ return m_wrapMessageId;
+}
+
+
+void generationContext::setWrapMessageId(const bool& wrapMessageId) {
+
+ m_wrapMessageId = wrapMessageId;
+}
+
+
+void generationContext::setEncodedParameterValueMode(const EncodedParameterValueModes mode) {
+
+ m_paramValueMode = mode;
+}
+
+
+generationContext::EncodedParameterValueModes
+ generationContext::getEncodedParameterValueMode() const {
+
+ return m_paramValueMode;
+}
+
+
+generationContext& generationContext::operator=(const generationContext& ctx) {
+
+ copyFrom(ctx);
+ return *this;
+}
+
+
+void generationContext::copyFrom(const generationContext& ctx) {
+
+ context::copyFrom(ctx);
+
+ m_maxLineLength = ctx.m_maxLineLength;
+ m_prologText = ctx.m_prologText;
+ m_epilogText = ctx.m_epilogText;
+ m_paramValueMode = ctx.m_paramValueMode;
+}
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/generationContext.hpp b/vmime-master/src/vmime/generationContext.hpp
new file mode 100644
index 0000000..5e36513
--- /dev/null
+++ b/vmime-master/src/vmime/generationContext.hpp
@@ -0,0 +1,171 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_GENERATIONCONTEXT_HPP_INCLUDED
+#define VMIME_GENERATIONCONTEXT_HPP_INCLUDED
+
+
+#include "vmime/context.hpp"
+
+
+namespace vmime {
+
+
+/** Holds configuration parameters used for generating messages.
+ */
+class VMIME_EXPORT generationContext : public context {
+
+public:
+
+ generationContext();
+ generationContext(const generationContext& ctx);
+
+ /** Returns the current maximum line length used when generating messages.
+ *
+ * @return current maximum line length, in bytes
+ */
+ size_t getMaxLineLength() const;
+
+ /** Sets the maximum line length used when generating messages.
+ * You may use the constants lineLengthLimits::convenient,
+ * lineLengthLimits::max and lineLengthLimits::infinite.
+ *
+ * @param maxLineLength new maximum line length, in bytes
+ */
+ void setMaxLineLength(const size_t maxLineLength);
+
+ /** Returns the current prolog text used when generating MIME body parts.
+ *
+ * @return current MIME prolog text
+ */
+ const string getPrologText() const;
+
+ /** Sets the prolog text used when generating MIME body parts. This text
+ * appears before the part, and should be displayed by MUAs which do not
+ * support MIME. This should be 7-bit ASCII text only.
+ *
+ * @param prologText MIME prolog text
+ */
+ void setPrologText(const string& prologText);
+
+ /** Returns the current epilog text used when generating MIME body parts.
+ *
+ * @return current MIME epilog text
+ */
+ const string getEpilogText() const;
+
+ /** Sets the epilog text used when generating MIME body parts. This test
+ * appears after the part, and should be displayed by MUAs which do not
+ * support MIME. This should be 7-bit ASCII text only.
+ */
+ void setEpilogText(const string& epilogText);
+
+ /** Returns a boolean variable that indicates whether the
+ * message id can be wrapped or not, i.e. from
+ *
+ * Message-Id: <very very long@domain>
+ *
+ * to
+ *
+ * Message-Id:
+ * <very very long@domain>
+ *
+ * @return boolean indicating if the Message-Id can be wrapped
+ */
+ bool getWrapMessageId() const;
+
+ /** Sets the boolean variable that indicates whether the
+ * Message-Id can be wrapped or not
+ */
+ void setWrapMessageId(const bool& wrapMessageId);
+
+ /** Modes available for generating values in parameterized header fields.
+ */
+ enum EncodedParameterValueModes {
+
+ PARAMETER_VALUE_NO_ENCODING, /**< Only generate 7-bit (ASCII-only) values,
+ even if the value contains non-ASCII chars or
+ if folding is needed. */
+ PARAMETER_VALUE_RFC2047_ONLY, /**< Only generate RFC-2047 values (do not use
+ RFC-2231). This is non-standard but most
+ mail clients support it. */
+ PARAMETER_VALUE_RFC2231_ONLY, /**< Only generate RFC-2231 values (do not use
+ RFC-2047). Some mail clients may not support
+ it. This is the default. */
+ PARAMETER_VALUE_RFC2231_AND_RFC2047 /**< Generate both RFC-2047- and RFC-2231-encoded
+ values. */
+ };
+
+ /** Sets the mode used for generating parameter values in a parameterized
+ * header field (see parameterizedHeaderField class).
+ *
+ * PARAMETER_VALUE_NO_ENCODING or PARAMETER_VALUE_RFC2047_ONLY
+ * can be used for compatibility with implementations that do not
+ * understand RFC-2231, to generate a normal parameter value.
+ * PARAMETER_VALUE_RFC2047_ONLY is non-standard (and expressly
+ * prohibited by the RFC) but most mail clients support it.
+ *
+ * Notice: if both the normal value and the extended value are present,
+ * the latter can be ignored by mail processing systems. This may lead
+ * to annoying problems, for example, with strange names of attachments
+ * with all but 7-bit ascii characters removed, etc. Either
+ * PARAMETER_VALUE_RFC2231_ONLY or PARAMETER_VALUE_RFC2047_ONLY should
+ * be preferred over PARAMETER_VALUE_RFC2231_AND_RFC2047, not to create
+ * a normal value if the extended value is to be generated.
+ *
+ * @param mode parameter value generation mode
+ */
+ void setEncodedParameterValueMode(const EncodedParameterValueModes mode);
+
+ /** Returns the mode used for generating parameter values in a parameterized
+ * header field (see parameterizedHeaderField class).
+ *
+ * @return parameter value generation mode
+ */
+ EncodedParameterValueModes getEncodedParameterValueMode() const;
+
+ /** Returns the default context used for generating messages.
+ *
+ * @return a reference to the default generation context
+ */
+ static generationContext& getDefaultContext();
+
+ generationContext& operator=(const generationContext& ctx);
+ void copyFrom(const generationContext& ctx);
+
+protected:
+
+ size_t m_maxLineLength;
+
+ string m_prologText;
+ string m_epilogText;
+ bool m_wrapMessageId;
+
+ EncodedParameterValueModes m_paramValueMode;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_GENERATIONCONTEXT_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/header.cpp b/vmime-master/src/vmime/header.cpp
new file mode 100644
index 0000000..c7d7ca0
--- /dev/null
+++ b/vmime-master/src/vmime/header.cpp
@@ -0,0 +1,417 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/header.hpp"
+#include "vmime/parserHelpers.hpp"
+
+#include <algorithm>
+#include <iterator>
+
+
+namespace vmime {
+
+
+header::header() {
+
+}
+
+
+header::~header() {
+
+ removeAllFields();
+}
+
+
+/*
+
+ RFC #822:
+ 3.2. HEADER FIELD DEFINITIONS
+
+field = field-name ":" [ field-body ] CRLF
+
+field-name = 1*<any CHAR, excluding CTLs, SPACE, and ":">
+
+field-body = field-body-contents
+ [CRLF LWSP-char field-body]
+
+field-body-contents =
+ <the ASCII characters making up the field-body, as
+ defined in the following sections, and consisting
+ of combinations of atom, quoted-string, and
+ specials tokens, or else consisting of texts>
+*/
+
+void header::parseImpl(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition
+) {
+
+ size_t pos = position;
+
+ removeAllFields();
+
+ while (pos < end) {
+
+ shared_ptr <headerField> field = headerField::parseNext(ctx, buffer, pos, end, &pos);
+ if (!field) break;
+
+ m_fields.push_back(field);
+ }
+
+ setParsedBounds(position, pos);
+
+ if (newPosition) {
+ *newPosition = pos;
+ }
+}
+
+
+void header::generateImpl(
+ const generationContext& ctx,
+ utility::outputStream& os,
+ const size_t /* curLinePos */,
+ size_t* newLinePos
+) const {
+
+ // Generate the fields
+ for (std::vector <shared_ptr <headerField> >::const_iterator it = m_fields.begin() ;
+ it != m_fields.end() ; ++it) {
+
+ (*it)->generate(ctx, os);
+ os << CRLF;
+ }
+
+ if (newLinePos) {
+ *newLinePos = 0;
+ }
+}
+
+
+size_t header::getGeneratedSize(const generationContext& ctx) {
+
+ return component::getGeneratedSize(ctx) + 2 * m_fields.size() /* CRLF */;
+}
+
+
+shared_ptr <component> header::clone() const {
+
+ shared_ptr <header> hdr = make_shared <header>();
+
+ hdr->m_fields.reserve(m_fields.size());
+
+ for (std::vector <shared_ptr <headerField> >::const_iterator it = m_fields.begin() ;
+ it != m_fields.end() ; ++it) {
+
+ hdr->m_fields.push_back(vmime::clone(*it));
+ }
+
+ return hdr;
+}
+
+
+void header::copyFrom(const component& other) {
+
+ const header& h = dynamic_cast <const header&>(other);
+
+ std::vector <shared_ptr <headerField> > fields;
+
+ fields.reserve(h.m_fields.size());
+
+ for (std::vector <shared_ptr <headerField> >::const_iterator it = h.m_fields.begin() ;
+ it != h.m_fields.end() ; ++it) {
+
+ fields.push_back(vmime::clone(*it));
+ }
+
+ m_fields.clear();
+ m_fields.resize(fields.size());
+
+ std::copy(fields.begin(), fields.end(), m_fields.begin());
+}
+
+
+header& header::operator=(const header& other) {
+
+ copyFrom(other);
+ return *this;
+}
+
+
+bool header::hasField(const string& fieldName) const {
+
+ std::vector <shared_ptr <headerField> >::const_iterator pos =
+ std::find_if(
+ m_fields.begin(), m_fields.end(),
+ fieldHasName(utility::stringUtils::toLower(fieldName))
+ );
+
+ return pos != m_fields.end();
+}
+
+
+shared_ptr <headerField> header::findField(const string& fieldName) const {
+
+ // Find the first field that matches the specified name
+ std::vector <shared_ptr <headerField> >::const_iterator pos =
+ std::find_if(
+ m_fields.begin(), m_fields.end(),
+ fieldHasName(utility::stringUtils::toLower(fieldName))
+ );
+
+ // No field with this name can be found
+ if (pos == m_fields.end()) {
+ return null;
+ }
+
+ // Else, return a reference to the existing field
+ return *pos;
+}
+
+
+std::vector <shared_ptr <headerField> > header::findAllFields(const string& fieldName) {
+
+ std::vector <shared_ptr <headerField> > result;
+ std::back_insert_iterator <std::vector <shared_ptr <headerField> > > back(result);
+
+ std::remove_copy_if(
+ m_fields.begin(), m_fields.end(), back,
+ fieldHasNotName(utility::stringUtils::toLower(fieldName))
+ );
+
+ return result;
+}
+
+
+shared_ptr <headerField> header::getField(const string& fieldName) {
+
+ const string name = utility::stringUtils::toLower(fieldName);
+
+ // Find the first field that matches the specified name
+ std::vector <shared_ptr <headerField> >::const_iterator pos = m_fields.begin();
+ const std::vector <shared_ptr <headerField> >::const_iterator end = m_fields.end();
+
+ while (pos != end && utility::stringUtils::toLower((*pos)->getName()) != name) {
+ ++pos;
+ }
+
+ // If no field with this name can be found, create a new one
+ if (pos == end) {
+
+ shared_ptr <headerField> field = headerFieldFactory::getInstance()->create(fieldName);
+
+ appendField(field);
+
+ // Return a reference to the new field
+ return (field);
+
+ // Else, return a reference to the existing field
+ } else {
+
+ return *pos;
+ }
+}
+
+
+void header::appendField(const shared_ptr <headerField>& field) {
+
+ m_fields.push_back(field);
+}
+
+
+void header::insertFieldBefore(
+ const shared_ptr <headerField>& beforeField,
+ const shared_ptr <headerField>& field
+) {
+
+ const std::vector <shared_ptr <headerField> >::iterator it =
+ std::find(m_fields.begin(), m_fields.end(), beforeField);
+
+ if (it == m_fields.end()) {
+ throw exceptions::no_such_field();
+ }
+
+ m_fields.insert(it, field);
+}
+
+
+void header::insertFieldBefore(const size_t pos, const shared_ptr <headerField>& field) {
+
+ m_fields.insert(m_fields.begin() + pos, field);
+}
+
+
+void header::insertFieldAfter(
+ const shared_ptr <headerField>& afterField,
+ const shared_ptr <headerField>& field
+) {
+
+ const std::vector <shared_ptr <headerField> >::iterator it =
+ std::find(m_fields.begin(), m_fields.end(), afterField);
+
+ if (it == m_fields.end()) {
+ throw exceptions::no_such_field();
+ }
+
+ m_fields.insert(it + 1, field);
+}
+
+
+void header::insertFieldAfter(const size_t pos, const shared_ptr <headerField>& field) {
+
+ m_fields.insert(m_fields.begin() + pos + 1, field);
+}
+
+
+void header::removeField(const shared_ptr <headerField>& field) {
+
+ const std::vector <shared_ptr <headerField> >::iterator it =
+ std::find(m_fields.begin(), m_fields.end(), field);
+
+ if (it == m_fields.end()) {
+ throw exceptions::no_such_field();
+ }
+
+ m_fields.erase(it);
+}
+
+
+void header::removeField(const size_t pos) {
+
+ const std::vector <shared_ptr <headerField> >::iterator it = m_fields.begin() + pos;
+
+ m_fields.erase(it);
+}
+
+
+void header::replaceField(
+ const shared_ptr <headerField>& field,
+ const shared_ptr <headerField>& newField
+) {
+
+ insertFieldBefore(field, newField);
+ removeField(field);
+}
+
+
+void header::removeAllFields() {
+
+ m_fields.clear();
+}
+
+
+void header::removeAllFields(const string& fieldName) {
+
+ std::vector <shared_ptr <headerField> > fields = findAllFields(fieldName);
+
+ for (unsigned int i = 0 ; i < fields.size() ; ++i) {
+ removeField(fields[i]);
+ }
+}
+
+
+size_t header::getFieldCount() const {
+
+ return m_fields.size();
+}
+
+
+bool header::isEmpty() const {
+
+ return m_fields.empty();
+}
+
+
+const shared_ptr <headerField> header::getFieldAt(const size_t pos) {
+
+ return m_fields[pos];
+}
+
+
+const shared_ptr <const headerField> header::getFieldAt(const size_t pos) const {
+
+ return m_fields[pos];
+}
+
+
+const std::vector <shared_ptr <const headerField> > header::getFieldList() const {
+
+ std::vector <shared_ptr <const headerField> > list;
+
+ list.reserve(m_fields.size());
+
+ for (std::vector <shared_ptr <headerField> >::const_iterator it = m_fields.begin() ;
+ it != m_fields.end() ; ++it) {
+
+ list.push_back(*it);
+ }
+
+ return list;
+}
+
+
+const std::vector <shared_ptr <headerField> > header::getFieldList() {
+
+ return m_fields;
+}
+
+
+const std::vector <shared_ptr <component> > header::getChildComponents() {
+
+ std::vector <shared_ptr <component> > list;
+
+ copy_vector(m_fields, list);
+
+ return list;
+}
+
+
+
+// Field search
+
+
+header::fieldHasName::fieldHasName(const string& name)
+ : m_name(name) {
+
+}
+
+bool header::fieldHasName::operator() (const shared_ptr <const headerField>& field) {
+
+ return utility::stringUtils::toLower(field->getName()) == m_name;
+}
+
+
+header::fieldHasNotName::fieldHasNotName(const string& name)
+ : m_name(name) {
+
+}
+
+bool header::fieldHasNotName::operator() (const shared_ptr <const headerField>& field) {
+
+ return utility::stringUtils::toLower(field->getName()) != m_name;
+}
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/header.hpp b/vmime-master/src/vmime/header.hpp
new file mode 100644
index 0000000..7b4a161
--- /dev/null
+++ b/vmime-master/src/vmime/header.hpp
@@ -0,0 +1,362 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_HEADER_HPP_INCLUDED
+#define VMIME_HEADER_HPP_INCLUDED
+
+
+#include "vmime/base.hpp"
+#include "vmime/component.hpp"
+#include "vmime/exception.hpp"
+
+#include "vmime/headerField.hpp"
+#include "vmime/headerFieldFactory.hpp"
+
+
+namespace vmime {
+
+
+class bodyPart;
+
+
+/** Header section of a MIME part.
+ */
+class VMIME_EXPORT header : public component {
+
+ friend class bodyPart;
+ friend class body;
+ friend class message;
+
+public:
+
+ header();
+ ~header();
+
+#define FIELD_ACCESS(methodName, fieldName) \
+ shared_ptr <headerField> methodName() { return getField(fields::fieldName); } \
+ shared_ptr <const headerField> methodName() const { return findField(fields::fieldName); }
+
+ FIELD_ACCESS(From, FROM)
+ FIELD_ACCESS(Sender, SENDER)
+ FIELD_ACCESS(ReplyTo, REPLY_TO)
+ FIELD_ACCESS(DeliveredTo, DELIVERED_TO)
+ FIELD_ACCESS(InReplyTo, IN_REPLY_TO)
+ FIELD_ACCESS(ReturnPath, RETURN_PATH)
+ FIELD_ACCESS(References, REFERENCES)
+
+ FIELD_ACCESS(To, TO)
+ FIELD_ACCESS(Cc, CC)
+ FIELD_ACCESS(Bcc, BCC)
+ FIELD_ACCESS(Date, DATE)
+ FIELD_ACCESS(Subject, SUBJECT)
+ FIELD_ACCESS(Organization, ORGANIZATION)
+ FIELD_ACCESS(UserAgent, USER_AGENT)
+
+ FIELD_ACCESS(ContentType, CONTENT_TYPE)
+ FIELD_ACCESS(ContentDescription, CONTENT_DESCRIPTION)
+ FIELD_ACCESS(ContentTransferEncoding, CONTENT_TRANSFER_ENCODING)
+ FIELD_ACCESS(MimeVersion, MIME_VERSION)
+ FIELD_ACCESS(ContentDisposition, CONTENT_DISPOSITION)
+ FIELD_ACCESS(ContentId, CONTENT_ID)
+ FIELD_ACCESS(MessageId, MESSAGE_ID)
+ FIELD_ACCESS(ContentLocation, CONTENT_LOCATION)
+
+ FIELD_ACCESS(OriginalMessageId, ORIGINAL_MESSAGE_ID)
+ FIELD_ACCESS(Disposition, DISPOSITION)
+ FIELD_ACCESS(DispositionNotificationTo, DISPOSITION_NOTIFICATION_TO)
+
+#undef FIELD_ACCESS
+
+ /** Checks whether (at least) one field with this name exists.
+ * Field name is case-insensitive.
+ *
+ * @return true if at least one field with the specified name
+ * exists, or false otherwise
+ */
+ bool hasField(const string& fieldName) const;
+
+ /** Find the first field that matches the specified name.
+ * Field name is case-insensitive.
+ * If no field is found, NULL is returned.
+ *
+ * @param fieldName name of field to return (eg: "X-Mailer" or "From",
+ * common field names are available in the vmime::fields namespace)
+ * @return first field with the specified name, or NULL if no field
+ * with this name was found
+ */
+ shared_ptr <headerField> findField(const string& fieldName) const;
+
+ /** Find the first field that matches the specified name,
+ * casted to the specified field type. Field name is case-insensitive.
+ * If no field is found, or the field is not of the specified type,
+ * NULL is returned.
+ *
+ * @param fieldName name of field whose value is to be returned
+ * (eg: "X-Mailer" or "From", common field names are available in
+ * the vmime::fields namespace)
+ * @return first field with the specified name, or NULL if no field
+ * with this name was found
+ */
+ template <typename T>
+ shared_ptr <T> findField(const string& fieldName) const {
+
+ return dynamicCast <T>(findField(fieldName));
+ }
+
+ /** Find the value of the first field that matches the specified name,
+ * casted to the specified value type. Field name is case-insensitive.
+ * If no field is found, or the field value is not of the specified
+ * type, NULL is returned.
+ *
+ * @param fieldName name of field to return (eg: "X-Mailer" or "From",
+ * common field names are available in the vmime::fields namespace)
+ * @return value of the first field with the specified name, or NULL
+ * if no field with this name was found, or the value is not of the
+ * specified type
+ */
+ template <typename T>
+ shared_ptr <T> findFieldValue(const string& fieldName) const {
+
+ shared_ptr <headerField> field = findField(fieldName);
+
+ if (field) {
+ return dynamicCast <T>(field->getValue());
+ } else {
+ return null;
+ }
+ }
+
+ /** Find all fields that match the specified name.
+ * If no field is found, an empty vector is returned.
+ *
+ * @param fieldName name of field to return (eg: "X-Mailer" or "From",
+ * common field names are available in the vmime::fields namespace)
+ * @return list of fields with the specified name
+ */
+ std::vector <shared_ptr <headerField> > findAllFields(const string& fieldName);
+
+ /** Find the first field that matches the specified name.
+ * If no field is found, one will be created and inserted into
+ * the header.
+ *
+ * @param fieldName name of field to return (eg: "X-Mailer" or "From",
+ * common field names are available in the vmime::fields namespace)
+ * @return first field with the specified name or a new field
+ * if no field is found
+ */
+ shared_ptr <headerField> getField(const string& fieldName);
+
+ /** Find the first field that matches the specified name,
+ * casted to the specified type.
+ * If no field is found, one will be created and inserted into
+ * the header.
+ *
+ * @return first field with the specified name or a new field
+ * if no field is found
+ */
+ template <typename T>
+ shared_ptr <T> getField(const string& fieldName) {
+
+ return dynamicCast <T>(getField(fieldName));
+ }
+
+ /** Add a field at the end of the list.
+ *
+ * @param field field to append
+ */
+ void appendField(const shared_ptr <headerField>& field);
+
+ /** Insert a new field before the specified field.
+ *
+ * @param beforeField field before which the new field will be inserted
+ * @param field field to insert
+ * @throw exceptions::no_such_field if the field is not in the list
+ */
+ void insertFieldBefore(
+ const shared_ptr <headerField>& beforeField,
+ const shared_ptr <headerField>& field
+ );
+
+ /** Insert a new field before the specified position.
+ *
+ * @param pos position at which to insert the new field (0 to insert at
+ * the beginning of the list)
+ * @param field field to insert
+ */
+ void insertFieldBefore(
+ const size_t pos,
+ const shared_ptr <headerField>& field
+ );
+
+ /** Insert a new field after the specified field.
+ *
+ * @param afterField field after which the new field will be inserted
+ * @param field field to insert
+ * @throw exceptions::no_such_field if the field is not in the list
+ */
+ void insertFieldAfter(
+ const shared_ptr <headerField>& afterField,
+ const shared_ptr <headerField>& field
+ );
+
+ /** Insert a new field after the specified position.
+ *
+ * @param pos position of the field before the new field
+ * @param field field to insert
+ */
+ void insertFieldAfter(
+ const size_t pos,
+ const shared_ptr <headerField>& field
+ );
+
+ /** Remove the specified field from the list.
+ *
+ * @param field field to remove
+ * @throw exceptions::no_such_field if the field is not in the list
+ */
+ void removeField(const shared_ptr <headerField>& field);
+
+ /** Remove the field at the specified position.
+ *
+ * @param pos position of the field to remove
+ */
+ void removeField(const size_t pos);
+
+ /** Replaces a field with another field.
+ *
+ * @param field field to be replaced
+ * @param newField field to replace with
+ * @throw exceptions::no_such_field if the field is not in the list
+ */
+ void replaceField(
+ const shared_ptr <headerField>& field,
+ const shared_ptr <headerField>& newField
+ );
+
+ /** Remove all fields from the list.
+ */
+ void removeAllFields();
+
+ /** Remove all fields with the specified name.
+ */
+ void removeAllFields(const string& fieldName);
+
+ /** Return the number of fields in the list.
+ *
+ * @return number of fields
+ */
+ size_t getFieldCount() const;
+
+ /** Tests whether the list of fields is empty.
+ *
+ * @return true if there is no field, false otherwise
+ */
+ bool isEmpty() const;
+
+ /** Return the field at the specified position.
+ *
+ * @param pos position
+ * @return field at position 'pos'
+ */
+ const shared_ptr <headerField> getFieldAt(const size_t pos);
+
+ /** Return the field at the specified position.
+ *
+ * @param pos position
+ * @return field at position 'pos'
+ */
+ const shared_ptr <const headerField> getFieldAt(const size_t pos) const;
+
+ /** Return the field list.
+ *
+ * @return list of fields
+ */
+ const std::vector <shared_ptr <const headerField> > getFieldList() const;
+
+ /** Return the field list.
+ *
+ * @return list of fields
+ */
+ const std::vector <shared_ptr <headerField> > getFieldList();
+
+ shared_ptr <component> clone() const;
+ void copyFrom(const component& other);
+ header& operator=(const header& other);
+
+ const std::vector <shared_ptr <component> > getChildComponents();
+
+ size_t getGeneratedSize(const generationContext& ctx);
+
+private:
+
+ std::vector <shared_ptr <headerField> > m_fields;
+
+
+ class fieldHasName {
+
+ public:
+
+ fieldHasName(const string& name);
+ bool operator() (const shared_ptr <const headerField>& field);
+
+ private:
+
+ string m_name;
+ };
+
+ class fieldHasNotName {
+
+ public:
+
+ fieldHasNotName(const string& name);
+ bool operator() (const shared_ptr <const headerField>& field);
+
+ private:
+
+ string m_name;
+ };
+
+protected:
+
+ // Component parsing & assembling
+ void parseImpl(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition = NULL
+ );
+
+ void generateImpl(
+ const generationContext& ctx,
+ utility::outputStream& os,
+ const size_t curLinePos = 0,
+ size_t* newLinePos = NULL
+ ) const;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_HEADER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/headerField.cpp b/vmime-master/src/vmime/headerField.cpp
new file mode 100644
index 0000000..bff365d
--- /dev/null
+++ b/vmime-master/src/vmime/headerField.cpp
@@ -0,0 +1,374 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/headerField.hpp"
+#include "vmime/headerFieldFactory.hpp"
+
+#include "vmime/parserHelpers.hpp"
+
+#include "vmime/exception.hpp"
+
+
+namespace vmime {
+
+
+headerField::headerField()
+ : m_name("X-Undefined") {
+
+}
+
+
+headerField::headerField(const string& fieldName)
+ : m_name(fieldName) {
+
+}
+
+
+headerField::~headerField() {
+
+}
+
+
+shared_ptr <component> headerField::clone() const {
+
+ shared_ptr <headerField> field = headerFieldFactory::getInstance()->create(m_name);
+
+ field->copyFrom(*this);
+
+ return field;
+}
+
+
+void headerField::copyFrom(const component& other) {
+
+ const headerField& hf = dynamic_cast <const headerField&>(other);
+
+ m_value->copyFrom(*hf.m_value);
+}
+
+
+headerField& headerField::operator=(const headerField& other) {
+
+ copyFrom(other);
+ return *this;
+}
+
+
+shared_ptr <headerField> headerField::parseNext(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition
+) {
+
+ size_t pos = position;
+
+ while (pos < end) {
+
+ char_t c = buffer[pos];
+
+ // Check for end of headers (empty line): although RFC-822 recommends
+ // to use CRLF for header/body separator (see 4.1 SYNTAX), here, we
+ // also check for LF for compatibility with broken implementations...
+ if (c == '\n') {
+
+ if (newPosition) {
+ *newPosition = pos + 1; // LF: illegal
+ }
+
+ return null;
+
+ } else if (c == '\r' && pos + 1 < end && buffer[pos + 1] == '\n') {
+
+ if (newPosition) {
+ *newPosition = pos + 2; // CR+LF
+ }
+
+ return null;
+ }
+
+ // This line may be a field description
+ if (!parserHelpers::isSpace(c)) {
+
+ const size_t nameStart = pos; // remember the start position of the line
+
+ while (pos < end && (buffer[pos] != ':' && !parserHelpers::isSpace(buffer[pos]))) {
+ ++pos;
+ }
+
+ const size_t nameEnd = pos;
+
+ while (pos < end && (buffer[pos] == ' ' || buffer[pos] == '\t')) {
+ ++pos;
+ }
+
+ if (buffer[pos] != ':') {
+
+ switch (ctx.getHeaderParseErrorRecoveryMethod()) {
+
+ case vmime::headerParseRecoveryMethod::SKIP_LINE:
+ // Humm...does not seem to be a valid header line.
+ // Skip this error and advance to the next line
+ pos = nameStart;
+
+ while (pos < end && buffer[pos] != '\n') {
+ ++pos;
+ }
+
+ if (pos < end && buffer[pos] == '\n') {
+ ++pos;
+ }
+
+ break;
+
+// case vmime::headerParseRecoveryMethod::APPEND_TO_PREVIOUS_LINE:
+//
+// // TODO Implement this...
+// break;
+
+ case vmime::headerParseRecoveryMethod::ASSUME_END_OF_HEADERS:
+
+ return null;
+ break;
+ }
+
+ } else {
+
+ // Extract the field name
+ const string name(
+ buffer.begin() + nameStart,
+ buffer.begin() + nameEnd
+ );
+
+ // Skip ':' character
+ while (pos < end && buffer[pos] == ':') {
+ ++pos;
+ }
+
+ // Skip spaces between ':' and the field contents
+ while (pos < end && (buffer[pos] == ' ' || buffer[pos] == '\t')) {
+ ++pos;
+ }
+
+ const size_t contentsStart = pos;
+ size_t contentsEnd = 0;
+
+ bool firstLine = true;
+
+ // Parse field value, taking care of line folding (value on multiple lines)
+ for (size_t eol = 0 ; parserHelpers::findEOL(buffer, pos, end, &eol) ; pos = eol) {
+
+ // If the line does not start with a folding indicator (SPACE or TAB),
+ // and this is not the first line, then stop parsing lines
+ if (!firstLine && !(buffer[pos] == ' ' || buffer[pos] == '\t')) {
+ break;
+ }
+
+ contentsEnd = eol;
+ firstLine = false;
+ }
+
+ if (pos == end && contentsEnd == 0) {
+
+ // End of data, and no CRLF was found at the end
+ contentsEnd = end;
+ }
+
+ // Strip spaces from end of header lines
+ while (contentsEnd > contentsStart &&
+ (buffer[contentsEnd - 1] == ' ' || buffer[contentsEnd - 1] == '\t' ||
+ buffer[contentsEnd - 1] == '\r' || buffer[contentsEnd - 1] == '\n')) {
+
+ contentsEnd--;
+ }
+
+ // Return a new field
+ shared_ptr <headerField> field = headerFieldFactory::getInstance()->create(name);
+
+ field->parse(ctx, buffer, contentsStart, contentsEnd, NULL);
+ field->setParsedBounds(nameStart, pos);
+
+ if (newPosition) {
+ *newPosition = pos;
+ }
+
+ return field;
+ }
+
+ } else {
+
+ // If the line contains only space characters, we assume it is
+ // the end of the headers.
+ while (pos < end && (buffer[pos] == ' ' || buffer[pos] == '\t')) {
+ ++pos;
+ }
+
+ if (pos < end && buffer[pos] == '\n') {
+
+ if (newPosition) {
+ *newPosition = pos + 1; // LF: illegal
+ }
+
+ return null;
+
+ } else if (pos + 1 < end && buffer[pos] == '\r' && buffer[pos + 1] == '\n') {
+
+ if (newPosition) {
+ *newPosition = pos + 2; // CR+LF
+ }
+
+ return null;
+ }
+
+ // Skip this error and advance to the next line
+ while (pos < end && buffer[pos] != '\n') {
+ ++pos;
+ }
+
+ if (buffer[pos] == '\n') {
+ ++pos;
+ }
+ }
+ }
+
+ if (newPosition) {
+ *newPosition = pos;
+ }
+
+ return null;
+}
+
+
+void headerField::parseImpl(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition
+) {
+
+ m_value->parse(ctx, buffer, position, end, newPosition);
+}
+
+
+void headerField::generateImpl(
+ const generationContext& ctx,
+ utility::outputStream& os,
+ const size_t curLinePos,
+ size_t* newLinePos
+) const {
+
+ os << m_name + ": ";
+
+ m_value->generate(ctx, os, curLinePos + m_name.length() + 2, newLinePos);
+}
+
+
+size_t headerField::getGeneratedSize(const generationContext& ctx) {
+
+ return m_name.length() + 2 /* ": " */ + m_value->getGeneratedSize(ctx);
+}
+
+
+const string headerField::getName() const {
+
+ return m_name;
+}
+
+
+void headerField::setName(const string& name) {
+
+ m_name = name;
+}
+
+
+bool headerField::isCustom() const {
+
+ return m_name.length() > 2 && m_name[0] == 'X' && m_name[1] == '-';
+}
+
+
+const std::vector <shared_ptr <component> > headerField::getChildComponents() {
+
+ std::vector <shared_ptr <component> > list;
+
+ if (m_value) {
+ list.push_back(m_value);
+ }
+
+ return list;
+}
+
+
+shared_ptr <const headerFieldValue> headerField::getValue() const {
+
+ return m_value;
+}
+
+
+shared_ptr <headerFieldValue> headerField::getValue() {
+
+ return m_value;
+}
+
+
+void headerField::setValue(const shared_ptr <headerFieldValue>& value) {
+
+ if (!headerFieldFactory::getInstance()->isValueTypeValid(*this, *value)) {
+ throw exceptions::bad_field_value_type(getName());
+ }
+
+ if (value != NULL) {
+ m_value = value;
+ }
+}
+
+
+void headerField::setValueConst(const shared_ptr <const headerFieldValue>& value) {
+
+ if (!headerFieldFactory::getInstance()->isValueTypeValid(*this, *value)) {
+ throw exceptions::bad_field_value_type(getName());
+ }
+
+ m_value = vmime::clone(value);
+}
+
+
+void headerField::setValue(const headerFieldValue& value) {
+
+ if (!headerFieldFactory::getInstance()->isValueTypeValid(*this, value)) {
+ throw exceptions::bad_field_value_type(getName());
+ }
+
+ m_value = vmime::clone(value);
+}
+
+
+void headerField::setValue(const string& value) {
+
+ parse(value);
+}
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/headerField.hpp b/vmime-master/src/vmime/headerField.hpp
new file mode 100644
index 0000000..66e9946
--- /dev/null
+++ b/vmime-master/src/vmime/headerField.hpp
@@ -0,0 +1,191 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_HEADERFIELD_HPP_INCLUDED
+#define VMIME_HEADERFIELD_HPP_INCLUDED
+
+
+#include "vmime/base.hpp"
+#include "vmime/component.hpp"
+#include "vmime/headerFieldValue.hpp"
+
+
+namespace vmime {
+
+
+/** Base class for header fields.
+ */
+class VMIME_EXPORT headerField : public component {
+
+ friend class headerFieldFactory;
+ friend class header;
+
+protected:
+
+ // Protected constructor to prevent the user from creating
+ // new objects without using 'headerFieldFactory'
+ headerField();
+ headerField(const string& fieldName);
+
+public:
+
+ ~headerField();
+
+ shared_ptr <component> clone() const;
+ void copyFrom(const component& other);
+ headerField& operator=(const headerField& other);
+
+ const std::vector <shared_ptr <component> > getChildComponents();
+
+ /** Sets the name of this field.
+ *
+ * @param name field name (eg: "From" or "X-MyField").
+ */
+ void setName(const string& name);
+
+ /** Return the name of this field.
+ *
+ * @return field name
+ */
+ const string getName() const;
+
+ /** Check whether this field is a custom (non-standard) field.
+ * Custom fields have a name beginning with "X-".
+ *
+ * @return true if the field is a custom field, false otherwise
+ */
+ bool isCustom() const;
+
+ /** Return the read-only value object attached to this field.
+ *
+ * @return read-only value object
+ */
+ virtual shared_ptr <const headerFieldValue> getValue() const;
+
+ /** Return the read-only value object attached to this field,
+ * casted to the specified type.
+ *
+ * @return value object
+ */
+ template <typename T>
+ shared_ptr <const T> getValue() const {
+
+ return dynamicCast <const T>(m_value);
+ }
+
+ /** Return the value object attached to this field.
+ *
+ * @return value object
+ */
+ virtual shared_ptr <headerFieldValue> getValue();
+
+ /** Return the value object attached to this field,
+ * casted to the specified type.
+ *
+ * @return value object
+ */
+ template <typename T>
+ shared_ptr <T> getValue() {
+
+ return dynamicCast <T>(m_value);
+ }
+
+ /** Set the value of this field.
+ *
+ * @throw exceptions::bad_field_value_type if the value type is not
+ * valid for this header field
+ * @param value new value
+ */
+ virtual void setValue(const shared_ptr <headerFieldValue>& value);
+
+ /** Set the value of this field by cloning the specified value.
+ *
+ * @throw exceptions::bad_field_value_type if the value type is not
+ * valid for this header field
+ * @param value new value
+ */
+ virtual void setValueConst(const shared_ptr <const headerFieldValue>& value);
+
+ /** Set the value of this field (reference version).
+ * The value will be cloned.
+ *
+ * @throw exceptions::bad_field_value_type if the value type is not
+ * valid for this header field
+ * @param value new value
+ */
+ virtual void setValue(const headerFieldValue& value);
+
+ /** Set the value of this field given a character string.
+ *
+ * @param value value string to parse
+ */
+ void setValue(const string& value);
+
+
+ /** Parse a header field from a buffer.
+ *
+ * @param ctx parsing context
+ * @param buffer input buffer
+ * @param position current position in the input buffer
+ * @param end end position in the input buffer
+ * @param newPosition will receive the new position in the input buffer
+ * @return parsed header field, or NULL if no more header field can be parsed
+ * in the input buffer
+ */
+ static shared_ptr <headerField> parseNext(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition = NULL
+ );
+
+ size_t getGeneratedSize(const generationContext& ctx);
+
+protected:
+
+ void parseImpl(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition = NULL
+ );
+
+ void generateImpl(
+ const generationContext& ctx,
+ utility::outputStream& os,
+ const size_t curLinePos = 0,
+ size_t* newLinePos = NULL
+ ) const;
+
+
+ string m_name;
+ shared_ptr <headerFieldValue> m_value;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_HEADERFIELD_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/headerFieldFactory.cpp b/vmime-master/src/vmime/headerFieldFactory.cpp
new file mode 100644
index 0000000..db281fa
--- /dev/null
+++ b/vmime-master/src/vmime/headerFieldFactory.cpp
@@ -0,0 +1,158 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/headerFieldFactory.hpp"
+#include "vmime/exception.hpp"
+
+#include "vmime/mailboxList.hpp"
+#include "vmime/dateTime.hpp"
+#include "vmime/text.hpp"
+#include "vmime/path.hpp"
+#include "vmime/relay.hpp"
+#include "vmime/encoding.hpp"
+#include "vmime/disposition.hpp"
+#include "vmime/messageIdSequence.hpp"
+
+#include "vmime/contentTypeField.hpp"
+#include "vmime/contentDispositionField.hpp"
+#include "vmime/mailboxField.hpp"
+
+
+namespace vmime {
+
+
+headerFieldFactory::headerFieldFactory() {
+
+ // Register parameterized fields
+ registerField <contentTypeField>(vmime::fields::CONTENT_TYPE);
+ registerField <parameterizedHeaderField>(vmime::fields::CONTENT_TRANSFER_ENCODING);
+ registerField <contentDispositionField>(vmime::fields::CONTENT_DISPOSITION);
+
+ registerField <mailboxField>(vmime::fields::FROM);
+ registerField <mailboxField>(vmime::fields::SENDER);
+ registerField <mailboxField>(vmime::fields::REPLY_TO);
+ registerField <mailboxField>(vmime::fields::DELIVERED_TO);
+
+ // Register standard field values
+ registerFieldValue <mailbox>(vmime::fields::FROM);
+ registerFieldValue <addressList>(vmime::fields::TO);
+ registerFieldValue <addressList>(vmime::fields::CC);
+ registerFieldValue <addressList>(vmime::fields::BCC);
+ registerFieldValue <mailbox>(vmime::fields::SENDER);
+ registerFieldValue <datetime>(vmime::fields::DATE);
+ registerFieldValue <relay>(vmime::fields::RECEIVED);
+ registerFieldValue <text>(vmime::fields::SUBJECT);
+ registerFieldValue <mailbox>(vmime::fields::REPLY_TO);
+ registerFieldValue <mailbox>(vmime::fields::DELIVERED_TO);
+ registerFieldValue <text>(vmime::fields::ORGANIZATION);
+ registerFieldValue <text>(vmime::fields::USER_AGENT);
+ registerFieldValue <path>(vmime::fields::RETURN_PATH);
+ registerFieldValue <mediaType>(vmime::fields::CONTENT_TYPE);
+ registerFieldValue <encoding>(vmime::fields::CONTENT_TRANSFER_ENCODING);
+ registerFieldValue <text>(vmime::fields::CONTENT_DESCRIPTION);
+ registerFieldValue <text>(vmime::fields::MIME_VERSION);
+ registerFieldValue <contentDisposition>(vmime::fields::CONTENT_DISPOSITION);
+ registerFieldValue <messageId>(vmime::fields::CONTENT_ID);
+ registerFieldValue <messageId>(vmime::fields::MESSAGE_ID);
+ registerFieldValue <text>(vmime::fields::CONTENT_LOCATION);
+ registerFieldValue <messageIdSequence>(vmime::fields::IN_REPLY_TO);
+ registerFieldValue <messageIdSequence>(vmime::fields::REFERENCES);
+
+ registerFieldValue <messageId>(vmime::fields::ORIGINAL_MESSAGE_ID);
+ registerFieldValue <disposition>(vmime::fields::DISPOSITION);
+ registerFieldValue <mailboxList>(vmime::fields::DISPOSITION_NOTIFICATION_TO);
+}
+
+
+headerFieldFactory::~headerFieldFactory() {
+
+}
+
+
+shared_ptr <headerFieldFactory> headerFieldFactory::getInstance() {
+
+ static headerFieldFactory instance;
+ return shared_ptr <headerFieldFactory>(&instance, noop_shared_ptr_deleter <headerFieldFactory>());
+}
+
+
+shared_ptr <headerField> headerFieldFactory::create(
+ const string& name,
+ const string& body
+) {
+
+ NameMap::const_iterator pos = m_nameMap.find(utility::stringUtils::toLower(name));
+ shared_ptr <headerField> field;
+
+ if (pos != m_nameMap.end()) {
+ field = ((*pos).second)();
+ } else {
+ field = registerer <headerField, headerField>::creator();
+ }
+
+ field->setName(name);
+ field->setValue(createValue(name));
+
+ if (body != NULL_STRING) {
+ field->parse(body);
+ }
+
+ return field;
+}
+
+
+shared_ptr <headerFieldValue> headerFieldFactory::createValue(const string& fieldName) {
+
+ ValueMap::const_iterator pos = m_valueMap.find(
+ utility::stringUtils::toLower(fieldName)
+ );
+
+ shared_ptr <headerFieldValue> value;
+
+ if (pos != m_valueMap.end()) {
+ value = ((*pos).second.allocFunc)();
+ } else {
+ value = registerer <headerFieldValue, text>::creator();
+ }
+
+ return value;
+}
+
+
+bool headerFieldFactory::isValueTypeValid(
+ const headerField& field,
+ const headerFieldValue& value
+) const {
+
+ ValueMap::const_iterator pos = m_valueMap.find
+ (utility::stringUtils::toLower(field.getName()));
+
+ if (pos != m_valueMap.end()) {
+ return ((*pos).second.checkTypeFunc)(value);
+ }
+
+ return true; // No info on this field
+}
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/headerFieldFactory.hpp b/vmime-master/src/vmime/headerFieldFactory.hpp
new file mode 100644
index 0000000..b3e3415
--- /dev/null
+++ b/vmime-master/src/vmime/headerFieldFactory.hpp
@@ -0,0 +1,159 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_HEADERFIELDFACTORY_HPP_INCLUDED
+#define VMIME_HEADERFIELDFACTORY_HPP_INCLUDED
+
+
+#include "vmime/headerField.hpp"
+#include "vmime/utility/stringUtils.hpp"
+
+
+namespace vmime {
+
+
+/** Creates header field and header field value objects.
+ */
+class VMIME_EXPORT headerFieldFactory {
+
+protected:
+
+ headerFieldFactory();
+ ~headerFieldFactory();
+
+ typedef shared_ptr <headerField> (*AllocFunc)(void);
+ typedef std::map <string, AllocFunc> NameMap;
+
+ NameMap m_nameMap;
+
+
+ struct ValueInfo {
+
+ typedef shared_ptr <headerFieldValue> (*ValueAllocFunc)(void);
+ typedef bool (*ValueTypeCheckFunc)(const object&);
+
+ ValueAllocFunc allocFunc;
+ ValueTypeCheckFunc checkTypeFunc;
+ };
+
+ typedef std::map <string, ValueInfo> ValueMap;
+
+ ValueMap m_valueMap;
+
+public:
+
+ static shared_ptr <headerFieldFactory> getInstance();
+
+#ifndef VMIME_BUILDING_DOC
+
+ // TYPE must inherit from BASE_TYPE
+ template <class BASE_TYPE, class TYPE>
+ class registerer {
+
+ public:
+
+ static bool checkType(const object& obj) {
+
+ const TYPE* typedObj = dynamic_cast <const TYPE*>(&obj);
+ return typedObj != NULL;
+ }
+
+ static shared_ptr <BASE_TYPE> creator() {
+
+ // Allocate a new object
+ return shared_ptr <BASE_TYPE>(new TYPE());
+ }
+ };
+
+#endif // VMIME_BUILDING_DOC
+
+
+ /** Register a field type.
+ *
+ * @param T field class (must inherit from 'headerField')
+ * @param name field name (eg. "X-MyField")
+ */
+ template <class T>
+ void registerField(const string& name) {
+
+ m_nameMap.insert(
+ NameMap::value_type(
+ utility::stringUtils::toLower(name),
+ &registerer <headerField, T>::creator
+ )
+ );
+ }
+
+ /** Register a field value type.
+ *
+ * @param T value class (must inherit from 'headerFieldValue')
+ * @param name field name
+ */
+ template <class T>
+ void registerFieldValue(const string& name) {
+
+ ValueInfo vi;
+ vi.allocFunc = &registerer <headerFieldValue, T>::creator;
+ vi.checkTypeFunc = &registerer <headerField, T>::checkType;
+
+ m_valueMap.insert(
+ ValueMap::value_type(
+ utility::stringUtils::toLower(name),
+ vi
+ )
+ );
+ }
+
+ /** Create a new field object for the specified field name.
+ * If the field name has not been registered, a default type
+ * is used.
+ *
+ * @param name field name
+ * @param body string that will be parsed to initialize
+ * the value of the field
+ * @return a new field object
+ */
+ shared_ptr <headerField> create(const string& name, const string& body = NULL_STRING);
+
+ /** Create a new field value for the specified field.
+ *
+ * @param fieldName name of the field for which to create value
+ * @return a new value object for the field
+ */
+ shared_ptr <headerFieldValue> createValue(const string& fieldName);
+
+ /** Returns whether the specified value type is valid for the specified field.
+ *
+ * @param field header field
+ * @param value value for this header field
+ * @return true if the value type is compatible with the header field, or
+ * false otherwise
+ */
+ bool isValueTypeValid(const headerField& field, const headerFieldValue& value) const;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_HEADERFIELDFACTORY_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/headerFieldValue.cpp b/vmime-master/src/vmime/headerFieldValue.cpp
new file mode 100644
index 0000000..073edbe
--- /dev/null
+++ b/vmime-master/src/vmime/headerFieldValue.cpp
@@ -0,0 +1,43 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/headerFieldValue.hpp"
+
+#include "vmime/utility/outputStreamAdapter.hpp"
+
+
+namespace vmime {
+
+
+size_t headerFieldValue::getGeneratedSize(const generationContext& ctx) {
+
+ std::ostringstream oss;
+ utility::outputStreamAdapter osa(oss);
+
+ generate(ctx, osa);
+
+ return oss.str().length();
+}
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/headerFieldValue.hpp b/vmime-master/src/vmime/headerFieldValue.hpp
new file mode 100644
index 0000000..20d1768
--- /dev/null
+++ b/vmime-master/src/vmime/headerFieldValue.hpp
@@ -0,0 +1,49 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_HEADERFIELDVALUE_HPP_INCLUDED
+#define VMIME_HEADERFIELDVALUE_HPP_INCLUDED
+
+
+#include "vmime/base.hpp"
+#include "vmime/component.hpp"
+
+
+namespace vmime {
+
+
+/** Base class for all classes that can be used as a value
+ * for a header field.
+ */
+class VMIME_EXPORT headerFieldValue : public component {
+
+public:
+
+ size_t getGeneratedSize(const generationContext& ctx);
+};
+
+
+} // vmime
+
+
+#endif // VMIME_HEADERFIELDVALUE_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/htmlTextPart.cpp b/vmime-master/src/vmime/htmlTextPart.cpp
new file mode 100644
index 0000000..a30023c
--- /dev/null
+++ b/vmime-master/src/vmime/htmlTextPart.cpp
@@ -0,0 +1,568 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/htmlTextPart.hpp"
+#include "vmime/exception.hpp"
+
+#include "vmime/contentTypeField.hpp"
+#include "vmime/contentDisposition.hpp"
+#include "vmime/text.hpp"
+
+#include "vmime/emptyContentHandler.hpp"
+#include "vmime/stringContentHandler.hpp"
+
+#include "vmime/utility/outputStreamAdapter.hpp"
+
+
+namespace vmime {
+
+
+htmlTextPart::htmlTextPart()
+ : m_plainText(make_shared <emptyContentHandler>()),
+ m_text(make_shared <emptyContentHandler>()) {
+
+}
+
+
+htmlTextPart::~htmlTextPart() {
+
+}
+
+
+const mediaType htmlTextPart::getType() const {
+
+ return mediaType(mediaTypes::TEXT, mediaTypes::TEXT_HTML);
+}
+
+
+size_t htmlTextPart::getPartCount() const {
+
+ return m_plainText->isEmpty() ? 1 : 2;
+}
+
+
+void htmlTextPart::generateIn(
+ const shared_ptr <bodyPart>& /* message */,
+ const shared_ptr <bodyPart>& parent
+) const {
+
+ // Plain text
+ if (!m_plainText->isEmpty()) {
+
+ // -- Create a new part
+ shared_ptr <bodyPart> part = make_shared <bodyPart>();
+ parent->getBody()->appendPart(part);
+
+ // -- Set contents
+ part->getBody()->setContents(
+ m_plainText,
+ mediaType(mediaTypes::TEXT, mediaTypes::TEXT_PLAIN),
+ m_charset,
+ encoding::decide(m_plainText, m_charset, encoding::USAGE_TEXT)
+ );
+ }
+
+ // HTML text
+ // -- Create a new part
+ shared_ptr <bodyPart> htmlPart = make_shared <bodyPart>();
+
+ // -- Set contents
+ htmlPart->getBody()->setContents(
+ m_text,
+ mediaType(mediaTypes::TEXT, mediaTypes::TEXT_HTML),
+ m_charset,
+ encoding::decide(m_text, m_charset, encoding::USAGE_TEXT)
+ );
+
+ // Handle the case we have embedded objects
+ if (!m_objects.empty()) {
+
+ // Create a "multipart/related" body part
+ shared_ptr <bodyPart> relPart = make_shared <bodyPart>();
+ parent->getBody()->appendPart(relPart);
+
+ relPart->getHeader()->ContentType()->setValue(
+ mediaType(mediaTypes::MULTIPART, mediaTypes::MULTIPART_RELATED)
+ );
+
+ // Add the HTML part into this part
+ relPart->getBody()->appendPart(htmlPart);
+
+ // Also add objects into this part
+ for (std::vector <shared_ptr <embeddedObject> >::const_iterator it = m_objects.begin() ;
+ it != m_objects.end() ; ++it) {
+
+ shared_ptr <bodyPart> objPart = make_shared <bodyPart>();
+ relPart->getBody()->appendPart(objPart);
+
+ string id = (*it)->getId();
+
+ if (id.length() >= 4 &&
+ (id[0] == 'c' || id[0] == 'C') &&
+ (id[1] == 'i' || id[1] == 'I') &&
+ (id[2] == 'd' || id[2] == 'D') &&
+ id[3] == ':') {
+
+ id = id.substr(4);
+ }
+
+ objPart->getHeader()->ContentType()->setValue((*it)->getType());
+ objPart->getHeader()->ContentId()->setValue(messageId("<" + id + ">"));
+ objPart->getHeader()->ContentDisposition()->setValue(contentDisposition(contentDispositionTypes::INLINE));
+ objPart->getHeader()->ContentTransferEncoding()->setValue((*it)->getEncoding());
+ //encoding(encodingTypes::BASE64);
+
+ objPart->getBody()->setContents((*it)->getData()->clone());
+ }
+
+ } else {
+
+ // Add the HTML part into the parent part
+ parent->getBody()->appendPart(htmlPart);
+ }
+}
+
+
+void htmlTextPart::findEmbeddedParts(
+ const bodyPart& part,
+ std::vector <shared_ptr <const bodyPart> >& cidParts,
+ std::vector <shared_ptr <const bodyPart> >& locParts
+) {
+
+ for (size_t i = 0 ; i < part.getBody()->getPartCount() ; ++i) {
+
+ shared_ptr <const bodyPart> p = part.getBody()->getPartAt(i);
+
+ // For a part to be an embedded object, it must have either a
+ // Content-Id field or a Content-Location field.
+ if (p->getHeader()->hasField(fields::CONTENT_ID)) {
+ cidParts.push_back(p);
+ }
+
+ if (p->getHeader()->hasField(fields::CONTENT_LOCATION)) {
+ locParts.push_back(p);
+ }
+
+ findEmbeddedParts(*p, cidParts, locParts);
+ }
+}
+
+
+void htmlTextPart::addEmbeddedObject(
+ const bodyPart& part,
+ const string& id,
+ const embeddedObject::ReferenceType refType
+) {
+
+ // The object may already exists. This can happen if an object is
+ // identified by both a Content-Id and a Content-Location. In this
+ // case, there will be two embedded objects with two different IDs
+ // but referencing the same content.
+
+ mediaType type;
+
+ shared_ptr <const headerField> ctf =
+ part.getHeader()->findField(fields::CONTENT_TYPE);
+
+ if (ctf) {
+
+ type = *ctf->getValue <mediaType>();
+
+ } else {
+
+ // No "Content-type" field: assume "application/octet-stream".
+ }
+
+ m_objects.push_back(
+ make_shared <embeddedObject>(
+ vmime::clone(part.getBody()->getContents()),
+ part.getBody()->getEncoding(),
+ id,
+ type,
+ refType
+ )
+ );
+}
+
+
+void htmlTextPart::parse(
+ const shared_ptr <const bodyPart>& message,
+ const shared_ptr <const bodyPart>& parent,
+ const shared_ptr <const bodyPart>& textPart
+) {
+
+ // Search for possible embedded objects in the _whole_ message.
+ std::vector <shared_ptr <const bodyPart> > cidParts;
+ std::vector <shared_ptr <const bodyPart> > locParts;
+
+ findEmbeddedParts(*message, cidParts, locParts);
+
+ // Extract HTML text
+ std::ostringstream oss;
+ utility::outputStreamAdapter adapter(oss);
+
+ textPart->getBody()->getContents()->extract(adapter);
+
+ const string data = oss.str();
+
+ m_text = textPart->getBody()->getContents()->clone();
+
+ // Find charset
+ shared_ptr <const contentTypeField> ctf =
+ textPart->getHeader()->findField <contentTypeField>(fields::CONTENT_TYPE);
+
+ if (ctf && ctf->hasCharset()) {
+ m_charset = ctf->getCharset();
+ } else {
+ m_charset = charset();
+ }
+
+ // Extract embedded objects. The algorithm is quite simple: for each previously
+ // found inline part, we check if its CID/Location is contained in the HTML text.
+ for (std::vector <shared_ptr <const bodyPart> >::const_iterator p = cidParts.begin() ;
+ p != cidParts.end() ; ++p) {
+
+ const shared_ptr <const headerField> midField =
+ (*p)->getHeader()->findField(fields::CONTENT_ID);
+
+ const messageId mid = *midField->getValue <messageId>();
+
+ if (data.find("CID:" + mid.getId()) != string::npos ||
+ data.find("cid:" + mid.getId()) != string::npos) {
+
+ // This part is referenced in the HTML text.
+ // Add it to the embedded object list.
+ addEmbeddedObject(**p, mid.getId(), embeddedObject::REFERENCED_BY_ID);
+ }
+ }
+
+ for (std::vector <shared_ptr <const bodyPart> >::const_iterator p = locParts.begin() ;
+ p != locParts.end() ; ++p) {
+
+ const shared_ptr <const headerField> locField =
+ (*p)->getHeader()->findField(fields::CONTENT_LOCATION);
+
+ const text loc = *locField->getValue <text>();
+ const string locStr = loc.getWholeBuffer();
+
+ if (data.find(locStr) != string::npos) {
+
+ // This part is referenced in the HTML text.
+ // Add it to the embedded object list.
+ addEmbeddedObject(**p, locStr, embeddedObject::REFERENCED_BY_LOCATION);
+ }
+ }
+
+ // Extract plain text, if any.
+ if (!findPlainTextPart(*message, *parent, *textPart)) {
+
+ m_plainText = make_shared <emptyContentHandler>();
+ }
+}
+
+
+bool htmlTextPart::findPlainTextPart(
+ const bodyPart& part,
+ const bodyPart& parent,
+ const bodyPart& textPart
+) {
+
+ // We search for the nearest "multipart/alternative" part.
+ const shared_ptr <const headerField> ctf =
+ part.getHeader()->findField(fields::CONTENT_TYPE);
+
+ if (ctf) {
+
+ const mediaType type = *ctf->getValue <mediaType>();
+
+ if (type.getType() == mediaTypes::MULTIPART &&
+ type.getSubType() == mediaTypes::MULTIPART_ALTERNATIVE) {
+
+ shared_ptr <const bodyPart> foundPart;
+
+ for (size_t i = 0 ; i < part.getBody()->getPartCount() ; ++i) {
+
+ const shared_ptr <const bodyPart> p = part.getBody()->getPartAt(i);
+
+ if (p.get() == &parent || // if "text/html" is in "multipart/related"
+ p.get() == &textPart) { // if not...
+
+ foundPart = p;
+ }
+ }
+
+ if (foundPart) {
+
+ bool found = false;
+
+ // Now, search for the alternative plain text part
+ for (size_t i = 0 ; !found && i < part.getBody()->getPartCount() ; ++i) {
+
+ const shared_ptr <const bodyPart> p = part.getBody()->getPartAt(i);
+
+ const shared_ptr <const headerField> ctf =
+ p->getHeader()->findField(fields::CONTENT_TYPE);
+
+ if (ctf) {
+
+ const mediaType type = *ctf->getValue <mediaType>();
+
+ if (type.getType() == mediaTypes::TEXT &&
+ type.getSubType() == mediaTypes::TEXT_PLAIN) {
+
+ m_plainText = p->getBody()->getContents()->clone();
+ found = true;
+ }
+
+ } else {
+
+ // No "Content-type" field.
+ }
+ }
+
+ // If we don't have found the plain text part here, it means that
+ // it does not exists (the MUA which built this message probably
+ // did not include it...).
+ return found;
+ }
+ }
+
+ } else {
+
+ // No "Content-type" field.
+ }
+
+ bool found = false;
+
+ for (size_t i = 0 ; !found && i < part.getBody()->getPartCount() ; ++i) {
+
+ found = findPlainTextPart(*part.getBody()->getPartAt(i), parent, textPart);
+ }
+
+ return found;
+}
+
+
+const charset& htmlTextPart::getCharset() const {
+
+ return m_charset;
+}
+
+
+void htmlTextPart::setCharset(const charset& ch) {
+
+ m_charset = ch;
+}
+
+
+shared_ptr <const contentHandler> htmlTextPart::getPlainText() const {
+
+ return m_plainText;
+}
+
+
+void htmlTextPart::setPlainText(const shared_ptr <contentHandler>& plainText) {
+
+ m_plainText = plainText->clone();
+}
+
+
+const shared_ptr <const contentHandler> htmlTextPart::getText() const {
+
+ return m_text;
+}
+
+
+void htmlTextPart::setText(const shared_ptr <contentHandler>& text) {
+
+ m_text = text->clone();
+}
+
+
+size_t htmlTextPart::getObjectCount() const {
+
+ return m_objects.size();
+}
+
+
+shared_ptr <const htmlTextPart::embeddedObject> htmlTextPart::getObjectAt(const size_t pos) const {
+
+ return m_objects[pos];
+}
+
+
+shared_ptr <const htmlTextPart::embeddedObject> htmlTextPart::findObject(const string& id) const
+{
+ for (std::vector <shared_ptr <embeddedObject> >::const_iterator o = m_objects.begin() ;
+ o != m_objects.end() ; ++o) {
+
+ if ((*o)->matchesId(id)) {
+ return *o;
+ }
+ }
+
+ return null;
+}
+
+
+bool htmlTextPart::hasObject(const string& id) const {
+
+ for (std::vector <shared_ptr <embeddedObject> >::const_iterator o = m_objects.begin() ;
+ o != m_objects.end() ; ++o) {
+
+ if ((*o)->matchesId(id)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+shared_ptr <const htmlTextPart::embeddedObject> htmlTextPart::addObject(
+ const shared_ptr <contentHandler>& data,
+ const vmime::encoding& enc,
+ const mediaType& type
+) {
+
+ const messageId mid(messageId::generateId());
+
+ shared_ptr <embeddedObject> obj = make_shared <embeddedObject>(
+ data, enc, mid.getId(), type, embeddedObject::REFERENCED_BY_ID
+ );
+
+ m_objects.push_back(obj);
+
+ return obj;
+}
+
+
+shared_ptr <const htmlTextPart::embeddedObject> htmlTextPart::addObject(
+ const shared_ptr <contentHandler>& data,
+ const mediaType& type
+) {
+
+ return addObject(data, encoding::decide(data), type);
+}
+
+
+shared_ptr <const htmlTextPart::embeddedObject> htmlTextPart::addObject(
+ const string& data,
+ const mediaType& type
+) {
+
+ shared_ptr <stringContentHandler> cts = make_shared <stringContentHandler>(data);
+ return addObject(cts, encoding::decide(cts), type);
+}
+
+
+
+//
+// htmlTextPart::embeddedObject
+//
+
+htmlTextPart::embeddedObject::embeddedObject(
+ const shared_ptr <contentHandler>& data,
+ const encoding& enc,
+ const string& id,
+ const mediaType& type,
+ const ReferenceType refType
+)
+ : m_data(vmime::clone(data)),
+ m_encoding(enc),
+ m_id(id),
+ m_type(type),
+ m_refType(refType) {
+
+}
+
+
+shared_ptr <const contentHandler> htmlTextPart::embeddedObject::getData() const {
+
+ return m_data;
+}
+
+
+const vmime::encoding htmlTextPart::embeddedObject::getEncoding() const {
+
+ return m_encoding;
+}
+
+
+const string htmlTextPart::embeddedObject::getId() const {
+
+ return m_id;
+}
+
+
+const string htmlTextPart::embeddedObject::getReferenceId() const {
+
+ if (m_refType == REFERENCED_BY_ID) {
+ return string("cid:") + m_id;
+ } else {
+ return m_id;
+ }
+}
+
+
+const mediaType htmlTextPart::embeddedObject::getType() const {
+
+ return m_type;
+}
+
+
+htmlTextPart::embeddedObject::ReferenceType htmlTextPart::embeddedObject::getReferenceType() const {
+
+ return m_refType;
+}
+
+
+bool htmlTextPart::embeddedObject::matchesId(const string& id) const {
+
+ if (m_refType == REFERENCED_BY_ID) {
+ return m_id == cleanId(id);
+ } else {
+ return m_id == id;
+ }
+}
+
+
+// static
+const string htmlTextPart::embeddedObject::cleanId(const string& id) {
+
+ if (id.length() >= 4 &&
+ (id[0] == 'c' || id[0] == 'C') &&
+ (id[1] == 'i' || id[1] == 'I') &&
+ (id[2] == 'd' || id[2] == 'D') &&
+ id[3] == ':') {
+
+ return id.substr(4);
+
+ } else {
+
+ return id;
+ }
+}
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/htmlTextPart.hpp b/vmime-master/src/vmime/htmlTextPart.hpp
new file mode 100644
index 0000000..ac2711b
--- /dev/null
+++ b/vmime-master/src/vmime/htmlTextPart.hpp
@@ -0,0 +1,268 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_HTMLTEXTPART_HPP_INCLUDED
+#define VMIME_HTMLTEXTPART_HPP_INCLUDED
+
+
+#include "vmime/textPart.hpp"
+#include "vmime/messageId.hpp"
+#include "vmime/encoding.hpp"
+
+#include "vmime/contentHandler.hpp"
+
+
+namespace vmime {
+
+
+/** Text part of type 'text/html'.
+ */
+class VMIME_EXPORT htmlTextPart : public textPart {
+
+public:
+
+ htmlTextPart();
+ ~htmlTextPart();
+
+ const mediaType getType() const;
+
+ const charset& getCharset() const;
+ void setCharset(const charset& ch);
+
+ shared_ptr <const contentHandler> getPlainText() const;
+ void setPlainText(const shared_ptr <contentHandler>& plainText);
+
+ const shared_ptr <const contentHandler> getText() const;
+ void setText(const shared_ptr <contentHandler>& text);
+
+ /** Embedded object (eg: image for &lt;IMG> tag).
+ */
+ class VMIME_EXPORT embeddedObject : public object {
+ public:
+
+ /** The ways embedded objects can be referenced. */
+ enum ReferenceType {
+ REFERENCED_BY_ID, /**< Referenced by Content-Id. */
+ REFERENCED_BY_LOCATION /**< Referenced by Content-Location. */
+ };
+
+ /** Constructs an embedded object.
+ *
+ * @param data content of the object
+ * @param enc encoding of the data
+ * @param id object identifier
+ * @param type object content type
+ * @param refType reference type
+ * @return a reference to a new embedded object
+ */
+ embeddedObject(
+ const shared_ptr <contentHandler>& data,
+ const encoding& enc,
+ const string& id,
+ const mediaType& type,
+ const ReferenceType refType
+ );
+
+ /** Return data stored in this embedded object.
+ *
+ * @return stored data
+ */
+ shared_ptr <const contentHandler> getData() const;
+
+ /** Return the encoding used for data in this
+ * embedded object.
+ *
+ * @return data encoding
+ */
+ const vmime::encoding getEncoding() const;
+
+ /** Returns the identifier of this embedded object (either a
+ * unique ID or a location).
+ *
+ * @return object identifier
+ */
+ const string getId() const;
+
+ /** Return the identifier used to reference this embedded object
+ * in a text document (for example, you can use the result as
+ * the "src" attribute of an &lt;img> tag).
+ *
+ * @return object reference identifier
+ */
+ const string getReferenceId() const;
+
+ /** Return the content type of data stored in
+ * this embedded object.
+ *
+ * @return data type
+ */
+ const mediaType getType() const;
+
+ /** Returns the way this object is referenced.
+ *
+ * @return reference type (see ReferenceType enum)
+ */
+ ReferenceType getReferenceType() const;
+
+ /** Returns whether this object matches the specified identifier.
+ *
+ * @param id identifier to test
+ * @return true if the specified identifier references this
+ * object, or false otherwise
+ */
+ bool matchesId(const string& id) const;
+
+ private:
+
+ static const string cleanId(const string& id);
+
+ shared_ptr <contentHandler> m_data;
+ encoding m_encoding;
+ string m_id;
+ mediaType m_type;
+ ReferenceType m_refType;
+ };
+
+
+ /** Test the existence of an embedded object given its identifier.
+ *
+ * @param id object identifier
+ * @return true if an object with this identifier exists,
+ * false otherwise
+ */
+ bool hasObject(const string& id) const;
+
+ /** Return the embedded object with the specified identifier.
+ *
+ * @param id object identifier
+ * @return embedded object with the specified identifier, or NULL if
+ * no object has been found
+ */
+ shared_ptr <const embeddedObject> findObject(const string& id) const;
+
+ /** Return the number of embedded objects.
+ *
+ * @return number of embedded objects
+ */
+ size_t getObjectCount() const;
+
+ /** Return the embedded object at the specified position.
+ *
+ * @param pos position of the embedded object
+ * @return embedded object at position 'pos'
+ */
+ shared_ptr <const embeddedObject> getObjectAt(const size_t pos) const;
+
+ /** Embed an object and returns a string which identifies it.
+ * The returned identifier is suitable for use in the 'src' attribute
+ * of an &lt;img> tag.
+ *
+ * \deprecated Use the addObject() methods which take a 'contentHandler'
+ * parameter type instead.
+ *
+ * @param data object data
+ * @param type data type
+ * @return an unique object identifier used to identify the new
+ * object among all other embedded objects
+ */
+ shared_ptr <const embeddedObject> addObject(
+ const string& data,
+ const mediaType& type
+ );
+
+ /** Embed an object and returns a string which identifies it.
+ * The returned identifier is suitable for use in the 'src' attribute
+ * of an &lt;img> tag.
+ *
+ * @param data object data
+ * @param type data type
+ * @return an unique object identifier used to identify the new
+ * object among all other embedded objects
+ */
+ shared_ptr <const embeddedObject> addObject(
+ const shared_ptr <contentHandler>& data,
+ const mediaType& type
+ );
+
+ /** Embed an object and returns a string which identifies it.
+ * The returned identifier is suitable for use in the 'src' attribute
+ * of an &lt;img> tag.
+ *
+ * @param data object data
+ * @param enc data encoding
+ * @param type data type
+ * @return an unique object identifier used to identify the new
+ * object among all other embedded objects
+ */
+ shared_ptr <const embeddedObject> addObject(
+ const shared_ptr <contentHandler>& data,
+ const encoding& enc,
+ const mediaType& type
+ );
+
+
+ size_t getPartCount() const;
+
+ void generateIn(
+ const shared_ptr <bodyPart>& message,
+ const shared_ptr <bodyPart>& parent
+ ) const;
+
+ void parse(
+ const shared_ptr <const bodyPart>& message,
+ const shared_ptr <const bodyPart>& parent,
+ const shared_ptr <const bodyPart>& textPart
+ );
+
+private:
+
+ shared_ptr <contentHandler> m_plainText;
+ shared_ptr <contentHandler> m_text;
+ charset m_charset;
+
+ std::vector <shared_ptr <embeddedObject> > m_objects;
+
+ void findEmbeddedParts(
+ const bodyPart& part,
+ std::vector <shared_ptr <const bodyPart> >& cidParts,
+ std::vector <shared_ptr <const bodyPart> >& locParts
+ );
+
+ void addEmbeddedObject(
+ const bodyPart& part,
+ const string& id,
+ const embeddedObject::ReferenceType refType
+ );
+
+ bool findPlainTextPart(
+ const bodyPart& part,
+ const bodyPart& parent,
+ const bodyPart& textPart
+ );
+};
+
+
+} // vmime
+
+
+#endif // VMIME_HTMLTEXTPART_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/mailbox.cpp b/vmime-master/src/vmime/mailbox.cpp
new file mode 100644
index 0000000..30a082e
--- /dev/null
+++ b/vmime-master/src/vmime/mailbox.cpp
@@ -0,0 +1,476 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/mailbox.hpp"
+#include "vmime/parserHelpers.hpp"
+#include "vmime/utility/outputStreamStringAdapter.hpp"
+
+
+namespace vmime {
+
+
+mailbox::mailbox() {
+
+}
+
+
+mailbox::mailbox(const mailbox& mbox)
+ : address(),
+ m_name(mbox.m_name),
+ m_email(mbox.m_email) {
+
+}
+
+
+mailbox::mailbox(const emailAddress& email)
+ : m_email(email) {
+
+}
+
+
+mailbox::mailbox(const text& name, const emailAddress& email)
+ : m_name(name),
+ m_email(email) {
+
+}
+
+
+/*
+
+ RFC #2822:
+ 3.4. ADDRESS SPECIFICATION
+
+mailbox = name-addr / addr-spec
+
+name-addr = [display-name] angle-addr
+
+angle-addr = [CFWS] "<" addr-spec ">" [CFWS] / obs-angle-addr
+
+*/
+
+void mailbox::parseImpl(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition
+) {
+
+ const char* const pend = buffer.data() + end;
+ const char* const pstart = buffer.data() + position;
+ const char* p = pstart;
+
+ // Current state for parsing machine
+ enum States {
+ State_None,
+ State_String,
+ State_Name,
+ State_Bracket,
+ State_Address_Bracketed,
+ State_Address_Unbracketed,
+ State_NameAt,
+ };
+
+ States state = State_None;
+
+ // Temporary buffers for extracted name and address
+ string name, address;
+ unsigned int hold = 0;
+ bool hadBrackets = false;
+
+ while (p < pend) {
+ if (state == State_None) {
+ while (p < pend && parserHelpers::isSpace(*p))
+ ++p;
+ if (*p == ',' || *p == ';')
+ /* Completely new mailbox -- stop parsing this one. */
+ break;
+ if (*p == '<') {
+ state = State_Bracket;
+ continue;
+ }
+ if (*p == '"') { // Quoted string
+ state = State_String;
+ ++p;
+ continue;
+ }
+ state = State_Name;
+ } else if (state == State_String) {
+ bool escaped = false;
+
+ for (; p < pend; ++p) {
+ if (escaped) {
+ name += *p;
+ escaped = false;
+ continue;
+ } else if (*p == '\\') {
+ escaped = true;
+ continue;
+ }
+ if (*p == '"') {
+ ++p;
+ state = State_None;
+ break;
+ }
+ name += *p;
+ }
+ } else if (state == State_Address_Bracketed) {
+ bool escaped = false;
+ int comment = 0;
+
+ for (; p < pend; ++p) {
+ if (escaped) {
+ if (!comment) {
+ address += *p;
+ name += *p;
+ ++hold;
+ }
+ escaped = false;
+ } else if (comment) {
+ if (*p == '\\') {
+ escaped = true;
+ } else if (*p == '(') {
+ ++comment;
+ } else if (*p == ')') {
+ --comment;
+ }
+ } else if (*p == '(') {
+ ++comment;
+ } else if (*p == '\\') {
+ escaped = true;
+ } else if (*p == '<') {
+ state = State_Bracket;
+ break;
+ } else if (*p == '>') {
+ hadBrackets = true;
+ name += *p++;
+ ++hold;
+ state = State_Name;
+ break;
+ } else if (parserHelpers::isSpace(*p)) {
+ name += *p;
+ ++hold;
+ } else {
+ address += *p;
+ name += *p;
+ ++hold;
+ }
+ }
+ } else if (state == State_Address_Unbracketed) {
+ bool escaped = false;
+ int comment = 0;
+
+ for (; p < pend; ++p) {
+ if (escaped) {
+ if (!comment) {
+ address += *p;
+ name += *p;
+ ++hold;
+ }
+ escaped = false;
+ } else if (comment) {
+ if (*p == '\\')
+ escaped = true;
+ else if (*p == '(')
+ ++comment;
+ else if (*p == ')')
+ --comment;
+ } else if (*p == '(') {
+ ++comment;
+ } else if (*p == '\\') {
+ escaped = true;
+ } else if (*p == '<') {
+ state = State_Bracket;
+ break;
+ } else if (*p == '>') {
+ name += *p++;
+ ++hold;
+ state = State_None;
+ break;
+ } else if (*p == ',' || *p == ';') {
+ state = State_None;
+ break;
+ } else if (parserHelpers::isSpace(*p)) {
+ state = State_Name;
+ break;
+ } else {
+ address += *p;
+ name += *p;
+ ++hold;
+ }
+ }
+ } else if (state == State_Name) {
+ bool escaped = false;
+ unsigned int comment = 0, at_hold = 0;
+
+ for (; p < pend; ++p) {
+ if (escaped) {
+ if (!comment) {
+ name += *p;
+ ++at_hold;
+ }
+ escaped = false;
+ } else if (comment) {
+ if (*p == '\\')
+ escaped = true;
+ else if (*p == '(')
+ ++comment;
+ else if (*p == ')')
+ --comment;
+ } else if (*p == '\\') {
+ escaped = true;
+ } else if (*p == '(') {
+ ++comment;
+ } else if (*p == '<') {
+ state = State_Bracket;
+ break;
+ } else if (*p == '@') {
+ hold = at_hold;
+ state = State_NameAt;
+ break;
+ } else if (parserHelpers::isSpace(*p)) {
+ name += *p;
+ ++hold;
+ at_hold = 1;
+ } else {
+ name += *p;
+ hold = 0;
+ ++at_hold;
+ }
+ }
+ } else if (state == State_Bracket) {
+ string::const_iterator q = name.cend();
+ unsigned int nh = 0;
+ while (nh < hold && q != name.cbegin() && parserHelpers::isSpace(*(q - 1))) {
+ --q;
+ ++nh;
+ }
+ hold = nh;
+ name += *p++;
+ ++hold;
+ if (!address.empty())
+ // If we found a '<' here, it means that the address
+ // starts _only_ here...and the stuff we have parsed
+ // before belongs actually to the display name!
+ address.clear();
+ state = State_Address_Bracketed;
+ } else if (state == State_NameAt) {
+ name += *p++;
+ ++hold;
+ // (*) Actually, we were parsing the local-part of an address
+ // and not a display name...
+ // Back up to the last whitespace and treat as address
+ string::const_iterator q = name.cend();
+ unsigned int nh = 0;
+ while (nh < hold && q != name.cbegin() && !parserHelpers::isSpace(*(q - 1))) {
+ --q;
+ ++nh;
+ }
+ address.assign(q, name.cend());
+ while (nh < hold && q != name.cbegin() && parserHelpers::isSpace(*(q - 1))) {
+ --q;
+ ++nh;
+ }
+ hold = nh;
+ state = State_Address_Unbracketed;
+ }
+ }
+
+ if (hold <= name.size())
+ name.erase(name.size() - hold);
+
+ // Swap name and address when no address was found
+ // (email address is mandatory, whereas name is optional).
+ if (address.empty() && !name.empty() && !hadBrackets) {
+
+ m_name.removeAllWords();
+ m_email.parse(ctx, name);
+
+ } else {
+
+ text::decodeAndUnfold(ctx, name, &m_name);
+ m_email.parse(ctx, address);
+ }
+
+ setParsedBounds(position, position + (p - pstart));
+
+ if (newPosition) {
+ *newPosition = position + (p - pstart);
+ }
+}
+
+
+void mailbox::generateImpl(
+ const generationContext& ctx,
+ utility::outputStream& os,
+ const size_t curLinePos,
+ size_t* newLinePos
+) const {
+
+ string generatedEmail;
+ utility::outputStreamStringAdapter generatedEmailStream(generatedEmail);
+ m_email.generate(ctx, generatedEmailStream, 0, NULL);
+
+ if (m_name.isEmpty()) {
+
+ size_t pos = curLinePos;
+
+ // No display name is specified, only email address.
+ if (curLinePos + generatedEmail.length() > ctx.getMaxLineLength()) {
+
+ os << NEW_LINE_SEQUENCE;
+ pos = NEW_LINE_SEQUENCE.length();
+ }
+
+ os << generatedEmail;
+ pos += generatedEmail.length();
+
+ if (newLinePos) {
+ *newLinePos = pos;
+ }
+
+ } else {
+
+ // We have to encode the name:
+ // - if it contains characters in a charset different from "US-ASCII",
+ // - and/or if it contains one or more of these special chars:
+ // CR LF TAB " ; , < > ( ) @ / ? . = :
+ // these special chars only require quoting, not full encoding
+ // Check whether there are words that are not "US-ASCII"
+ // and/or contain the special chars.
+ bool forceEncode = false;
+
+ for (size_t w = 0 ; !forceEncode && w != m_name.getWordCount() ; ++w) {
+
+ if (m_name.getWordAt(w)->getCharset() != charset(charsets::US_ASCII)) {
+ forceEncode = true;
+ }
+ }
+
+ size_t pos = curLinePos;
+
+ m_name.encodeAndFold(
+ ctx, os, pos, &pos,
+ text::QUOTE_IF_POSSIBLE | (forceEncode ? text::FORCE_ENCODING : 0)
+ );
+
+ if (pos + generatedEmail.length() + 3 > ctx.getMaxLineLength()) {
+
+ os << NEW_LINE_SEQUENCE;
+ pos = NEW_LINE_SEQUENCE.length();
+ }
+
+ os << " <" << generatedEmail << ">";
+ pos += 2 + generatedEmail.length() + 1;
+
+ if (newLinePos) {
+ *newLinePos = pos;
+ }
+ }
+}
+
+
+bool mailbox::operator==(const class mailbox& mailbox) const {
+
+ return m_name == mailbox.m_name && m_email == mailbox.m_email;
+}
+
+
+bool mailbox::operator!=(const class mailbox& mailbox) const {
+
+ return !(*this == mailbox);
+}
+
+
+void mailbox::copyFrom(const component& other) {
+
+ const mailbox& source = dynamic_cast <const mailbox&>(other);
+
+ m_name = source.m_name;
+ m_email = source.m_email;
+}
+
+
+mailbox& mailbox::operator=(const mailbox& other) {
+
+ copyFrom(other);
+ return *this;
+}
+
+
+shared_ptr <component>mailbox::clone() const {
+
+ return make_shared <mailbox>(*this);
+}
+
+
+bool mailbox::isEmpty() const {
+
+ return m_email.isEmpty();
+}
+
+
+void mailbox::clear() {
+
+ m_name.removeAllWords();
+ m_email = emailAddress();
+}
+
+
+bool mailbox::isGroup() const {
+
+ return false;
+}
+
+
+const text& mailbox::getName() const {
+
+ return m_name;
+}
+
+
+void mailbox::setName(const text& name) {
+
+ m_name = name;
+}
+
+
+const emailAddress& mailbox::getEmail() const {
+
+ return m_email;
+}
+
+
+void mailbox::setEmail(const emailAddress& email) {
+
+ m_email = email;
+}
+
+
+const std::vector <shared_ptr <component> > mailbox::getChildComponents() {
+
+ return std::vector <shared_ptr <component> >();
+}
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/mailbox.hpp b/vmime-master/src/vmime/mailbox.hpp
new file mode 100644
index 0000000..c563129
--- /dev/null
+++ b/vmime-master/src/vmime/mailbox.hpp
@@ -0,0 +1,123 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_MAILBOX_HPP_INCLUDED
+#define VMIME_MAILBOX_HPP_INCLUDED
+
+
+#include "vmime/emailAddress.hpp"
+#include "vmime/address.hpp"
+#include "vmime/text.hpp"
+
+
+namespace vmime {
+
+
+/** A mailbox: full name + email (basic type).
+ */
+class VMIME_EXPORT mailbox : public address {
+
+ friend class mailboxGroup;
+ friend class mailboxField;
+
+public:
+
+ mailbox();
+ mailbox(const mailbox& mbox);
+ mailbox(const emailAddress& email);
+ mailbox(const text& name, const emailAddress& email);
+
+ /** Return the full name of the mailbox (empty if not specified).
+ *
+ * @return full name of the mailbox
+ */
+ const text& getName() const;
+
+ /** Set the full name of the mailbox.
+ *
+ * @param name full name of the mailbox
+ */
+ void setName(const text& name);
+
+ /** Return the email of the mailbox.
+ *
+ * @return email of the mailbox
+ */
+ const emailAddress& getEmail() const;
+
+ /** Set the email of the mailbox.
+ *
+ * @param email email of the mailbox
+ */
+ void setEmail(const emailAddress& email);
+
+ // Comparison
+ bool operator==(const class mailbox& mailbox) const;
+ bool operator!=(const class mailbox& mailbox) const;
+
+ // Assignment
+ void copyFrom(const component& other);
+ shared_ptr <component> clone() const;
+ mailbox& operator=(const mailbox& other);
+
+ bool isEmpty() const;
+
+ void clear();
+
+ const std::vector <shared_ptr <component> > getChildComponents();
+
+
+ bool isGroup() const;
+
+protected:
+
+ text m_name;
+ emailAddress m_email;
+
+public:
+
+ using address::parse;
+ using address::generate;
+
+ // Component parsing & assembling
+ void parseImpl(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition = NULL
+ );
+
+ void generateImpl(
+ const generationContext& ctx,
+ utility::outputStream& os,
+ const size_t curLinePos = 0,
+ size_t* newLinePos = NULL
+ ) const;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_MAILBOX_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/mailboxField.cpp b/vmime-master/src/vmime/mailboxField.cpp
new file mode 100644
index 0000000..82ef592
--- /dev/null
+++ b/vmime-master/src/vmime/mailboxField.cpp
@@ -0,0 +1,96 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/mailboxField.hpp"
+#include "vmime/mailboxGroup.hpp"
+
+
+#ifndef VMIME_BUILDING_DOC
+
+
+namespace vmime {
+
+
+mailboxField::mailboxField() {
+
+}
+
+
+mailboxField::mailboxField(const mailboxField&)
+ : headerField() {
+
+}
+
+
+void mailboxField::parse(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition
+) {
+
+ shared_ptr <mailbox> mbox = make_shared <mailbox>();
+
+ // Here, we cannot simply call "m_mailbox.parse()" because it
+ // may have more than one address specified (even if this field
+ // should contain only one). We are never too much careful...
+ shared_ptr <address> parsedAddress = address::parseNext(
+ ctx, buffer, position, end, newPosition, NULL
+ );
+
+ if (parsedAddress) {
+
+ if (parsedAddress->isGroup()) {
+
+ // If it is a group of mailboxes, take the first
+ // mailbox of the group
+ shared_ptr <mailboxGroup> group = dynamicCast <mailboxGroup>(parsedAddress);
+
+ if (!group->isEmpty()) {
+ mbox = group->getMailboxAt(0);
+ }
+
+ } else {
+
+ // Parse only if it is a mailbox
+ mbox = dynamicCast <mailbox>(parsedAddress);
+ }
+ }
+
+ mbox->setParsedBounds(position, end);
+
+ setValue(mbox);
+
+ setParsedBounds(position, end);
+
+ if (newPosition) {
+ *newPosition = end;
+ }
+}
+
+
+} // vmime
+
+
+#endif // VMIME_BUILDING_DOC
diff --git a/vmime-master/src/vmime/mailboxField.hpp b/vmime-master/src/vmime/mailboxField.hpp
new file mode 100644
index 0000000..6c65361
--- /dev/null
+++ b/vmime-master/src/vmime/mailboxField.hpp
@@ -0,0 +1,69 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_MAILBOXFIELD_HPP_INCLUDED
+#define VMIME_MAILBOXFIELD_HPP_INCLUDED
+
+
+#include "vmime/headerField.hpp"
+#include "vmime/mailbox.hpp"
+
+
+// Hide implementation details from user
+#ifndef VMIME_BUILDING_DOC
+
+
+namespace vmime {
+
+
+/** Work-around for malformed header fields that are of type 'mailbox'
+ * and contains multiple addresses.
+ */
+class VMIME_EXPORT mailboxField : public headerField {
+
+ friend class headerFieldFactory;
+
+protected:
+
+ mailboxField();
+ mailboxField(const mailboxField&);
+
+public:
+
+ void parse(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t * newPosition = NULL
+ );
+};
+
+
+#endif // VMIME_BUILDING_DOC
+
+
+} // vmime
+
+
+#endif // VMIME_MAILBOXFIELD_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/mailboxGroup.cpp b/vmime-master/src/vmime/mailboxGroup.cpp
new file mode 100644
index 0000000..38a6e35
--- /dev/null
+++ b/vmime-master/src/vmime/mailboxGroup.cpp
@@ -0,0 +1,406 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/mailboxGroup.hpp"
+#include "vmime/parserHelpers.hpp"
+#include "vmime/exception.hpp"
+
+
+namespace vmime {
+
+
+mailboxGroup::mailboxGroup() {
+
+}
+
+
+mailboxGroup::mailboxGroup(const mailboxGroup& mboxGroup)
+ : address() {
+
+ copyFrom(mboxGroup);
+}
+
+
+mailboxGroup::mailboxGroup(const text& name)
+ : m_name(name) {
+
+}
+
+
+mailboxGroup::~mailboxGroup() {
+
+ removeAllMailboxes();
+}
+
+
+void mailboxGroup::parseImpl(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition
+) {
+
+ const char* const pend = buffer.data() + end;
+ const char* const pstart = buffer.data() + position;
+ const char* p = pstart;
+
+ while (p < pend && parserHelpers::isSpace(*p)) {
+ ++p;
+ }
+
+ string name;
+
+ while (p < pend && *p != ':') {
+ name += *p;
+ ++p;
+ }
+
+ if (p < pend && *p == ':') {
+ ++p;
+ }
+
+
+ size_t pos = position + (p - pstart);
+ bool isLastAddressOfGroup = false;
+
+ while (pos < end && !isLastAddressOfGroup) {
+
+ shared_ptr <address> parsedAddress =
+ address::parseNext(ctx, buffer, pos, end, &pos, &isLastAddressOfGroup);
+
+ if (parsedAddress) {
+
+ if (parsedAddress->isGroup()) {
+
+ shared_ptr <mailboxGroup> group = dynamicCast <mailboxGroup>(parsedAddress);
+
+ // Sub-groups are not allowed in mailbox groups: so, we add all
+ // the contents of the sub-group into this group...
+ for (size_t i = 0 ; i < group->getMailboxCount() ; ++i) {
+ m_list.push_back(vmime::clone(group->getMailboxAt(i)));
+ }
+
+ } else {
+
+ m_list.push_back(dynamicCast <mailbox>(parsedAddress));
+ }
+ }
+ }
+
+ text::decodeAndUnfold(ctx, utility::stringUtils::trim(name), &m_name);
+
+ setParsedBounds(position, end);
+
+ if (newPosition) {
+ *newPosition = end;
+ }
+}
+
+
+void mailboxGroup::generateImpl(
+ const generationContext& ctx,
+ utility::outputStream& os,
+ const size_t curLinePos,
+ size_t* newLinePos
+) const {
+
+ // We have to encode the name:
+ // - if it contains characters in a charset different from "US-ASCII",
+ // - and/or if it contains one or more of these special chars:
+ // SPACE TAB " ; , < > ( ) @ / ? . = :
+
+ // Check whether there are words that are not "US-ASCII"
+ // and/or contain the special chars.
+ bool forceEncode = false;
+
+ for (size_t w = 0 ; !forceEncode && w < m_name.getWordCount() ; ++w) {
+
+ if (m_name.getWordAt(w)->getCharset() == charset(charsets::US_ASCII)) {
+
+ const string& buffer = m_name.getWordAt(w)->getBuffer();
+
+ for (string::const_iterator c = buffer.begin() ;
+ !forceEncode && c != buffer.end() ; ++c) {
+
+ switch (*c) {
+
+ case ' ':
+ case '\t':
+ case ';':
+ case ',':
+ case '<': case '>':
+ case '(': case ')':
+ case '@':
+ case '/':
+ case '?':
+ case '.':
+ case '=':
+ case ':':
+
+ forceEncode = true;
+ break;
+ }
+ }
+ }
+ }
+
+ size_t pos = curLinePos;
+
+ generationContext tmpCtx(ctx);
+ tmpCtx.setMaxLineLength(ctx.getMaxLineLength() - 2);
+
+ m_name.encodeAndFold(
+ ctx, os, pos, &pos,
+ forceEncode ? text::FORCE_ENCODING : 0
+ );
+
+ os << ":";
+ ++pos;
+
+ for (std::vector <shared_ptr <mailbox> >::const_iterator it = m_list.begin() ;
+ it != m_list.end() ; ++it) {
+
+ if (it != m_list.begin()) {
+
+ os << ", ";
+ pos += 2;
+
+ } else {
+
+ os << " ";
+ ++pos;
+ }
+
+ (*it)->generate(tmpCtx, os, pos, &pos);
+ }
+
+ os << ";";
+ pos++;
+
+ if (newLinePos) {
+ *newLinePos = pos;
+ }
+}
+
+
+void mailboxGroup::copyFrom(const component& other) {
+
+ const mailboxGroup& source = dynamic_cast <const mailboxGroup&>(other);
+
+ m_name = source.m_name;
+
+ removeAllMailboxes();
+
+ for (std::vector <shared_ptr <mailbox> >::const_iterator it = source.m_list.begin() ;
+ it != source.m_list.end() ; ++it) {
+
+ m_list.push_back(vmime::clone(*it));
+ }
+}
+
+
+shared_ptr <component> mailboxGroup::clone() const {
+
+ return make_shared <mailboxGroup>(*this);
+}
+
+
+mailboxGroup& mailboxGroup::operator=(const component& other) {
+
+ copyFrom(other);
+ return *this;
+}
+
+
+const text& mailboxGroup::getName() const {
+
+ return m_name;
+}
+
+
+void mailboxGroup::setName(const text& name) {
+
+ m_name = name;
+}
+
+
+bool mailboxGroup::isGroup() const {
+
+ return true;
+}
+
+
+bool mailboxGroup::isEmpty() const {
+
+ return m_list.empty();
+}
+
+
+void mailboxGroup::appendMailbox(const shared_ptr <mailbox>& mbox) {
+
+ m_list.push_back(mbox);
+}
+
+
+void mailboxGroup::insertMailboxBefore(
+ const shared_ptr <mailbox>& beforeMailbox,
+ const shared_ptr <mailbox>& mbox
+) {
+
+ const std::vector <shared_ptr <mailbox> >::iterator it =
+ std::find(m_list.begin(), m_list.end(), beforeMailbox);
+
+ if (it == m_list.end()) {
+ throw std::out_of_range("Invalid position");
+ }
+
+ m_list.insert(it, mbox);
+}
+
+
+void mailboxGroup::insertMailboxBefore(
+ const size_t pos,
+ const shared_ptr <mailbox>& mbox
+) {
+
+ if (pos >= m_list.size()) {
+ throw std::out_of_range("Invalid position");
+ }
+
+ m_list.insert(m_list.begin() + pos, mbox);
+}
+
+
+void mailboxGroup::insertMailboxAfter(
+ const shared_ptr <mailbox>& afterMailbox,
+ const shared_ptr <mailbox>& mbox
+) {
+
+ const std::vector <shared_ptr <mailbox> >::iterator it =
+ std::find(m_list.begin(), m_list.end(), afterMailbox);
+
+ if (it == m_list.end()) {
+ throw std::out_of_range("Invalid position");
+ }
+
+ m_list.insert(it + 1, mbox);
+}
+
+
+void mailboxGroup::insertMailboxAfter(
+ const size_t pos,
+ const shared_ptr <mailbox>& mbox
+) {
+
+ if (pos >= m_list.size()) {
+ throw std::out_of_range("Invalid position");
+ }
+
+ m_list.insert(m_list.begin() + pos + 1, mbox);
+}
+
+
+void mailboxGroup::removeMailbox(const shared_ptr <mailbox>& mbox) {
+
+ const std::vector <shared_ptr <mailbox> >::iterator it =
+ std::find(m_list.begin(), m_list.end(), mbox);
+
+ if (it == m_list.end()) {
+ throw std::out_of_range("Invalid position");
+ }
+
+ m_list.erase(it);
+}
+
+
+void mailboxGroup::removeMailbox(const size_t pos) {
+
+ if (pos >= m_list.size()) {
+ throw std::out_of_range("Invalid position");
+ }
+
+ const std::vector <shared_ptr <mailbox> >::iterator it = m_list.begin() + pos;
+
+ m_list.erase(it);
+}
+
+
+void mailboxGroup::removeAllMailboxes() {
+
+ m_list.clear();
+}
+
+
+size_t mailboxGroup::getMailboxCount() const {
+
+ return m_list.size();
+}
+
+
+shared_ptr <mailbox> mailboxGroup::getMailboxAt(const size_t pos) {
+
+ return m_list[pos];
+}
+
+
+const shared_ptr <const mailbox> mailboxGroup::getMailboxAt(const size_t pos) const {
+
+ return m_list[pos];
+}
+
+
+const std::vector <shared_ptr <const mailbox> > mailboxGroup::getMailboxList() const {
+
+ std::vector <shared_ptr <const mailbox> > list;
+
+ list.reserve(m_list.size());
+
+ for (std::vector <shared_ptr <mailbox> >::const_iterator it = m_list.begin() ;
+ it != m_list.end() ; ++it) {
+
+ list.push_back(*it);
+ }
+
+ return list;
+}
+
+
+const std::vector <shared_ptr <mailbox> > mailboxGroup::getMailboxList() {
+
+ return m_list;
+}
+
+
+const std::vector <shared_ptr <component> > mailboxGroup::getChildComponents() {
+
+ std::vector <shared_ptr <component> > list;
+
+ copy_vector(m_list, list);
+
+ return list;
+
+}
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/mailboxGroup.hpp b/vmime-master/src/vmime/mailboxGroup.hpp
new file mode 100644
index 0000000..4a7da3e
--- /dev/null
+++ b/vmime-master/src/vmime/mailboxGroup.hpp
@@ -0,0 +1,206 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_MAILBOXGROUP_HPP_INCLUDED
+#define VMIME_MAILBOXGROUP_HPP_INCLUDED
+
+
+#include "vmime/address.hpp"
+#include "vmime/mailbox.hpp"
+#include "vmime/text.hpp"
+
+
+namespace vmime {
+
+
+/** A group of mailboxes (basic type).
+ */
+class VMIME_EXPORT mailboxGroup : public address {
+
+public:
+
+ mailboxGroup();
+ mailboxGroup(const mailboxGroup& mboxGroup);
+ mailboxGroup(const text& name);
+
+ ~mailboxGroup();
+
+
+ void copyFrom(const component& other);
+ shared_ptr <component> clone() const;
+ mailboxGroup& operator=(const component& other);
+
+ const std::vector <shared_ptr <component> > getChildComponents();
+
+ /** Return the name of the group.
+ *
+ * @return group name
+ */
+ const text& getName() const;
+
+ /** Set the name of the group.
+ *
+ * @param name group name
+ */
+ void setName(const text& name);
+
+ /** Add a mailbox at the end of the list.
+ *
+ * @param mbox mailbox to append
+ */
+ void appendMailbox(const shared_ptr <mailbox>& mbox);
+
+ /** Insert a new mailbox before the specified mailbox.
+ *
+ * @param beforeMailbox mailbox before which the new mailbox will be inserted
+ * @param mbox mailbox to insert
+ * @throw std::out_of_range if the mailbox is not in the list
+ */
+ void insertMailboxBefore(
+ const shared_ptr <mailbox>& beforeMailbox,
+ const shared_ptr <mailbox>& mbox
+ );
+
+ /** Insert a new mailbox before the specified position.
+ *
+ * @param pos position at which to insert the new mailbox (0 to insert at
+ * the beginning of the list)
+ * @param mbox mailbox to insert
+ * @throw std::out_of_range if the position is out of range
+ */
+ void insertMailboxBefore(
+ const size_t pos,
+ const shared_ptr <mailbox>& mbox
+ );
+
+ /** Insert a new mailbox after the specified mailbox.
+ *
+ * @param afterMailbox mailbox after which the new mailbox will be inserted
+ * @param mbox mailbox to insert
+ * @throw std::out_of_range if the mailbox is not in the list
+ */
+ void insertMailboxAfter(
+ const shared_ptr <mailbox>& afterMailbox,
+ const shared_ptr <mailbox>& mbox
+ );
+
+ /** Insert a new mailbox after the specified position.
+ *
+ * @param pos position of the mailbox before the new mailbox
+ * @param mbox mailbox to insert
+ * @throw std::out_of_range if the position is out of range
+ */
+ void insertMailboxAfter(
+ const size_t pos,
+ const shared_ptr <mailbox>& mbox
+ );
+
+ /** Remove the specified mailbox from the list.
+ *
+ * @param mbox mailbox to remove
+ * @throw std::out_of_range if the mailbox is not in the list
+ */
+ void removeMailbox(const shared_ptr <mailbox>& mbox);
+
+ /** Remove the mailbox at the specified position.
+ *
+ * @param pos position of the mailbox to remove
+ * @throw std::out_of_range if the position is out of range
+ */
+ void removeMailbox(const size_t pos);
+
+ /** Remove all mailboxes from the list.
+ */
+ void removeAllMailboxes();
+
+ /** Return the number of mailboxes in the list.
+ *
+ * @return number of mailboxes
+ */
+ size_t getMailboxCount() const;
+
+ /** Tests whether the list of mailboxes is empty.
+ *
+ * @return true if there is no mailbox, false otherwise
+ */
+ bool isEmpty() const;
+
+ /** Return the mailbox at the specified position.
+ *
+ * @param pos position
+ * @return mailbox at position 'pos'
+ * @throw std::out_of_range if the position is out of range
+ */
+ shared_ptr <mailbox> getMailboxAt(const size_t pos);
+
+ /** Return the mailbox at the specified position.
+ *
+ * @param pos position
+ * @return mailbox at position 'pos'
+ * @throw std::out_of_range if the position is out of range
+ */
+ const shared_ptr <const mailbox> getMailboxAt(const size_t pos) const;
+
+ /** Return the mailbox list.
+ *
+ * @return list of mailboxes
+ */
+ const std::vector <shared_ptr <const mailbox> > getMailboxList() const;
+
+ /** Return the mailbox list.
+ *
+ * @return list of mailboxes
+ */
+ const std::vector <shared_ptr <mailbox> > getMailboxList();
+
+ bool isGroup() const;
+
+private:
+
+ text m_name;
+ std::vector <shared_ptr <mailbox> > m_list;
+
+protected:
+
+ // Component parsing & assembling
+ void parseImpl(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition = NULL
+ );
+
+ void generateImpl(
+ const generationContext& ctx,
+ utility::outputStream& os,
+ const size_t curLinePos = 0,
+ size_t* newLinePos = NULL
+ ) const;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_MAILBOXGROUP_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/mailboxList.cpp b/vmime-master/src/vmime/mailboxList.cpp
new file mode 100644
index 0000000..e7aba81
--- /dev/null
+++ b/vmime-master/src/vmime/mailboxList.cpp
@@ -0,0 +1,252 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/mailboxList.hpp"
+#include "vmime/mailboxGroup.hpp"
+#include "vmime/exception.hpp"
+
+
+namespace vmime {
+
+
+mailboxList::mailboxList() {
+
+}
+
+
+mailboxList::mailboxList(const mailboxList& mboxList)
+ : headerFieldValue(),
+ m_list(mboxList.m_list) {
+
+}
+
+
+void mailboxList::appendMailbox(const shared_ptr <mailbox>& mbox) {
+
+ m_list.appendAddress(mbox);
+}
+
+
+void mailboxList::insertMailboxBefore(
+ const shared_ptr <mailbox>& beforeMailbox,
+ const shared_ptr <mailbox>& mbox
+) {
+
+ m_list.insertAddressBefore(beforeMailbox, mbox);
+}
+
+
+void mailboxList::insertMailboxBefore(
+ const size_t pos,
+ const shared_ptr <mailbox>& mbox
+) {
+
+ m_list.insertAddressBefore(pos, mbox);
+}
+
+
+void mailboxList::insertMailboxAfter(
+ const shared_ptr <mailbox>& afterMailbox,
+ const shared_ptr <mailbox>& mbox
+) {
+
+ m_list.insertAddressAfter(afterMailbox, mbox);
+}
+
+
+void mailboxList::insertMailboxAfter(
+ const size_t pos,
+ const shared_ptr <mailbox>& mbox
+) {
+
+ m_list.insertAddressAfter(pos, mbox);
+}
+
+
+void mailboxList::removeMailbox(const shared_ptr <mailbox>& mbox) {
+
+ m_list.removeAddress(mbox);
+}
+
+
+void mailboxList::removeMailbox(const size_t pos) {
+
+ m_list.removeAddress(pos);
+}
+
+
+void mailboxList::removeAllMailboxes() {
+
+ m_list.removeAllAddresses();
+}
+
+
+size_t mailboxList::getMailboxCount() const {
+
+ return m_list.getAddressCount();
+}
+
+
+bool mailboxList::isEmpty() const {
+
+ return m_list.isEmpty();
+}
+
+
+shared_ptr <mailbox> mailboxList::getMailboxAt(const size_t pos) {
+
+ return dynamicCast <mailbox>(m_list.getAddressAt(pos));
+}
+
+
+const shared_ptr <const mailbox> mailboxList::getMailboxAt(const size_t pos) const {
+
+ return dynamicCast <const mailbox>(m_list.getAddressAt(pos));
+}
+
+
+const std::vector <shared_ptr <const mailbox> > mailboxList::getMailboxList() const {
+
+ const std::vector <shared_ptr <const address> > addrList = m_list.getAddressList();
+ std::vector <shared_ptr <const mailbox> > res;
+
+ for (std::vector <shared_ptr <const address> >::const_iterator it = addrList.begin() ;
+ it != addrList.end() ; ++it) {
+
+ const shared_ptr <const mailbox> mbox = dynamicCast <const mailbox>(*it);
+
+ if (mbox) {
+ res.push_back(mbox);
+ }
+ }
+
+ return res;
+}
+
+
+const std::vector <shared_ptr <mailbox> > mailboxList::getMailboxList() {
+
+ const std::vector <shared_ptr <address> > addrList = m_list.getAddressList();
+ std::vector <shared_ptr <mailbox> > res;
+
+ for (std::vector <shared_ptr <address> >::const_iterator it = addrList.begin() ;
+ it != addrList.end() ; ++it) {
+
+ const shared_ptr <mailbox> mbox = dynamicCast <mailbox>(*it);
+
+ if (mbox) {
+ res.push_back(mbox);
+ }
+ }
+
+ return res;
+}
+
+
+shared_ptr <component> mailboxList::clone() const {
+
+ return make_shared <mailboxList>(*this);
+}
+
+
+void mailboxList::copyFrom(const component& other) {
+
+ const mailboxList& mboxList = dynamic_cast <const mailboxList&>(other);
+
+ m_list = mboxList.m_list;
+}
+
+
+mailboxList& mailboxList::operator=(const mailboxList& other) {
+
+ copyFrom(other);
+ return *this;
+}
+
+
+const std::vector <shared_ptr <component> > mailboxList::getChildComponents() {
+
+ return m_list.getChildComponents();
+}
+
+
+void mailboxList::parseImpl(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition
+) {
+
+ m_list.removeAllAddresses();
+
+ size_t pos = position;
+
+ while (pos < end) {
+
+ shared_ptr <address> parsedAddress = address::parseNext(ctx, buffer, pos, end, &pos, NULL);
+
+ if (parsedAddress) {
+
+ if (parsedAddress->isGroup()) {
+
+ shared_ptr <mailboxGroup> group = dynamicCast <mailboxGroup>(parsedAddress);
+
+ for (size_t i = 0 ; i < group->getMailboxCount() ; ++i) {
+ m_list.appendAddress(group->getMailboxAt(i));
+ }
+
+ } else {
+
+ m_list.appendAddress(parsedAddress);
+ }
+ }
+ }
+
+ setParsedBounds(position, end);
+
+ if (newPosition) {
+ *newPosition = end;
+ }
+}
+
+
+void mailboxList::generateImpl(
+ const generationContext& ctx,
+ utility::outputStream& os,
+ const size_t curLinePos,
+ size_t* newLinePos
+) const {
+
+ m_list.generate(ctx, os, curLinePos, newLinePos);
+}
+
+
+shared_ptr <addressList> mailboxList::toAddressList() const {
+
+ return vmime::clone(m_list);
+}
+
+
+} // vmime
+
diff --git a/vmime-master/src/vmime/mailboxList.hpp b/vmime-master/src/vmime/mailboxList.hpp
new file mode 100644
index 0000000..8d799d2
--- /dev/null
+++ b/vmime-master/src/vmime/mailboxList.hpp
@@ -0,0 +1,184 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_MAILBOXLIST_HPP_INCLUDED
+#define VMIME_MAILBOXLIST_HPP_INCLUDED
+
+
+#include "vmime/addressList.hpp"
+#include "vmime/mailbox.hpp"
+
+
+namespace vmime {
+
+
+/** A list of mailboxes (basic type).
+ *
+ * This class works exactly like 'addressList' except it prevents user
+ * from inserting mailbox groups where it is not allowed by the RFC.
+ */
+class VMIME_EXPORT mailboxList : public headerFieldValue {
+
+public:
+
+ mailboxList();
+ mailboxList(const mailboxList& mboxList);
+
+
+ shared_ptr <component> clone() const;
+ void copyFrom(const component& other);
+ mailboxList& operator=(const mailboxList& other);
+
+ const std::vector <shared_ptr <component> > getChildComponents();
+
+ /** Add a mailbox at the end of the list.
+ *
+ * @param mbox mailbox to append
+ */
+ void appendMailbox(const shared_ptr <mailbox>& mbox);
+
+ /** Insert a new mailbox before the specified mailbox.
+ *
+ * @param beforeMailbox mailbox before which the new mailbox will be inserted
+ * @param mbox mailbox to insert
+ * @throw std::out_of_range if the mailbox is not in the list
+ */
+ void insertMailboxBefore(const shared_ptr <mailbox>& beforeMailbox, const shared_ptr <mailbox>& mbox);
+
+ /** Insert a new mailbox before the specified position.
+ *
+ * @param pos position at which to insert the new mailbox (0 to insert at
+ * the beginning of the list)
+ * @param mbox mailbox to insert
+ * @throw std::out_of_range if the position is out of range
+ */
+ void insertMailboxBefore(const size_t pos, const shared_ptr <mailbox>& mbox);
+
+ /** Insert a new mailbox after the specified mailbox.
+ *
+ * @param afterMailbox mailbox after which the new mailbox will be inserted
+ * @param mbox mailbox to insert
+ * @throw std::out_of_range if the mailbox is not in the list
+ */
+ void insertMailboxAfter(const shared_ptr <mailbox>& afterMailbox, const shared_ptr <mailbox>& mbox);
+
+ /** Insert a new mailbox after the specified position.
+ *
+ * @param pos position of the mailbox before the new mailbox
+ * @param mbox mailbox to insert
+ * @throw std::out_of_range if the position is out of range
+ */
+ void insertMailboxAfter(const size_t pos, const shared_ptr <mailbox>& mbox);
+
+ /** Remove the specified mailbox from the list.
+ *
+ * @param mbox mailbox to remove
+ * @throw std::out_of_range if the mailbox is not in the list
+ */
+ void removeMailbox(const shared_ptr <mailbox>& mbox);
+
+ /** Remove the mailbox at the specified position.
+ *
+ * @param pos position of the mailbox to remove
+ * @throw std::out_of_range if the position is out of range
+ */
+ void removeMailbox(const size_t pos);
+
+ /** Remove all mailboxes from the list.
+ */
+ void removeAllMailboxes();
+
+ /** Return the number of mailboxes in the list.
+ *
+ * @return number of mailboxes
+ */
+ size_t getMailboxCount() const;
+
+ /** Tests whether the list of mailboxes is empty.
+ *
+ * @return true if there is no mailbox, false otherwise
+ */
+ bool isEmpty() const;
+
+ /** Return the mailbox at the specified position.
+ *
+ * @param pos position
+ * @return mailbox at position 'pos'
+ * @throw std::out_of_range if the position is out of range
+ */
+ shared_ptr <mailbox> getMailboxAt(const size_t pos);
+
+ /** Return the mailbox at the specified position.
+ *
+ * @param pos position
+ * @return mailbox at position 'pos'
+ * @throw std::out_of_range if the position is out of range
+ */
+ const shared_ptr <const mailbox> getMailboxAt(const size_t pos) const;
+
+ /** Return the mailbox list.
+ *
+ * @return list of mailboxes
+ */
+ const std::vector <shared_ptr <const mailbox> > getMailboxList() const;
+
+ /** Return the mailbox list.
+ *
+ * @return list of mailboxes
+ */
+ const std::vector <shared_ptr <mailbox> > getMailboxList();
+
+ /** Return a list of addresses.
+ *
+ * @return list of addresses
+ */
+ shared_ptr <addressList> toAddressList() const;
+
+private:
+
+ addressList m_list;
+
+protected:
+
+ // Component parsing & assembling
+ void parseImpl(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition = NULL
+ );
+
+ void generateImpl(
+ const generationContext& ctx,
+ utility::outputStream& os,
+ const size_t curLinePos = 0,
+ size_t* newLinePos = NULL
+ ) const;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_MAILBOXLIST_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/mdn/MDNHelper.cpp b/vmime-master/src/vmime/mdn/MDNHelper.cpp
new file mode 100644
index 0000000..a21a181
--- /dev/null
+++ b/vmime-master/src/vmime/mdn/MDNHelper.cpp
@@ -0,0 +1,362 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/mdn/MDNHelper.hpp"
+
+#include "vmime/exception.hpp"
+#include "vmime/stringContentHandler.hpp"
+
+#include "vmime/contentTypeField.hpp"
+
+#include "vmime/path.hpp"
+#include "vmime/dateTime.hpp"
+
+#include "vmime/utility/outputStreamAdapter.hpp"
+
+
+namespace vmime {
+namespace mdn {
+
+
+void MDNHelper::attachMDNRequest(const shared_ptr <message>& msg, const mailboxList& mailboxes) {
+
+ shared_ptr <header> hdr = msg->getHeader();
+
+ hdr->DispositionNotificationTo()->setValue(mailboxes);
+}
+
+
+void MDNHelper::attachMDNRequest(const shared_ptr <message>& msg, const mailbox& mbox) {
+
+ mailboxList mboxList;
+ mboxList.appendMailbox(vmime::clone(mbox));
+
+ attachMDNRequest(msg, mboxList);
+}
+
+
+const std::vector <sendableMDNInfos> MDNHelper::getPossibleMDNs(const shared_ptr <const message>& msg) {
+
+ std::vector <sendableMDNInfos> result;
+
+ const shared_ptr <const header> hdr = msg->getHeader();
+
+ if (hdr->hasField(fields::DISPOSITION_NOTIFICATION_TO)) {
+
+ const mailboxList& dnto =
+ *hdr->DispositionNotificationTo()->getValue <mailboxList>();
+
+ for (size_t i = 0 ; i < dnto.getMailboxCount() ; ++i) {
+ result.push_back(sendableMDNInfos(msg, *dnto.getMailboxAt(i)));
+ }
+ }
+
+ return result;
+}
+
+
+bool MDNHelper::isMDN(const shared_ptr <const message>& msg)
+{
+ const shared_ptr <const header> hdr = msg->getHeader();
+
+ // A MDN message implies the following:
+ // - a Content-Type field is present and its value is "multipart/report"
+ // - a "report-type" parameter is present in the Content-Type field,
+ // and its value is "disposition-notification"
+ if (hdr->hasField(fields::CONTENT_TYPE)) {
+
+ const contentTypeField& ctf = *dynamicCast <const contentTypeField>(hdr->ContentType());
+
+ const mediaType type = *ctf.getValue <mediaType>();
+
+ if (type.getType() == vmime::mediaTypes::MULTIPART &&
+ type.getSubType() == vmime::mediaTypes::MULTIPART_REPORT) {
+
+ if (ctf.hasParameter("report-type") &&
+ ctf.getReportType() == "disposition-notification") {
+
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+
+receivedMDNInfos MDNHelper::getReceivedMDN(const shared_ptr <const message>& msg)
+{
+ if (!isMDN(msg)) {
+ throw exceptions::invalid_argument();
+ }
+
+ return receivedMDNInfos(msg);
+}
+
+
+bool MDNHelper::needConfirmation(const shared_ptr <const message>& msg)
+{
+ shared_ptr <const header> hdr = msg->getHeader();
+
+ // No "Return-Path" field
+ if (!hdr->hasField(fields::RETURN_PATH)) {
+ return true;
+ }
+
+ // More than one address in Disposition-Notification-To
+ if (hdr->hasField(fields::DISPOSITION_NOTIFICATION_TO)) {
+
+ const mailboxList& dnto = *hdr->DispositionNotificationTo()->getValue <mailboxList>();
+
+ if (dnto.getMailboxCount() > 1) {
+ return true;
+ } else if (dnto.getMailboxCount() == 0) {
+ return false;
+ }
+
+ // Return-Path != Disposition-Notification-To
+ const mailbox& mbox = *dnto.getMailboxAt(0);
+ const path& rp = *hdr->ReturnPath()->getValue <path>();
+
+ if (mbox.getEmail() != rp.getLocalPart() + "@" + rp.getDomain()) {
+ return true;
+ }
+ }
+
+ // User confirmation not needed
+ return false;
+}
+
+
+shared_ptr <message> MDNHelper::buildMDN(
+ const sendableMDNInfos& mdnInfos,
+ const string& text,
+ const charset& ch,
+ const mailbox& expeditor,
+ const disposition& dispo,
+ const string& reportingUA,
+ const std::vector <string>& reportingUAProducts,
+ const std::map <string, string>& fields
+) {
+
+ // Create a new message
+ shared_ptr <message> msg = make_shared <message>();
+
+ // Fill-in header fields
+ shared_ptr <header> hdr = msg->getHeader();
+
+ hdr->ContentType()->setValue(
+ mediaType(vmime::mediaTypes::MULTIPART, vmime::mediaTypes::MULTIPART_REPORT)
+ );
+
+ dynamicCast <contentTypeField>(hdr->ContentType())->setReportType("disposition-notification");
+
+ hdr->Disposition()->setValue(dispo);
+
+ addressList to;
+ to.appendAddress(make_shared <mailbox>(mdnInfos.getRecipient()));
+ hdr->To()->setValue(to);
+
+ hdr->From()->setValue(expeditor);
+
+ hdr->Subject()->setValue(vmime::text(word("Disposition notification")));
+
+ hdr->Date()->setValue(datetime::now());
+ hdr->MimeVersion()->setValue(string(SUPPORTED_MIME_VERSION));
+
+ msg->getBody()->appendPart(createFirstMDNPart(mdnInfos, text, ch));
+ msg->getBody()->appendPart(createSecondMDNPart(mdnInfos,
+ dispo, reportingUA, reportingUAProducts, fields));
+ msg->getBody()->appendPart(createThirdMDNPart(mdnInfos));
+
+ return msg;
+}
+
+
+shared_ptr <bodyPart> MDNHelper::createFirstMDNPart(
+ const sendableMDNInfos& /* mdnInfos */,
+ const string& text,
+ const charset& ch
+) {
+
+ shared_ptr <bodyPart> part = make_shared <bodyPart>();
+
+ // Header
+ shared_ptr <header> hdr = part->getHeader();
+
+ hdr->ContentType()->setValue(
+ mediaType(vmime::mediaTypes::TEXT, vmime::mediaTypes::TEXT_PLAIN)
+ );
+
+ dynamicCast <contentTypeField>(hdr->ContentType())->setCharset(ch);
+
+ // Body
+ part->getBody()->setContents(make_shared <stringContentHandler>(text));
+
+ return part;
+}
+
+
+shared_ptr <bodyPart> MDNHelper::createSecondMDNPart(
+ const sendableMDNInfos& mdnInfos,
+ const disposition& dispo,
+ const string& reportingUA,
+ const std::vector <string>& reportingUAProducts,
+ const std::map <string, string>& additionalFields
+) {
+
+ shared_ptr <bodyPart> part = make_shared <bodyPart>();
+
+ // Header
+ shared_ptr <header> hdr = part->getHeader();
+
+ hdr->ContentDisposition()->setValue(vmime::contentDispositionTypes::INLINE);
+ hdr->ContentType()->setValue(mediaType(vmime::mediaTypes::MESSAGE,
+ vmime::mediaTypes::MESSAGE_DISPOSITION_NOTIFICATION));
+
+ // Body
+ //
+ // The body of a message/disposition-notification consists of one or
+ // more "fields" formatted according to the ABNF of [RFC-MSGFMT] header
+ // "fields". The syntax of the message/disposition-notification content
+ // is as follows:
+ //
+ // disposition-notification-content = [ reporting-ua-field CRLF ]
+ // [ mdn-gateway-field CRLF ]
+ // [ original-recipient-field CRLF ]
+ // final-recipient-field CRLF
+ // [ original-message-id-field CRLF ]
+ // disposition-field CRLF
+ // *( failure-field CRLF )
+ // *( error-field CRLF )
+ // *( warning-field CRLF )
+ // *( extension-field CRLF )
+ //
+ header fields;
+
+ // -- Reporting-UA (optional)
+ if (!reportingUA.empty()) {
+
+ string ruaText;
+ ruaText = reportingUA;
+
+ for (unsigned int i = 0 ; i < reportingUAProducts.size() ; ++i) {
+
+ if (i == 0) {
+ ruaText += "; ";
+ } else {
+ ruaText += ", ";
+ }
+
+ ruaText += reportingUAProducts[i];
+ }
+
+ shared_ptr <headerField> rua = headerFieldFactory::getInstance()->
+ create(vmime::fields::REPORTING_UA);
+
+ rua->setValue(ruaText);
+
+ fields.appendField(rua);
+ }
+
+ // -- Final-Recipient
+ shared_ptr <headerField> fr = headerFieldFactory::getInstance()->
+ create(vmime::fields::FINAL_RECIPIENT);
+
+ fr->setValue("rfc822; " + mdnInfos.getRecipient().getEmail().generate());
+
+ fields.appendField(fr);
+
+ // -- Original-Message-ID
+ if (mdnInfos.getMessage()->getHeader()->hasField(vmime::fields::MESSAGE_ID)) {
+
+ fields.OriginalMessageId()->setValueConst
+ (mdnInfos.getMessage()->getHeader()->MessageId()->getValue());
+ }
+
+ // -- Disposition
+ fields.Disposition()->setValue(dispo);
+
+ // -- Failure, Error and Warning fields
+ std::map <string, string>::const_iterator it;
+
+ if (additionalFields.size() > 0) {
+
+ if ((it = additionalFields.find(vmime::fields::ERROR)) != additionalFields.end()) {
+
+ shared_ptr <headerField> error = headerFieldFactory::getInstance()->create(vmime::fields::ERROR);
+ error->setValue(it->second);
+ fields.appendField(error);
+ }
+
+ if ((it = additionalFields.find(vmime::fields::WARNING)) != additionalFields.end()) {
+
+ shared_ptr <headerField> warn = headerFieldFactory::getInstance()->create(vmime::fields::WARNING);
+ warn->setValue(it->second);
+ fields.appendField(warn);
+ }
+
+ if ((it = additionalFields.find(vmime::fields::FAILURE)) != additionalFields.end()) {
+
+ shared_ptr <headerField> fail = headerFieldFactory::getInstance()->create(vmime::fields::FAILURE);
+ fail->setValue(it->second);
+ fields.appendField(fail);
+ }
+ }
+
+ std::ostringstream oss;
+ utility::outputStreamAdapter vos(oss);
+
+ fields.generate(vos);
+
+ part->getBody()->setContents(make_shared <stringContentHandler>(oss.str()));
+
+ return part;
+}
+
+
+shared_ptr <bodyPart> MDNHelper::createThirdMDNPart(const sendableMDNInfos& mdnInfos) {
+
+ shared_ptr <bodyPart> part = make_shared <bodyPart>();
+
+ // Header
+ shared_ptr <header> hdr = part->getHeader();
+
+ hdr->ContentDisposition()->setValue(vmime::contentDispositionTypes::INLINE);
+ hdr->ContentType()->setValue(mediaType(vmime::mediaTypes::TEXT,
+ vmime::mediaTypes::TEXT_RFC822_HEADERS));
+
+ // Body: original message headers
+ std::ostringstream oss;
+ utility::outputStreamAdapter vos(oss);
+
+ mdnInfos.getMessage()->getHeader()->generate(vos);
+
+ part->getBody()->setContents(make_shared <stringContentHandler>(oss.str()));
+
+ return part;
+}
+
+
+} // mdn
+} // vmime
diff --git a/vmime-master/src/vmime/mdn/MDNHelper.hpp b/vmime-master/src/vmime/mdn/MDNHelper.hpp
new file mode 100644
index 0000000..c1bec2f
--- /dev/null
+++ b/vmime-master/src/vmime/mdn/MDNHelper.hpp
@@ -0,0 +1,142 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_MDN_MDNHELPER_HPP_INCLUDED
+#define VMIME_MDN_MDNHELPER_HPP_INCLUDED
+
+
+#include "vmime/mdn/receivedMDNInfos.hpp"
+#include "vmime/mdn/sendableMDNInfos.hpp"
+
+#include "vmime/mailboxList.hpp"
+
+
+namespace vmime {
+namespace mdn {
+
+
+/** Helper for creating or extracting Message Disposition
+ * Notifications (MDN), as defined in RFC-3798.
+ */
+class VMIME_EXPORT MDNHelper {
+
+public:
+
+ /** Attach a MDN request to the specified message.
+ *
+ * @param msg message in which to add a MDN request
+ * @param mailboxes list of mailboxes to which the MDN will be sent
+ */
+ static void attachMDNRequest(const shared_ptr <message>& msg, const mailboxList& mailboxes);
+
+ /** Attach a MDN request to the specified message.
+ *
+ * @param msg message in which to add a MDN request
+ * @param mbox mailbox to which the MDN will be sent
+ */
+ static void attachMDNRequest(const shared_ptr <message>& msg, const mailbox& mbox);
+
+ /** Return a list of possible MDNs that can be generated
+ * for the specified message.
+ *
+ * @param msg message for which to send a MDN
+ * @return list of possible MDNs
+ */
+ static const std::vector <sendableMDNInfos> getPossibleMDNs(const shared_ptr <const message>& msg);
+
+ /** Test whether the specified message is a MDN.
+ *
+ * @param msg message
+ * @return true if the message is a MDN, false otherwise
+ */
+ static bool isMDN(const shared_ptr <const message>& msg);
+
+ /** If the specified message is a MDN, return information
+ * about it.
+ *
+ * @param msg message
+ * @throw exceptions::invalid_argument if the message is not a MDN
+ * @return information about the MDN
+ */
+ static receivedMDNInfos getReceivedMDN(const shared_ptr <const message>& msg);
+
+ /** Check whether we need user confirmation for sending a MDN even
+ * if he/she explicitely allowed automatic send of MDNs. This can
+ * happen in some situations, described in RFC-3798.
+ *
+ * @param msg message for which to send a MDN
+ * @return true if user confirmation should be asked, false otherwise
+ */
+ static bool needConfirmation(const shared_ptr <const message>& msg);
+
+ /** Build a new MDN for the message. The resulting MDN can then be
+ * sent over SMTP transport service.
+ *
+ * @param mdnInfos information about the MDN to construct
+ * @param text human readable message. The purpose of this message is
+ * to provide an easily-understood description of the
+ * condition(s) that caused the report to be generated.
+ * @param ch charset of the text
+ * @param expeditor expeditor of the MDN
+ * @param dispo disposition information
+ * @param reportingUA name of reporting user-agent (optional)
+ * @param reportingUAProducts list of products in the reporting user-agent (optional)
+ * @param fields additional MDN fields, like "Error", "Warning" or "Failure" (optional)
+ * @return a new message object containing the MDN
+ */
+ static shared_ptr <message> buildMDN(
+ const sendableMDNInfos& mdnInfos,
+ const string& text,
+ const charset& ch,
+ const mailbox& expeditor,
+ const disposition& dispo,
+ const string& reportingUA = NULL_STRING,
+ const std::vector <string>& reportingUAProducts = std::vector <string>(),
+ const std::map <string, string>& fields = std::map <string, string>()
+ );
+
+private:
+
+ static shared_ptr <bodyPart> createFirstMDNPart(
+ const sendableMDNInfos& mdnInfos,
+ const string& text,
+ const charset& ch
+ );
+
+ static shared_ptr <bodyPart> createSecondMDNPart(
+ const sendableMDNInfos& mdnInfos,
+ const disposition& dispo,
+ const string& reportingUA,
+ const std::vector <string>& reportingUAProducts,
+ const std::map <string, string>& fields
+ );
+
+ static shared_ptr <bodyPart> createThirdMDNPart(const sendableMDNInfos& mdnInfos);
+};
+
+
+} // mdn
+} // vmime
+
+
+#endif // VMIME_MDN_MDNHELPER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/mdn/MDNInfos.cpp b/vmime-master/src/vmime/mdn/MDNInfos.cpp
new file mode 100644
index 0000000..3efe9f9
--- /dev/null
+++ b/vmime-master/src/vmime/mdn/MDNInfos.cpp
@@ -0,0 +1,38 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/mdn/MDNInfos.hpp"
+
+
+namespace vmime {
+namespace mdn {
+
+
+
+MDNInfos::~MDNInfos() {
+
+}
+
+
+} // mdn
+} // vmime
diff --git a/vmime-master/src/vmime/mdn/MDNInfos.hpp b/vmime-master/src/vmime/mdn/MDNInfos.hpp
new file mode 100644
index 0000000..f6d7929
--- /dev/null
+++ b/vmime-master/src/vmime/mdn/MDNInfos.hpp
@@ -0,0 +1,57 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_MDN_MDNINFOS_HPP_INCLUDED
+#define VMIME_MDN_MDNINFOS_HPP_INCLUDED
+
+
+#include "vmime/types.hpp"
+#include "vmime/message.hpp"
+
+
+namespace vmime {
+namespace mdn {
+
+
+/** Holds information about Message Disposition Notifications (MDN).
+ */
+class VMIME_EXPORT MDNInfos : public object {
+
+public:
+
+ virtual ~MDNInfos();
+
+
+ /** Return the message related to this MDN.
+ *
+ * @return related message
+ */
+ virtual const shared_ptr <const message> getMessage() const = 0;
+};
+
+
+} // mdn
+} // vmime
+
+
+#endif // VMIME_MDN_MDNINFOS_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/mdn/receivedMDNInfos.cpp b/vmime-master/src/vmime/mdn/receivedMDNInfos.cpp
new file mode 100644
index 0000000..6f4463e
--- /dev/null
+++ b/vmime-master/src/vmime/mdn/receivedMDNInfos.cpp
@@ -0,0 +1,140 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/mdn/receivedMDNInfos.hpp"
+
+#include "vmime/utility/outputStreamAdapter.hpp"
+
+
+namespace vmime {
+namespace mdn {
+
+
+receivedMDNInfos::receivedMDNInfos(const shared_ptr <const message>& msg)
+ : m_msg(msg) {
+
+ extract();
+}
+
+
+receivedMDNInfos::receivedMDNInfos(const receivedMDNInfos& other)
+ : MDNInfos() {
+
+ copyFrom(other);
+}
+
+
+receivedMDNInfos& receivedMDNInfos::operator=(const receivedMDNInfos& other) {
+
+ copyFrom(other);
+ return *this;
+}
+
+
+const shared_ptr <const message> receivedMDNInfos::getMessage() const {
+
+ return m_msg;
+}
+
+
+const messageId receivedMDNInfos::getOriginalMessageId() const {
+
+ return m_omid;
+}
+
+
+const disposition receivedMDNInfos::getDisposition() const {
+
+ return m_disp;
+}
+
+
+const string receivedMDNInfos::getContentMIC() const {
+
+ return m_contentMIC;
+}
+
+
+void receivedMDNInfos::copyFrom(const receivedMDNInfos& other) {
+
+ m_msg = other.m_msg;
+ m_omid = other.m_omid;
+ m_disp = other.m_disp;
+ m_contentMIC = other.m_contentMIC;
+}
+
+
+void receivedMDNInfos::extract() {
+
+ const shared_ptr <const body> bdy = m_msg->getBody();
+
+ for (size_t i = 0 ; i < bdy->getPartCount() ; ++i) {
+
+ const shared_ptr <const bodyPart> part = bdy->getPartAt(i);
+
+ if (!part->getHeader()->hasField(fields::CONTENT_TYPE)) {
+ continue;
+ }
+
+ const mediaType& type = *part->getHeader()->ContentType()->getValue <mediaType>();
+
+ // Extract from second part (message/disposition-notification)
+ if (type.getType() == vmime::mediaTypes::MESSAGE &&
+ type.getSubType() == vmime::mediaTypes::MESSAGE_DISPOSITION_NOTIFICATION) {
+
+ std::ostringstream oss;
+ utility::outputStreamAdapter vos(oss);
+
+ part->getBody()->getContents()->extract(vos);
+
+ // Body actually contains fields
+ header fields;
+ fields.parse(oss.str());
+
+ shared_ptr <messageId> omid =
+ fields.findFieldValue <messageId>(fields::ORIGINAL_MESSAGE_ID);
+
+ if (omid) {
+ m_omid = *omid;
+ }
+
+ shared_ptr <disposition> disp =
+ fields.findFieldValue <disposition>(fields::DISPOSITION);
+
+ if (disp) {
+ m_disp = *disp;
+ }
+
+ shared_ptr <text> contentMIC =
+ fields.findFieldValue <text>("Received-content-MIC");
+
+ if (contentMIC) {
+ m_contentMIC = contentMIC->generate();
+ }
+ }
+ }
+}
+
+
+} // mdn
+} // vmime
diff --git a/vmime-master/src/vmime/mdn/receivedMDNInfos.hpp b/vmime-master/src/vmime/mdn/receivedMDNInfos.hpp
new file mode 100644
index 0000000..7809acb
--- /dev/null
+++ b/vmime-master/src/vmime/mdn/receivedMDNInfos.hpp
@@ -0,0 +1,93 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_MDN_RECEIVEDMDNINFOS_HPP_INCLUDED
+#define VMIME_MDN_RECEIVEDMDNINFOS_HPP_INCLUDED
+
+
+#include "vmime/mdn/MDNInfos.hpp"
+
+#include "vmime/disposition.hpp"
+#include "vmime/messageId.hpp"
+#include "vmime/mailbox.hpp"
+
+
+namespace vmime {
+namespace mdn {
+
+
+/** Holds information about a Message Disposition Notification (MDN)
+ * that has been received.
+ */
+class VMIME_EXPORT receivedMDNInfos : public MDNInfos {
+
+public:
+
+ receivedMDNInfos(const shared_ptr <const message>& msg);
+ receivedMDNInfos(const receivedMDNInfos& other);
+
+ receivedMDNInfos& operator=(const receivedMDNInfos& other);
+
+
+ const shared_ptr <const message> getMessage() const;
+
+ /** Return the identifier of the message for which this MDN
+ * has been generated.
+ *
+ * @return original message-id
+ */
+ const messageId getOriginalMessageId() const;
+
+ /** Return information about the disposition.
+ *
+ * @return disposition information
+ */
+ const disposition getDisposition() const;
+
+ /** Return the Message Integrity Check (MIC), that is the value
+ * of the "Received-content-MIC" field.
+ *
+ * @return MIC hash value, or an empty string if not specified
+ */
+ const string getContentMIC() const;
+
+private:
+
+ void copyFrom(const receivedMDNInfos& other);
+
+ void extract();
+
+
+ shared_ptr <const message> m_msg;
+
+ disposition m_disp;
+ messageId m_omid;
+ string m_contentMIC;
+};
+
+
+} // mdn
+} // vmime
+
+
+#endif // VMIME_MDN_RECEIVEDMDNINFOS_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/mdn/sendableMDNInfos.cpp b/vmime-master/src/vmime/mdn/sendableMDNInfos.cpp
new file mode 100644
index 0000000..281655f
--- /dev/null
+++ b/vmime-master/src/vmime/mdn/sendableMDNInfos.cpp
@@ -0,0 +1,72 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/mdn/sendableMDNInfos.hpp"
+
+
+namespace vmime {
+namespace mdn {
+
+
+sendableMDNInfos::sendableMDNInfos(const shared_ptr <const message>& msg, const mailbox& mbox)
+ : m_msg(msg),
+ m_mailbox(mbox) {
+
+}
+
+
+sendableMDNInfos::sendableMDNInfos(const sendableMDNInfos& other)
+ : MDNInfos() {
+
+ copyFrom(other);
+}
+
+
+sendableMDNInfos& sendableMDNInfos::operator=(const sendableMDNInfos& other) {
+
+ copyFrom(other);
+ return *this;
+}
+
+
+const shared_ptr <const message> sendableMDNInfos::getMessage() const {
+
+ return m_msg;
+}
+
+
+const mailbox& sendableMDNInfos::getRecipient() const {
+
+ return m_mailbox;
+}
+
+
+void sendableMDNInfos::copyFrom(const sendableMDNInfos& other) {
+
+ m_msg = other.m_msg;
+ m_mailbox = other.m_mailbox;
+}
+
+
+} // mdn
+} // vmime
diff --git a/vmime-master/src/vmime/mdn/sendableMDNInfos.hpp b/vmime-master/src/vmime/mdn/sendableMDNInfos.hpp
new file mode 100644
index 0000000..5b69b94
--- /dev/null
+++ b/vmime-master/src/vmime/mdn/sendableMDNInfos.hpp
@@ -0,0 +1,72 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_MDN_SENDABLEMDNINFOS_HPP_INCLUDED
+#define VMIME_MDN_SENDABLEMDNINFOS_HPP_INCLUDED
+
+
+#include "vmime/mdn/MDNInfos.hpp"
+
+#include "vmime/mailbox.hpp"
+
+
+namespace vmime {
+namespace mdn {
+
+
+/** Holds information about a Message Disposition Notifications (MDN)
+ * that is to be sent.
+ */
+class VMIME_EXPORT sendableMDNInfos : public MDNInfos {
+
+public:
+
+ sendableMDNInfos(const shared_ptr <const message>& msg, const mailbox& mbox);
+ sendableMDNInfos(const sendableMDNInfos& other);
+
+ sendableMDNInfos& operator=(const sendableMDNInfos& other);
+
+ const shared_ptr <const message> getMessage() const;
+
+ /** Return the recipient of the MDN (the mailbox that will receive
+ * the notification message).
+ *
+ * @return recipient of the MDN
+ */
+ const mailbox& getRecipient() const;
+
+private:
+
+ void copyFrom(const sendableMDNInfos& other);
+
+
+ shared_ptr <const message> m_msg;
+ mailbox m_mailbox;
+};
+
+
+} // mdn
+} // vmime
+
+
+#endif // VMIME_MDN_SENDABLEMDNINFOS_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/mediaType.cpp b/vmime-master/src/vmime/mediaType.cpp
new file mode 100644
index 0000000..9547593
--- /dev/null
+++ b/vmime-master/src/vmime/mediaType.cpp
@@ -0,0 +1,207 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/mediaType.hpp"
+#include "vmime/parserHelpers.hpp"
+
+
+namespace vmime {
+
+
+mediaType::mediaType()
+ : m_type(mediaTypes::APPLICATION),
+ m_subType(mediaTypes::APPLICATION_OCTET_STREAM) {
+
+}
+
+
+mediaType::mediaType(const string& type) {
+
+ parse(type);
+}
+
+
+mediaType::mediaType(const string& type, const string& subType)
+ : m_type(utility::stringUtils::toLower(type)),
+ m_subType(utility::stringUtils::toLower(subType)) {
+
+}
+
+
+void mediaType::parseImpl(
+ const parsingContext& /* ctx */,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition
+) {
+
+ const char* const pend = buffer.data() + end;
+ const char* const pstart = buffer.data() + position;
+ const char* p = pstart;
+
+ // Extract the type
+ const size_t typeStart = position;
+
+ while (p < pend && *p != '/') ++p;
+
+ m_type = utility::stringUtils::trim(
+ utility::stringUtils::toLower(
+ string(
+ buffer.begin() + typeStart,
+ buffer.begin() + position + (p - pstart)
+ )
+ )
+ );
+
+ if (p < pend) {
+
+ // Skip '/' character
+ ++p;
+
+ // Extract the sub-type
+ m_subType = utility::stringUtils::trim(
+ utility::stringUtils::toLower(
+ string(
+ buffer.begin() + position + (p - pstart),
+ buffer.begin() + end
+ )
+ )
+ );
+ }
+
+ setParsedBounds(position, end);
+
+ if (newPosition) {
+ *newPosition = end;
+ }
+}
+
+
+void mediaType::generateImpl(
+ const generationContext& ctx,
+ utility::outputStream& os,
+ const size_t curLinePos,
+ size_t* newLinePos
+) const {
+
+ const string value = m_type + "/" + m_subType;
+
+ if (curLinePos + value.length() > ctx.getMaxLineLength()) {
+
+ os << NEW_LINE_SEQUENCE;
+ os << value;
+
+ if (newLinePos) {
+ *newLinePos = NEW_LINE_SEQUENCE_LENGTH + value.length();
+ }
+
+ } else {
+
+ os << value;
+
+ if (newLinePos) {
+ *newLinePos = curLinePos + value.length();
+ }
+ }
+}
+
+
+bool mediaType::operator==(const mediaType& type) const {
+
+ return m_type == type.m_type && m_subType == type.m_subType;
+}
+
+
+bool mediaType::operator!=(const mediaType& type) const {
+
+ return !(*this == type);
+}
+
+
+mediaType& mediaType::operator=(const string& type) {
+
+ parse(type);
+ return *this;
+}
+
+
+shared_ptr <component> mediaType::clone() const {
+
+ return make_shared <mediaType>(m_type, m_subType);
+}
+
+
+void mediaType::copyFrom(const component& other) {
+
+ const mediaType& mt = dynamic_cast <const mediaType&>(other);
+
+ m_type = mt.m_type;
+ m_subType = mt.m_subType;
+}
+
+
+mediaType& mediaType::operator=(const mediaType& other) {
+
+ copyFrom(other);
+ return *this;
+}
+
+
+const string& mediaType::getType() const {
+
+ return m_type;
+}
+
+
+void mediaType::setType(const string& type) {
+
+ m_type = utility::stringUtils::toLower(type);
+}
+
+
+const string& mediaType::getSubType() const {
+
+ return m_subType;
+}
+
+
+void mediaType::setSubType(const string& subType) {
+
+ m_subType = utility::stringUtils::toLower(subType);
+}
+
+
+void mediaType::setFromString(const string& type) {
+
+ parse(type);
+}
+
+
+const std::vector <shared_ptr <component> > mediaType::getChildComponents() {
+
+ return std::vector <shared_ptr <component> >();
+}
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/mediaType.hpp b/vmime-master/src/vmime/mediaType.hpp
new file mode 100644
index 0000000..4026167
--- /dev/null
+++ b/vmime-master/src/vmime/mediaType.hpp
@@ -0,0 +1,119 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_MEDIATYPE_HPP_INCLUDED
+#define VMIME_MEDIATYPE_HPP_INCLUDED
+
+
+#include "vmime/base.hpp"
+#include "vmime/headerFieldValue.hpp"
+
+
+namespace vmime {
+
+
+/** Content media type (basic type).
+ */
+class VMIME_EXPORT mediaType : public headerFieldValue {
+
+public:
+
+ mediaType();
+ mediaType(const string& type);
+ mediaType(const string& type, const string& subType);
+
+public:
+
+ bool operator==(const mediaType& type) const;
+ bool operator!=(const mediaType& type) const;
+
+ mediaType& operator=(const string& type);
+
+ shared_ptr <component> clone() const;
+ void copyFrom(const component& other);
+ mediaType& operator=(const mediaType& other);
+
+ const std::vector <shared_ptr <component> > getChildComponents();
+
+ /** Return the media type.
+ * See the constants in vmime::mediaTypes.
+ *
+ * @return media type
+ */
+ const string& getType() const;
+
+ /** Set the media type.
+ * See the constants in vmime::mediaTypes.
+ *
+ * @param type media type
+ */
+ void setType(const string& type);
+
+ /** Return the media subtype.
+ * See the constants in vmime::mediaTypes.
+ *
+ * @return media subtype
+ */
+ const string& getSubType() const;
+
+ /** Set the media subtype.
+ * See the constants in vmime::mediaTypes.
+ *
+ * @param subType media subtype
+ */
+ void setSubType(const string& subType);
+
+ /** Set the media type and subtype from a string
+ * in the form "type/subtype" (eg: "image/jpeg").
+ *
+ * @param type media type and subtype
+ */
+ void setFromString(const string& type);
+
+protected:
+
+ string m_type;
+ string m_subType;
+
+ // Component parsing & assembling
+ void parseImpl(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition = NULL
+ );
+
+ void generateImpl(
+ const generationContext& ctx,
+ utility::outputStream& os,
+ const size_t curLinePos = 0,
+ size_t* newLinePos = NULL
+ ) const;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_MEDIATYPE_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/message.cpp b/vmime-master/src/vmime/message.cpp
new file mode 100644
index 0000000..f034cdb
--- /dev/null
+++ b/vmime-master/src/vmime/message.cpp
@@ -0,0 +1,49 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/message.hpp"
+
+#include "vmime/utility/outputStreamAdapter.hpp"
+
+#include <sstream>
+
+
+namespace vmime {
+
+
+message::message() {
+
+}
+
+
+const string message::generate(
+ const size_t maxLineLength,
+ const size_t curLinePos
+) const {
+
+ return bodyPart::generate(maxLineLength, curLinePos);
+}
+
+
+} // vmime
+
diff --git a/vmime-master/src/vmime/message.hpp b/vmime-master/src/vmime/message.hpp
new file mode 100644
index 0000000..1b97a5d
--- /dev/null
+++ b/vmime-master/src/vmime/message.hpp
@@ -0,0 +1,60 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_MESSAGE_HPP_INCLUDED
+#define VMIME_MESSAGE_HPP_INCLUDED
+
+
+#include "vmime/bodyPart.hpp"
+#include "vmime/generationContext.hpp"
+
+
+namespace vmime {
+
+
+/** A MIME message.
+ */
+class VMIME_EXPORT message : public bodyPart {
+
+public:
+
+ message();
+
+public:
+
+ using bodyPart::parse;
+ using bodyPart::generate;
+
+ // Override default generate() functions so that we can change
+ // the default 'maxLineLength' value
+ const string generate(
+ const size_t maxLineLength = generationContext::getDefaultContext().getMaxLineLength(),
+ const size_t curLinePos = 0
+ ) const;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_MESSAGE_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/messageAttachment.hpp b/vmime-master/src/vmime/messageAttachment.hpp
new file mode 100644
index 0000000..2d95d20
--- /dev/null
+++ b/vmime-master/src/vmime/messageAttachment.hpp
@@ -0,0 +1,52 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_MESSAGEATTACHMENT_HPP_INCLUDED
+#define VMIME_MESSAGEATTACHMENT_HPP_INCLUDED
+
+
+#include "vmime/attachment.hpp"
+#include "vmime/message.hpp"
+
+
+namespace vmime {
+
+
+/** Attachment of type message/rfc822.
+ */
+class VMIME_EXPORT messageAttachment : public attachment {
+
+public:
+
+ /** Return the message encapsulated in this attachment.
+ *
+ * @return encapsulated message
+ */
+ virtual shared_ptr <message> getMessage() const = 0;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_MESSAGEATTACHMENT_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/messageBuilder.cpp b/vmime-master/src/vmime/messageBuilder.cpp
new file mode 100644
index 0000000..4de81bf
--- /dev/null
+++ b/vmime-master/src/vmime/messageBuilder.cpp
@@ -0,0 +1,333 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/messageBuilder.hpp"
+
+#include "vmime/dateTime.hpp"
+#include "vmime/textPartFactory.hpp"
+
+
+namespace vmime {
+
+
+messageBuilder::messageBuilder() {
+
+ // By default there is one text part of type "text/plain"
+ constructTextPart(mediaType(mediaTypes::TEXT, mediaTypes::TEXT_PLAIN));
+}
+
+
+messageBuilder::~messageBuilder() {
+
+}
+
+
+shared_ptr <message> messageBuilder::construct() const {
+
+ // Create a new message
+ shared_ptr <message> msg = make_shared <message>();
+
+ // Generate the header fields
+ msg->getHeader()->Subject()->setValue(m_subject);
+
+ if (((m_to.isEmpty()) || (m_to.getAddressAt(0)->isEmpty() && !m_to.getAddressAt(0)->isGroup())) &&
+ (m_cc.isEmpty() || m_cc.getAddressAt(0)->isEmpty()) &&
+ (m_bcc.isEmpty() || m_bcc.getAddressAt(0)->isEmpty())) {
+
+ throw exceptions::no_recipient();
+ }
+
+ if (!m_from.isEmpty()) {
+ msg->getHeader()->From()->setValue(m_from);
+ }
+
+ if (!m_to.isEmpty()) {
+ msg->getHeader()->To()->setValue(m_to);
+ }
+
+ if (!m_cc.isEmpty()) {
+ msg->getHeader()->Cc()->setValue(m_cc);
+ }
+
+ if (!m_bcc.isEmpty()) {
+ msg->getHeader()->Bcc()->setValue(m_bcc);
+ }
+
+ // Add a "Date" field
+ msg->getHeader()->Date()->setValue(datetime::now());
+
+ // Add a "Mime-Version" header field
+ msg->getHeader()->MimeVersion()->setValue(string(SUPPORTED_MIME_VERSION));
+
+ // If there is one or more attachments (or other parts that are
+ // not "text/...") and if there is more than one parts for the
+ // text part, we generate these text parts into a sub-part:
+ //
+ // [message]
+ // |
+ // +-- multipart/mixed
+ // |
+ // +-- multipart/alternative
+ // | |
+ // | +-- text part #1 (eg. plain text "text/plain")
+ // | +-- text part #2 (eg. HTML "text/html")
+ // | +-- ...
+ // |
+ // +-- application/octet-stream (attachment #1)
+ // |
+ // +-- ... (other attachments/parts)
+ //
+ if (!m_attach.empty() && m_textPart->getPartCount() > 1) {
+
+ // Set parent part (message) to "multipart/mixed"
+ msg->getHeader()->ContentType()->setValue(
+ mediaType(mediaTypes::MULTIPART, mediaTypes::MULTIPART_MIXED)
+ );
+
+ // Create a sub-part "multipart/alternative" for text parts
+ shared_ptr <bodyPart> subPart = make_shared <bodyPart>();
+ msg->getBody()->appendPart(subPart);
+
+ subPart->getHeader()->ContentType()->setValue(
+ mediaType(mediaTypes::MULTIPART, mediaTypes::MULTIPART_ALTERNATIVE)
+ );
+
+ // Generate the text parts into this sub-part (normally, this
+ // sub-part will have the "multipart/alternative" content-type...)
+ m_textPart->generateIn(msg, subPart);
+
+ } else {
+
+ // Generate the text part(s) directly into the message
+ m_textPart->generateIn(msg, msg);
+
+ // If any attachment, set message content-type to "multipart/mixed"
+ if (!m_attach.empty()) {
+
+ msg->getHeader()->ContentType()->setValue(
+ mediaType(mediaTypes::MULTIPART, mediaTypes::MULTIPART_MIXED)
+ );
+
+ // Else, set it to "multipart/alternative" if there are more than one text part.
+ } else if (m_textPart->getPartCount() > 1) {
+
+ msg->getHeader()->ContentType()->setValue(
+ mediaType(mediaTypes::MULTIPART, mediaTypes::MULTIPART_ALTERNATIVE)
+ );
+ }
+ }
+
+ // Generate the attachments
+ if (!m_attach.empty()) {
+
+ for (std::vector <shared_ptr <attachment> >::const_iterator a = m_attach.begin() ;
+ a != m_attach.end() ; ++a) {
+
+ (*a)->generateIn(msg);
+ }
+ }
+
+ // If there is only one part in the message, move it into the message
+ // (hence, the message will not be multipart...)
+ if (msg->getBody()->getPartCount() == 1) {
+
+ const bodyPart& part = *msg->getBody()->getPartAt(0);
+
+ // Make a full copy of the body, otherwise the copyFrom() will delete the body we're copying
+ shared_ptr <body> bodyCopy = vmime::clone(part.getBody());
+
+ // First, copy (and replace) the header fields
+ const std::vector <shared_ptr <const headerField> > fields = part.getHeader()->getFieldList();
+
+ for (std::vector <shared_ptr <const headerField> >::const_iterator it = fields.begin() ;
+ it != fields.end() ; ++it) {
+
+ *(msg->getHeader()->getField((*it)->getName())) = **it;
+ }
+
+ // Second, copy the body contents and sub-parts (this also remove
+ // the body part we are copying...)
+ msg->getBody()->copyFrom(*bodyCopy);
+ }
+
+ return msg;
+}
+
+
+void messageBuilder::attach(const shared_ptr <attachment>& attach) {
+
+ appendAttachment(attach);
+}
+
+
+void messageBuilder::appendAttachment(const shared_ptr <attachment>& attach) {
+
+ m_attach.push_back(attach);
+}
+
+
+void messageBuilder::constructTextPart(const mediaType& type) {
+
+ shared_ptr <textPart> part;
+
+ try {
+ part = textPartFactory::getInstance()->create(type);
+ } catch (exceptions::no_factory_available& e) {
+ throw;
+ }
+
+ m_textPart = part;
+}
+
+
+shared_ptr <textPart> messageBuilder::getTextPart() {
+
+ return m_textPart;
+}
+
+
+const mailbox& messageBuilder::getExpeditor() const {
+
+ return m_from;
+}
+
+
+void messageBuilder::setExpeditor(const mailbox& expeditor) {
+
+ m_from = expeditor;
+}
+
+
+const addressList& messageBuilder::getRecipients() const {
+
+ return m_to;
+}
+
+
+addressList& messageBuilder::getRecipients() {
+
+ return m_to;
+}
+
+
+void messageBuilder::setRecipients(const addressList& recipients) {
+
+ m_to = recipients;
+}
+
+
+const addressList& messageBuilder::getCopyRecipients() const {
+
+ return m_cc;
+}
+
+
+addressList& messageBuilder::getCopyRecipients() {
+
+ return m_cc;
+}
+
+
+void messageBuilder::setCopyRecipients(const addressList& cc) {
+
+ m_cc = cc;
+}
+
+
+const addressList& messageBuilder::getBlindCopyRecipients() const {
+
+ return m_bcc;
+}
+
+
+addressList& messageBuilder::getBlindCopyRecipients() {
+
+ return m_bcc;
+}
+
+
+void messageBuilder::setBlindCopyRecipients(const addressList& bcc) {
+
+ m_bcc = bcc;
+}
+
+
+const text& messageBuilder::getSubject() const {
+
+ return m_subject;
+}
+
+
+void messageBuilder::setSubject(const text& subject) {
+
+ m_subject = subject;
+}
+
+
+void messageBuilder::removeAttachment(const size_t pos) {
+
+ m_attach.erase(m_attach.begin() + pos);
+}
+
+
+const shared_ptr <const attachment> messageBuilder::getAttachmentAt(const size_t pos) const {
+
+ return m_attach[pos];
+}
+
+
+shared_ptr <attachment> messageBuilder::getAttachmentAt(const size_t pos) {
+
+ return m_attach[pos];
+}
+
+
+size_t messageBuilder::getAttachmentCount() const {
+
+ return m_attach.size();
+}
+
+
+const std::vector <shared_ptr <const attachment> > messageBuilder::getAttachmentList() const {
+
+ std::vector <shared_ptr <const attachment> > res;
+
+ res.reserve(m_attach.size());
+
+ for (std::vector <shared_ptr <attachment> >::const_iterator it = m_attach.begin() ;
+ it != m_attach.end() ; ++it) {
+
+ res.push_back(*it);
+ }
+
+ return res;
+}
+
+
+const std::vector <shared_ptr <attachment> > messageBuilder::getAttachmentList() {
+
+ return m_attach;
+}
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/messageBuilder.hpp b/vmime-master/src/vmime/messageBuilder.hpp
new file mode 100644
index 0000000..bfe5ed9
--- /dev/null
+++ b/vmime-master/src/vmime/messageBuilder.hpp
@@ -0,0 +1,221 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_MESSAGEBUILDER_HPP_INCLUDED
+#define VMIME_MESSAGEBUILDER_HPP_INCLUDED
+
+
+#include "vmime/base.hpp"
+
+#include "vmime/mailbox.hpp"
+#include "vmime/addressList.hpp"
+#include "vmime/text.hpp"
+#include "vmime/message.hpp"
+#include "vmime/mediaType.hpp"
+#include "vmime/attachment.hpp"
+#include "vmime/textPart.hpp"
+#include "vmime/bodyPart.hpp"
+
+
+namespace vmime {
+
+
+/** A helper for building MIME messages.
+ */
+class VMIME_EXPORT messageBuilder {
+
+public:
+
+ messageBuilder();
+ ~messageBuilder();
+
+public:
+
+ /** Return the expeditor of the message (From:).
+ *
+ * @return expeditor of the message
+ */
+ const mailbox& getExpeditor() const;
+
+ /** Set the expeditor of the message (From:).
+ *
+ * @param expeditor expeditor of the message
+ */
+ void setExpeditor(const mailbox& expeditor);
+
+ /** Return the recipients of the message (To:).
+ *
+ * return recipients of the message
+ */
+ const addressList& getRecipients() const;
+
+ /** Return the recipients of the message (To:).
+ *
+ * return recipients of the message
+ */
+ addressList& getRecipients();
+
+ /** Set the recipients of the message (To:).
+ *
+ * @param recipients list of recipients
+ */
+ void setRecipients(const addressList& recipients);
+
+ /** Return the copy recipients of the message (Cc:).
+ *
+ * @return copy recipients of the message
+ */
+ const addressList& getCopyRecipients() const;
+
+ /** Return the copy recipients of the message (Cc:).
+ *
+ * @return copy recipients of the message
+ */
+ addressList& getCopyRecipients();
+
+ /** Set the copy recipients of the message (Cc:).
+ *
+ * @param cc list of copy recipients
+ */
+ void setCopyRecipients(const addressList& cc);
+
+ /** Return the blind-copy recipients of the message (Bcc:).
+ *
+ * @return blind-copy recipients of the message
+ */
+ const addressList& getBlindCopyRecipients() const;
+
+ /** Return the blind-copy recipients of the message (Bcc:).
+ *
+ * @return blind-copy recipients of the message
+ */
+ addressList& getBlindCopyRecipients();
+
+ /** Set the blind-copy recipients of the message (Bcc:).
+ *
+ * @param bcc list of blind-copy recipients
+ */
+ void setBlindCopyRecipients(const addressList& bcc);
+
+ /** Return the subject of the message.
+ *
+ * @return subject of the message
+ */
+ const text& getSubject() const;
+
+ /** Set the subject of the message.
+ *
+ * @param subject message subject
+ */
+ void setSubject(const text& subject);
+
+ /** Attach a new object to the message.
+ * \deprecated Use messageBuilder::appendAttachment() instead.
+ *
+ * @param attach new attachment
+ */
+ void attach(const shared_ptr <attachment>& attach);
+
+ /** Attach a new object to the message.
+ *
+ * @param attach new attachment
+ */
+ void appendAttachment(const shared_ptr <attachment>& attach);
+
+ /** Remove the attachment at the specified position.
+ *
+ * @param pos position of the attachment to remove
+ */
+ void removeAttachment(const size_t pos);
+
+ /** Return the attachment at the specified position.
+ *
+ * @param pos position of the attachment
+ * @return attachment at the specified position
+ */
+ const shared_ptr <const attachment> getAttachmentAt(const size_t pos) const;
+
+ /** Return the attachment at the specified position.
+ *
+ * @param pos position of the attachment
+ * @return attachment at the specified position
+ */
+ shared_ptr <attachment> getAttachmentAt(const size_t pos);
+
+ /** Return the number of attachments in the message.
+ *
+ * @return number of attachments
+ */
+ size_t getAttachmentCount() const;
+
+ /** Return the list of attachments.
+ *
+ * @return list of attachments
+ */
+ const std::vector <shared_ptr <const attachment> > getAttachmentList() const;
+
+ /** Return the list of attachments.
+ *
+ * @return list of attachments
+ */
+ const std::vector <shared_ptr <attachment> > getAttachmentList();
+
+ /** Change the type of the text part and construct a new part.
+ *
+ * @param type media type of the text part
+ */
+ void constructTextPart(const mediaType& type);
+
+ /** Return the text part of the message.
+ *
+ * @return text part of the message
+ */
+ shared_ptr <textPart> getTextPart();
+
+ /** Construct a new message based on the information specified
+ * in this object.
+ *
+ * @return a new message
+ */
+ shared_ptr <message> construct() const;
+
+private:
+
+ mailbox m_from;
+
+ addressList m_to;
+ addressList m_cc;
+ addressList m_bcc;
+
+ text m_subject;
+
+ shared_ptr <textPart> m_textPart;
+
+ std::vector <shared_ptr <attachment> > m_attach;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_MESSAGEBUILDER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/messageId.cpp b/vmime-master/src/vmime/messageId.cpp
new file mode 100644
index 0000000..c8ea642
--- /dev/null
+++ b/vmime-master/src/vmime/messageId.cpp
@@ -0,0 +1,329 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/messageId.hpp"
+#include "vmime/utility/random.hpp"
+#include "vmime/platform.hpp"
+#include "vmime/parserHelpers.hpp"
+
+
+namespace vmime {
+
+
+messageId::messageId() {
+
+}
+
+
+messageId::messageId(const string& id) {
+
+ parse(id);
+}
+
+
+messageId::messageId(const messageId& mid)
+ : headerFieldValue(),
+ m_left(mid.m_left),
+ m_right(mid.m_right) {
+
+}
+
+
+messageId::messageId(const string& left, const string& right)
+ : m_left(left),
+ m_right(right) {
+
+}
+
+
+/*
+ RFC-2822:
+ 3.6.4. Identification fields
+
+ msg-id = [CFWS] "<" id-left "@" id-right ">" [CFWS]
+*/
+
+void messageId::parseImpl(
+ const parsingContext& /* ctx */,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition
+) {
+
+ const char* const pend = buffer.data() + end;
+ const char* const pstart = buffer.data() + position;
+ const char* p = pstart;
+
+ m_left.clear();
+ m_right.clear();
+
+ unsigned int commentLevel = 0;
+ bool escape = false;
+ bool stop = false;
+
+ for ( ; !stop && p < pend ; ++p) {
+
+ if (escape) {
+
+ // Ignore this character
+
+ } else {
+
+ switch (*p) {
+
+ case '(': ++commentLevel; break;
+ case ')': --commentLevel; break;
+ case '\\': escape = true; break;
+ case '<': {
+
+ if (commentLevel == 0) {
+ stop = true;
+ break;
+ }
+ }
+
+ }
+ }
+ }
+
+ // Fix for message ids without angle brackets (invalid)
+ bool hasBrackets = true;
+
+ if (p == pend) { // no opening angle bracket found
+
+ hasBrackets = false;
+ p = pstart;
+
+ while (p < pend && parserHelpers::isSpace(*p)) {
+ ++p;
+ }
+ }
+
+ if (p < pend) {
+
+ // Extract left part
+ const size_t leftStart = position + (p - pstart);
+
+ while (p < pend && *p != '@' && *p != '>') ++p;
+
+ m_left = string(
+ buffer.begin() + leftStart,
+ buffer.begin() + position + (p - pstart)
+ );
+
+ if (p < pend) {
+
+ // Skip '@'
+ ++p;
+
+ // Extract right part
+ const size_t rightStart = position + (p - pstart);
+
+ while (p < pend && *p != '>' && (hasBrackets || !parserHelpers::isSpace(*p))) ++p;
+
+ m_right = string(
+ buffer.begin() + rightStart,
+ buffer.begin() + position + (p - pstart)
+ );
+ }
+ }
+
+ setParsedBounds(position, end);
+
+ if (newPosition) {
+ *newPosition = end;
+ }
+}
+
+
+shared_ptr <messageId> messageId::parseNext(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition
+) {
+
+ size_t pos = position;
+
+ while (pos < end && parserHelpers::isSpace(buffer[pos])) {
+ ++pos;
+ }
+
+ if (pos != end) {
+
+ const size_t begin = pos;
+
+ while (pos < end && !parserHelpers::isSpace(buffer[pos])) {
+ ++pos;
+ }
+
+ shared_ptr <messageId> mid = make_shared <messageId>();
+ mid->parse(ctx, buffer, begin, pos, NULL);
+
+ if (newPosition) {
+ *newPosition = pos;
+ }
+
+ return mid;
+ }
+
+ if (newPosition) {
+ *newPosition = end;
+ }
+
+ return null;
+}
+
+
+const string messageId::getId() const {
+
+ if (m_right.empty()) {
+ return m_left;
+ }
+
+ return m_left + '@' + m_right;
+}
+
+
+void messageId::generateImpl(
+ const generationContext& ctx,
+ utility::outputStream& os,
+ const size_t curLinePos,
+ size_t* newLinePos
+) const {
+
+ size_t pos = curLinePos;
+
+ if (ctx.getWrapMessageId() &&
+ (curLinePos + m_left.length() + m_right.length() + 3 > ctx.getMaxLineLength())) {
+
+ os << NEW_LINE_SEQUENCE;
+ pos = NEW_LINE_SEQUENCE_LENGTH;
+ }
+
+ os << '<' << m_left;
+
+ if (m_right != "") {
+ os << '@' << m_right;
+ }
+
+ os << '>';
+
+ if (newLinePos) {
+ *newLinePos = pos + m_left.length() + m_right.length() + 3;
+ }
+}
+
+
+messageId& messageId::operator=(const string& id) {
+
+ parse(id);
+ return *this;
+}
+
+
+messageId messageId::generateId() {
+
+ std::ostringstream left;
+ left.imbue(std::locale::classic());
+
+ left << "vmime";
+ left << '.';
+ left << std::hex << utility::random::getTime();
+ left << '.';
+ left << std::hex << utility::random::getProcess();
+ left << '.';
+ left << std::hex << utility::random::getNext();
+ left << std::hex << utility::random::getNext();
+
+ return messageId(left.str(), platform::getHandler()->getHostName());
+}
+
+
+bool messageId::operator==(const messageId& mid) const {
+
+ return m_left == mid.m_left && m_right == mid.m_right;
+}
+
+
+bool messageId::operator!=(const messageId& mid) const {
+
+ return !(*this == mid);
+}
+
+
+shared_ptr <component> messageId::clone() const {
+
+ return make_shared <messageId>(*this);
+}
+
+
+void messageId::copyFrom(const component& other) {
+
+ const messageId& mid = dynamic_cast <const messageId&>(other);
+
+ m_left = mid.m_left;
+ m_right = mid.m_right;
+}
+
+
+messageId& messageId::operator=(const messageId& other) {
+
+ copyFrom(other);
+ return *this;
+}
+
+
+const string& messageId::getLeft() const {
+
+ return m_left;
+}
+
+
+void messageId::setLeft(const string& left) {
+
+ m_left = left;
+}
+
+
+const string& messageId::getRight() const {
+
+ return m_right;
+}
+
+
+void messageId::setRight(const string& right) {
+
+ m_right = right;
+}
+
+
+const std::vector <shared_ptr <component> > messageId::getChildComponents() {
+
+ return std::vector <shared_ptr <component> >();
+}
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/messageId.hpp b/vmime-master/src/vmime/messageId.hpp
new file mode 100644
index 0000000..8edbe3e
--- /dev/null
+++ b/vmime-master/src/vmime/messageId.hpp
@@ -0,0 +1,144 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_MESSAGEID_HPP_INCLUDED
+#define VMIME_MESSAGEID_HPP_INCLUDED
+
+
+#include "vmime/base.hpp"
+#include "vmime/headerFieldValue.hpp"
+
+
+namespace vmime {
+
+
+/** Message identifier (basic type).
+ */
+class VMIME_EXPORT messageId : public headerFieldValue {
+
+ friend class messageIdSequence;
+
+public:
+
+ messageId();
+ messageId(const string& id);
+ messageId(const messageId& mid);
+ messageId(const string& left, const string& right);
+
+public:
+
+ /** Return the left part of the message identifier.
+ *
+ * @return left part of message identifier
+ */
+ const string& getLeft() const;
+
+ /** Set the left part of the message identifier.
+ *
+ * @param left left part of message identifier
+ */
+ void setLeft(const string& left);
+
+ /** Return the right part of the message identifier.
+ *
+ * @return right part of message identifier
+ */
+ const string& getRight() const;
+
+ /** Set the right part of the message identifier.
+ *
+ * @param right right part of message identifier
+ */
+ void setRight(const string& right);
+
+
+ messageId& operator=(const string& id);
+
+ bool operator==(const messageId& mid) const;
+ bool operator!=(const messageId& mid) const;
+
+ /** Generate a random message identifier.
+ *
+ * @return randomly created message identifier
+ */
+ static messageId generateId();
+
+ /** Return the message identifier constructed by using
+ * the right part and the left part, separated by
+ * a '@' character.
+ *
+ * @return full message identifier
+ */
+ const string getId() const;
+
+ shared_ptr <component> clone() const;
+ void copyFrom(const component& other);
+ messageId& operator=(const messageId& other);
+
+ const std::vector <shared_ptr <component> > getChildComponents();
+
+private:
+
+ string m_left;
+ string m_right;
+
+protected:
+
+ // Component parsing & assembling
+ void parseImpl(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition = NULL
+ );
+
+ void generateImpl(
+ const generationContext& ctx,
+ utility::outputStream& os,
+ const size_t curLinePos = 0,
+ size_t* newLinePos = NULL
+ ) const;
+
+ /** Parse a message-id from an input buffer.
+ *
+ * @param buffer input buffer
+ * @param position position in the input buffer
+ * @param end end position in the input buffer
+ * @param newPosition will receive the new position in the input buffer
+ * @return a new message-id object, or null if no more message-id can be parsed from the input buffer
+ */
+ static shared_ptr <messageId> parseNext(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition
+ );
+};
+
+
+} // vmime
+
+
+#endif // VMIME_MESSAGEID_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/messageIdSequence.cpp b/vmime-master/src/vmime/messageIdSequence.cpp
new file mode 100644
index 0000000..2b68bcc
--- /dev/null
+++ b/vmime-master/src/vmime/messageIdSequence.cpp
@@ -0,0 +1,277 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/messageIdSequence.hpp"
+#include "vmime/exception.hpp"
+
+#include <algorithm>
+
+
+namespace vmime {
+
+
+messageIdSequence::messageIdSequence() {
+
+}
+
+
+messageIdSequence::~messageIdSequence() {
+
+ removeAllMessageIds();
+}
+
+
+messageIdSequence::messageIdSequence(const messageIdSequence& midSeq)
+ : headerFieldValue() {
+
+ copyFrom(midSeq);
+}
+
+
+shared_ptr <component> messageIdSequence::clone() const {
+
+ return make_shared <messageIdSequence>(*this);
+}
+
+
+void messageIdSequence::copyFrom(const component& other) {
+
+ const messageIdSequence& midSeq = dynamic_cast <const messageIdSequence&>(other);
+
+ removeAllMessageIds();
+
+ for (unsigned int i = 0 ; i < midSeq.m_list.size() ; ++i) {
+ m_list.push_back(vmime::clone(midSeq.m_list[i]));
+ }
+}
+
+
+messageIdSequence& messageIdSequence::operator=(const messageIdSequence& other) {
+
+ copyFrom(other);
+ return *this;
+}
+
+
+const std::vector <shared_ptr <component> > messageIdSequence::getChildComponents() {
+
+ std::vector <shared_ptr <component> > res;
+
+ copy_vector(m_list, res);
+
+ return res;
+}
+
+
+void messageIdSequence::parseImpl(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition
+) {
+
+ removeAllMessageIds();
+
+ size_t pos = position;
+
+ while (pos < end) {
+
+ shared_ptr <messageId> parsedMid = messageId::parseNext(ctx, buffer, pos, end, &pos);
+
+ if (parsedMid) {
+ m_list.push_back(parsedMid);
+ }
+ }
+
+ setParsedBounds(position, end);
+
+ if (newPosition) {
+ *newPosition = end;
+ }
+}
+
+
+void messageIdSequence::generateImpl(
+ const generationContext& ctx,
+ utility::outputStream& os,
+ const size_t curLinePos,
+ size_t* newLinePos
+) const {
+
+ size_t pos = curLinePos;
+
+ if (!m_list.empty()) {
+
+ generationContext tmpCtx(ctx);
+ tmpCtx.setMaxLineLength(ctx.getMaxLineLength() - 2);
+
+ for (std::vector <shared_ptr <messageId> >::const_iterator it = m_list.begin() ; ; ) {
+
+ (*it)->generate(ctx, os, pos, &pos);
+
+ if (++it == m_list.end()) {
+ break;
+ }
+
+ os << " ";
+ pos++;
+ }
+ }
+
+ if (newLinePos) {
+ *newLinePos = pos;
+ }
+}
+
+
+void messageIdSequence::appendMessageId(const shared_ptr <messageId>& mid) {
+
+ m_list.push_back(mid);
+}
+
+
+void messageIdSequence::insertMessageIdBefore(
+ const shared_ptr <messageId>& beforeMid,
+ const shared_ptr <messageId>& mid
+) {
+
+ const std::vector <shared_ptr <messageId> >::iterator it =
+ std::find(m_list.begin(), m_list.end(), beforeMid);
+
+ if (it == m_list.end()) {
+ throw exceptions::no_such_message_id();
+ }
+
+ m_list.insert(it, mid);
+}
+
+
+void messageIdSequence::insertMessageIdBefore(
+ const size_t pos,
+ const shared_ptr <messageId>& mid
+) {
+
+ m_list.insert(m_list.begin() + pos, mid);
+}
+
+
+void messageIdSequence::insertMessageIdAfter(
+ const shared_ptr <messageId>& afterMid,
+ const shared_ptr <messageId>& mid
+) {
+
+ const std::vector <shared_ptr <messageId> >::iterator it =
+ std::find(m_list.begin(), m_list.end(), afterMid);
+
+ if (it == m_list.end()) {
+ throw exceptions::no_such_message_id();
+ }
+
+ m_list.insert(it + 1, mid);
+}
+
+
+void messageIdSequence::insertMessageIdAfter(
+ const size_t pos,
+ const shared_ptr <messageId>& mid
+) {
+
+ m_list.insert(m_list.begin() + pos + 1, mid);
+}
+
+
+void messageIdSequence::removeMessageId(const shared_ptr <messageId>& mid)
+{
+ const std::vector <shared_ptr <messageId> >::iterator it =
+ std::find(m_list.begin(), m_list.end(), mid);
+
+ if (it == m_list.end()) {
+ throw exceptions::no_such_message_id();
+ }
+
+ m_list.erase(it);
+}
+
+
+void messageIdSequence::removeMessageId(const size_t pos) {
+
+ const std::vector <shared_ptr <messageId> >::iterator it = m_list.begin() + pos;
+
+ m_list.erase(it);
+}
+
+
+void messageIdSequence::removeAllMessageIds() {
+
+ m_list.clear();
+}
+
+
+size_t messageIdSequence::getMessageIdCount() const {
+
+ return m_list.size();
+}
+
+
+bool messageIdSequence::isEmpty() const {
+
+ return m_list.empty();
+}
+
+
+const shared_ptr <messageId> messageIdSequence::getMessageIdAt(const size_t pos) {
+
+ return m_list[pos];
+}
+
+
+const shared_ptr <const messageId> messageIdSequence::getMessageIdAt(const size_t pos) const {
+
+ return m_list[pos];
+}
+
+
+const std::vector <shared_ptr <const messageId> > messageIdSequence::getMessageIdList() const {
+
+ std::vector <shared_ptr <const messageId> > list;
+
+ list.reserve(m_list.size());
+
+ for (std::vector <shared_ptr <messageId> >::const_iterator it = m_list.begin() ;
+ it != m_list.end() ; ++it) {
+
+ list.push_back(*it);
+ }
+
+ return list;
+}
+
+
+const std::vector <shared_ptr <messageId> > messageIdSequence::getMessageIdList() {
+
+ return m_list;
+}
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/messageIdSequence.hpp b/vmime-master/src/vmime/messageIdSequence.hpp
new file mode 100644
index 0000000..e5d0eb6
--- /dev/null
+++ b/vmime-master/src/vmime/messageIdSequence.hpp
@@ -0,0 +1,175 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_MESSAGEIDSEQUENCE_HPP_INCLUDED
+#define VMIME_MESSAGEIDSEQUENCE_HPP_INCLUDED
+
+
+#include "vmime/messageId.hpp"
+
+
+namespace vmime {
+
+
+/** A list of message identifiers (basic type).
+ */
+class VMIME_EXPORT messageIdSequence : public headerFieldValue {
+
+public:
+
+ messageIdSequence();
+ messageIdSequence(const messageIdSequence& midSeq);
+
+ ~messageIdSequence();
+
+
+ shared_ptr <component> clone() const;
+ void copyFrom(const component& other);
+ messageIdSequence& operator=(const messageIdSequence& other);
+
+ const std::vector <shared_ptr <component> > getChildComponents();
+
+
+ /** Add a message-id at the end of the list.
+ *
+ * @param mid message-id to append
+ */
+ void appendMessageId(const shared_ptr <messageId>& mid);
+
+ /** Insert a new message-id before the specified message-id.
+ *
+ * @param beforeMid message-id before which the new message-id will be inserted
+ * @param mid message-id to insert
+ * @throw exceptions::no_such_messageid if the message-id is not in the list
+ */
+ void insertMessageIdBefore(const shared_ptr <messageId>& beforeMid, const shared_ptr <messageId>& mid);
+
+ /** Insert a new message-id before the specified position.
+ *
+ * @param pos position at which to insert the new message-id (0 to insert at
+ * the beginning of the list)
+ * @param mid message-id to insert
+ */
+ void insertMessageIdBefore(const size_t pos, const shared_ptr <messageId>& mid);
+
+ /** Insert a new message-id after the specified message-id.
+ *
+ * @param afterMid message-id after which the new message-id will be inserted
+ * @param mid message-id to insert
+ * @throw exceptions::no_such_message_id if the message-id is not in the list
+ */
+ void insertMessageIdAfter(
+ const shared_ptr <messageId>& afterMid,
+ const shared_ptr <messageId>& mid
+ );
+
+ /** Insert a new message-id after the specified position.
+ *
+ * @param pos position of the message-id before the new message-id
+ * @param mid message-id to insert
+ */
+ void insertMessageIdAfter(const size_t pos, const shared_ptr <messageId>& mid);
+
+ /** Remove the specified message-id from the list.
+ *
+ * @param mid message-id to remove
+ * @throw exceptions::no_such_message_id if the message-id is not in the list
+ */
+ void removeMessageId(const shared_ptr <messageId>& mid);
+
+ /** Remove the message-id at the specified position.
+ *
+ * @param pos position of the message-id to remove
+ */
+ void removeMessageId(const size_t pos);
+
+ /** Remove all message-ids from the list.
+ */
+ void removeAllMessageIds();
+
+ /** Return the number of message-ides in the list.
+ *
+ * @return number of message-ides
+ */
+ size_t getMessageIdCount() const;
+
+ /** Tests whether the list of message-ides is empty.
+ *
+ * @return true if there is no message-id, false otherwise
+ */
+ bool isEmpty() const;
+
+ /** Return the message-id at the specified position.
+ *
+ * @param pos position
+ * @return message-id at position 'pos'
+ */
+ const shared_ptr <messageId> getMessageIdAt(const size_t pos);
+
+ /** Return the message-id at the specified position.
+ *
+ * @param pos position
+ * @return message-id at position 'pos'
+ */
+ const shared_ptr <const messageId> getMessageIdAt(const size_t pos) const;
+
+ /** Return the message-id list.
+ *
+ * @return list of message-ids
+ */
+ const std::vector <shared_ptr <const messageId> > getMessageIdList() const;
+
+ /** Return the message-id list.
+ *
+ * @return list of message-ids
+ */
+ const std::vector <shared_ptr <messageId> > getMessageIdList();
+
+private:
+
+ std::vector <shared_ptr <messageId> > m_list;
+
+protected:
+
+ // Component parsing & assembling
+ void parseImpl(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition = NULL
+ );
+
+ void generateImpl(
+ const generationContext& ctx,
+ utility::outputStream& os,
+ const size_t curLinePos = 0,
+ size_t* newLinePos = NULL
+ ) const;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_MESSAGEIDSEQUENCE_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/messageParser.cpp b/vmime-master/src/vmime/messageParser.cpp
new file mode 100644
index 0000000..21ac09b
--- /dev/null
+++ b/vmime-master/src/vmime/messageParser.cpp
@@ -0,0 +1,328 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/messageParser.hpp"
+
+#include "vmime/attachmentHelper.hpp"
+
+#include "vmime/defaultAttachment.hpp"
+#include "vmime/textPartFactory.hpp"
+
+#include "vmime/relay.hpp"
+#include "vmime/contentTypeField.hpp"
+#include "vmime/contentDispositionField.hpp"
+
+
+namespace vmime {
+
+
+messageParser::messageParser(const string& buffer) {
+
+ shared_ptr <message> msg = make_shared <message>();
+ msg->parse(buffer);
+
+ parse(msg);
+}
+
+
+messageParser::messageParser(const shared_ptr <const message>& msg) {
+
+ parse(msg);
+}
+
+
+messageParser::~messageParser() {
+
+}
+
+
+void messageParser::parse(const shared_ptr <const message>& msg) {
+
+ // Header fields (if field is present, copy its value, else do nothing)
+#ifndef VMIME_BUILDING_DOC
+
+#define TRY_FIELD(var, type, name) { \
+ shared_ptr <type> fldValue = msg->getHeader()->findFieldValue <type>(name); \
+ if (fldValue) { \
+ var = *fldValue; \
+ } \
+ }
+
+ TRY_FIELD(m_from, mailbox, fields::FROM);
+
+ TRY_FIELD(m_to, addressList, fields::TO);
+ TRY_FIELD(m_cc, addressList, fields::CC);
+ TRY_FIELD(m_bcc, addressList, fields::BCC);
+
+ TRY_FIELD(m_subject, text, fields::SUBJECT);
+
+#undef TRY_FIELD
+
+#endif // VMIME_BUILDING_DOC
+
+ // Date
+ shared_ptr <const headerField> recv = msg->getHeader()->findField(fields::RECEIVED);
+
+ if (recv) {
+
+ m_date = recv->getValue <relay>()->getDate();
+
+ } else {
+
+ shared_ptr <const headerField> date = msg->getHeader()->findField(fields::DATE);
+
+ if (date) {
+ m_date = *date->getValue <datetime>();
+ } else {
+ m_date = datetime::now();
+ }
+ }
+
+ // Attachments
+ findAttachments(msg);
+
+ // Text parts
+ findTextParts(msg, msg);
+}
+
+
+void messageParser::findAttachments(const shared_ptr <const message>& msg) {
+
+ m_attach = attachmentHelper::findAttachmentsInMessage(msg);
+}
+
+
+void messageParser::findTextParts(
+ const shared_ptr <const bodyPart>& msg,
+ const shared_ptr <const bodyPart>& part
+) {
+
+ // Handle the case in which the message is not multipart: if the body part is
+ // "text/*", take this part.
+ if (part->getBody()->getPartCount() == 0) {
+
+ mediaType type(mediaTypes::TEXT, mediaTypes::TEXT_PLAIN);
+ bool accept = false;
+
+ shared_ptr <const contentTypeField> ctf =
+ msg->getHeader()->findField <contentTypeField>(fields::CONTENT_TYPE);
+
+ if (ctf) {
+
+ const mediaType ctfType = *ctf->getValue <mediaType>();
+
+ if (ctfType.getType() == mediaTypes::TEXT) {
+
+ type = ctfType;
+ accept = true;
+ }
+
+ } else {
+
+ // No "Content-type" field: assume "text/plain".
+ accept = true;
+ }
+
+ if (accept) {
+
+ shared_ptr <textPart> txtPart = textPartFactory::getInstance()->create(type);
+ txtPart->parse(msg, msg, msg);
+
+ m_textParts.push_back(txtPart);
+ }
+
+ // Multipart message
+ } else {
+
+ findSubTextParts(msg, part);
+ }
+}
+
+
+bool messageParser::findSubTextParts(
+ const shared_ptr <const bodyPart>& msg,
+ const shared_ptr <const bodyPart>& part
+) {
+
+ // In general, all the text parts are contained in parallel in the same
+ // parent part (or message).
+ // So, wherever the text parts are, all we have to do is to find the first
+ // MIME part which is a text part.
+
+ std::vector <shared_ptr <const bodyPart> > textParts;
+
+ for (size_t i = 0 ; i < part->getBody()->getPartCount() ; ++i) {
+
+ const shared_ptr <const bodyPart> p = part->getBody()->getPartAt(i);
+
+ shared_ptr <const contentTypeField> ctf =
+ p->getHeader()->findField <contentTypeField>(fields::CONTENT_TYPE);
+
+ if (ctf) {
+
+ const mediaType type = *ctf->getValue <mediaType>();
+ contentDisposition disp; // default should be inline
+
+ if (type.getType() == mediaTypes::TEXT) {
+
+ shared_ptr <const contentDispositionField> cdf = p->getHeader()->
+ findField <contentDispositionField>(fields::CONTENT_DISPOSITION);
+
+ if (cdf) {
+
+ disp = *cdf->getValue <contentDisposition>();
+
+ } else {
+
+ // No "Content-Disposition" field, assume default
+ }
+
+ if (disp.getName() == contentDispositionTypes::INLINE) {
+ textParts.push_back(p);
+ }
+ }
+
+ } else {
+
+ // No "Content-type" field.
+ }
+ }
+
+ if (textParts.size()) {
+
+ // Okay. So we have found at least one text part
+ for (std::vector <shared_ptr <const bodyPart> >::const_iterator p = textParts.begin() ;
+ p != textParts.end() ; ++p) {
+
+ const contentTypeField& ctf =
+ *(*p)->getHeader()->findField <contentTypeField>(fields::CONTENT_TYPE);
+
+ const mediaType type = *ctf.getValue <mediaType>();
+
+ try {
+
+ shared_ptr <textPart> txtPart = textPartFactory::getInstance()->create(type);
+ txtPart->parse(msg, part, *p);
+
+ m_textParts.push_back(txtPart);
+
+ } catch (exceptions::no_factory_available& e) {
+
+ // Content-type not recognized.
+ }
+ }
+ }
+
+ bool found = false;
+
+ for (size_t i = 0 ; !found && (i < part->getBody()->getPartCount()) ; ++i) {
+ found = findSubTextParts(msg, part->getBody()->getPartAt(i));
+ }
+
+ return found;
+}
+
+
+const mailbox& messageParser::getExpeditor() const {
+
+ return m_from;
+}
+
+
+const addressList& messageParser::getRecipients() const {
+
+ return m_to;
+}
+
+
+const addressList& messageParser::getCopyRecipients() const {
+
+ return m_cc;
+}
+
+
+const addressList& messageParser::getBlindCopyRecipients() const {
+
+ return m_bcc;
+}
+
+
+const text& messageParser::getSubject() const {
+
+ return m_subject;
+}
+
+
+const datetime& messageParser::getDate() const {
+
+ return m_date;
+}
+
+
+const std::vector <shared_ptr <const attachment> > messageParser::getAttachmentList() const {
+
+ return m_attach;
+}
+
+
+size_t messageParser::getAttachmentCount() const {
+
+ return m_attach.size();
+}
+
+
+const shared_ptr <const attachment> messageParser::getAttachmentAt(const size_t pos) const {
+
+ return m_attach[pos];
+}
+
+
+const std::vector <shared_ptr <const textPart> > messageParser::getTextPartList() const {
+
+ std::vector <shared_ptr <const textPart> > res;
+
+ res.reserve(m_textParts.size());
+
+ for (std::vector <shared_ptr <textPart> >::const_iterator it = m_textParts.begin() ;
+ it != m_textParts.end() ; ++it) {
+
+ res.push_back(*it);
+ }
+
+ return res;
+}
+
+
+size_t messageParser::getTextPartCount() const {
+
+ return m_textParts.size();
+}
+
+
+const shared_ptr <const textPart> messageParser::getTextPartAt(const size_t pos) const {
+
+ return m_textParts[pos];
+}
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/messageParser.hpp b/vmime-master/src/vmime/messageParser.hpp
new file mode 100644
index 0000000..8019ef3
--- /dev/null
+++ b/vmime-master/src/vmime/messageParser.hpp
@@ -0,0 +1,164 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_MESSAGEPARSER_HPP_INCLUDED
+#define VMIME_MESSAGEPARSER_HPP_INCLUDED
+
+
+#include "vmime/base.hpp"
+
+#include "vmime/message.hpp"
+#include "vmime/attachment.hpp"
+
+#include "vmime/mailbox.hpp"
+#include "vmime/addressList.hpp"
+#include "vmime/dateTime.hpp"
+
+#include "vmime/textPart.hpp"
+
+
+namespace vmime {
+
+
+/** A helper for parsing MIME messages.
+ */
+class VMIME_EXPORT messageParser {
+
+public:
+
+ messageParser(const string& buffer);
+ messageParser(const shared_ptr <const message>& msg);
+ ~messageParser();
+
+public:
+
+ /** Return the expeditor of the message (From:).
+ *
+ * @return expeditor of the message
+ */
+ const mailbox& getExpeditor() const;
+
+ /** Return the recipients of the message (To:).
+ *
+ * return recipients of the message
+ */
+ const addressList& getRecipients() const;
+
+ /** Return the copy recipients of the message (Cc:).
+ *
+ * @return copy recipients of the message
+ */
+ const addressList& getCopyRecipients() const;
+
+ /** Return the blind-copy recipients of the message (Bcc:).
+ *
+ * @return blind-copy recipients of the message
+ */
+ const addressList& getBlindCopyRecipients() const;
+
+ /** Return the subject of the message.
+ *
+ * @return subject of the message
+ */
+ const text& getSubject() const;
+
+ /** Return the date of the message.
+ *
+ * @return date of the message
+ */
+ const datetime& getDate() const;
+
+ /** Return the number of attachments in the message.
+ *
+ * @return number of attachments
+ */
+ size_t getAttachmentCount() const;
+
+ /** Return the attachment at the specified position.
+ *
+ * @param pos position of the attachment
+ * @return attachment at position 'pos'
+ */
+ const shared_ptr <const attachment> getAttachmentAt(const size_t pos) const;
+
+ /** Return the attachments of the message.
+ *
+ * @return list of attachments in the message
+ */
+ const std::vector <shared_ptr <const attachment> > getAttachmentList() const;
+
+ /** Return the text parts of the message.
+ *
+ * @return list of text parts in the message
+ */
+ const std::vector <shared_ptr <const textPart> > getTextPartList() const;
+
+ /** Return the number of text parts in the message.
+ *
+ * @return number of text parts
+ */
+ size_t getTextPartCount() const;
+
+ /** Return the text part at the specified position.
+ *
+ * @param pos position of the text part
+ * @return text part at position 'pos'
+ */
+ const shared_ptr <const textPart> getTextPartAt(const size_t pos) const;
+
+private:
+
+ mailbox m_from;
+
+ addressList m_to;
+ addressList m_cc;
+ addressList m_bcc;
+
+ text m_subject;
+
+ datetime m_date;
+
+ std::vector <shared_ptr <const attachment> > m_attach;
+
+ std::vector <shared_ptr <textPart> > m_textParts;
+
+ void parse(const shared_ptr <const message>& msg);
+
+ void findAttachments(const shared_ptr <const message>& msg);
+
+ void findTextParts(
+ const shared_ptr <const bodyPart>& msg,
+ const shared_ptr <const bodyPart>& part
+ );
+
+ bool findSubTextParts(
+ const shared_ptr <const bodyPart>& msg,
+ const shared_ptr <const bodyPart>& part
+ );
+};
+
+
+} // vmime
+
+
+#endif // VMIME_MESSAGEPARSER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/misc/importanceHelper.cpp b/vmime-master/src/vmime/misc/importanceHelper.cpp
new file mode 100644
index 0000000..20c8e13
--- /dev/null
+++ b/vmime-master/src/vmime/misc/importanceHelper.cpp
@@ -0,0 +1,163 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/misc/importanceHelper.hpp"
+#include "vmime/exception.hpp"
+
+#include "vmime/text.hpp"
+
+
+namespace vmime {
+namespace misc {
+
+
+void importanceHelper::resetImportance(const shared_ptr <message>& msg) {
+
+ resetImportanceHeader(msg->getHeader());
+}
+
+
+void importanceHelper::resetImportanceHeader(const shared_ptr <header>& hdr) {
+
+ shared_ptr <headerField> fld;
+
+ if ((fld = hdr->findField("X-Priority")))
+ hdr->removeField(fld);
+
+ if ((fld = hdr->findField("Importance")))
+ hdr->removeField(fld);
+}
+
+
+importanceHelper::Importance importanceHelper::getImportance(const shared_ptr <const message>& msg) {
+
+ return getImportanceHeader(msg->getHeader());
+}
+
+
+importanceHelper::Importance importanceHelper::getImportanceHeader(const shared_ptr <const header>& hdr) {
+
+ // Try "X-Priority" field
+ shared_ptr <const headerField> fld = hdr->findField("X-Priority");
+
+ if (fld) {
+
+ const string value = fld->getValue <text>()->getWholeBuffer();
+
+ int n = IMPORTANCE_NORMAL;
+
+ std::istringstream iss(value);
+ iss.imbue(std::locale::classic());
+
+ iss >> n;
+
+ Importance i = IMPORTANCE_NORMAL;
+
+ switch (n) {
+ case 1: i = IMPORTANCE_HIGHEST; break;
+ case 2: i = IMPORTANCE_HIGH; break;
+ case 3: i = IMPORTANCE_NORMAL; break;
+ case 4: i = IMPORTANCE_LOW; break;
+ case 5: i = IMPORTANCE_LOWEST; break;
+ }
+
+ return i;
+
+ } else {
+
+ // Try "Importance" field
+ fld = hdr->findField("Importance");
+
+ if (fld) {
+
+ const string value = utility::stringUtils::toLower(utility::stringUtils::trim
+ (fld->getValue <text>()->getWholeBuffer()));
+
+ if (value == "low") {
+ return IMPORTANCE_LOWEST;
+ } else if (value == "high") {
+ return IMPORTANCE_HIGHEST;
+ } else {
+ return IMPORTANCE_NORMAL;
+ }
+
+ } else {
+
+ // Default
+ return IMPORTANCE_NORMAL;
+ }
+ }
+
+ // Should not go here...
+ return IMPORTANCE_NORMAL;
+}
+
+
+void importanceHelper::setImportance(const shared_ptr <message>& msg, const Importance i) {
+
+ setImportanceHeader(msg->getHeader(), i);
+}
+
+
+void importanceHelper::setImportanceHeader(const shared_ptr <header>& hdr, const Importance i) {
+
+ // "X-Priority:" Field
+ shared_ptr <headerField> fld = hdr->getField("X-Priority");
+
+ switch (i) {
+ case IMPORTANCE_HIGHEST: fld->setValue("1 (Highest)"); break;
+ case IMPORTANCE_HIGH: fld->setValue("2 (High)"); break;
+ default:
+ case IMPORTANCE_NORMAL: fld->setValue("3 (Normal)"); break;
+ case IMPORTANCE_LOW: fld->setValue("4 (Low)"); break;
+ case IMPORTANCE_LOWEST: fld->setValue("5 (Lowest)"); break;
+ }
+
+ // "Importance:" Field
+ fld = hdr->getField("Importance");
+
+ switch (i) {
+
+ case IMPORTANCE_HIGHEST:
+ case IMPORTANCE_HIGH:
+
+ fld->setValue("high");
+ break;
+
+ default:
+ case IMPORTANCE_NORMAL:
+
+ fld->setValue("normal");
+ break;
+
+ case IMPORTANCE_LOWEST:
+ case IMPORTANCE_LOW:
+
+ fld->setValue("low");
+ break;
+ }
+}
+
+
+} // misc
+} // vmime
diff --git a/vmime-master/src/vmime/misc/importanceHelper.hpp b/vmime-master/src/vmime/misc/importanceHelper.hpp
new file mode 100644
index 0000000..45e0bcc
--- /dev/null
+++ b/vmime-master/src/vmime/misc/importanceHelper.hpp
@@ -0,0 +1,103 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_MISC_IMPORTANCEHELPER_HPP_INCLUDED
+#define VMIME_MISC_IMPORTANCEHELPER_HPP_INCLUDED
+
+
+#include "vmime/message.hpp"
+
+
+namespace vmime {
+namespace misc {
+
+
+/** Deals with setting and retrieving message importance (also
+ * known as priority).
+ *
+ * Basically, it wraps the use of the 'X-Priority' (non standard)
+ * and 'Importance' (RFC-1327, RFC-1911) fields.
+ */
+class VMIME_EXPORT importanceHelper {
+
+public:
+
+ /** Different levels of importance. */
+ enum Importance {
+ IMPORTANCE_HIGHEST,
+ IMPORTANCE_HIGH,
+ IMPORTANCE_NORMAL,
+ IMPORTANCE_LOW,
+ IMPORTANCE_LOWEST
+ };
+
+
+ /** Reset the importance of the message to the default importance.
+ *
+ * @param msg message on which to reset importance
+ */
+ static void resetImportance(const shared_ptr <message>& msg);
+
+ /** Reset the importance of a message to the default importance.
+ *
+ * @param hdr message header on which to reset importance
+ */
+ static void resetImportanceHeader(const shared_ptr <header>& hdr);
+
+ /** Return the importance of the specified message.
+ *
+ * @param msg message from which to retrieve importance
+ * @return importance of the message, or default importance is no
+ * information about importance is given in the message
+ */
+ static Importance getImportance(const shared_ptr <const message>& msg);
+
+ /** Return the importance of a message, given its header.
+ *
+ * @param hdr message header from which to retrieve importance
+ * @return importance of the message, or default importance is no
+ * information about importance is given in the message
+ */
+ static Importance getImportanceHeader(const shared_ptr <const header>& hdr);
+
+ /** Set the importance of the specified message.
+ *
+ * @param msg message on which to set importance
+ * @param i new message importance
+ */
+ static void setImportance(const shared_ptr <message>& msg, const Importance i);
+
+ /** Set the importance of a message, given its header.
+ *
+ * @param hdr message header on which to set importance
+ * @param i new message importance
+ */
+ static void setImportanceHeader(const shared_ptr <header>& hdr, const Importance i);
+};
+
+
+} // misc
+} // vmime
+
+
+#endif // VMIME_MISC_IMPORTANCEHELPER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/builtinServices.inl b/vmime-master/src/vmime/net/builtinServices.inl
new file mode 100644
index 0000000..2f67d2e
--- /dev/null
+++ b/vmime-master/src/vmime/net/builtinServices.inl
@@ -0,0 +1,76 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+
+// Include registration helpers
+#include "vmime/net/serviceRegistration.inl"
+
+
+#ifndef VMIME_BUILDING_DOC
+
+
+#if VMIME_HAVE_MESSAGING_PROTO_POP3
+ #include "vmime/net/pop3/POP3Store.hpp"
+ REGISTER_SERVICE(pop3::POP3Store, pop3, TYPE_STORE);
+
+ #if VMIME_HAVE_TLS_SUPPORT
+ #include "vmime/net/pop3/POP3SStore.hpp"
+ REGISTER_SERVICE(pop3::POP3SStore, pop3s, TYPE_STORE);
+ #endif // VMIME_HAVE_TLS_SUPPORT
+#endif
+
+
+#if VMIME_HAVE_MESSAGING_PROTO_SMTP
+ #include "vmime/net/smtp/SMTPTransport.hpp"
+ REGISTER_SERVICE(smtp::SMTPTransport, smtp, TYPE_TRANSPORT);
+
+ #if VMIME_HAVE_TLS_SUPPORT
+ #include "vmime/net/smtp/SMTPSTransport.hpp"
+ REGISTER_SERVICE(smtp::SMTPSTransport, smtps, TYPE_TRANSPORT);
+ #endif // VMIME_HAVE_TLS_SUPPORT
+#endif
+
+
+#if VMIME_HAVE_MESSAGING_PROTO_IMAP
+ #include "vmime/net/imap/IMAPStore.hpp"
+ REGISTER_SERVICE(imap::IMAPStore, imap, TYPE_STORE);
+
+ #if VMIME_HAVE_TLS_SUPPORT
+ #include "vmime/net/imap/IMAPSStore.hpp"
+ REGISTER_SERVICE(imap::IMAPSStore, imaps, TYPE_STORE);
+ #endif // VMIME_HAVE_TLS_SUPPORT
+#endif
+
+
+#if VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+ #include "vmime/net/maildir/maildirStore.hpp"
+ REGISTER_SERVICE(maildir::maildirStore, maildir, TYPE_STORE);
+#endif
+
+#if VMIME_HAVE_MESSAGING_PROTO_SENDMAIL
+ #include "vmime/net/sendmail/sendmailTransport.hpp"
+ REGISTER_SERVICE(sendmail::sendmailTransport, sendmail, TYPE_TRANSPORT);
+#endif
+
+
+#endif // VMIME_BUILDING_DOC
diff --git a/vmime-master/src/vmime/net/connectionInfos.hpp b/vmime-master/src/vmime/net/connectionInfos.hpp
new file mode 100644
index 0000000..0e519c7
--- /dev/null
+++ b/vmime-master/src/vmime/net/connectionInfos.hpp
@@ -0,0 +1,68 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_CONNECTIONINFOS_HPP_INCLUDED
+#define VMIME_NET_CONNECTIONINFOS_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/object.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+/** Information about the connection used by a service.
+ */
+class VMIME_EXPORT connectionInfos : public object {
+
+public:
+
+ /** Return the host to which the service is connected.
+ *
+ * @return server host name or address
+ */
+ virtual const string getHost() const = 0;
+
+ /** Return the port to which the service is connected.
+ *
+ * @return server port
+ */
+ virtual port_t getPort() const = 0;
+};
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+#endif // VMIME_NET_CONNECTIONINFOS_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/defaultConnectionInfos.cpp b/vmime-master/src/vmime/net/defaultConnectionInfos.cpp
new file mode 100644
index 0000000..889f214
--- /dev/null
+++ b/vmime-master/src/vmime/net/defaultConnectionInfos.cpp
@@ -0,0 +1,60 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/net/defaultConnectionInfos.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+defaultConnectionInfos::defaultConnectionInfos(const string& host, const port_t port)
+ : m_host(host), m_port(port) {
+
+}
+
+
+const string defaultConnectionInfos::getHost() const {
+
+ return m_host;
+}
+
+
+port_t defaultConnectionInfos::getPort() const {
+
+ return m_port;
+}
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
diff --git a/vmime-master/src/vmime/net/defaultConnectionInfos.hpp b/vmime-master/src/vmime/net/defaultConnectionInfos.hpp
new file mode 100644
index 0000000..f348859
--- /dev/null
+++ b/vmime-master/src/vmime/net/defaultConnectionInfos.hpp
@@ -0,0 +1,66 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_DEFAULTCONNECTIONINFOS_HPP_INCLUDED
+#define VMIME_NET_DEFAULTCONNECTIONINFOS_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/net/connectionInfos.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+/** Information about the connection used by a service.
+ */
+class VMIME_EXPORT defaultConnectionInfos : public connectionInfos {
+
+public:
+
+ defaultConnectionInfos(const string& host, const port_t port);
+
+ const string getHost() const;
+ port_t getPort() const;
+
+private:
+
+ string m_host;
+ port_t m_port;
+};
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+#endif // VMIME_NET_DEFAULTCONNECTIONINFOS_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/defaultTimeoutHandler.cpp b/vmime-master/src/vmime/net/defaultTimeoutHandler.cpp
new file mode 100644
index 0000000..f5dcc7d
--- /dev/null
+++ b/vmime-master/src/vmime/net/defaultTimeoutHandler.cpp
@@ -0,0 +1,78 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/net/defaultTimeoutHandler.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+defaultTimeoutHandler::defaultTimeoutHandler() {
+
+ m_startTime = time(NULL);
+}
+
+
+defaultTimeoutHandler::~defaultTimeoutHandler() {
+
+}
+
+
+bool defaultTimeoutHandler::isTimeOut() {
+
+ return time(NULL) - m_startTime >= 30;
+}
+
+
+void defaultTimeoutHandler::resetTimeOut() {
+
+ m_startTime = time(NULL);
+}
+
+
+bool defaultTimeoutHandler::handleTimeOut() {
+
+ return false;
+}
+
+
+
+
+shared_ptr <timeoutHandler> defaultTimeoutHandlerFactory::create() {
+
+ return make_shared <defaultTimeoutHandler>();
+}
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
diff --git a/vmime-master/src/vmime/net/defaultTimeoutHandler.hpp b/vmime-master/src/vmime/net/defaultTimeoutHandler.hpp
new file mode 100644
index 0000000..545c655
--- /dev/null
+++ b/vmime-master/src/vmime/net/defaultTimeoutHandler.hpp
@@ -0,0 +1,80 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_DEFAULTTIMEOUTHANDLER_HPP_INCLUDED
+#define VMIME_NET_DEFAULTTIMEOUTHANDLER_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/net/timeoutHandler.hpp"
+
+#include <ctime>
+
+
+namespace vmime {
+namespace net {
+
+
+/** A default timeout handler for messaging services. The default action
+ * is to throw a exceptions::operation_timed_out exception when an
+ * operation is blocked for more than 30 seconds.
+ */
+class VMIME_EXPORT defaultTimeoutHandler : public timeoutHandler {
+
+public:
+
+ defaultTimeoutHandler();
+ ~defaultTimeoutHandler();
+
+ bool isTimeOut();
+ void resetTimeOut();
+ bool handleTimeOut();
+
+private:
+
+ time_t m_startTime;
+};
+
+
+/** A class that creates default timeout handlers.
+ */
+class defaultTimeoutHandlerFactory : public timeoutHandlerFactory {
+
+public:
+
+ shared_ptr <timeoutHandler> create();
+};
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+#endif // VMIME_NET_DEFAULTTIMEOUTHANDLER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/dsnAttributes.cpp b/vmime-master/src/vmime/net/dsnAttributes.cpp
new file mode 100644
index 0000000..dc949b9
--- /dev/null
+++ b/vmime-master/src/vmime/net/dsnAttributes.cpp
@@ -0,0 +1,71 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2020 Jan Osusky <jan@osusky.name>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/net/dsnAttributes.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+dsnAttributes::dsnAttributes(const string& dsnNotify, const string& dsnRet, const string& dsnEnvelopId)
+ : m_notifications(dsnNotify), m_returnFormat(dsnRet), m_envelopId(dsnEnvelopId) {
+
+}
+
+
+string dsnAttributes::getNotificationConditions() const {
+
+ return m_notifications;
+}
+
+
+string dsnAttributes::getReturnFormat() const {
+
+ return m_returnFormat;
+}
+
+
+string dsnAttributes::getEnvelopId() const {
+
+ return m_envelopId;
+}
+
+
+bool dsnAttributes::isEmpty() const {
+
+ return m_notifications.empty() && m_returnFormat.empty() && m_envelopId.empty();
+}
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
diff --git a/vmime-master/src/vmime/net/dsnAttributes.hpp b/vmime-master/src/vmime/net/dsnAttributes.hpp
new file mode 100644
index 0000000..945da28
--- /dev/null
+++ b/vmime-master/src/vmime/net/dsnAttributes.hpp
@@ -0,0 +1,114 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2020 Jan Osusky <jan@osusky.name>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_DSNATTRIBUTES_HPP_INCLUDED
+#define VMIME_NET_DSNATTRIBUTES_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include <vector>
+
+#include "vmime/types.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+/** Holds a set of attributes for Delivery Status Notifications (DSN).
+ */
+class VMIME_EXPORT dsnAttributes : public object {
+
+public:
+
+ /** Constructs an empty dsnAttributes object.
+ */
+ dsnAttributes() = default;
+
+ /** Constructs a new dsnAttributes object by copying an existing object.
+ *
+ * @param dsn object to copy
+ */
+ dsnAttributes(const dsnAttributes& dsn) = default;
+
+ /** Constructs a new dsnAttributes object by moving an existing object.
+ *
+ * @param dsn object (Rvalue reference) to move from.
+ */
+ dsnAttributes(dsnAttributes&& dsn) = default;
+
+ ~dsnAttributes() = default;
+
+ /** Constructs a new dsnAttributes object by specifying the attributes.
+ *
+ * @param dsnNotify comma separated list of notification conditions as specified in RFC 1891
+ * @param dsnRet content of DSN - full message or headers only ("FULL" or "HDRS")
+ * @param dsnEnvelopId envelop ID to be able to pair the DSN with original message (plain text not in "<" ">")
+ */
+ dsnAttributes(const string& dsnNotify, const string& dsnRet, const string& dsnEnvelopId);
+
+ /** Returns comma separated list of notification conditions as specified in RFC 1891
+ *
+ * @return comma separated list of notification conditions as specified in RFC 1891
+ */
+ string getNotificationConditions() const;
+
+ /** Returns requested format of the notification (RET parameter of the ESMTP MAIL command).
+ *
+ * @return requested format of the notification.
+ */
+ string getReturnFormat() const;
+
+ /** Returns envelop ID used to pair the DSN with the original message.
+ *
+ * @return envelop ID used to pair the DSN with the original message.
+ */
+ string getEnvelopId() const;
+
+ /** Returns whether the object is empty, and no attribute has been set.
+ *
+ * @return true if object is empty, or false otherwise
+ */
+ bool isEmpty() const;
+
+private:
+
+ string m_notifications;
+ string m_returnFormat;
+ string m_envelopId;
+};
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+
+#endif // VMIME_NET_DSNATTRIBUTES_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/events.cpp b/vmime-master/src/vmime/net/events.cpp
new file mode 100644
index 0000000..8660812
--- /dev/null
+++ b/vmime-master/src/vmime/net/events.cpp
@@ -0,0 +1,180 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/net/events.hpp"
+#include "vmime/net/folder.hpp"
+
+#include <algorithm>
+
+
+namespace vmime {
+namespace net {
+namespace events {
+
+
+//
+// event
+//
+
+event::event() {
+
+}
+
+
+event::~event() {
+
+}
+
+
+//
+// messageCountEvent
+//
+
+const char* messageCountEvent::EVENT_CLASS = "messageCountEvent";
+
+
+messageCountEvent::messageCountEvent(
+ const shared_ptr <folder>& folder,
+ const Types type,
+ const std::vector <size_t>& nums
+)
+ : m_folder(folder),
+ m_type(type) {
+
+ m_nums.resize(nums.size());
+ std::copy(nums.begin(), nums.end(), m_nums.begin());
+}
+
+
+shared_ptr <folder> messageCountEvent::getFolder() const { return (m_folder); }
+messageCountEvent::Types messageCountEvent::getType() const { return (m_type); }
+const std::vector <size_t>& messageCountEvent::getNumbers() const { return (m_nums); }
+
+
+void messageCountEvent::dispatch(messageCountListener* listener) {
+
+ if (m_type == TYPE_ADDED) {
+ listener->messagesAdded(dynamicCast <messageCountEvent>(shared_from_this()));
+ } else {
+ listener->messagesRemoved(dynamicCast <messageCountEvent>(shared_from_this()));
+ }
+}
+
+
+const char* messageCountEvent::getClass() const {
+
+ return EVENT_CLASS;
+}
+
+
+//
+// messageChangedEvent
+//
+
+const char* messageChangedEvent::EVENT_CLASS = "messageChangedEvent";
+
+
+messageChangedEvent::messageChangedEvent(
+ const shared_ptr <folder>& folder,
+ const Types type,
+ const std::vector <size_t>& nums
+)
+ : m_folder(folder),
+ m_type(type) {
+
+ m_nums.resize(nums.size());
+ std::copy(nums.begin(), nums.end(), m_nums.begin());
+}
+
+
+shared_ptr <folder> messageChangedEvent::getFolder() const { return (m_folder); }
+messageChangedEvent::Types messageChangedEvent::getType() const { return (m_type); }
+const std::vector <size_t>& messageChangedEvent::getNumbers() const { return (m_nums); }
+
+
+void messageChangedEvent::dispatch(messageChangedListener* listener) {
+
+ listener->messageChanged(dynamicCast <messageChangedEvent>(shared_from_this()));
+}
+
+
+const char* messageChangedEvent::getClass() const {
+
+ return EVENT_CLASS;
+}
+
+
+//
+// folderEvent
+//
+
+const char* folderEvent::EVENT_CLASS = "folderEvent";
+
+
+folderEvent::folderEvent(
+ const shared_ptr <folder>& folder,
+ const Types type,
+ const utility::path& oldPath,
+ const utility::path& newPath
+)
+ : m_folder(folder),
+ m_type(type),
+ m_oldPath(oldPath),
+ m_newPath(newPath) {
+
+}
+
+
+shared_ptr <folder> folderEvent::getFolder() const { return (m_folder); }
+folderEvent::Types folderEvent::getType() const { return (m_type); }
+
+
+void folderEvent::dispatch(folderListener* listener) {
+
+ switch (m_type) {
+ case TYPE_CREATED: listener->folderCreated(dynamicCast <folderEvent>(shared_from_this())); break;
+ case TYPE_RENAMED: listener->folderRenamed(dynamicCast <folderEvent>(shared_from_this())); break;
+ case TYPE_DELETED: listener->folderDeleted(dynamicCast <folderEvent>(shared_from_this())); break;
+ }
+}
+
+
+const char* folderEvent::getClass() const {
+
+ return EVENT_CLASS;
+}
+
+
+} // events
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
diff --git a/vmime-master/src/vmime/net/events.hpp b/vmime-master/src/vmime/net/events.hpp
new file mode 100644
index 0000000..2ad64e7
--- /dev/null
+++ b/vmime-master/src/vmime/net/events.hpp
@@ -0,0 +1,276 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_EVENTS_HPP_INCLUDED
+#define VMIME_NET_EVENTS_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include <vector>
+
+#include "vmime/utility/path.hpp"
+
+
+namespace vmime {
+namespace net {
+
+class folder;
+
+namespace events {
+
+
+/** Event occurring on folders or messages.
+ */
+class VMIME_EXPORT event : public object, public enable_shared_from_this <event> {
+
+public:
+
+ event();
+ virtual ~event();
+
+ virtual const char* getClass() const = 0;
+};
+
+
+/** Event about the message count in a folder.
+ */
+class VMIME_EXPORT messageCountEvent : public event {
+
+public:
+
+ static const char* EVENT_CLASS;
+
+
+ enum Types {
+ TYPE_ADDED, /**< New messages have been added. */
+ TYPE_REMOVED /**< Messages have been expunged (renumbering). */
+ };
+
+
+ messageCountEvent(
+ const shared_ptr <folder>& folder,
+ const Types type,
+ const std::vector <size_t>& nums
+ );
+
+ /** Return the folder in which messages have been added/removed.
+ *
+ * @return folder in which message count changed
+ */
+ shared_ptr <folder> getFolder() const;
+
+ /** Return the event type.
+ *
+ * @return event type (see messageCountEvent::Types)
+ */
+ Types getType() const;
+
+ /** Return the numbers of the messages that have been added/removed.
+ *
+ * @return a list of message numbers
+ */
+ const std::vector <size_t>& getNumbers() const;
+
+ /** Dispatch the event to the specified listener.
+ *
+ * @param listener listener to notify
+ */
+ void dispatch(class messageCountListener* listener);
+
+
+ const char* getClass() const;
+
+private:
+
+ shared_ptr <folder> m_folder;
+ const Types m_type;
+ std::vector <size_t> m_nums;
+};
+
+
+/** Listener for events about the message count in a folder.
+ */
+class VMIME_EXPORT messageCountListener {
+
+protected:
+
+ virtual ~messageCountListener() { }
+
+public:
+
+ virtual void messagesAdded(const shared_ptr <messageCountEvent>& event) = 0;
+ virtual void messagesRemoved(const shared_ptr <messageCountEvent>& event) = 0;
+};
+
+
+/** Event occuring on a message.
+ */
+class VMIME_EXPORT messageChangedEvent : public event {
+
+public:
+
+ static const char* EVENT_CLASS;
+
+
+ enum Types {
+ TYPE_FLAGS // flags changed
+ };
+
+
+ messageChangedEvent(
+ const shared_ptr <folder>& folder,
+ const Types type,
+ const std::vector <size_t>& nums
+ );
+
+ /** Return the folder in which messages have changed.
+ *
+ * @return folder in which message count changed
+ */
+ shared_ptr <folder> getFolder() const;
+
+ /** Return the event type.
+ *
+ * @return event type (see messageChangedEvent::Types)
+ */
+ Types getType() const;
+
+ /** Return the numbers of the messages that have changed.
+ *
+ * @return a list of message numbers
+ */
+ const std::vector <size_t>& getNumbers() const;
+
+ /** Dispatch the event to the specified listener.
+ *
+ * @param listener listener to notify
+ */
+ void dispatch(class messageChangedListener* listener);
+
+
+ const char* getClass() const;
+
+private:
+
+ shared_ptr <folder> m_folder;
+ const Types m_type;
+ std::vector <size_t> m_nums;
+};
+
+
+/** Listener for events occuring on a message.
+ */
+class VMIME_EXPORT messageChangedListener {
+
+protected:
+
+ virtual ~messageChangedListener() { }
+
+public:
+
+ virtual void messageChanged(const shared_ptr <messageChangedEvent>& event) = 0;
+};
+
+
+/** Event occuring on a folder.
+ */
+class VMIME_EXPORT folderEvent : public event {
+
+public:
+
+ static const char* EVENT_CLASS;
+
+
+ enum Types {
+ TYPE_CREATED, /**< A folder was created. */
+ TYPE_DELETED, /**< A folder was deleted. */
+ TYPE_RENAMED /**< A folder was renamed. */
+ };
+
+
+ folderEvent(
+ const shared_ptr <folder>& folder,
+ const Types type,
+ const utility::path& oldPath,
+ const utility::path& newPath
+ );
+
+ /** Return the folder on which the event occurred.
+ *
+ * @return folder on which the event occurred
+ */
+ shared_ptr <folder> getFolder() const;
+
+ /** Return the event type.
+ *
+ * @return event type (see folderEvent::Types)
+ */
+ Types getType() const;
+
+ /** Dispatch the event to the specified listener.
+ *
+ * @param listener listener to notify
+ */
+ void dispatch(class folderListener* listener);
+
+
+ const char* getClass() const;
+
+private:
+
+ shared_ptr <folder> m_folder;
+ const Types m_type;
+ const utility::path m_oldPath;
+ const utility::path m_newPath;
+};
+
+
+/** Listener for events occuring on a folder.
+ */
+class VMIME_EXPORT folderListener {
+
+protected:
+
+ virtual ~folderListener() { }
+
+public:
+
+ virtual void folderCreated(const shared_ptr <folderEvent>& event) = 0;
+ virtual void folderRenamed(const shared_ptr <folderEvent>& event) = 0;
+ virtual void folderDeleted(const shared_ptr <folderEvent>& event) = 0;
+};
+
+
+} // events
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+#endif // VMIME_NET_EVENTS_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/fetchAttributes.cpp b/vmime-master/src/vmime/net/fetchAttributes.cpp
new file mode 100644
index 0000000..d9b54b8
--- /dev/null
+++ b/vmime-master/src/vmime/net/fetchAttributes.cpp
@@ -0,0 +1,98 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/net/fetchAttributes.hpp"
+
+#include "vmime/utility/stringUtils.hpp"
+
+#include <algorithm>
+
+
+namespace vmime {
+namespace net {
+
+
+fetchAttributes::fetchAttributes()
+ : m_predefinedAttribs(0) {
+
+}
+
+
+fetchAttributes::fetchAttributes(const int attribs)
+ : m_predefinedAttribs(attribs) {
+
+}
+
+
+fetchAttributes::fetchAttributes(const fetchAttributes& attribs)
+ : object() {
+
+ m_predefinedAttribs = attribs.m_predefinedAttribs;
+ m_headers = attribs.m_headers;
+}
+
+
+void fetchAttributes::add(const int attribs) {
+
+ m_predefinedAttribs |= attribs;
+}
+
+
+void fetchAttributes::add(const string& header) {
+
+ m_headers.push_back(utility::stringUtils::toLower(header));
+}
+
+
+bool fetchAttributes::has(const int attribs) const {
+
+ return (m_predefinedAttribs & attribs) != 0;
+}
+
+
+bool fetchAttributes::has(const string& header) const {
+
+ return std::find(
+ m_headers.begin(), m_headers.end(),
+ utility::stringUtils::toLower(header)
+ ) != m_headers.end();
+}
+
+
+const std::vector <string> fetchAttributes::getHeaderFields() const {
+
+ return m_headers;
+}
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
diff --git a/vmime-master/src/vmime/net/fetchAttributes.hpp b/vmime-master/src/vmime/net/fetchAttributes.hpp
new file mode 100644
index 0000000..19d9262
--- /dev/null
+++ b/vmime-master/src/vmime/net/fetchAttributes.hpp
@@ -0,0 +1,140 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_FETCHATTRIBUTES_HPP_INCLUDED
+#define VMIME_NET_FETCHATTRIBUTES_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include <vector>
+
+#include "vmime/types.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+/** Holds a set of attributes to fetch for a message.
+ */
+class VMIME_EXPORT fetchAttributes : public object {
+
+public:
+
+ /** Predefined attributes that can be fetched.
+ */
+ enum PredefinedFetchAttributes {
+ ENVELOPE = (1 << 0), /**< Sender, recipients, date, subject. */
+ STRUCTURE = (1 << 1), /**< MIME structure (body parts). */
+ CONTENT_INFO = (1 << 2), /**< Top-level content type. */
+ FLAGS = (1 << 3), /**< Message flags. */
+ SIZE = (1 << 4), /**< Message size (exact or estimated). */
+ FULL_HEADER = (1 << 5), /**< Full RFC-[2]822 header. */
+ UID = (1 << 6), /**< Unique identifier (protocol specific). */
+ IMPORTANCE = (1 << 7), /**< Header fields suitable for use with misc::importanceHelper. */
+
+ CUSTOM = (1 << 16) /**< Reserved for future use. */
+ };
+
+ /** Constructs an empty fetchAttributes object.
+ */
+ fetchAttributes();
+
+ /** Constructs a new fetchAttributes object by specifying one or more
+ * predefined objects.
+ *
+ * @param attribs one or more OR-ed values of the PredefinedFetchAttributes enum
+ */
+ fetchAttributes(const int attribs);
+
+ /** Constructs a new fetchAttributes object by copying an existing object.
+ *
+ * @param attribs object to copy
+ */
+ fetchAttributes(const fetchAttributes& attribs);
+
+ /** Adds the specified predefined attribute to the set of attributes to fetch.
+ *
+ * @param attribs one or more OR-ed values of the PredefinedFetchAttributes enum
+ */
+ void add(const int attribs);
+
+ /** Adds the specified header field to the set of attributes to fetch.
+ * Fetching custom header fields is not supported by all protocols.
+ * At this time, only IMAP supports this.
+ *
+ * @param header name of header field (eg. "X-Mailer")
+ */
+ void add(const string& header);
+
+ /** Returns true if the set contains the specified attribute(s).
+ *
+ * @param attribs one or more OR-ed values of the PredefinedFetchAttributes enum
+ * @return true if the specified attributes are to be fetched
+ */
+ bool has(const int attribs) const;
+
+ /** Returns true if the set contains the specified header field.
+ *
+ * @param header name of header field (eg. "X-Mailer")
+ * @return true if the specified header fields are to be fetched
+ */
+ bool has(const string& header) const;
+
+ /** Returns true if the set contains the specified attribute(s).
+ *
+ * \deprecated Use the has() methods instead
+ *
+ * @param attribs one or more OR-ed values of the PredefinedFetchAttributes enum
+ * @return true if the specified attributes are to be fetched
+ */
+ VMIME_DEPRECATED inline bool operator&(const int attribs) const {
+ return has(attribs);
+ }
+
+ /** Returns a list of header fields to fetch.
+ *
+ * @return list of header names (eg. "X-Mailer")
+ */
+ const std::vector <string> getHeaderFields() const;
+
+private:
+
+ int m_predefinedAttribs;
+ std::vector <string> m_headers;
+};
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+
+#endif // VMIME_NET_FETCHATTRIBUTES_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/folder.cpp b/vmime-master/src/vmime/net/folder.cpp
new file mode 100644
index 0000000..6e01b60
--- /dev/null
+++ b/vmime-master/src/vmime/net/folder.cpp
@@ -0,0 +1,134 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/net/folder.hpp"
+
+#include <algorithm>
+
+
+namespace vmime {
+namespace net {
+
+
+int folder::getType() {
+
+ return getAttributes().getType();
+}
+
+
+int folder::getFlags() {
+
+ return getAttributes().getFlags();
+}
+
+
+void folder::addMessageChangedListener(events::messageChangedListener* l) {
+
+ m_messageChangedListeners.push_back(l);
+}
+
+
+void folder::removeMessageChangedListener(events::messageChangedListener* l) {
+
+ std::remove(m_messageChangedListeners.begin(), m_messageChangedListeners.end(), l);
+}
+
+
+void folder::notifyMessageChanged(const shared_ptr <events::messageChangedEvent>& event) {
+
+ for (std::list <events::messageChangedListener*>::iterator
+ it = m_messageChangedListeners.begin() ; it != m_messageChangedListeners.end() ; ++it) {
+
+ event->dispatch(*it);
+ }
+}
+
+
+void folder::addMessageCountListener(events::messageCountListener* l) {
+
+ m_messageCountListeners.push_back(l);
+}
+
+
+void folder::removeMessageCountListener(events::messageCountListener* l) {
+
+ std::remove(m_messageCountListeners.begin(), m_messageCountListeners.end(), l);
+}
+
+
+void folder::notifyMessageCount(const shared_ptr <events::messageCountEvent>& event) {
+
+ for (std::list <events::messageCountListener*>::iterator
+ it = m_messageCountListeners.begin() ; it != m_messageCountListeners.end() ; ++it) {
+
+ event->dispatch(*it);
+ }
+}
+
+
+void folder::addFolderListener(events::folderListener* l) {
+
+ m_folderListeners.push_back(l);
+}
+
+
+void folder::removeFolderListener(events::folderListener* l) {
+
+ std::remove(m_folderListeners.begin(), m_folderListeners.end(), l);
+}
+
+
+void folder::notifyFolder(const shared_ptr <events::folderEvent>& event) {
+
+ for (std::list <events::folderListener*>::iterator
+ it = m_folderListeners.begin() ; it != m_folderListeners.end() ; ++it) {
+
+ event->dispatch(*it);
+ }
+}
+
+
+void folder::notifyEvent(const shared_ptr <events::event>& event) {
+
+ if (event->getClass() == events::messageCountEvent::EVENT_CLASS) {
+ notifyMessageCount(dynamicCast <events::messageCountEvent>(event));
+ } else if (event->getClass() == events::messageChangedEvent::EVENT_CLASS) {
+ notifyMessageChanged(dynamicCast <events::messageChangedEvent>(event));
+ } else if (event->getClass() == events::folderEvent::EVENT_CLASS) {
+ notifyFolder(dynamicCast <events::folderEvent>(event));
+ }
+}
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
diff --git a/vmime-master/src/vmime/net/folder.hpp b/vmime-master/src/vmime/net/folder.hpp
new file mode 100644
index 0000000..4d5cf6e
--- /dev/null
+++ b/vmime-master/src/vmime/net/folder.hpp
@@ -0,0 +1,440 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_FOLDER_HPP_INCLUDED
+#define VMIME_NET_FOLDER_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include <vector>
+
+#include "vmime/types.hpp"
+#include "vmime/dateTime.hpp"
+
+#include "vmime/message.hpp"
+#include "vmime/net/message.hpp"
+#include "vmime/net/messageSet.hpp"
+#include "vmime/net/events.hpp"
+#include "vmime/net/folderStatus.hpp"
+#include "vmime/net/fetchAttributes.hpp"
+#include "vmime/net/folderAttributes.hpp"
+
+#include "vmime/utility/path.hpp"
+#include "vmime/utility/stream.hpp"
+#include "vmime/utility/progressListener.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+class store;
+
+
+/** Abstract representation of a folder in a message store.
+ */
+class VMIME_EXPORT folder : public object, public enable_shared_from_this <folder> {
+
+protected:
+
+ folder(const folder&) : object(), enable_shared_from_this <folder>() { }
+ folder() { }
+
+
+ enum PrivateConstants {
+ TYPE_UNDEFINED = 9999, /**< Used internally to indicate type has not
+ been initialized yet. */
+ FLAG_UNDEFINED = 9999 /**< Used internally to indicate flags have not
+ been initialized yet. */
+ };
+
+public:
+
+ virtual ~folder() { }
+
+ /** Type used for fully qualified path name of a folder.
+ */
+ typedef vmime::utility::path path;
+
+
+ /** Open mode.
+ */
+ enum Modes {
+ MODE_READ_ONLY, /**< Read-only mode (no modification to folder or messages is possible). */
+ MODE_READ_WRITE /**< Full access mode (read and write). */
+ };
+
+
+ /** Return the type of this folder.
+ *
+ * \deprecated Use the getAttributes().getType() method instead
+ *
+ * @return folder type (see folderAttributes::Types enum)
+ */
+ int getType();
+
+ /** Return the flags of this folder.
+ *
+ * \deprecated Use the getAttributes().getFlags() method instead
+ *
+ * @return folder flags (see folderAttributes::Flags enum)
+ */
+ int getFlags();
+
+ /** Return the attributes of the folder.
+ *
+ * @return folder attributes (see folder::Flags)
+ */
+ virtual const folderAttributes getAttributes() = 0;
+
+ /** Return the mode in which the folder has been open.
+ *
+ * @return folder opening mode (see folder::Modes)
+ */
+ virtual int getMode() const = 0;
+
+ /** Return the name of this folder.
+ *
+ * @return folder name
+ */
+ virtual const folder::path::component getName() const = 0;
+
+ /** Return the fully qualified path name of this folder.
+ *
+ * @return absolute path of the folder
+ */
+ virtual const folder::path getFullPath() const = 0;
+
+ /** Open this folder.
+ *
+ * @param mode open mode (see folder::Modes)
+ * @param failIfModeIsNotAvailable if set to false and if the requested mode
+ * is not available, a more restricted mode will be selected automatically.
+ * If set to true and if the requested mode is not available, the opening
+ * will fail.
+ * @throw exceptions::net_exception if an error occurs
+ * @throw exceptions::folder_already_open if the folder is already open
+ * in the same session
+ */
+ virtual void open(const int mode, bool failIfModeIsNotAvailable = false) = 0;
+
+ /** Close this folder.
+ *
+ * @param expunge if set to true, deleted messages are expunged
+ * @throw exceptions::net_exception if an error occurs
+ */
+ virtual void close(const bool expunge) = 0;
+
+ /** Create this folder.
+ *
+ * @param attribs attributes of the new folder
+ * @throw exceptions::net_exception if an error occurs
+ */
+ virtual void create(const folderAttributes& attribs) = 0;
+
+ /** Test whether this folder exists.
+ *
+ * @return true if the folder exists, false otherwise
+ */
+ virtual bool exists() = 0;
+
+ /** Delete this folder.
+ * The folder should be closed before attempting to delete it.
+ *
+ * @throw exceptions::net_exception if an error occurs
+ */
+ virtual void destroy() = 0;
+
+ /** Test whether this folder is open.
+ *
+ * @return true if the folder is open, false otherwise
+ */
+ virtual bool isOpen() const = 0;
+
+ /** Get a new reference to a message in this folder, given its number.
+ *
+ * @param num message sequence number
+ * @return a new object referencing the specified message
+ * @throw exceptions::net_exception if an error occurs
+ */
+ virtual shared_ptr <message> getMessage(const size_t num) = 0;
+
+ /** Get new references to messages in this folder, given either their
+ * sequence numbers or UIDs.
+ *
+ * To retrieve messages by their number, use:
+ * \code{.cpp}
+ * // Get messages from sequence number 5 to sequence number 8 (including)
+ * folder->getMessage(vmime::net::messageSet::byNumber(5, 8));
+ *
+ * // Get all messages in the folder, starting from number 42
+ * folder->getMessage(vmime::net::messageSet::byNumber(42, -1));
+ * \endcode
+ * Or, to retrieve messages by their UID, use:
+ * \code{.cpp}
+ * // Get messages from UID 1000 to UID 1042 (including)
+ * folder->getMessage(vmime::net::messageSet::byUID(1000, 1042));
+ *
+ * // Get message with UID 1042
+ * folder->getMessage(vmime::net::messageSet::byUID(1042));
+ *
+ * // Get all messages in the folder, starting from UID 1000
+ * folder->getMessage(vmime::net::messageSet::byUID(1000, "*"));
+ * \endcode
+ *
+ * @param msgs index set of messages to retrieve
+ * @return new objects referencing the specified messages
+ * @throw exceptions::net_exception if an error occurs
+ */
+ virtual std::vector <shared_ptr <message> > getMessages(const messageSet& msgs) = 0;
+
+ /** Return the number of messages in this folder.
+ *
+ * @return number of messages in the folder
+ */
+ virtual size_t getMessageCount() = 0;
+
+ /** Get a new reference to a sub-folder in this folder.
+ *
+ * @param name sub-folder name
+ * @return a new object referencing the specified folder
+ * @throw exceptions::net_exception if an error occurs
+ */
+ virtual shared_ptr <folder> getFolder(const folder::path::component& name) = 0;
+
+ /** Get the list of all sub-folders in this folder.
+ *
+ * @param recursive if set to true, all the descendant are returned.
+ * If set to false, only the direct children are returned.
+ * @return list of sub-folders
+ * @throw exceptions::net_exception if an error occurs
+ */
+ virtual std::vector <shared_ptr <folder> > getFolders(const bool recursive = false) = 0;
+
+ /** Rename (move) this folder to another location.
+ *
+ * @param newPath new path of the folder
+ * @throw exceptions::net_exception if an error occurs
+ */
+ virtual void rename(const folder::path& newPath) = 0;
+
+ /** Remove one or more messages from this folder.
+ *
+ * @param msgs index set of messages to delete
+ * @throw exceptions::net_exception if an error occurs
+ */
+ virtual void deleteMessages(const messageSet& msgs) = 0;
+
+ /** Change the flags for one or more messages in this folder.
+ *
+ * @param msgs index set of messages on which to set the flags
+ * @param flags set of flags (see message::Flags)
+ * @param mode indicate how to treat old and new flags (see message::FlagsModes)
+ * @throw exceptions::net_exception if an error occurs
+ */
+ virtual void setMessageFlags(const messageSet& msgs, const int flags, const int mode = message::FLAG_MODE_SET) = 0;
+
+ /** Add a message to this folder.
+ *
+ * @param msg message to add (data: header + body)
+ * @param flags flags for the new message (if -1, default flags are used)
+ * @param date date/time for the new message (if NULL, the current time is used)
+ * @param progress progress listener, or NULL if not used
+ * @return a message set containing the number or UID of the new message, or
+ * an empty set if the information could not be obtained (ie. the server does not
+ * support returning the number or UID of an added message)
+ * @throw exceptions::net_exception if an error occurs
+ */
+ virtual messageSet addMessage(
+ const shared_ptr <vmime::message>& msg,
+ const int flags = -1,
+ vmime::datetime* date = NULL,
+ utility::progressListener* progress = NULL
+ ) = 0;
+
+ /** Add a message to this folder.
+ *
+ * @param is message to add (data: header + body)
+ * @param size size of the message to add (in bytes)
+ * @param flags flags for the new message (if -1, default flags are used)
+ * @param date date/time for the new message (if NULL, the current time is used)
+ * @param progress progress listener, or NULL if not used
+ * @return a message set containing the number or UID of the new message, or
+ * an empty set if the information could not be obtained (ie. the server does not
+ * support returning the number or UID of an added message)
+ * @throw exceptions::net_exception if an error occurs
+ */
+ virtual messageSet addMessage(
+ utility::inputStream& is,
+ const size_t size,
+ const int flags = -1,
+ vmime::datetime* date = NULL,
+ utility::progressListener* progress = NULL
+ ) = 0;
+
+ /** Copy messages from this folder to another folder.
+ *
+ * @param dest destination folder path
+ * @param msgs index set of messages to copy
+ * @return a message set containing the number(s) or UID(s) of the copied message(s),
+ * or an empty set if the information could not be obtained (ie. the server does not
+ * support returning the number or UID of a copied message)
+ * @throw exceptions::net_exception if an error occurs
+ */
+ virtual messageSet copyMessages(
+ const folder::path& dest,
+ const messageSet& msgs
+ ) = 0;
+
+ /** Request folder status without opening it.
+ *
+ * \deprecated Use the new getStatus() method
+ *
+ * @param count will receive the number of messages in the folder
+ * @param unseen will receive the number of unseen messages in the folder
+ * @throw exceptions::net_exception if an error occurs
+ */
+ virtual void status(size_t& count, size_t& unseen) = 0;
+
+ /** Request folder status without opening it.
+ *
+ * @return current folder status
+ * @throw exceptions::net_exception if an error occurs
+ */
+ virtual shared_ptr <folderStatus> getStatus() = 0;
+
+ /** Expunge deleted messages.
+ *
+ * @throw exceptions::net_exception if an error occurs
+ */
+ virtual void expunge() = 0;
+
+ /** Return a new folder object referencing the parent folder of this folder.
+ *
+ * @return parent folder object
+ */
+ virtual shared_ptr <folder> getParent() = 0;
+
+ /** Return a reference to the store to which this folder belongs.
+ *
+ * @return the store object to which this folder is attached
+ */
+ virtual shared_ptr <const store> getStore() const = 0;
+
+ /** Return a reference to the store to which this folder belongs.
+ *
+ * @return the store object to which this folder is attached
+ */
+ virtual shared_ptr <store> getStore() = 0;
+
+ /** Fetch objects for the specified messages.
+ *
+ * @param msg list of message sequence numbers
+ * @param attribs set of attributes to fetch
+ * @param progress progress listener, or NULL if not used
+ * @throw exceptions::net_exception if an error occurs
+ */
+ virtual void fetchMessages(
+ std::vector <shared_ptr <message> >& msg,
+ const fetchAttributes& attribs,
+ utility::progressListener* progress = NULL
+ ) = 0;
+
+ /** Fetch objects for the specified message.
+ *
+ * @param msg the message
+ * @param attribs set of attributes to fetch
+ * @throw exceptions::net_exception if an error occurs
+ */
+ virtual void fetchMessage(
+ const shared_ptr <message>& msg,
+ const fetchAttributes& attribs
+ ) = 0;
+
+ /** Get new references to messages in this folder, given either their
+ * sequence numbers or UIDs, and fetch objects for them at the same time.
+ *
+ * @param msgs index set of messages to retrieve
+ * @param attribs set of attributes to fetch
+ * @return new objects referencing the specified messages
+ * @throw exceptions::net_exception if an error occurs
+ * @see folder::getMessages()
+ * @see folder::fetchMessages()
+ */
+ virtual std::vector <shared_ptr <message> > getAndFetchMessages(
+ const messageSet& msgs,
+ const fetchAttributes& attribs
+ ) = 0;
+
+ /** Return the list of fetchable objects supported by
+ * the underlying protocol (see folder::fetchAttributes).
+ *
+ * @return list of supported fetchable objects
+ */
+ virtual int getFetchCapabilities() const = 0;
+
+ /** Return the sequence numbers of messages whose UID equal or greater than
+ * the specified UID.
+ *
+ * @param uid the uid of the first message
+ * @throw exceptions::net_exception if an error occurs
+ */
+ virtual std::vector <size_t> getMessageNumbersStartingOnUID(const message::uid& uid) = 0;
+
+ // Event listeners
+ void addMessageChangedListener(events::messageChangedListener* l);
+ void removeMessageChangedListener(events::messageChangedListener* l);
+
+ void addMessageCountListener(events::messageCountListener* l);
+ void removeMessageCountListener(events::messageCountListener* l);
+
+ void addFolderListener(events::folderListener* l);
+ void removeFolderListener(events::folderListener* l);
+
+protected:
+
+ void notifyMessageChanged(const shared_ptr <events::messageChangedEvent>& event);
+ void notifyMessageCount(const shared_ptr <events::messageCountEvent>& event);
+ void notifyFolder(const shared_ptr <events::folderEvent>& event);
+ void notifyEvent(const shared_ptr <events::event>& event);
+
+private:
+
+ std::list <events::messageChangedListener*> m_messageChangedListeners;
+ std::list <events::messageCountListener*> m_messageCountListeners;
+ std::list <events::folderListener*> m_folderListeners;
+};
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+#endif // VMIME_NET_FOLDER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/folderAttributes.cpp b/vmime-master/src/vmime/net/folderAttributes.cpp
new file mode 100644
index 0000000..107007c
--- /dev/null
+++ b/vmime-master/src/vmime/net/folderAttributes.cpp
@@ -0,0 +1,122 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/net/folderAttributes.hpp"
+
+#include <algorithm>
+
+
+namespace vmime {
+namespace net {
+
+
+folderAttributes::folderAttributes()
+ : m_type(TYPE_CONTAINS_FOLDERS | TYPE_CONTAINS_MESSAGES),
+ m_flags(0),
+ m_specialUse(SPECIALUSE_NONE) {
+
+}
+
+
+folderAttributes::folderAttributes(const folderAttributes& attribs)
+ : object(),
+ m_type(attribs.m_type),
+ m_flags(attribs.m_flags),
+ m_userFlags(attribs.m_userFlags),
+ m_specialUse(attribs.m_specialUse) {
+
+}
+
+
+int folderAttributes::getType() const {
+
+ return m_type;
+}
+
+
+void folderAttributes::setType(const int type) {
+
+ m_type = type;
+}
+
+
+int folderAttributes::getSpecialUse() const {
+
+ return m_specialUse;
+}
+
+
+void folderAttributes::setSpecialUse(const int use) {
+
+ m_specialUse = use;
+}
+
+
+int folderAttributes::getFlags() const {
+
+ return m_flags;
+}
+
+
+void folderAttributes::setFlags(const int flags) {
+
+ m_flags = flags;
+}
+
+
+bool folderAttributes::hasFlag(const int flag) {
+
+ return (m_flags & flag) != 0;
+}
+
+
+const std::vector <string> folderAttributes::getUserFlags() const {
+
+ return m_userFlags;
+}
+
+
+void folderAttributes::setUserFlags(const std::vector <string>& flags) {
+
+ m_userFlags = flags;
+}
+
+
+bool folderAttributes::hasUserFlag(const string& flag) {
+
+ return std::find(m_userFlags.begin(), m_userFlags.end(), flag) != m_userFlags.end();
+}
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
diff --git a/vmime-master/src/vmime/net/folderAttributes.hpp b/vmime-master/src/vmime/net/folderAttributes.hpp
new file mode 100644
index 0000000..715b72a
--- /dev/null
+++ b/vmime-master/src/vmime/net/folderAttributes.hpp
@@ -0,0 +1,177 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_FOLDERATTRIBUTES_HPP_INCLUDED
+#define VMIME_NET_FOLDERATTRIBUTES_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include <vector>
+
+#include "vmime/types.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+/** Holds a set of attributes for a folder.
+ */
+class VMIME_EXPORT folderAttributes : public object {
+
+public:
+
+ /** Folder types.
+ */
+ enum Types {
+ TYPE_CONTAINS_FOLDERS = (1 << 0), /**< Folder can contain folders. */
+ TYPE_CONTAINS_MESSAGES = (1 << 1) /**< Folder can contain messages. */
+ };
+
+ /** Folder flags.
+ */
+ enum Flags {
+ FLAG_HAS_CHILDREN = (1 << 0), /**< Folder contains subfolders. */
+ FLAG_NO_OPEN = (1 << 1) /**< Folder cannot be open. */
+ };
+
+ /** Folder special uses.
+ * Not all protocols support this. At the current time, only IMAP supports this,
+ * if the server has the SPECIAL-USE capability.
+ */
+ enum SpecialUses {
+ SPECIALUSE_NONE, /**< User folder, no special use (or unknown). */
+ SPECIALUSE_ALL, /**< Virtual folder containing all messages. */
+ SPECIALUSE_INBOX, /**< Inbox. */
+ SPECIALUSE_ARCHIVE, /**< Folder is used to archives messages (server-dependent). */
+ SPECIALUSE_DRAFTS, /**< Folder is used to hold draft messages - typically, messages
+ that are being composed but have not yet been sent. */
+ SPECIALUSE_FLAGGED, /**< Virtual folder containing all messages which are marked
+ in some way as "important" or "flagged". */
+ SPECIALUSE_JUNK, /**< Folder is used to hold junk mail. */
+ SPECIALUSE_SENT, /**< Folder is is used to hold copies of messages that have
+ been sent. */
+ SPECIALUSE_TRASH, /**< Folder is used to hold messages that have been deleted or
+ marked for deletion (may be a virtual folder). */
+ SPECIALUSE_IMPORTANT /**< Folder contains messages that are likely important to the
+ user. */
+ };
+
+
+ /** Construct a new folderAttributes object with the default set of attributes.
+ */
+ folderAttributes();
+
+ /** Construct a new folderAttributes object by copying an existing object.
+ *
+ * @param attribs object to copy
+ */
+ folderAttributes(const folderAttributes& attribs);
+
+ /** Return the type of the folder.
+ *
+ * @return combination of one ore more folder types (see folderAttributes::Types enum)
+ */
+ int getType() const;
+
+ /** Set the type of the folder.
+ *
+ * @param type combination of one ore more folder types (see folderAttributes::Types enum)
+ */
+ void setType(const int type);
+
+ /** Return the special use of the folder.
+ * Not all protocols support this. At the current time, only IMAP supports this,
+ * if the server has the SPECIAL-USE capability.
+ *
+ * @return a value which indicates a special use (see folderAttributes::SpecialUses enum)
+ */
+ int getSpecialUse() const;
+
+ /** Set the special use of the folder.
+ * Not all protocols support this. At the current time, only IMAP supports this,
+ * if the server has the SPECIAL-USE capability.
+ *
+ * @param use a value which indicates a special use (see folderAttributes::SpecialUses enum)
+ */
+ void setSpecialUse(const int use);
+
+ /** Return the standard (non-user) flags of the folder.
+ *
+ * @return combination of one ore more folder flags (see folderAttributes::Flags enum)
+ */
+ int getFlags() const;
+
+ /** Set the standard (non-user) flags of the folder.
+ *
+ * @param type combination of one ore more folder flags (see folderAttributes::Flags enum)
+ */
+ void setFlags(const int flags);
+
+ /** Return whether the specified folder flag(s) is/are set.
+ *
+ * @param flag combination of one ore more folder flags (see folderAttributes::Flags enum)
+ * @return true if the specified flags are all set, or false otherwise
+ */
+ bool hasFlag(const int flag);
+
+ /** Set the user-defined flags of the folder.
+ *
+ * @return a list of user-defined flags
+ */
+ const std::vector <string> getUserFlags() const;
+
+ /** Set the user-defined flags of the folder.
+ *
+ * @param flags a list of user-defined flags
+ */
+ void setUserFlags(const std::vector <string>& flags);
+
+ /** Return whether the specified user-defined flag is set.
+ *
+ * @return true if the specified flag is set, or false otherwise
+ */
+ bool hasUserFlag(const string& flag);
+
+private:
+
+ int m_type;
+ int m_flags;
+ std::vector <string> m_userFlags;
+ int m_specialUse;
+};
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+
+#endif // VMIME_NET_FOLDERATTRIBUTES_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/folderStatus.hpp b/vmime-master/src/vmime/net/folderStatus.hpp
new file mode 100644
index 0000000..fcc4afc
--- /dev/null
+++ b/vmime-master/src/vmime/net/folderStatus.hpp
@@ -0,0 +1,73 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_FOLDERSTATUS_HPP_INCLUDED
+#define VMIME_NET_FOLDERSTATUS_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/base.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+/** Holds the status of a mail store folder.
+ */
+class VMIME_EXPORT folderStatus : public object {
+
+public:
+
+ /** Returns the total number of messages in the folder.
+ *
+ * @return number of messages
+ */
+ virtual size_t getMessageCount() const = 0;
+
+ /** Returns the number of unseen messages in the folder.
+ *
+ * @return number of unseen messages
+ */
+ virtual size_t getUnseenCount() const = 0;
+
+ /** Clones this object.
+ *
+ * @return a copy of this object
+ */
+ virtual shared_ptr <folderStatus> clone() const = 0;
+};
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+#endif // VMIME_NET_FOLDERSTATUS_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/imap/IMAPCommand.cpp b/vmime-master/src/vmime/net/imap/IMAPCommand.cpp
new file mode 100644
index 0000000..8911ed0
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPCommand.cpp
@@ -0,0 +1,437 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/net/imap/IMAPCommand.hpp"
+#include "vmime/net/imap/IMAPConnection.hpp"
+#include "vmime/net/imap/IMAPUtils.hpp"
+
+#include <sstream>
+
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+IMAPCommand::IMAPCommand(const string& text, const string& traceText)
+ : m_text(text),
+ m_traceText(traceText) {
+
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::LOGIN(const string& username, const string& password) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "LOGIN " << IMAPUtils::quoteString(username)
+ << " " << IMAPUtils::quoteString(password);
+
+ std::ostringstream trace;
+ trace.imbue(std::locale::classic());
+ trace << "LOGIN {username} {password}";
+
+ return createCommand(cmd.str(), trace.str());
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::AUTHENTICATE(const string& mechName) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "AUTHENTICATE " << mechName;
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::AUTHENTICATE(const string& mechName, const string& initialResponse) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "AUTHENTICATE " << mechName << " " << initialResponse;
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::LIST(const string& refName, const string& mailboxName) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "LIST " << IMAPUtils::quoteString(refName)
+ << " " << IMAPUtils::quoteString(mailboxName);
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::SELECT(
+ const bool readOnly,
+ const string& mailboxName,
+ const std::vector <string>& params
+) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+
+ if (readOnly) {
+ cmd << "EXAMINE ";
+ } else {
+ cmd << "SELECT ";
+ }
+
+ cmd << IMAPUtils::quoteString(mailboxName);
+
+ if (!params.empty()) {
+
+ cmd << " (";
+
+ for (size_t i = 0, n = params.size() ; i < n ; ++i) {
+ if (i != 0) cmd << " ";
+ cmd << params[i];
+ }
+
+ cmd << ")";
+ }
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::STATUS(
+ const string& mailboxName,
+ const std::vector <string>& attribs
+) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "STATUS " << IMAPUtils::quoteString(mailboxName);
+
+ cmd << " (";
+
+ for (size_t i = 0, n = attribs.size() ; i < n ; ++i) {
+ if (i != 0) cmd << " ";
+ cmd << attribs[i];
+ }
+
+ cmd << ")";
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::CREATE(
+ const string& mailboxName,
+ const std::vector <string>& params
+) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "CREATE " << IMAPUtils::quoteString(mailboxName);
+
+ if (!params.empty()) {
+
+ cmd << " (";
+
+ for (size_t i = 0, n = params.size() ; i < n ; ++i) {
+ if (i != 0) cmd << " ";
+ cmd << params[i];
+ }
+
+ cmd << ")";
+ }
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::DELETE(const string& mailboxName) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "DELETE " << IMAPUtils::quoteString(mailboxName);
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::RENAME(
+ const string& mailboxName,
+ const string& newMailboxName
+) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "RENAME " << IMAPUtils::quoteString(mailboxName)
+ << " " << IMAPUtils::quoteString(newMailboxName);
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::FETCH(
+ const messageSet& msgs,
+ const std::vector <string>& params
+) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+
+ if (msgs.isUIDSet()) {
+ cmd << "UID FETCH " << IMAPUtils::messageSetToSequenceSet(msgs);
+ } else {
+ cmd << "FETCH " << IMAPUtils::messageSetToSequenceSet(msgs);
+ }
+
+ if (params.size() == 1) {
+
+ cmd << " " << params[0];
+
+ } else {
+
+ cmd << " (";
+
+ for (size_t i = 0, n = params.size() ; i < n ; ++i) {
+ if (i != 0) cmd << " ";
+ cmd << params[i];
+ }
+
+ cmd << ")";
+ }
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::STORE(
+ const messageSet& msgs,
+ const int mode,
+ const std::vector <string>& flags
+) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+
+ if (msgs.isUIDSet()) {
+ cmd << "UID STORE " << IMAPUtils::messageSetToSequenceSet(msgs);
+ } else {
+ cmd << "STORE " << IMAPUtils::messageSetToSequenceSet(msgs);
+ }
+
+ if (mode == message::FLAG_MODE_ADD) {
+ cmd << " +FLAGS ";
+ } else if (mode == message::FLAG_MODE_REMOVE) {
+ cmd << " -FLAGS ";
+ } else { // if (mode == message::FLAG_MODE_SET)
+ cmd << " FLAGS ";
+ }
+
+ cmd << "(";
+
+ for (size_t i = 0, n = flags.size() ; i < n ; ++i) {
+ if (i != 0) cmd << " ";
+ cmd << flags[i];
+ }
+
+ cmd << ")";
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::APPEND(
+ const string& mailboxName,
+ const std::vector <string>& flags,
+ vmime::datetime* date,
+ const size_t size
+) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "APPEND " << IMAPUtils::quoteString(mailboxName);
+
+ if (!flags.empty()) {
+
+ cmd << " (";
+
+ for (size_t i = 0, n = flags.size() ; i < n ; ++i) {
+ if (i != 0) cmd << " ";
+ cmd << flags[i];
+ }
+
+ cmd << ")";
+ }
+
+ if (date != NULL) {
+ cmd << " " << IMAPUtils::dateTime(*date);
+ }
+
+ cmd << " {" << size << "}";
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::COPY(
+ const messageSet& msgs,
+ const string& mailboxName
+) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+
+ if (msgs.isUIDSet()) {
+ cmd << "UID COPY " << IMAPUtils::messageSetToSequenceSet(msgs);
+ } else {
+ cmd << "COPY " << IMAPUtils::messageSetToSequenceSet(msgs);
+ }
+
+ cmd << " " << IMAPUtils::quoteString(mailboxName);
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::SEARCH(
+ const std::vector <string>& keys,
+ const vmime::charset* charset
+) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "SEARCH";
+
+ if (charset) {
+ cmd << " CHARSET " << charset->getName();
+ }
+
+ for (size_t i = 0, n = keys.size() ; i < n ; ++i) {
+ cmd << " " << keys[i];
+ }
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::STARTTLS() {
+
+ return createCommand("STARTTLS");
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::CAPABILITY() {
+
+ return createCommand("CAPABILITY");
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::NOOP() {
+
+ return createCommand("NOOP");
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::EXPUNGE() {
+
+ return createCommand("EXPUNGE");
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::CLOSE() {
+
+ return createCommand("CLOSE");
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::LOGOUT() {
+
+ return createCommand("LOGOUT");
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPCommand::createCommand(
+ const string& text,
+ const string& traceText
+) {
+
+ if (traceText.empty()) {
+ return shared_ptr <IMAPCommand>(new IMAPCommand(text, text));
+ } else {
+ return shared_ptr <IMAPCommand>(new IMAPCommand(text, traceText));
+ }
+}
+
+
+const string IMAPCommand::getText() const {
+
+ return m_text;
+}
+
+
+const string IMAPCommand::getTraceText() const {
+
+ return m_traceText;
+}
+
+
+void IMAPCommand::send(const shared_ptr <IMAPConnection>& conn) {
+
+ conn->sendCommand(dynamicCast <IMAPCommand>(shared_from_this()));
+}
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
diff --git a/vmime-master/src/vmime/net/imap/IMAPCommand.hpp b/vmime-master/src/vmime/net/imap/IMAPCommand.hpp
new file mode 100644
index 0000000..4915a57
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPCommand.hpp
@@ -0,0 +1,124 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_IMAP_IMAPCOMMAND_HPP_INCLUDED
+#define VMIME_NET_IMAP_IMAPCOMMAND_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/object.hpp"
+#include "vmime/base.hpp"
+#include "vmime/dateTime.hpp"
+
+#include "vmime/net/messageSet.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+class IMAPConnection;
+
+
+/** An IMAP command that will be sent to the server.
+ */
+class VMIME_EXPORT IMAPCommand : public object, public enable_shared_from_this <IMAPCommand> {
+
+public:
+
+ static shared_ptr <IMAPCommand> LOGIN(const string& username, const string& password);
+ static shared_ptr <IMAPCommand> AUTHENTICATE(const string& mechName);
+ static shared_ptr <IMAPCommand> AUTHENTICATE(const string& mechName, const string& initialResponse);
+ static shared_ptr <IMAPCommand> LIST(const string& refName, const string& mailboxName);
+ static shared_ptr <IMAPCommand> SELECT(const bool readOnly, const string& mailboxName, const std::vector <string>& params);
+ static shared_ptr <IMAPCommand> STATUS(const string& mailboxName, const std::vector <string>& attribs);
+ static shared_ptr <IMAPCommand> CREATE(const string& mailboxName, const std::vector <string>& params);
+ static shared_ptr <IMAPCommand> DELETE(const string& mailboxName);
+ static shared_ptr <IMAPCommand> RENAME(const string& mailboxName, const string& newMailboxName);
+ static shared_ptr <IMAPCommand> FETCH(const messageSet& msgs, const std::vector <string>& params);
+ static shared_ptr <IMAPCommand> STORE(const messageSet& msgs, const int mode, const std::vector <string>& flags);
+ static shared_ptr <IMAPCommand> APPEND(const string& mailboxName, const std::vector <string>& flags, vmime::datetime* date, const size_t size);
+ static shared_ptr <IMAPCommand> COPY(const messageSet& msgs, const string& mailboxName);
+ static shared_ptr <IMAPCommand> SEARCH(const std::vector <string>& keys, const vmime::charset* charset);
+ static shared_ptr <IMAPCommand> STARTTLS();
+ static shared_ptr <IMAPCommand> CAPABILITY();
+ static shared_ptr <IMAPCommand> NOOP();
+ static shared_ptr <IMAPCommand> EXPUNGE();
+ static shared_ptr <IMAPCommand> CLOSE();
+ static shared_ptr <IMAPCommand> LOGOUT();
+
+ /** Creates a new IMAP command with the specified text.
+ *
+ * @param text command text
+ * @param traceText trace text (if empty, command text is used)
+ * @return a new IMAPCommand object
+ */
+ static shared_ptr <IMAPCommand> createCommand(const string& text, const string& traceText = "");
+
+ /** Sends this command over the specified connection.
+ *
+ * @param conn connection onto which the command will be sent
+ */
+ virtual void send(const shared_ptr <IMAPConnection>& conn);
+
+ /** Returns the full text of the command, including command name
+ * and parameters (if any). This is the text that will be sent
+ * to the server.
+ *
+ * @return command text (eg. "LOGIN myusername mypassword")
+ */
+ virtual const string getText() const;
+
+ /** Returns the full text of the command, suitable for outputing
+ * to the tracer.
+ *
+ * @return trace text (eg. "LOGIN {username} {password}")
+ */
+ virtual const string getTraceText() const;
+
+protected:
+
+ IMAPCommand(const string& text, const string& traceText);
+ IMAPCommand(const IMAPCommand&);
+
+private:
+
+ string m_text;
+ string m_traceText;
+};
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+#endif // VMIME_NET_IMAP_IMAPCOMMAND_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/imap/IMAPConnection.cpp b/vmime-master/src/vmime/net/imap/IMAPConnection.cpp
new file mode 100644
index 0000000..df3da1c
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPConnection.cpp
@@ -0,0 +1,886 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/net/imap/IMAPTag.hpp"
+#include "vmime/net/imap/IMAPConnection.hpp"
+#include "vmime/net/imap/IMAPUtils.hpp"
+#include "vmime/net/imap/IMAPStore.hpp"
+#include "vmime/net/imap/IMAPCommand.hpp"
+
+#include "vmime/exception.hpp"
+#include "vmime/platform.hpp"
+
+#include "vmime/utility/stringUtils.hpp"
+
+#include "vmime/net/defaultConnectionInfos.hpp"
+
+#if VMIME_HAVE_SASL_SUPPORT
+ #include "vmime/security/sasl/SASLContext.hpp"
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+#if VMIME_HAVE_TLS_SUPPORT
+ #include "vmime/net/tls/TLSSession.hpp"
+ #include "vmime/net/tls/TLSSecuredConnectionInfos.hpp"
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+#include <sstream>
+
+
+// Helpers for service properties
+#define GET_PROPERTY(type, prop) \
+ (m_store.lock()->getInfos().getPropertyValue <type>(getSession(), \
+ dynamic_cast <const IMAPServiceInfos&>(m_store.lock()->getInfos()).getProperties().prop))
+#define HAS_PROPERTY(prop) \
+ (m_store.lock()->getInfos().hasProperty(getSession(), \
+ dynamic_cast <const IMAPServiceInfos&>(m_store.lock()->getInfos()).getProperties().prop))
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+IMAPConnection::IMAPConnection(
+ const shared_ptr <IMAPStore>& store,
+ const shared_ptr <security::authenticator>& auth
+)
+ : m_store(store),
+ m_auth(auth),
+ m_socket(null),
+ m_parser(null),
+ m_tag(null),
+ m_hierarchySeparator('\0'),
+ m_state(STATE_NONE),
+ m_timeoutHandler(null),
+ m_secured(false),
+ m_firstTag(true),
+ m_capabilitiesFetched(false),
+ m_noModSeq(false) {
+
+ static int connectionId = 0;
+
+ m_tag = make_shared <IMAPTag>();
+
+ if (store->getTracerFactory()) {
+ m_tracer = store->getTracerFactory()->create(store, ++connectionId);
+ }
+
+ m_parser = make_shared <IMAPParser>();
+ m_parser->setTracer(m_tracer);
+}
+
+
+IMAPConnection::~IMAPConnection() {
+
+ try {
+
+ if (isConnected()) {
+ disconnect();
+ } else if (m_socket) {
+ internalDisconnect();
+ }
+
+ } catch (...) {
+
+ // Don't throw in destructor
+ }
+}
+
+
+void IMAPConnection::connect() {
+
+ if (isConnected()) {
+ throw exceptions::already_connected();
+ }
+
+ m_state = STATE_NONE;
+ m_hierarchySeparator = '\0';
+
+ const string address = GET_PROPERTY(string, PROPERTY_SERVER_ADDRESS);
+ const port_t port = GET_PROPERTY(port_t, PROPERTY_SERVER_PORT);
+
+ shared_ptr <IMAPStore> store = m_store.lock();
+
+ // Create the time-out handler
+ if (store->getTimeoutHandlerFactory()) {
+ m_timeoutHandler = store->getTimeoutHandlerFactory()->create();
+ }
+
+ // Create and connect the socket
+ m_socket = store->getSocketFactory()->create(m_timeoutHandler);
+ m_socket->setTracer(m_tracer);
+
+#if VMIME_HAVE_TLS_SUPPORT
+ if (store->isIMAPS()) { // dedicated port/IMAPS
+
+ shared_ptr <tls::TLSSession> tlsSession = tls::TLSSession::create
+ (store->getCertificateVerifier(),
+ store->getSession()->getTLSProperties());
+
+ shared_ptr <tls::TLSSocket> tlsSocket =
+ tlsSession->getSocket(m_socket);
+
+ m_socket = tlsSocket;
+
+ m_secured = true;
+ m_cntInfos = make_shared <tls::TLSSecuredConnectionInfos>(address, port, tlsSession, tlsSocket);
+
+ } else
+#endif // VMIME_HAVE_TLS_SUPPORT
+ {
+ m_cntInfos = make_shared <defaultConnectionInfos>(address, port);
+ }
+
+ m_socket->connect(address, port);
+
+
+ m_parser->setSocket(m_socket);
+ m_parser->setTimeoutHandler(m_timeoutHandler);
+
+
+ setState(STATE_NON_AUTHENTICATED);
+
+
+ // Connection greeting
+ //
+ // eg: C: <connection to server>
+ // --- S: * OK mydomain.org IMAP4rev1 v12.256 server ready
+
+ scoped_ptr <IMAPParser::greeting> greet(m_parser->readGreeting());
+ bool needAuth = false;
+
+ if (greet->resp_cond_bye) {
+
+ internalDisconnect();
+ throw exceptions::connection_greeting_error(greet->getErrorLog());
+
+ } else if (greet->resp_cond_auth->condition != IMAPParser::resp_cond_auth::PREAUTH) {
+
+ needAuth = true;
+ }
+
+ if (greet->resp_cond_auth->resp_text->resp_text_code &&
+ greet->resp_cond_auth->resp_text->resp_text_code->capability_data) {
+
+ processCapabilityResponseData(greet->resp_cond_auth->resp_text->resp_text_code->capability_data.get());
+ }
+
+#if VMIME_HAVE_TLS_SUPPORT
+ // Setup secured connection, if requested
+ const bool tls = HAS_PROPERTY(PROPERTY_CONNECTION_TLS)
+ && GET_PROPERTY(bool, PROPERTY_CONNECTION_TLS);
+ const bool tlsRequired = HAS_PROPERTY(PROPERTY_CONNECTION_TLS_REQUIRED)
+ && GET_PROPERTY(bool, PROPERTY_CONNECTION_TLS_REQUIRED);
+
+ if (!store->isIMAPS() && tls) { // only if not IMAPS
+
+ try {
+
+ startTLS();
+
+ // Non-fatal error
+ } catch (exceptions::command_error&) {
+
+ if (tlsRequired) {
+ m_state = STATE_NONE;
+ throw;
+ } else {
+ // TLS is not required, so don't bother
+ }
+
+ // Fatal error
+ } catch (...) {
+
+ m_state = STATE_NONE;
+ throw;
+ }
+ }
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+ // Authentication
+ if (needAuth) {
+
+ try {
+
+ authenticate();
+
+ } catch (...) {
+
+ m_state = STATE_NONE;
+ throw;
+ }
+ }
+
+ // Get the hierarchy separator character
+ initHierarchySeparator();
+
+ // Switch to state "Authenticated"
+ setState(STATE_AUTHENTICATED);
+}
+
+
+void IMAPConnection::authenticate() {
+
+ getAuthenticator()->setService(m_store.lock());
+
+#if VMIME_HAVE_SASL_SUPPORT
+ // First, try SASL authentication
+ if (GET_PROPERTY(bool, PROPERTY_OPTIONS_SASL)) {
+
+ try {
+
+ authenticateSASL();
+ return;
+
+ } catch (exceptions::authentication_error&) {
+
+ if (!GET_PROPERTY(bool, PROPERTY_OPTIONS_SASL_FALLBACK)) {
+
+ // Can't fallback on normal authentication
+ internalDisconnect();
+ throw;
+
+ } else {
+
+ // Ignore, will try normal authentication
+ }
+
+ } catch (exception&) {
+
+ internalDisconnect();
+ throw;
+ }
+ }
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+ // Normal authentication
+ const string username = getAuthenticator()->getUsername();
+ const string password = getAuthenticator()->getPassword();
+
+ shared_ptr <IMAPConnection> conn = dynamicCast <IMAPConnection>(shared_from_this());
+ IMAPCommand::LOGIN(username, password)->send(conn);
+
+ scoped_ptr <IMAPParser::response> resp(m_parser->readResponse(*m_tag));
+
+ if (resp->isBad()) {
+
+ internalDisconnect();
+ throw exceptions::command_error("LOGIN", resp->getErrorLog());
+
+ } else if (resp->response_done->response_tagged->
+ resp_cond_state->status != IMAPParser::resp_cond_state::OK) {
+
+ internalDisconnect();
+ throw exceptions::authentication_error(resp->getErrorLog());
+ }
+
+ // Server capabilities may change when logged in
+ if (!processCapabilityResponseData(resp.get())) {
+ invalidateCapabilities();
+ }
+}
+
+
+#if VMIME_HAVE_SASL_SUPPORT
+
+void IMAPConnection::authenticateSASL() {
+
+ if (!dynamicCast <security::sasl::SASLAuthenticator>(getAuthenticator())) {
+ throw exceptions::authentication_error("No SASL authenticator available.");
+ }
+
+ const std::vector <string> capa = getCapabilities();
+ std::vector <string> saslMechs;
+
+ for (unsigned int i = 0 ; i < capa.size() ; ++i) {
+
+ const string& x = capa[i];
+
+ if (x.length() > 5 &&
+ (x[0] == 'A' || x[0] == 'a') &&
+ (x[1] == 'U' || x[1] == 'u') &&
+ (x[2] == 'T' || x[2] == 't') &&
+ (x[3] == 'H' || x[3] == 'h') &&
+ x[4] == '=') {
+
+ saslMechs.push_back(string(x.begin() + 5, x.end()));
+ }
+ }
+
+ if (saslMechs.empty()) {
+ throw exceptions::authentication_error("No SASL mechanism available.");
+ }
+
+ std::vector <shared_ptr <security::sasl::SASLMechanism> > mechList;
+
+ shared_ptr <security::sasl::SASLContext> saslContext =
+ security::sasl::SASLContext::create();
+
+ for (unsigned int i = 0 ; i < saslMechs.size() ; ++i) {
+
+ try {
+ mechList.push_back(saslContext->createMechanism(saslMechs[i]));
+ } catch (exceptions::no_such_mechanism&) {
+ // Ignore mechanism
+ }
+ }
+
+ if (mechList.empty()) {
+ throw exceptions::authentication_error("No SASL mechanism available.");
+ }
+
+ // Try to suggest a mechanism among all those supported
+ shared_ptr <security::sasl::SASLMechanism> suggestedMech =
+ saslContext->suggestMechanism(mechList);
+
+ if (!suggestedMech) {
+ throw exceptions::authentication_error("Unable to suggest SASL mechanism.");
+ }
+
+ // Allow application to choose which mechanisms to use
+ mechList = dynamicCast <security::sasl::SASLAuthenticator>(getAuthenticator())->
+ getAcceptableMechanisms(mechList, suggestedMech);
+
+ if (mechList.empty()) {
+ throw exceptions::authentication_error("No SASL mechanism available.");
+ }
+
+ // Try each mechanism in the list in turn
+ for (unsigned int i = 0 ; i < mechList.size() ; ++i) {
+
+ shared_ptr <security::sasl::SASLMechanism> mech = mechList[i];
+
+ shared_ptr <security::sasl::SASLSession> saslSession =
+ saslContext->createSession("imap", getAuthenticator(), mech);
+
+ saslSession->init();
+
+ shared_ptr <IMAPCommand> authCmd;
+
+ if (saslSession->getMechanism()->hasInitialResponse()) {
+
+ byte_t* initialResp = 0;
+ size_t initialRespLen = 0;
+
+ saslSession->evaluateChallenge(NULL, 0, &initialResp, &initialRespLen);
+
+ string encodedInitialResp(saslContext->encodeB64(initialResp, initialRespLen));
+ delete [] initialResp;
+
+ if (encodedInitialResp.empty()) {
+ authCmd = IMAPCommand::AUTHENTICATE(mech->getName(), "=");
+ } else {
+ authCmd = IMAPCommand::AUTHENTICATE(mech->getName(), encodedInitialResp);
+ }
+
+ } else {
+
+ authCmd = IMAPCommand::AUTHENTICATE(mech->getName());
+ }
+
+ authCmd->send(dynamicCast <IMAPConnection>(shared_from_this()));
+
+ for (bool cont = true ; cont ; ) {
+
+ scoped_ptr <IMAPParser::response> resp(m_parser->readResponse(*m_tag));
+
+ if (resp->response_done &&
+ resp->response_done->response_tagged &&
+ resp->response_done->response_tagged->resp_cond_state->
+ status == IMAPParser::resp_cond_state::OK) {
+
+ m_socket = saslSession->getSecuredSocket(m_socket);
+ return;
+
+ } else {
+
+ string response;
+ bool hasResponse = false;
+
+ for (auto &respData : resp->continue_req_or_response_data) {
+
+ if (respData->continue_req) {
+
+ response = respData->continue_req->resp_text->text;
+ hasResponse = true;
+ break;
+ }
+ }
+
+ if (!hasResponse) {
+ cont = false;
+ continue;
+ }
+
+ byte_t* challenge = 0;
+ size_t challengeLen = 0;
+
+ byte_t* resp = 0;
+ size_t respLen = 0;
+
+ try {
+
+ // Extract challenge
+ saslContext->decodeB64(response, &challenge, &challengeLen);
+
+ // Prepare response
+ saslSession->evaluateChallenge
+ (challenge, challengeLen, &resp, &respLen);
+
+ // Send response
+ const string respB64 = saslContext->encodeB64(resp, respLen) + "\r\n";
+ sendRaw(utility::stringUtils::bytesFromString(respB64), respB64.length());
+
+ if (m_tracer) {
+ m_tracer->traceSendBytes(respB64.length() - 2, "SASL exchange");
+ }
+
+ // Server capabilities may change when logged in
+ invalidateCapabilities();
+
+ } catch (exceptions::sasl_exception& e) {
+
+ if (challenge) {
+ delete [] challenge;
+ challenge = NULL;
+ }
+
+ if (resp) {
+ delete [] resp;
+ resp = NULL;
+ }
+
+ // Cancel SASL exchange
+ sendRaw(utility::stringUtils::bytesFromString("*\r\n"), 3);
+
+ if (m_tracer) {
+ m_tracer->traceSend("*");
+ }
+
+ } catch (...) {
+
+ if (challenge) {
+ delete [] challenge;
+ }
+
+ if (resp) {
+ delete [] resp;
+ }
+
+ throw;
+ }
+
+ if (challenge) {
+ delete [] challenge;
+ }
+
+ if (resp) {
+ delete [] resp;
+ }
+ }
+ }
+ }
+
+ throw exceptions::authentication_error("Could not authenticate using SASL: all mechanisms failed.");
+}
+
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+
+#if VMIME_HAVE_TLS_SUPPORT
+
+void IMAPConnection::startTLS() {
+
+ try {
+
+ IMAPCommand::STARTTLS()->send(dynamicCast <IMAPConnection>(shared_from_this()));
+
+ scoped_ptr <IMAPParser::response> resp(m_parser->readResponse(*m_tag));
+
+ if (resp->isBad() || resp->response_done->response_tagged->
+ resp_cond_state->status != IMAPParser::resp_cond_state::OK) {
+
+ throw exceptions::command_error("STARTTLS", resp->getErrorLog(), "bad response");
+ }
+
+ shared_ptr <tls::TLSSession> tlsSession = tls::TLSSession::create(
+ m_store.lock()->getCertificateVerifier(),
+ m_store.lock()->getSession()->getTLSProperties()
+ );
+
+ shared_ptr <tls::TLSSocket> tlsSocket = tlsSession->getSocket(m_socket);
+
+ tlsSocket->handshake();
+
+ m_socket = tlsSocket;
+ m_parser->setSocket(m_socket);
+
+ m_secured = true;
+ m_cntInfos = make_shared <tls::TLSSecuredConnectionInfos>(
+ m_cntInfos->getHost(), m_cntInfos->getPort(), tlsSession, tlsSocket
+ );
+
+ // " Once TLS has been started, the client MUST discard cached
+ // information about server capabilities and SHOULD re-issue the
+ // CAPABILITY command. This is necessary to protect against
+ // man-in-the-middle attacks which alter the capabilities list prior
+ // to STARTTLS. " (RFC-2595)
+ invalidateCapabilities();
+
+ } catch (exceptions::command_error&) {
+
+ // Non-fatal error
+ throw;
+
+ } catch (exception&) {
+
+ // Fatal error
+ internalDisconnect();
+ throw;
+ }
+}
+
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+
+const std::vector <string> IMAPConnection::getCapabilities() {
+
+ if (!m_capabilitiesFetched) {
+ fetchCapabilities();
+ }
+
+ return m_capabilities;
+}
+
+
+bool IMAPConnection::hasCapability(const string& capa) {
+
+ if (!m_capabilitiesFetched) {
+ fetchCapabilities();
+ }
+
+ const string normCapa = utility::stringUtils::toUpper(capa);
+
+ for (size_t i = 0, n = m_capabilities.size() ; i < n ; ++i) {
+
+ if (m_capabilities[i] == normCapa) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+bool IMAPConnection::hasCapability(const string& capa) const {
+
+ const string normCapa = utility::stringUtils::toUpper(capa);
+
+ for (size_t i = 0, n = m_capabilities.size() ; i < n ; ++i) {
+
+ if (m_capabilities[i] == normCapa)
+ return true;
+ }
+
+ return false;
+}
+
+
+void IMAPConnection::invalidateCapabilities() {
+
+ m_capabilities.clear();
+ m_capabilitiesFetched = false;
+}
+
+
+void IMAPConnection::fetchCapabilities() {
+
+ IMAPCommand::CAPABILITY()->send(dynamicCast <IMAPConnection>(shared_from_this()));
+
+ scoped_ptr <IMAPParser::response> resp(m_parser->readResponse(*m_tag));
+
+ if (resp->response_done->response_tagged->
+ resp_cond_state->status == IMAPParser::resp_cond_state::OK) {
+
+ processCapabilityResponseData(resp.get());
+ }
+}
+
+
+bool IMAPConnection::processCapabilityResponseData(const IMAPParser::response* resp) {
+
+ for (auto &respData : resp->continue_req_or_response_data) {
+
+ if (respData->response_data == NULL) {
+ continue;
+ }
+
+ auto &capaData = respData->response_data->capability_data;
+
+ if (!capaData) {
+ continue;
+ }
+
+ processCapabilityResponseData(capaData.get());
+ return true;
+ }
+
+ return false;
+}
+
+
+void IMAPConnection::processCapabilityResponseData(const IMAPParser::capability_data* capaData) {
+
+ std::vector <string> res;
+
+ for (auto &cap : capaData->capabilities) {
+
+ if (cap->auth_type) {
+ res.push_back("AUTH=" + cap->auth_type->name);
+ } else {
+ res.push_back(utility::stringUtils::toUpper(cap->atom->value));
+ }
+ }
+
+ m_capabilities = res;
+ m_capabilitiesFetched = true;
+}
+
+
+shared_ptr <security::authenticator> IMAPConnection::getAuthenticator() {
+
+ return m_auth;
+}
+
+
+bool IMAPConnection::isConnected() const {
+
+ return m_socket
+ && m_socket->isConnected()
+ && (m_state == STATE_AUTHENTICATED || m_state == STATE_SELECTED);
+}
+
+
+bool IMAPConnection::isSecuredConnection() const {
+
+ return m_secured;
+}
+
+
+shared_ptr <connectionInfos> IMAPConnection::getConnectionInfos() const {
+
+ return m_cntInfos;
+}
+
+
+void IMAPConnection::disconnect() {
+
+ if (!isConnected()) {
+ throw exceptions::not_connected();
+ }
+
+ internalDisconnect();
+}
+
+
+void IMAPConnection::internalDisconnect() {
+
+ if (isConnected()) {
+
+ IMAPCommand::LOGOUT()->send(dynamicCast <IMAPConnection>(shared_from_this()));
+
+ m_socket->disconnect();
+ m_socket = null;
+ }
+
+ m_timeoutHandler = null;
+
+ m_state = STATE_LOGOUT;
+
+ m_secured = false;
+ m_cntInfos = null;
+}
+
+
+void IMAPConnection::initHierarchySeparator() {
+
+ IMAPCommand::LIST("", "")->send(dynamicCast <IMAPConnection>(shared_from_this()));
+
+ scoped_ptr <IMAPParser::response> resp(m_parser->readResponse(*m_tag));
+
+ if (resp->isBad() || resp->response_done->response_tagged->
+ resp_cond_state->status != IMAPParser::resp_cond_state::OK) {
+
+ internalDisconnect();
+ throw exceptions::command_error("LIST", resp->getErrorLog(), "bad response");
+ }
+
+ const auto& respDataList = resp->continue_req_or_response_data;
+
+ bool found = false;
+
+ for (unsigned int i = 0 ; !found && i < respDataList.size() ; ++i) {
+
+ if (!respDataList[i]->response_data) {
+ continue;
+ }
+
+ auto &mailboxData = respDataList[i]->response_data->mailbox_data;
+
+ if (!mailboxData || mailboxData->type != IMAPParser::mailbox_data::LIST) {
+ continue;
+ }
+
+ if (mailboxData->mailbox_list->quoted_char != '\0') {
+ m_hierarchySeparator = mailboxData->mailbox_list->quoted_char;
+ found = true;
+ }
+ }
+
+ if (!found) { // default
+ m_hierarchySeparator = '/';
+ }
+}
+
+
+void IMAPConnection::sendCommand(const shared_ptr <IMAPCommand>& cmd) {
+
+ if (!m_firstTag) {
+ ++(*m_tag);
+ }
+
+ m_socket->send(*m_tag);
+ m_socket->send(" ");
+ m_socket->send(cmd->getText());
+ m_socket->send("\r\n");
+
+ m_firstTag = false;
+
+ if (m_tracer) {
+
+ std::ostringstream oss;
+ oss << string(*m_tag) << " " << cmd->getText();
+
+ m_tracer->traceSend(oss.str());
+ }
+}
+
+
+void IMAPConnection::sendRaw(const byte_t* buffer, const size_t count) {
+
+ m_socket->sendRaw(buffer, count);
+}
+
+
+IMAPParser::response* IMAPConnection::readResponse(IMAPParser::literalHandler* lh) {
+
+ return m_parser->readResponse(*m_tag, lh);
+}
+
+
+IMAPConnection::ProtocolStates IMAPConnection::state() const {
+
+ return m_state;
+}
+
+
+void IMAPConnection::setState(const ProtocolStates state) {
+
+ m_state = state;
+}
+
+
+char IMAPConnection::hierarchySeparator() const {
+
+ return m_hierarchySeparator;
+}
+
+
+shared_ptr <const IMAPStore> IMAPConnection::getStore() const {
+
+ return m_store.lock();
+}
+
+
+shared_ptr <IMAPStore> IMAPConnection::getStore() {
+
+ return m_store.lock();
+}
+
+
+shared_ptr <session> IMAPConnection::getSession() {
+
+ return m_store.lock()->getSession();
+}
+
+
+shared_ptr <const socket> IMAPConnection::getSocket() const {
+
+ return m_socket;
+}
+
+
+void IMAPConnection::setSocket(const shared_ptr <socket>& sok) {
+
+ m_socket = sok;
+ m_parser->setSocket(sok);
+}
+
+
+shared_ptr <tracer> IMAPConnection::getTracer() {
+
+ return m_tracer;
+}
+
+
+shared_ptr <IMAPTag> IMAPConnection::getTag() {
+
+ return m_tag;
+}
+
+
+bool IMAPConnection::isMODSEQDisabled() const {
+
+ return m_noModSeq;
+}
+
+
+void IMAPConnection::disableMODSEQ() {
+
+ m_noModSeq = true;
+}
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
diff --git a/vmime-master/src/vmime/net/imap/IMAPConnection.hpp b/vmime-master/src/vmime/net/imap/IMAPConnection.hpp
new file mode 100644
index 0000000..99750d4
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPConnection.hpp
@@ -0,0 +1,172 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_IMAP_IMAPCONNECTION_HPP_INCLUDED
+#define VMIME_NET_IMAP_IMAPCONNECTION_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/net/socket.hpp"
+#include "vmime/net/timeoutHandler.hpp"
+#include "vmime/net/tracer.hpp"
+#include "vmime/net/session.hpp"
+#include "vmime/net/connectionInfos.hpp"
+
+#include "vmime/net/imap/IMAPParser.hpp"
+
+#include "vmime/security/authenticator.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+class IMAPTag;
+class IMAPStore;
+class IMAPCommand;
+
+
+class VMIME_EXPORT IMAPConnection : public object, public enable_shared_from_this <IMAPConnection> {
+
+public:
+
+ IMAPConnection(const shared_ptr <IMAPStore>& store, const shared_ptr <security::authenticator>& auth);
+ ~IMAPConnection();
+
+
+ void connect();
+ bool isConnected() const;
+ void disconnect();
+
+
+ enum ProtocolStates {
+ STATE_NONE,
+ STATE_NON_AUTHENTICATED,
+ STATE_AUTHENTICATED,
+ STATE_SELECTED,
+ STATE_LOGOUT
+ };
+
+ ProtocolStates state() const;
+ void setState(const ProtocolStates state);
+
+
+ char hierarchySeparator() const;
+
+
+ void sendCommand(const shared_ptr <IMAPCommand>& cmd);
+ void sendRaw(const byte_t* buffer, const size_t count);
+
+ IMAPParser::response* readResponse(IMAPParser::literalHandler* lh = NULL);
+
+
+ shared_ptr <const IMAPStore> getStore() const;
+ shared_ptr <IMAPStore> getStore();
+
+ shared_ptr <session> getSession();
+
+ void fetchCapabilities();
+ void invalidateCapabilities();
+ const std::vector <string> getCapabilities();
+ bool hasCapability(const string& capa);
+ bool hasCapability(const string& capa) const;
+
+ shared_ptr <security::authenticator> getAuthenticator();
+
+ bool isSecuredConnection() const;
+ shared_ptr <connectionInfos> getConnectionInfos() const;
+
+ shared_ptr <const socket> getSocket() const;
+ void setSocket(const shared_ptr <socket>& sok);
+
+ shared_ptr <tracer> getTracer();
+
+ shared_ptr <IMAPTag> getTag();
+
+ bool isMODSEQDisabled() const;
+ void disableMODSEQ();
+
+private:
+
+ void authenticate();
+#if VMIME_HAVE_SASL_SUPPORT
+ void authenticateSASL();
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+#if VMIME_HAVE_TLS_SUPPORT
+ void startTLS();
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+ bool processCapabilityResponseData(const IMAPParser::response* resp);
+ void processCapabilityResponseData(const IMAPParser::capability_data* capaData);
+
+
+ weak_ptr <IMAPStore> m_store;
+
+ shared_ptr <security::authenticator> m_auth;
+
+ shared_ptr <socket> m_socket;
+
+ shared_ptr <IMAPParser> m_parser;
+
+ shared_ptr <IMAPTag> m_tag;
+
+ char m_hierarchySeparator;
+
+ ProtocolStates m_state;
+
+ shared_ptr <timeoutHandler> m_timeoutHandler;
+
+ bool m_secured;
+ shared_ptr <connectionInfos> m_cntInfos;
+
+ bool m_firstTag;
+
+ std::vector <string> m_capabilities;
+ bool m_capabilitiesFetched;
+
+ bool m_noModSeq;
+
+ shared_ptr <tracer> m_tracer;
+
+
+ void internalDisconnect();
+
+ void initHierarchySeparator();
+};
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+#endif // VMIME_NET_IMAP_IMAPCONNECTION_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/imap/IMAPFolder.cpp b/vmime-master/src/vmime/net/imap/IMAPFolder.cpp
new file mode 100644
index 0000000..98bc05d
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPFolder.cpp
@@ -0,0 +1,1622 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/net/imap/IMAPFolder.hpp"
+
+#include "vmime/net/imap/IMAPStore.hpp"
+#include "vmime/net/imap/IMAPParser.hpp"
+#include "vmime/net/imap/IMAPMessage.hpp"
+#include "vmime/net/imap/IMAPUtils.hpp"
+#include "vmime/net/imap/IMAPConnection.hpp"
+#include "vmime/net/imap/IMAPFolderStatus.hpp"
+#include "vmime/net/imap/IMAPCommand.hpp"
+
+#include "vmime/message.hpp"
+
+#include "vmime/exception.hpp"
+
+#include "vmime/utility/outputStreamAdapter.hpp"
+
+#include <algorithm>
+#include <sstream>
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+IMAPFolder::IMAPFolder(
+ const folder::path& path,
+ const shared_ptr <IMAPStore>& store,
+ const shared_ptr <folderAttributes>& attribs
+)
+ : m_store(store),
+ m_connection(store->connection()),
+ m_path(path),
+ m_name(path.isEmpty() ? folder::path::component("") : path.getLastComponent()),
+ m_mode(-1),
+ m_open(false),
+ m_attribs(attribs) {
+
+ store->registerFolder(this);
+
+ m_status = make_shared <IMAPFolderStatus>();
+}
+
+
+IMAPFolder::~IMAPFolder() {
+
+ try {
+
+ shared_ptr <IMAPStore> store = m_store.lock();
+
+ if (store) {
+
+ if (m_open) {
+ close(false);
+ }
+
+ store->unregisterFolder(this);
+
+ } else if (m_open) {
+
+ m_connection = null;
+ onClose();
+ }
+
+ } catch (...) {
+
+ // Don't throw in destructor
+ }
+}
+
+
+int IMAPFolder::getMode() const {
+
+ if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ }
+
+ return m_mode;
+}
+
+
+const folderAttributes IMAPFolder::getAttributes() {
+
+ // Root folder
+ if (m_path.isEmpty()) {
+
+ folderAttributes attribs;
+ attribs.setType(folderAttributes::TYPE_CONTAINS_FOLDERS);
+ attribs.setFlags(folderAttributes::FLAG_HAS_CHILDREN | folderAttributes::FLAG_NO_OPEN);
+
+ return attribs;
+
+ } else {
+
+ if (!m_attribs) {
+ testExistAndGetType();
+ }
+
+ return *m_attribs;
+ }
+}
+
+
+const folder::path::component IMAPFolder::getName() const {
+
+ return m_name;
+}
+
+
+const folder::path IMAPFolder::getFullPath() const {
+
+ return m_path;
+}
+
+
+void IMAPFolder::open(const int mode, bool failIfModeIsNotAvailable) {
+
+ shared_ptr <IMAPStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ }
+
+ // Ensure this folder is not already open in the same session
+ for (std::list <IMAPFolder*>::iterator it = store->m_folders.begin() ;
+ it != store->m_folders.end() ; ++it) {
+
+ if ((*it) != this && (*it)->getFullPath() == m_path) {
+ throw exceptions::folder_already_open();
+ }
+ }
+
+ // Open a connection for this folder
+ shared_ptr <IMAPConnection> connection =
+ make_shared <IMAPConnection>(store, store->getAuthenticator());
+
+ try {
+
+ connection->connect();
+
+ // Emit the "SELECT" command
+ //
+ // Example: C: A142 SELECT INBOX
+ // S: * 172 EXISTS
+ // S: * 1 RECENT
+ // S: * OK [UNSEEN 12] Message 12 is first unseen
+ // S: * OK [UIDVALIDITY 3857529045] UIDs valid
+ // S: * FLAGS (\Answered \Flagged \Deleted \Seen \Draft)
+ // S: * OK [PERMANENTFLAGS (\Deleted \Seen \*)] Limited
+ // S: A142 OK [READ-WRITE] SELECT completed
+
+ std::vector <string> selectParams;
+
+ if (m_connection->hasCapability("CONDSTORE")) {
+ selectParams.push_back("CONDSTORE");
+ }
+
+ IMAPCommand::SELECT(
+ mode == MODE_READ_ONLY,
+ IMAPUtils::pathToString(connection->hierarchySeparator(), getFullPath()),
+ selectParams
+ )->send(connection);
+
+ // Read the response
+ scoped_ptr <IMAPParser::response> resp(connection->readResponse());
+
+ if (resp->isBad() || resp->response_done->response_tagged->
+ resp_cond_state->status != IMAPParser::resp_cond_state::OK) {
+
+ throw exceptions::command_error("SELECT", resp->getErrorLog(), "bad response");
+ }
+
+ auto &respDataList = resp->continue_req_or_response_data;
+
+ for (auto it = respDataList.begin() ; it != respDataList.end() ; ++it) {
+
+ auto *responseData = (*it)->response_data.get();
+
+ if (!responseData) {
+ throw exceptions::command_error("SELECT", resp->getErrorLog(), "invalid response");
+ }
+
+ // OK Untagged responses: UNSEEN, PERMANENTFLAGS, UIDVALIDITY (optional)
+ if (responseData->resp_cond_state) {
+
+ auto *code = responseData->resp_cond_state->resp_text->resp_text_code.get();
+
+ if (code) {
+
+ switch (code->type) {
+
+ case IMAPParser::resp_text_code::NOMODSEQ:
+
+ connection->disableMODSEQ();
+ break;
+
+ default:
+
+ break;
+ }
+ }
+
+ // Untagged responses: FLAGS, EXISTS, RECENT (required)
+ } else if (responseData->mailbox_data) {
+
+ switch (responseData->mailbox_data->type) {
+
+ default: break;
+
+ case IMAPParser::mailbox_data::FLAGS: {
+
+ if (!m_attribs) {
+ m_attribs = make_shared <folderAttributes>();
+ }
+
+ IMAPUtils::mailboxFlagsToFolderAttributes(
+ connection,
+ m_path,
+ *responseData->mailbox_data->mailbox_flag_list,
+ *m_attribs
+ );
+
+ break;
+ }
+ }
+ }
+ }
+
+ processStatusUpdate(resp.get());
+
+ // Check for access mode (read-only or read-write)
+ auto *respTextCode = resp->response_done->response_tagged->resp_cond_state->resp_text->resp_text_code.get();
+
+ if (respTextCode) {
+
+ const int openMode =
+ (respTextCode->type == IMAPParser::resp_text_code::READ_WRITE)
+ ? MODE_READ_WRITE
+ : MODE_READ_ONLY;
+
+ if (failIfModeIsNotAvailable &&
+ mode == MODE_READ_WRITE && openMode == MODE_READ_ONLY) {
+
+ throw exceptions::operation_not_supported();
+ }
+ }
+
+ m_connection = connection;
+ m_open = true;
+ m_mode = mode;
+
+ } catch (std::exception&) {
+
+ throw;
+ }
+}
+
+
+void IMAPFolder::close(const bool expunge) {
+
+ shared_ptr <IMAPStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ }
+
+ if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ }
+
+ shared_ptr <IMAPConnection> oldConnection = m_connection;
+
+ // Emit the "CLOSE" command to expunge messages marked
+ // as deleted (this is fastest than "EXPUNGE")
+ if (expunge) {
+
+ if (m_mode == MODE_READ_ONLY) {
+ throw exceptions::operation_not_supported();
+ }
+
+ IMAPCommand::CLOSE()->send(oldConnection);
+ }
+
+ // Close this folder connection
+ oldConnection->disconnect();
+
+ // Now use default store connection
+ m_connection = m_store.lock()->connection();
+
+ m_open = false;
+ m_mode = -1;
+
+ m_status = make_shared <IMAPFolderStatus>();
+
+ onClose();
+}
+
+
+void IMAPFolder::onClose() {
+
+ for (std::vector <IMAPMessage*>::iterator it = m_messages.begin() ;
+ it != m_messages.end() ; ++it) {
+
+ (*it)->onFolderClosed();
+ }
+
+ m_messages.clear();
+}
+
+
+void IMAPFolder::create(const folderAttributes& attribs) {
+
+ shared_ptr <IMAPStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ } else if (isOpen()) {
+ throw exceptions::illegal_state("Folder is open");
+ } else if (exists()) {
+ throw exceptions::illegal_state("Folder already exists");
+ } else if (!store->isValidFolderName(m_name)) {
+ throw exceptions::invalid_folder_name();
+ }
+
+ // Emit the "CREATE" command
+ //
+ // Example: C: A003 CREATE owatagusiam/
+ // S: A003 OK CREATE completed
+ // C: A004 CREATE owatagusiam/blurdybloop
+ // S: A004 OK CREATE completed
+
+ string mailbox = IMAPUtils::pathToString
+ (m_connection->hierarchySeparator(), getFullPath());
+
+ if (attribs.getType() & folderAttributes::TYPE_CONTAINS_FOLDERS) {
+ mailbox += m_connection->hierarchySeparator();
+ }
+
+ std::vector <string> createParams;
+
+ if (attribs.getSpecialUse() != folderAttributes::SPECIALUSE_NONE) {
+
+ if (!m_connection->hasCapability("CREATE-SPECIAL-USE")) {
+ throw exceptions::operation_not_supported();
+ }
+
+ // C: t2 CREATE MySpecial (USE (\Drafts \Sent))
+ std::ostringstream oss;
+ oss << "USE (";
+
+ switch (attribs.getSpecialUse()) {
+
+ case folderAttributes::SPECIALUSE_NONE: // should not happen
+ case folderAttributes::SPECIALUSE_ALL: oss << "\\All"; break;
+ case folderAttributes::SPECIALUSE_ARCHIVE: oss << "\\Archive"; break;
+ case folderAttributes::SPECIALUSE_DRAFTS: oss << "\\Drafts"; break;
+ case folderAttributes::SPECIALUSE_FLAGGED: oss << "\\Flagged"; break;
+ case folderAttributes::SPECIALUSE_JUNK: oss << "\\Junk"; break;
+ case folderAttributes::SPECIALUSE_SENT: oss << "\\Sent"; break;
+ case folderAttributes::SPECIALUSE_TRASH: oss << "\\Trash"; break;
+ case folderAttributes::SPECIALUSE_IMPORTANT: oss << "\\Important"; break;
+ }
+
+ oss << ")";
+
+ createParams.push_back(oss.str());
+ }
+
+ IMAPCommand::CREATE(mailbox, createParams)->send(m_connection);
+
+
+ scoped_ptr <IMAPParser::response> resp(m_connection->readResponse());
+
+ if (resp->isBad() || resp->response_done->response_tagged->
+ resp_cond_state->status != IMAPParser::resp_cond_state::OK) {
+
+ throw exceptions::command_error("CREATE", resp->getErrorLog(), "bad response");
+ }
+
+ // Notify folder created
+ shared_ptr <events::folderEvent> event =
+ make_shared <events::folderEvent>(
+ dynamicCast <folder>(shared_from_this()),
+ events::folderEvent::TYPE_CREATED,
+ m_path, m_path
+ );
+
+ notifyFolder(event);
+}
+
+
+void IMAPFolder::destroy() {
+
+ shared_ptr <IMAPStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ }
+
+ if (isOpen()) {
+ throw exceptions::illegal_state("Folder is open");
+ }
+
+ const string mailbox = IMAPUtils::pathToString(
+ m_connection->hierarchySeparator(), getFullPath()
+ );
+
+ IMAPCommand::DELETE(mailbox)->send(m_connection);
+
+
+ scoped_ptr <IMAPParser::response> resp(m_connection->readResponse());
+
+ if (resp->isBad() || resp->response_done->response_tagged->
+ resp_cond_state->status != IMAPParser::resp_cond_state::OK) {
+
+ throw exceptions::command_error("DELETE", resp->getErrorLog(), "bad response");
+ }
+
+ // Notify folder deleted
+ shared_ptr <events::folderEvent> event =
+ make_shared <events::folderEvent>(
+ dynamicCast <folder>(shared_from_this()),
+ events::folderEvent::TYPE_DELETED,
+ m_path, m_path
+ );
+
+ notifyFolder(event);
+}
+
+
+bool IMAPFolder::exists() {
+
+ shared_ptr <IMAPStore> store = m_store.lock();
+
+ if (!isOpen() && !store) {
+ throw exceptions::illegal_state("Store disconnected");
+ }
+
+ return testExistAndGetType() != -1;
+}
+
+
+int IMAPFolder::testExistAndGetType() {
+
+ // To test whether a folder exists, we simple list it using
+ // the "LIST" command, and there should be one unique mailbox
+ // with this name...
+ //
+ // Eg. Test whether '/foo/bar' exists
+ //
+ // C: a005 list "" foo/bar
+ // S: * LIST (\NoSelect) "/" foo/bar
+ // S: a005 OK LIST completed
+ //
+ // ==> OK, exists
+ //
+ // Test whether '/foo/bar/zap' exists
+ //
+ // C: a005 list "" foo/bar/zap
+ // S: a005 OK LIST completed
+ //
+ // ==> NO, does not exist
+
+ IMAPCommand::LIST(
+ "",
+ IMAPUtils::pathToString(
+ m_connection->hierarchySeparator(),
+ getFullPath()
+ )
+ )->send(m_connection);
+
+
+ scoped_ptr <IMAPParser::response> resp(m_connection->readResponse());
+
+ if (resp->isBad() || resp->response_done->response_tagged->
+ resp_cond_state->status != IMAPParser::resp_cond_state::OK) {
+
+ throw exceptions::command_error("LIST", resp->getErrorLog(), "bad response");
+ }
+
+ // Check whether the result mailbox list contains this folder
+ auto& respDataList = resp->continue_req_or_response_data;
+
+ folderAttributes attribs;
+ attribs.setType(-1);
+
+ for (auto it = respDataList.begin() ; it != respDataList.end() ; ++it) {
+
+ if (!(*it)->response_data) {
+ throw exceptions::command_error("LIST", resp->getErrorLog(), "invalid response");
+ }
+
+ auto *mailboxData = (*it)->response_data->mailbox_data.get();
+
+ // We are only interested in responses of type "LIST"
+ if (mailboxData &&
+ mailboxData->type == IMAPParser::mailbox_data::LIST) {
+
+ // Get the folder type/flags at the same time
+ IMAPUtils::mailboxFlagsToFolderAttributes(
+ m_connection,
+ m_path,
+ *mailboxData->mailbox_list->mailbox_flag_list,
+ attribs
+ );
+ }
+ }
+
+ m_attribs = make_shared <folderAttributes>(attribs);
+
+ return m_attribs->getType();
+}
+
+
+bool IMAPFolder::isOpen() const {
+
+ return m_open;
+}
+
+
+shared_ptr <message> IMAPFolder::getMessage(const size_t num) {
+
+ if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ }
+
+ if (num < 1 || num > m_status->getMessageCount()) {
+ throw exceptions::message_not_found();
+ }
+
+ return make_shared <IMAPMessage>(dynamicCast <IMAPFolder>(shared_from_this()), num);
+}
+
+
+std::vector <shared_ptr <message> > IMAPFolder::getMessages(const messageSet& msgs) {
+
+ if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ }
+
+ if (msgs.isEmpty()) {
+ return std::vector <shared_ptr <message> >();
+ }
+
+ std::vector <shared_ptr <message> > messages;
+
+ // Sequence number message set:
+ // C: . FETCH uuuu1,uuuu2,uuuu3 UID
+ // S: * nnnn1 FETCH (UID uuuu1)
+ // S: * nnnn2 FETCH (UID uuuu2)
+ // S: * nnnn3 FETCH (UID uuuu3)
+ // S: . OK FETCH completed
+
+ // UID message set:
+ // C: . UID FETCH uuuu1,uuuu2,uuuu3 UID
+ // S: * nnnn1 FETCH (UID uuuu1)
+ // S: * nnnn2 FETCH (UID uuuu2)
+ // S: * nnnn3 FETCH (UID uuuu3)
+ // S: . OK UID FETCH completed
+
+ std::vector <string> params;
+ params.push_back("UID");
+
+ IMAPCommand::FETCH(msgs, params)->send(m_connection);
+
+ // Get the response
+ scoped_ptr <IMAPParser::response> resp(m_connection->readResponse());
+
+ if (resp->isBad() || resp->response_done->response_tagged->
+ resp_cond_state->status != IMAPParser::resp_cond_state::OK) {
+
+ throw exceptions::command_error("UID FETCH ... UID", resp->getErrorLog(), "bad response");
+ }
+
+ // Process the response
+ auto &respDataList = resp->continue_req_or_response_data;
+
+ for (auto it = respDataList.begin() ; it != respDataList.end() ; ++it) {
+
+ if (!(*it)->response_data) {
+ throw exceptions::command_error("UID FETCH ... UID", resp->getErrorLog(), "invalid response");
+ }
+
+ auto *messageData = (*it)->response_data->message_data.get();
+
+ // We are only interested in responses of type "FETCH"
+ if (!messageData || messageData->type != IMAPParser::message_data::FETCH) {
+ continue;
+ }
+
+ // Find UID in message attributes
+ const size_t msgNum = messageData->number;
+ message::uid msgUID;
+
+ for (auto &att : messageData->msg_att->items) {
+
+ if (att->type == IMAPParser::msg_att_item::UID) {
+ msgUID = att->uniqueid->value;
+ break;
+ }
+ }
+
+ if (!msgUID.empty()) {
+ shared_ptr <IMAPFolder> thisFolder = dynamicCast <IMAPFolder>(shared_from_this());
+ messages.push_back(make_shared <IMAPMessage>(thisFolder, msgNum, msgUID));
+ }
+ }
+
+ return messages;
+}
+
+
+size_t IMAPFolder::getMessageCount() {
+
+ if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ }
+
+ return m_status->getMessageCount();
+}
+
+
+vmime_uint32 IMAPFolder::getUIDValidity() const {
+
+ if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ }
+
+ return m_status->getUIDValidity();
+}
+
+
+vmime_uint64 IMAPFolder::getHighestModSequence() const {
+
+ if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ }
+
+ return m_status->getHighestModSeq();
+}
+
+
+shared_ptr <folder> IMAPFolder::getFolder(const folder::path::component& name) {
+
+ shared_ptr <IMAPStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ }
+
+ return make_shared <IMAPFolder>(m_path / name, store, shared_ptr <folderAttributes>());
+}
+
+
+std::vector <shared_ptr <folder> > IMAPFolder::getFolders(const bool recursive) {
+
+ shared_ptr <IMAPStore> store = m_store.lock();
+
+ if (!isOpen() && !store) {
+ throw exceptions::illegal_state("Store disconnected");
+ }
+
+ // Eg. List folders in '/foo/bar'
+ //
+ // C: a005 list "foo/bar" *
+ // S: * LIST (\NoSelect) "/" foo/bar
+ // S: * LIST (\NoInferiors) "/" foo/bar/zap
+ // S: a005 OK LIST completed
+
+ shared_ptr <IMAPCommand> cmd;
+
+ const string pathString = IMAPUtils::pathToString(
+ m_connection->hierarchySeparator(), getFullPath()
+ );
+
+ if (recursive) {
+
+ cmd = IMAPCommand::LIST(pathString, "*");
+
+ } else {
+
+ cmd = IMAPCommand::LIST(
+ pathString.empty()
+ ? ""
+ : (pathString + m_connection->hierarchySeparator()),
+ "%"
+ );
+ }
+
+ cmd->send(m_connection);
+
+
+ scoped_ptr <IMAPParser::response> resp(m_connection->readResponse());
+
+ if (resp->isBad() || resp->response_done->response_tagged->
+ resp_cond_state->status != IMAPParser::resp_cond_state::OK) {
+
+ throw exceptions::command_error("LIST", resp->getErrorLog(), "bad response");
+ }
+
+ auto &respDataList = resp->continue_req_or_response_data;
+
+ std::vector <shared_ptr <folder> > v;
+
+ for (auto it = respDataList.begin() ; it != respDataList.end() ; ++it) {
+
+ if (!(*it)->response_data) {
+ throw exceptions::command_error("LIST", resp->getErrorLog(), "invalid response");
+ }
+
+ auto *mailboxData = (*it)->response_data->mailbox_data.get();
+
+ if (!mailboxData || mailboxData->type != IMAPParser::mailbox_data::LIST) {
+ continue;
+ }
+
+ // Get folder path
+ auto &mailbox = mailboxData->mailbox_list->mailbox;
+
+ folder::path path = IMAPUtils::stringToPath(
+ mailboxData->mailbox_list->quoted_char, mailbox->name
+ );
+
+ if (recursive || m_path.isDirectParentOf(path)) {
+
+ // Append folder to list
+ shared_ptr <folderAttributes> attribs = make_shared <folderAttributes>();
+
+ IMAPUtils::mailboxFlagsToFolderAttributes(
+ m_connection,
+ path,
+ *mailboxData->mailbox_list->mailbox_flag_list,
+ *attribs
+ );
+
+ v.push_back(make_shared <IMAPFolder>(path, store, attribs));
+ }
+ }
+
+ return v;
+}
+
+
+void IMAPFolder::fetchMessages(
+ std::vector <shared_ptr <message> >& msg,
+ const fetchAttributes& options,
+ utility::progressListener* progress
+) {
+
+ shared_ptr <IMAPStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ } else if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ }
+
+ if (msg.empty()) {
+ return;
+ }
+
+ // Build message numbers list
+ std::vector <size_t> list;
+ list.reserve(msg.size());
+
+ std::map <size_t, shared_ptr <IMAPMessage> > numberToMsg;
+
+ for (std::vector <shared_ptr <message> >::iterator it = msg.begin() ; it != msg.end() ; ++it) {
+
+ list.push_back((*it)->getNumber());
+ numberToMsg[(*it)->getNumber()] = dynamicCast <IMAPMessage>(*it);
+ }
+
+ // Send the request
+ IMAPUtils::buildFetchCommand(
+ m_connection, messageSet::byNumber(list), options
+ )->send(m_connection);
+
+ // Get the response
+ scoped_ptr <IMAPParser::response> resp(m_connection->readResponse());
+
+ if (resp->isBad() || resp->response_done->response_tagged->
+ resp_cond_state->status != IMAPParser::resp_cond_state::OK) {
+
+ throw exceptions::command_error("FETCH", resp->getErrorLog(), "bad response");
+ }
+
+ auto &respDataList = resp->continue_req_or_response_data;
+
+ const size_t total = msg.size();
+ size_t current = 0;
+
+ if (progress) {
+ progress->start(total);
+ }
+
+ try {
+
+ for (auto it = respDataList.begin() ; it != respDataList.end() ; ++it) {
+
+ if (!(*it)->response_data) {
+ throw exceptions::command_error("FETCH", resp->getErrorLog(), "invalid response");
+ }
+
+ auto *messageData = (*it)->response_data->message_data.get();
+
+ // We are only interested in responses of type "FETCH"
+ if (!messageData || messageData->type != IMAPParser::message_data::FETCH) {
+ continue;
+ }
+
+ // Process fetch response for this message
+ const size_t num = messageData->number;
+
+ std::map <size_t, shared_ptr <IMAPMessage> >::iterator msg = numberToMsg.find(num);
+
+ if (msg != numberToMsg.end()) {
+
+ (*msg).second->processFetchResponse(options, *messageData);
+
+ if (progress) {
+ progress->progress(++current, total);
+ }
+ }
+ }
+
+ } catch (...) {
+
+ if (progress) {
+ progress->stop(total);
+ }
+
+ throw;
+ }
+
+ if (progress) {
+ progress->stop(total);
+ }
+
+ processStatusUpdate(resp.get());
+}
+
+
+void IMAPFolder::fetchMessage(const shared_ptr <message>& msg, const fetchAttributes& options) {
+
+ std::vector <shared_ptr <message> > msgs;
+ msgs.push_back(msg);
+
+ fetchMessages(msgs, options, /* progress */ NULL);
+}
+
+
+std::vector <shared_ptr <message> > IMAPFolder::getAndFetchMessages(
+ const messageSet& msgs,
+ const fetchAttributes& attribs
+) {
+
+ shared_ptr <IMAPStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ } else if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ }
+
+ if (msgs.isEmpty()) {
+ return std::vector <shared_ptr <message> >();
+ }
+
+ // Ensure we also get the UID for each message
+ fetchAttributes attribsWithUID(attribs);
+ attribsWithUID.add(fetchAttributes::UID);
+
+ // Send the request
+ IMAPUtils::buildFetchCommand(m_connection, msgs, attribsWithUID)->send(m_connection);
+
+ // Get the response
+ scoped_ptr <IMAPParser::response> resp(m_connection->readResponse());
+
+ if (resp->isBad() || resp->response_done->response_tagged->
+ resp_cond_state->status != IMAPParser::resp_cond_state::OK) {
+
+ throw exceptions::command_error("FETCH", resp->getErrorLog(), "bad response");
+ }
+
+ auto &respDataList = resp->continue_req_or_response_data;
+
+ std::vector <shared_ptr <message> > messages;
+
+ for (auto it = respDataList.begin() ; it != respDataList.end() ; ++it) {
+
+ if (!(*it)->response_data) {
+ throw exceptions::command_error("FETCH", resp->getErrorLog(), "invalid response");
+ }
+
+ auto *messageData = (*it)->response_data->message_data.get();
+
+ // We are only interested in responses of type "FETCH"
+ if (!messageData || messageData->type != IMAPParser::message_data::FETCH) {
+ continue;
+ }
+
+ // Get message number
+ const size_t msgNum = messageData->number;
+
+ // Get message UID
+ message::uid msgUID;
+
+ for (auto &att : messageData->msg_att->items) {
+
+ if (att->type == IMAPParser::msg_att_item::UID) {
+ msgUID = att->uniqueid->value;
+ break;
+ }
+ }
+
+ // Create a new message reference
+ shared_ptr <IMAPFolder> thisFolder = dynamicCast <IMAPFolder>(shared_from_this());
+ shared_ptr <IMAPMessage> msg = make_shared <IMAPMessage>(thisFolder, msgNum, msgUID);
+
+ messages.push_back(msg);
+
+ // Process fetch response for this message
+ msg->processFetchResponse(attribsWithUID, *messageData);
+ }
+
+ processStatusUpdate(resp.get());
+
+ return messages;
+}
+
+
+int IMAPFolder::getFetchCapabilities() const {
+
+ return fetchAttributes::ENVELOPE | fetchAttributes::CONTENT_INFO |
+ fetchAttributes::STRUCTURE | fetchAttributes::FLAGS |
+ fetchAttributes::SIZE | fetchAttributes::FULL_HEADER |
+ fetchAttributes::UID | fetchAttributes::IMPORTANCE;
+}
+
+
+shared_ptr <folder> IMAPFolder::getParent() {
+
+ if (m_path.isEmpty()) {
+
+ return null;
+
+ } else {
+
+ return make_shared <IMAPFolder>(
+ m_path.getParent(), m_store.lock(), shared_ptr <folderAttributes>()
+ );
+ }
+}
+
+
+shared_ptr <const store> IMAPFolder::getStore() const {
+
+ return m_store.lock();
+}
+
+
+shared_ptr <store> IMAPFolder::getStore() {
+
+ return m_store.lock();
+}
+
+
+void IMAPFolder::registerMessage(IMAPMessage* msg) {
+
+ m_messages.push_back(msg);
+}
+
+
+void IMAPFolder::unregisterMessage(IMAPMessage* msg) {
+
+ std::vector <IMAPMessage*>::iterator it =
+ std::find(m_messages.begin(), m_messages.end(), msg);
+
+ if (it != m_messages.end()) {
+ m_messages.erase(it);
+ }
+}
+
+
+void IMAPFolder::onStoreDisconnected() {
+
+ m_store.reset();
+}
+
+
+void IMAPFolder::deleteMessages(const messageSet& msgs) {
+
+ shared_ptr <IMAPStore> store = m_store.lock();
+
+ if (msgs.isEmpty()) {
+ throw exceptions::invalid_argument();
+ }
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ } else if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ } else if (m_mode == MODE_READ_ONLY) {
+ throw exceptions::illegal_state("Folder is read-only");
+ }
+
+ // Send the request
+ IMAPCommand::STORE(
+ msgs, message::FLAG_MODE_ADD,
+ IMAPUtils::messageFlagList(message::FLAG_DELETED)
+ )->send(m_connection);
+
+ // Get the response
+ scoped_ptr <IMAPParser::response> resp(m_connection->readResponse());
+
+ if (resp->isBad() || resp->response_done->response_tagged->
+ resp_cond_state->status != IMAPParser::resp_cond_state::OK) {
+
+ throw exceptions::command_error("STORE", resp->getErrorLog(), "bad response");
+ }
+
+ processStatusUpdate(resp.get());
+}
+
+
+void IMAPFolder::setMessageFlags(
+ const messageSet& msgs,
+ const int flags,
+ const int mode
+) {
+
+ const std::vector <string> flagList = IMAPUtils::messageFlagList(flags);
+
+ if ((mode == message::FLAG_MODE_SET) || !flagList.empty()) {
+
+ // Send the request
+ IMAPCommand::STORE(msgs, mode, flagList)->send(m_connection);
+
+ // Get the response
+ scoped_ptr <IMAPParser::response> resp(m_connection->readResponse());
+
+ if (resp->isBad() || resp->response_done->response_tagged->
+ resp_cond_state->status != IMAPParser::resp_cond_state::OK) {
+
+ throw exceptions::command_error("STORE", resp->getErrorLog(), "bad response");
+ }
+
+ processStatusUpdate(resp.get());
+ }
+}
+
+
+messageSet IMAPFolder::addMessage(
+ const shared_ptr <vmime::message>& msg,
+ const int flags,
+ vmime::datetime* date,
+ utility::progressListener* progress
+) {
+
+ std::ostringstream oss;
+ utility::outputStreamAdapter ossAdapter(oss);
+
+ msg->generate(ossAdapter);
+
+ const string& str = oss.str();
+ utility::inputStreamStringAdapter strAdapter(str);
+
+ return addMessage(strAdapter, str.length(), flags, date, progress);
+}
+
+
+messageSet IMAPFolder::addMessage(
+ utility::inputStream& is,
+ const size_t size,
+ const int flags,
+ vmime::datetime* date,
+ utility::progressListener* progress
+) {
+
+ shared_ptr <IMAPStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ } else if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ } else if (m_mode == MODE_READ_ONLY) {
+ throw exceptions::illegal_state("Folder is read-only");
+ }
+
+ // Send the request
+ IMAPCommand::APPEND(
+ IMAPUtils::pathToString(m_connection->hierarchySeparator(), getFullPath()),
+ IMAPUtils::messageFlagList(flags), date, size
+ )->send(m_connection);
+
+ // Get the response
+ scoped_ptr <IMAPParser::response> resp(m_connection->readResponse());
+
+ bool ok = false;
+ auto &respList = resp->continue_req_or_response_data;
+
+ for (auto it = respList.begin() ; !ok && (it != respList.end()) ; ++it) {
+
+ if ((*it)->continue_req) {
+ ok = true;
+ }
+ }
+
+ if (!ok) {
+ throw exceptions::command_error("APPEND", resp->getErrorLog(), "bad response");
+ }
+
+ processStatusUpdate(resp.get());
+
+ // Send message data
+ const size_t total = size;
+ size_t current = 0;
+
+ if (progress) {
+ progress->start(total);
+ }
+
+ const size_t blockSize = std::min(
+ is.getBlockSize(),
+ static_cast <size_t>(m_connection->getSocket()->getBlockSize())
+ );
+
+ std::vector <byte_t> vbuffer(blockSize);
+ byte_t* buffer = &vbuffer.front();
+
+ while (!is.eof()) {
+
+ // Read some data from the input stream
+ const size_t read = is.read(buffer, blockSize);
+ current += read;
+
+ // Put read data into socket output stream
+ m_connection->sendRaw(buffer, read);
+
+ // Notify progress
+ if (progress) {
+ progress->progress(current, total);
+ }
+ }
+
+ m_connection->sendRaw(utility::stringUtils::bytesFromString("\r\n"), 2);
+
+ if (m_connection->getTracer()) {
+ m_connection->getTracer()->traceSendBytes(current);
+ }
+
+ if (progress) {
+ progress->stop(total);
+ }
+
+ // Get the response
+ scoped_ptr <IMAPParser::response> finalResp(m_connection->readResponse());
+
+ if (finalResp->isBad() || finalResp->response_done->response_tagged->
+ resp_cond_state->status != IMAPParser::resp_cond_state::OK) {
+
+ throw exceptions::command_error("APPEND", resp->getErrorLog(), "bad response");
+ }
+
+ processStatusUpdate(finalResp.get());
+
+ auto *respTextCode =
+ finalResp->response_done->response_tagged->resp_cond_state->resp_text->resp_text_code.get();
+
+ if (respTextCode && respTextCode->type == IMAPParser::resp_text_code::APPENDUID) {
+ return IMAPUtils::buildMessageSet(*respTextCode->uid_set);
+ }
+
+ return messageSet::empty();
+}
+
+
+void IMAPFolder::expunge() {
+
+ shared_ptr <IMAPStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ } else if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ } else if (m_mode == MODE_READ_ONLY) {
+ throw exceptions::illegal_state("Folder is read-only");
+ }
+
+ // Send the request
+ IMAPCommand::EXPUNGE()->send(m_connection);
+
+ // Get the response
+ scoped_ptr <IMAPParser::response> resp(m_connection->readResponse());
+
+ if (resp->isBad() || resp->response_done->response_tagged->
+ resp_cond_state->status != IMAPParser::resp_cond_state::OK) {
+
+ throw exceptions::command_error("EXPUNGE", resp->getErrorLog(), "bad response");
+ }
+
+ processStatusUpdate(resp.get());
+}
+
+
+void IMAPFolder::rename(const folder::path& newPath) {
+
+ shared_ptr <IMAPStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ } else if (m_path.isEmpty() || newPath.isEmpty()) {
+ throw exceptions::illegal_operation("Cannot rename root folder");
+ } else if (m_path.getSize() == 1 && m_name.getBuffer() == "INBOX") {
+ throw exceptions::illegal_operation("Cannot rename 'INBOX' folder");
+ } else if (!store->isValidFolderName(newPath.getLastComponent())) {
+ throw exceptions::invalid_folder_name();
+ }
+
+ // Send the request
+ IMAPCommand::RENAME(
+ IMAPUtils::pathToString(m_connection->hierarchySeparator(), getFullPath()),
+ IMAPUtils::pathToString(m_connection->hierarchySeparator(), newPath)
+ )->send(m_connection);
+
+ // Get the response
+ scoped_ptr <IMAPParser::response> resp(m_connection->readResponse());
+
+ if (resp->isBad() || resp->response_done->response_tagged->
+ resp_cond_state->status != IMAPParser::resp_cond_state::OK) {
+
+ throw exceptions::command_error("RENAME", resp->getErrorLog(), "bad response");
+ }
+
+ // Notify folder renamed
+ folder::path oldPath(m_path);
+
+ m_path = newPath;
+ m_name = newPath.getLastComponent();
+
+ shared_ptr <events::folderEvent> event =
+ make_shared <events::folderEvent>(
+ dynamicCast <folder>(shared_from_this()),
+ events::folderEvent::TYPE_RENAMED,
+ oldPath,
+ newPath
+ );
+
+ notifyFolder(event);
+
+ // Notify sub-folders
+ for (std::list <IMAPFolder*>::iterator it = store->m_folders.begin() ;
+ it != store->m_folders.end() ; ++it) {
+
+ if ((*it) != this && oldPath.isParentOf((*it)->getFullPath())) {
+
+ folder::path oldPath((*it)->m_path);
+
+ (*it)->m_path.renameParent(oldPath, newPath);
+
+ shared_ptr <events::folderEvent> event =
+ make_shared <events::folderEvent>(
+ dynamicCast <folder>((*it)->shared_from_this()),
+ events::folderEvent::TYPE_RENAMED,
+ oldPath, (*it)->m_path
+ );
+
+ (*it)->notifyFolder(event);
+ }
+ }
+
+ processStatusUpdate(resp.get());
+}
+
+
+messageSet IMAPFolder::copyMessages(const folder::path& dest, const messageSet& set) {
+
+ shared_ptr <IMAPStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ } else if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ }
+
+ // Send the request
+ IMAPCommand::COPY(
+ set,
+ IMAPUtils::pathToString(m_connection->hierarchySeparator(), dest)
+ )->send(m_connection);
+
+ // Get the response
+ scoped_ptr <IMAPParser::response> resp(m_connection->readResponse());
+
+ if (resp->isBad() || resp->response_done->response_tagged->
+ resp_cond_state->status != IMAPParser::resp_cond_state::OK) {
+
+ throw exceptions::command_error("COPY", resp->getErrorLog(), "bad response");
+ }
+
+ processStatusUpdate(resp.get());
+
+ auto *respTextCode =
+ resp->response_done->response_tagged->resp_cond_state->resp_text->resp_text_code.get();
+
+ if (respTextCode && respTextCode->type == IMAPParser::resp_text_code::COPYUID) {
+ return IMAPUtils::buildMessageSet(*respTextCode->uid_set2);
+ }
+
+ return messageSet::empty();
+}
+
+
+void IMAPFolder::status(size_t& count, size_t& unseen) {
+
+ count = 0;
+ unseen = 0;
+
+ shared_ptr <folderStatus> status = getStatus();
+
+ count = status->getMessageCount();
+ unseen = status->getUnseenCount();
+}
+
+
+shared_ptr <folderStatus> IMAPFolder::getStatus() {
+
+ shared_ptr <IMAPStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ }
+
+ // Build the attributes list
+ std::vector <string> attribs;
+
+ attribs.push_back("MESSAGES");
+ attribs.push_back("UNSEEN");
+ attribs.push_back("UIDNEXT");
+ attribs.push_back("UIDVALIDITY");
+
+ if (m_connection->hasCapability("CONDSTORE")) {
+ attribs.push_back("HIGHESTMODSEQ");
+ }
+
+ // Send the request
+ IMAPCommand::STATUS(
+ IMAPUtils::pathToString(m_connection->hierarchySeparator(), getFullPath()),
+ attribs
+ )->send(m_connection);
+
+ // Get the response
+ scoped_ptr <IMAPParser::response> resp(m_connection->readResponse());
+
+ if (resp->isBad() || resp->response_done->response_tagged->
+ resp_cond_state->status != IMAPParser::resp_cond_state::OK) {
+
+ throw exceptions::command_error("STATUS", resp->getErrorLog(), "bad response");
+ }
+
+ auto &respDataList = resp->continue_req_or_response_data;
+
+ for (auto it = respDataList.begin() ; it != respDataList.end() ; ++it) {
+
+ if ((*it)->response_data) {
+
+ auto &responseData = (*it)->response_data;
+
+ if (responseData->mailbox_data &&
+ responseData->mailbox_data->type == IMAPParser::mailbox_data::STATUS) {
+
+ shared_ptr <IMAPFolderStatus> status = make_shared <IMAPFolderStatus>();
+ status->updateFromResponse(*responseData->mailbox_data);
+
+ m_status->updateFromResponse(*responseData->mailbox_data);
+
+ return status;
+ }
+ }
+ }
+
+ throw exceptions::command_error("STATUS", resp->getErrorLog(), "invalid response");
+}
+
+
+void IMAPFolder::noop() {
+
+ shared_ptr <IMAPStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ }
+
+ IMAPCommand::NOOP()->send(m_connection);
+
+ scoped_ptr <IMAPParser::response> resp(m_connection->readResponse());
+
+ if (resp->isBad() || resp->response_done->response_tagged->
+ resp_cond_state->status != IMAPParser::resp_cond_state::OK) {
+
+ throw exceptions::command_error("NOOP", resp->getErrorLog());
+ }
+
+ processStatusUpdate(resp.get());
+}
+
+
+std::vector <size_t> IMAPFolder::getMessageNumbersStartingOnUID(const message::uid& uid) {
+
+ // Send the request
+ std::ostringstream uidSearchKey;
+ uidSearchKey.imbue(std::locale::classic());
+ uidSearchKey << "UID " << uid << ":*";
+
+ std::vector <string> searchKeys;
+ searchKeys.push_back(uidSearchKey.str());
+
+ IMAPCommand::SEARCH(searchKeys, /* charset */ NULL)->send(m_connection);
+
+ // Get the response
+ scoped_ptr <IMAPParser::response> resp(m_connection->readResponse());
+
+ if (resp->isBad() ||
+ resp->response_done->response_tagged->resp_cond_state->status != IMAPParser::resp_cond_state::OK) {
+
+ throw exceptions::command_error("SEARCH", resp->getErrorLog(), "bad response");
+ }
+
+ auto& respDataList = resp->continue_req_or_response_data;
+
+ std::vector <size_t> seqNumbers;
+
+ for (auto it = respDataList.begin() ; it != respDataList.end() ; ++it) {
+
+ if (!(*it)->response_data) {
+ throw exceptions::command_error("SEARCH", resp->getErrorLog(), "invalid response");
+ }
+
+ auto *mailboxData = (*it)->response_data->mailbox_data.get();
+
+ // We are only interested in responses of type "SEARCH"
+ if (!mailboxData ||
+ mailboxData->type != IMAPParser::mailbox_data::SEARCH) {
+
+ continue;
+ }
+
+ for (auto &nzn : mailboxData->search_nz_number_list) {
+ seqNumbers.push_back(nzn->value);
+ }
+ }
+
+ processStatusUpdate(resp.get());
+
+ return seqNumbers;
+}
+
+
+void IMAPFolder::processStatusUpdate(const IMAPParser::response* resp) {
+
+ std::vector <shared_ptr <events::event> > events;
+
+ shared_ptr <IMAPFolderStatus> oldStatus = vmime::clone(m_status);
+ int expungedMessageCount = 0;
+
+ // Process tagged response
+ if (resp->response_done &&
+ resp->response_done->response_tagged &&
+ resp->response_done->response_tagged->resp_cond_state->resp_text->resp_text_code) {
+
+ m_status->updateFromResponse(
+ *resp->response_done->response_tagged->resp_cond_state->resp_text->resp_text_code
+ );
+ }
+
+ // Process untagged responses
+ for (auto it = resp->continue_req_or_response_data.begin() ;
+ it != resp->continue_req_or_response_data.end() ; ++it) {
+
+ if ((*it)->response_data &&
+ (*it)->response_data->resp_cond_state &&
+ (*it)->response_data->resp_cond_state->resp_text->resp_text_code) {
+
+ m_status->updateFromResponse(
+ *(*it)->response_data->resp_cond_state->resp_text->resp_text_code
+ );
+
+ } else if ((*it)->response_data &&
+ (*it)->response_data->mailbox_data) {
+
+ m_status->updateFromResponse(*(*it)->response_data->mailbox_data);
+
+ // Update folder attributes, if available
+ if ((*it)->response_data->mailbox_data->type == IMAPParser::mailbox_data::LIST) {
+
+ folderAttributes attribs;
+ IMAPUtils::mailboxFlagsToFolderAttributes(
+ m_connection,
+ m_path,
+ *(*it)->response_data->mailbox_data->mailbox_list->mailbox_flag_list,
+ attribs
+ );
+
+ m_attribs = make_shared <folderAttributes>(attribs);
+ }
+
+ } else if ((*it)->response_data && (*it)->response_data->message_data) {
+
+ auto* msgData = (*it)->response_data->message_data.get();
+ const size_t msgNumber = msgData->number;
+
+ if (msgData->type == IMAPParser::message_data::FETCH) {
+
+ // Message changed
+ for (std::vector <IMAPMessage*>::iterator mit =
+ m_messages.begin() ; mit != m_messages.end() ; ++mit) {
+
+ if ((*mit)->getNumber() == msgNumber) {
+ (*mit)->processFetchResponse(/* options */ 0, *msgData);
+ }
+ }
+
+ events.push_back(
+ make_shared <events::messageChangedEvent>(
+ dynamicCast <folder>(shared_from_this()),
+ events::messageChangedEvent::TYPE_FLAGS,
+ std::vector <size_t>(1, msgNumber)
+ )
+ );
+
+ } else if (msgData->type == IMAPParser::message_data::EXPUNGE) {
+
+ // A message has been expunged, renumber messages
+ for (std::vector <IMAPMessage*>::iterator jt =
+ m_messages.begin() ; jt != m_messages.end() ; ++jt) {
+
+ if ((*jt)->getNumber() == msgNumber) {
+ (*jt)->setExpunged();
+ } else if ((*jt)->getNumber() > msgNumber) {
+ (*jt)->renumber((*jt)->getNumber() - 1);
+ }
+ }
+
+ events.push_back(
+ make_shared <events::messageCountEvent>(
+ dynamicCast <folder>(shared_from_this()),
+ events::messageCountEvent::TYPE_REMOVED,
+ std::vector <size_t>(1, msgNumber)
+ )
+ );
+
+ expungedMessageCount++;
+ }
+ }
+ }
+
+ // New messages arrived
+ if (m_status->getMessageCount() > oldStatus->getMessageCount() - expungedMessageCount) {
+
+ std::vector <size_t> newMessageNumbers;
+
+ for (size_t msgNumber = oldStatus->getMessageCount() - expungedMessageCount ;
+ msgNumber <= m_status->getMessageCount() ; ++msgNumber) {
+
+ newMessageNumbers.push_back(msgNumber);
+ }
+
+ events.push_back(
+ make_shared <events::messageCountEvent>(
+ dynamicCast <folder>(shared_from_this()),
+ events::messageCountEvent::TYPE_ADDED,
+ newMessageNumbers
+ )
+ );
+ }
+
+ // Dispatch notifications
+ for (std::vector <shared_ptr <events::event> >::iterator evit =
+ events.begin() ; evit != events.end() ; ++evit) {
+
+ notifyEvent(*evit);
+ }
+}
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
diff --git a/vmime-master/src/vmime/net/imap/IMAPFolder.hpp b/vmime-master/src/vmime/net/imap/IMAPFolder.hpp
new file mode 100644
index 0000000..3e6b04b
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPFolder.hpp
@@ -0,0 +1,230 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_IMAP_IMAPFOLDER_HPP_INCLUDED
+#define VMIME_NET_IMAP_IMAPFOLDER_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include <vector>
+#include <map>
+
+#include "vmime/types.hpp"
+
+#include "vmime/net/folder.hpp"
+
+#include "vmime/net/imap/IMAPParser.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+class IMAPStore;
+class IMAPMessage;
+class IMAPConnection;
+class IMAPFolderStatus;
+
+
+/** IMAP folder implementation.
+ */
+class VMIME_EXPORT IMAPFolder : public folder {
+
+private:
+
+ friend class IMAPStore;
+ friend class IMAPMessage;
+
+ IMAPFolder(const IMAPFolder&);
+
+public:
+
+ IMAPFolder(
+ const folder::path& path,
+ const shared_ptr <IMAPStore>& store,
+ const shared_ptr <folderAttributes>& attribs
+ );
+
+ ~IMAPFolder();
+
+ int getMode() const;
+
+ const folderAttributes getAttributes();
+
+ const folder::path::component getName() const;
+ const folder::path getFullPath() const;
+
+ void open(const int mode, bool failIfModeIsNotAvailable = false);
+ void close(const bool expunge);
+ void create(const folderAttributes& attribs);
+
+ bool exists();
+
+ void destroy();
+
+ bool isOpen() const;
+
+ shared_ptr <message> getMessage(const size_t num);
+ std::vector <shared_ptr <message> > getMessages(const messageSet& msgs);
+
+ std::vector <size_t> getMessageNumbersStartingOnUID(const message::uid& uid);
+
+ size_t getMessageCount();
+
+ shared_ptr <folder> getFolder(const folder::path::component& name);
+ std::vector <shared_ptr <folder> > getFolders(const bool recursive = false);
+
+ void rename(const folder::path& newPath);
+
+ void deleteMessages(const messageSet& msgs);
+
+ void setMessageFlags(
+ const messageSet& msgs,
+ const int flags,
+ const int mode = message::FLAG_MODE_SET
+ );
+
+ messageSet addMessage(
+ const shared_ptr <vmime::message>& msg,
+ const int flags = -1,
+ vmime::datetime* date = NULL,
+ utility::progressListener* progress = NULL
+ );
+
+ messageSet addMessage(
+ utility::inputStream& is,
+ const size_t size,
+ const int flags = -1,
+ vmime::datetime* date = NULL,
+ utility::progressListener* progress = NULL
+ );
+
+ messageSet copyMessages(const folder::path& dest, const messageSet& msgs);
+
+ void status(size_t& count, size_t& unseen);
+ shared_ptr <folderStatus> getStatus();
+
+ void noop();
+
+ void expunge();
+
+ shared_ptr <folder> getParent();
+
+ shared_ptr <const store> getStore() const;
+ shared_ptr <store> getStore();
+
+
+ void fetchMessages(
+ std::vector <shared_ptr <message> >& msg,
+ const fetchAttributes& options,
+ utility::progressListener* progress = NULL
+ );
+
+ void fetchMessage(const shared_ptr <message>& msg, const fetchAttributes& options);
+
+ std::vector <shared_ptr <message> > getAndFetchMessages(
+ const messageSet& msgs,
+ const fetchAttributes& attribs
+ );
+
+ int getFetchCapabilities() const;
+
+ /** Returns the UID validity of the folder for the current session.
+ * If the server is capable of persisting UIDs accross sessions,
+ * this value should never change for a folder. If the UID validity
+ * differs across sessions, then the UIDs obtained during a previous
+ * session may not correspond to the UIDs of the same messages in
+ * this session.
+ *
+ * @return UID validity of the folder
+ */
+ vmime_uint32 getUIDValidity() const;
+
+ /** Returns the highest modification sequence of this folder, ie the
+ * modification sequence of the last message that changed in this
+ * folder.
+ *
+ * @return modification sequence, or zero if not supported by
+ * the underlying protocol
+ */
+ vmime_uint64 getHighestModSequence() const;
+
+private:
+
+ void registerMessage(IMAPMessage* msg);
+ void unregisterMessage(IMAPMessage* msg);
+
+ void onStoreDisconnected();
+
+ void onClose();
+
+ int testExistAndGetType();
+
+ void setMessageFlagsImpl(const string& set, const int flags, const int mode);
+
+ void copyMessagesImpl(const string& set, const folder::path& dest);
+
+
+ /** Process status updates ("unsolicited responses") contained in the
+ * specified response. Example:
+ *
+ * C: a006 NOOP
+ * S: * 930 EXISTS <-- this is a status update
+ * S: a006 OK Success
+ *
+ * @param resp parsed IMAP response
+ */
+ void processStatusUpdate(const IMAPParser::response* resp);
+
+
+ weak_ptr <IMAPStore> m_store;
+ shared_ptr <IMAPConnection> m_connection;
+
+ folder::path m_path;
+ folder::path::component m_name;
+
+ int m_mode;
+ bool m_open;
+
+ shared_ptr <folderAttributes> m_attribs;
+
+ shared_ptr <IMAPFolderStatus> m_status;
+
+ std::vector <IMAPMessage*> m_messages;
+};
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+#endif // VMIME_NET_IMAP_IMAPFOLDER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/imap/IMAPFolderStatus.cpp b/vmime-master/src/vmime/net/imap/IMAPFolderStatus.cpp
new file mode 100644
index 0000000..55df337
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPFolderStatus.cpp
@@ -0,0 +1,292 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/net/imap/IMAPFolderStatus.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+IMAPFolderStatus::IMAPFolderStatus()
+ : m_count(0),
+ m_unseen(0),
+ m_recent(0),
+ m_uidValidity(0),
+ m_uidNext(0),
+ m_highestModSeq(0) {
+
+}
+
+
+IMAPFolderStatus::IMAPFolderStatus(const IMAPFolderStatus& other)
+ : folderStatus(),
+ m_count(other.m_count),
+ m_unseen(other.m_unseen),
+ m_recent(other.m_recent),
+ m_uidValidity(other.m_uidValidity),
+ m_uidNext(other.m_uidNext),
+ m_highestModSeq(other.m_highestModSeq) {
+
+}
+
+
+size_t IMAPFolderStatus::getMessageCount() const {
+
+ return m_count;
+}
+
+
+size_t IMAPFolderStatus::getUnseenCount() const {
+
+ return m_unseen;
+}
+
+
+size_t IMAPFolderStatus::getRecentCount() const {
+
+ return m_recent;
+}
+
+
+vmime_uint32 IMAPFolderStatus::getUIDValidity() const {
+
+ return m_uidValidity;
+}
+
+
+vmime_uint32 IMAPFolderStatus::getUIDNext() const {
+
+ return m_uidNext;
+}
+
+
+vmime_uint64 IMAPFolderStatus::getHighestModSeq() const {
+
+ return m_highestModSeq;
+}
+
+
+shared_ptr <folderStatus> IMAPFolderStatus::clone() const {
+
+ return make_shared <IMAPFolderStatus>(*this);
+}
+
+
+bool IMAPFolderStatus::updateFromResponse(const IMAPParser::mailbox_data& resp) {
+
+ bool changed = false;
+
+ if (resp.type == IMAPParser::mailbox_data::STATUS) {
+
+ for (auto &attval : resp.status_att_list->values) {
+
+ switch (attval->type) {
+
+ case IMAPParser::status_att_val::MESSAGES: {
+
+ const size_t count =
+ static_cast <size_t>(attval->value_as_number()->value);
+
+ if (m_count != count) {
+ m_count = count;
+ changed = true;
+ }
+
+ break;
+ }
+ case IMAPParser::status_att_val::UNSEEN: {
+
+ const size_t unseen =
+ static_cast <size_t>(attval->value_as_number()->value);
+
+ if (m_unseen != unseen) {
+ m_unseen = unseen;
+ changed = true;
+ }
+
+ break;
+ }
+ case IMAPParser::status_att_val::RECENT: {
+
+ const size_t recent =
+ static_cast <size_t>(attval->value_as_number()->value);
+
+ if (m_recent != recent) {
+ m_recent = recent;
+ changed = true;
+ }
+
+ break;
+ }
+ case IMAPParser::status_att_val::UIDNEXT: {
+
+ const vmime_uint32 uidNext =
+ static_cast <vmime_uint32>(attval->value_as_number()->value);
+
+ if (m_uidNext != uidNext) {
+ m_uidNext = uidNext;
+ changed = true;
+ }
+
+ break;
+ }
+ case IMAPParser::status_att_val::UIDVALIDITY: {
+
+ const vmime_uint32 uidValidity =
+ static_cast <vmime_uint32>(attval->value_as_number()->value);
+
+ if (m_uidValidity != uidValidity) {
+ m_uidValidity = uidValidity;
+ changed = true;
+ }
+
+ break;
+ }
+ case IMAPParser::status_att_val::HIGHESTMODSEQ: {
+
+ const vmime_uint64 highestModSeq =
+ static_cast <vmime_uint64>(attval->value_as_mod_sequence_value()->value);
+
+ if (m_highestModSeq != highestModSeq) {
+ m_highestModSeq = highestModSeq;
+ changed = true;
+ }
+
+ break;
+ }
+
+ }
+ }
+
+ } else if (resp.type == IMAPParser::mailbox_data::EXISTS) {
+
+ const size_t count =
+ static_cast <size_t>(resp.number->value);
+
+ if (m_count != count) {
+ m_count = count;
+ changed = true;
+ }
+
+ } else if (resp.type == IMAPParser::mailbox_data::RECENT) {
+
+ const size_t recent =
+ static_cast <size_t>(resp.number->value);
+
+ if (m_recent != recent) {
+ m_recent = recent;
+ changed = true;
+ }
+ }
+
+ return changed;
+}
+
+
+bool IMAPFolderStatus::updateFromResponse(const IMAPParser::resp_text_code& resp) {
+
+ bool changed = false;
+
+ switch (resp.type) {
+
+ case IMAPParser::resp_text_code::UIDVALIDITY: {
+
+ const vmime_uint32 uidValidity =
+ static_cast <vmime_uint32>(resp.nz_number->value);
+
+ if (m_uidValidity != uidValidity) {
+ m_uidValidity = uidValidity;
+ changed = true;
+ }
+
+ break;
+ }
+ case IMAPParser::resp_text_code::UIDNEXT: {
+
+ const vmime_uint32 uidNext =
+ static_cast <vmime_uint32>(resp.nz_number->value);
+
+ if (m_uidNext != uidNext) {
+ m_uidNext = uidNext;
+ changed = true;
+ }
+
+ break;
+ }
+ case IMAPParser::resp_text_code::UNSEEN: {
+
+ const size_t unseen =
+ static_cast <size_t>(resp.nz_number->value);
+
+ if (m_unseen != unseen)
+ {
+ m_unseen = unseen;
+ changed = true;
+ }
+
+ break;
+ }
+ case IMAPParser::resp_text_code::HIGHESTMODSEQ: {
+
+ const vmime_uint64 highestModSeq =
+ static_cast <vmime_uint64>(resp.mod_sequence_value->value);
+
+ if (m_highestModSeq != highestModSeq) {
+ m_highestModSeq = highestModSeq;
+ changed = true;
+ }
+
+ break;
+ }
+ case IMAPParser::resp_text_code::NOMODSEQ: {
+
+ if (m_highestModSeq != 0) {
+ m_highestModSeq = 0;
+ changed = true;
+ }
+
+ break;
+ }
+ default:
+
+ break;
+ }
+
+ return changed;
+}
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
diff --git a/vmime-master/src/vmime/net/imap/IMAPFolderStatus.hpp b/vmime-master/src/vmime/net/imap/IMAPFolderStatus.hpp
new file mode 100644
index 0000000..b9a73ec
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPFolderStatus.hpp
@@ -0,0 +1,123 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_IMAP_IMAPFOLDERSTATUS_HPP_INCLUDED
+#define VMIME_NET_IMAP_IMAPFOLDERSTATUS_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/net/folderStatus.hpp"
+
+#include "vmime/net/imap/IMAPParser.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+/** Holds the status of an IMAP folder.
+ */
+class VMIME_EXPORT IMAPFolderStatus : public folderStatus {
+
+public:
+
+ IMAPFolderStatus();
+ IMAPFolderStatus(const IMAPFolderStatus& other);
+
+ // Inherited from folderStatus
+ size_t getMessageCount() const;
+ size_t getUnseenCount() const;
+
+ shared_ptr <folderStatus> clone() const;
+
+ /** Returns the the number of messages with the Recent flag set.
+ *
+ * @return number of messages flagged Recent
+ */
+ size_t getRecentCount() const;
+
+ /** Returns the UID validity of the folder for the current session.
+ * If the server is capable of persisting UIDs accross sessions,
+ * this value should never change for a folder.
+ *
+ * @return UID validity of the folder
+ */
+ vmime_uint32 getUIDValidity() const;
+
+ /** Returns the UID value that will be assigned to a new message
+ * in the folder. If the server does not support the UIDPLUS
+ * extension, it will return 0.
+ *
+ * @return UID of the next message
+ */
+ vmime_uint32 getUIDNext() const;
+
+ /** Returns the highest modification sequence of all messages
+ * in the folder, or 0 if not available for this folder, or not
+ * supported by the server. The server must support the CONDSTORE
+ * extension for this to be available.
+ *
+ * @return highest modification sequence
+ */
+ vmime_uint64 getHighestModSeq() const;
+
+
+ /** Reads the folder status from the specified IMAP response.
+ *
+ * @param resp parsed IMAP response
+ * @return true if the status changed, or false otherwise
+ */
+ bool updateFromResponse(const IMAPParser::mailbox_data& resp);
+
+ /** Reads the folder status from the specified IMAP response.
+ *
+ * @param resp parsed IMAP response
+ * @return true if the status changed, or false otherwise
+ */
+ bool updateFromResponse(const IMAPParser::resp_text_code& resp);
+
+private:
+
+ size_t m_count;
+ size_t m_unseen;
+ size_t m_recent;
+ vmime_uint32 m_uidValidity;
+ vmime_uint32 m_uidNext;
+ vmime_uint64 m_highestModSeq;
+};
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+#endif // VMIME_NET_IMAP_IMAPFOLDERSTATUS_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/imap/IMAPMessage.cpp b/vmime-master/src/vmime/net/imap/IMAPMessage.cpp
new file mode 100644
index 0000000..f74a4a4
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPMessage.cpp
@@ -0,0 +1,760 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/net/imap/IMAPParser.hpp"
+#include "vmime/net/imap/IMAPMessage.hpp"
+#include "vmime/net/imap/IMAPFolder.hpp"
+#include "vmime/net/imap/IMAPFolderStatus.hpp"
+#include "vmime/net/imap/IMAPStore.hpp"
+#include "vmime/net/imap/IMAPConnection.hpp"
+#include "vmime/net/imap/IMAPUtils.hpp"
+#include "vmime/net/imap/IMAPMessageStructure.hpp"
+#include "vmime/net/imap/IMAPMessagePart.hpp"
+#include "vmime/net/imap/IMAPMessagePartContentHandler.hpp"
+
+#include "vmime/utility/outputStreamAdapter.hpp"
+
+#include <sstream>
+#include <iterator>
+#include <typeinfo>
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+#ifndef VMIME_BUILDING_DOC
+
+//
+// IMAPMessage_literalHandler
+//
+
+class IMAPMessage_literalHandler : public IMAPParser::literalHandler {
+
+public:
+
+ IMAPMessage_literalHandler(utility::outputStream& os, utility::progressListener* progress) {
+
+ m_target = shared_ptr <target>(new targetStream(progress, os));
+ }
+
+ shared_ptr <target> targetFor(const IMAPParser::component& comp, const int /* data */) {
+
+ if (typeid(comp) == typeid(IMAPParser::msg_att_item)) {
+
+ const int type = static_cast
+ <const IMAPParser::msg_att_item&>(comp).type;
+
+ if (type == IMAPParser::msg_att_item::BODY_SECTION ||
+ type == IMAPParser::msg_att_item::RFC822_TEXT) {
+
+ return m_target;
+ }
+ }
+
+ return shared_ptr <target>();
+ }
+
+ shared_ptr <target> getTarget() {
+
+ return m_target;
+ }
+
+private:
+
+ shared_ptr <target> m_target;
+};
+
+#endif // VMIME_BUILDING_DOC
+
+
+
+//
+// IMAPMessage
+//
+
+
+IMAPMessage::IMAPMessage(
+ const shared_ptr <IMAPFolder>& folder,
+ const size_t num
+)
+ : m_folder(folder),
+ m_num(num),
+ m_size(-1U),
+ m_flags(FLAG_UNDEFINED),
+ m_expunged(false),
+ m_modseq(0),
+ m_structure(null) {
+
+ folder->registerMessage(this);
+}
+
+
+IMAPMessage::IMAPMessage(
+ const shared_ptr <IMAPFolder>& folder,
+ const size_t num,
+ const uid& uid
+)
+ : m_folder(folder),
+ m_num(num),
+ m_size(-1),
+ m_flags(FLAG_UNDEFINED),
+ m_expunged(false),
+ m_uid(uid),
+ m_modseq(0),
+ m_structure(null) {
+
+ folder->registerMessage(this);
+}
+
+
+IMAPMessage::~IMAPMessage() {
+
+ try {
+
+ shared_ptr <IMAPFolder> folder = m_folder.lock();
+
+ if (folder) {
+ folder->unregisterMessage(this);
+ }
+
+ } catch (...) {
+
+ // Don't throw in destructor
+ }
+}
+
+
+void IMAPMessage::onFolderClosed() {
+
+ m_folder.reset();
+}
+
+
+size_t IMAPMessage::getNumber() const {
+
+ return m_num;
+}
+
+
+const message::uid IMAPMessage::getUID() const {
+
+ return m_uid;
+}
+
+
+vmime_uint64 IMAPMessage::getModSequence() const {
+
+ return m_modseq;
+}
+
+
+size_t IMAPMessage::getSize() const {
+
+ if (m_size == -1U) {
+ throw exceptions::unfetched_object();
+ }
+
+ return m_size;
+}
+
+
+bool IMAPMessage::isExpunged() const {
+
+ return m_expunged;
+}
+
+
+int IMAPMessage::getFlags() const {
+
+ if (m_flags == FLAG_UNDEFINED) {
+ throw exceptions::unfetched_object();
+ }
+
+ return m_flags;
+}
+
+
+shared_ptr <const messageStructure> IMAPMessage::getStructure() const {
+
+ if (m_structure == NULL) {
+ throw exceptions::unfetched_object();
+ }
+
+ return m_structure;
+}
+
+
+shared_ptr <messageStructure> IMAPMessage::getStructure() {
+
+ if (m_structure == NULL) {
+ throw exceptions::unfetched_object();
+ }
+
+ return m_structure;
+}
+
+
+shared_ptr <const header> IMAPMessage::getHeader() const {
+
+ if (m_header == NULL) {
+ throw exceptions::unfetched_object();
+ }
+
+ return m_header;
+}
+
+
+void IMAPMessage::extract(
+ utility::outputStream& os,
+ utility::progressListener* progress,
+ const size_t start,
+ const size_t length,
+ const bool peek
+) const {
+
+ shared_ptr <const IMAPFolder> folder = m_folder.lock();
+
+ if (!folder) {
+ throw exceptions::folder_not_found();
+ }
+
+ extractImpl(
+ null, os, progress, start, length,
+ EXTRACT_HEADER | EXTRACT_BODY | (peek ? EXTRACT_PEEK : 0)
+ );
+}
+
+
+void IMAPMessage::extractPart(
+ const shared_ptr <const messagePart>& p,
+ utility::outputStream& os,
+ utility::progressListener* progress,
+ const size_t start,
+ const size_t length,
+ const bool peek
+) const {
+
+ shared_ptr <const IMAPFolder> folder = m_folder.lock();
+
+ if (!folder) {
+ throw exceptions::folder_not_found();
+ }
+
+ extractImpl(
+ p, os, progress, start, length,
+ EXTRACT_HEADER | EXTRACT_BODY | (peek ? EXTRACT_PEEK : 0)
+ );
+}
+
+
+void IMAPMessage::fetchPartHeader(const shared_ptr <messagePart>& p) {
+
+ shared_ptr <IMAPFolder> folder = m_folder.lock();
+
+ if (!folder) {
+ throw exceptions::folder_not_found();
+ }
+
+ std::ostringstream oss;
+ utility::outputStreamAdapter ossAdapter(oss);
+
+ extractImpl(p, ossAdapter, NULL, 0, -1, EXTRACT_HEADER | EXTRACT_PEEK);
+
+ dynamicCast <IMAPMessagePart>(p)->getOrCreateHeader().parse(oss.str());
+}
+
+
+void IMAPMessage::fetchPartHeaderForStructure(const shared_ptr <messageStructure>& str) {
+
+ for (size_t i = 0, n = str->getPartCount() ; i < n ; ++i) {
+
+ shared_ptr <messagePart> part = str->getPartAt(i);
+
+ // Fetch header of current part
+ fetchPartHeader(part);
+
+ // Fetch header of sub-parts
+ fetchPartHeaderForStructure(part->getStructure());
+ }
+}
+
+
+size_t IMAPMessage::extractImpl(
+ const shared_ptr <const messagePart>& p,
+ utility::outputStream& os,
+ utility::progressListener* progress,
+ const size_t start,
+ const size_t length,
+ const int extractFlags
+) const {
+
+ shared_ptr <const IMAPFolder> folder = m_folder.lock();
+
+ IMAPMessage_literalHandler literalHandler(os, progress);
+
+ if (length == 0) {
+ return 0;
+ }
+
+ // Construct section identifier
+ std::ostringstream section;
+ section.imbue(std::locale::classic());
+
+ if (p != NULL) {
+
+ shared_ptr <const IMAPMessagePart> currentPart = dynamicCast <const IMAPMessagePart>(p);
+ std::vector <size_t> numbers;
+
+ numbers.push_back(currentPart->getNumber());
+ currentPart = currentPart->getParent();
+
+ while (currentPart != NULL) {
+ numbers.push_back(currentPart->getNumber());
+ currentPart = currentPart->getParent();
+ }
+
+ numbers.erase(numbers.end() - 1);
+
+ for (std::vector <size_t>::reverse_iterator it = numbers.rbegin() ; it != numbers.rend() ; ++it) {
+ if (it != numbers.rbegin()) section << ".";
+ section << (*it + 1);
+ }
+ }
+
+ // Build the body descriptor for FETCH
+ /*
+ BODY[] header + body
+ BODY.PEEK[] header + body (peek)
+ BODY[HEADER] header
+ BODY.PEEK[HEADER] header (peek)
+ BODY[TEXT] body
+ BODY.PEEK[TEXT] body (peek)
+ */
+ std::ostringstream bodyDesc;
+ bodyDesc.imbue(std::locale::classic());
+
+ bodyDesc << "BODY";
+
+ if (extractFlags & EXTRACT_PEEK) {
+ bodyDesc << ".PEEK";
+ }
+
+ bodyDesc << "[";
+
+ if (section.str().empty()) {
+
+ // header + body
+ if ((extractFlags & EXTRACT_HEADER) && (extractFlags & EXTRACT_BODY)) {
+ bodyDesc << "";
+ // body only
+ } else if (extractFlags & EXTRACT_BODY) {
+ bodyDesc << "TEXT";
+ // header only
+ } else if (extractFlags & EXTRACT_HEADER) {
+ bodyDesc << "HEADER";
+ }
+
+ } else {
+
+ bodyDesc << section.str();
+
+ // header + body
+ if ((extractFlags & EXTRACT_HEADER) && (extractFlags & EXTRACT_BODY)) {
+
+ // First, extract header
+ std::ostringstream header;
+ utility::outputStreamAdapter headerStream(header);
+
+ const size_t headerLength = extractImpl(
+ p, headerStream, /* progress */ NULL,
+ /* start */ 0, /* length */ -1, extractFlags & ~EXTRACT_BODY
+ );
+
+ size_t s = start;
+ size_t l = length;
+
+ if (s < headerLength) {
+
+ if (l == static_cast <size_t>(-1)) {
+
+ os.write(header.str().data() + s, headerLength - s);
+
+ } else {
+
+ size_t headerCopyLength = l;
+
+ if (start + headerCopyLength > headerLength) {
+ headerCopyLength = headerLength - start;
+ }
+
+ os.write(header.str().data() + s, headerCopyLength);
+
+ l -= headerCopyLength;
+ }
+
+ s = 0;
+
+ } else {
+
+ s -= headerLength;
+ }
+
+ // Then, extract body
+ return extractImpl(p, os, progress, s, l, extractFlags & ~EXTRACT_HEADER);
+
+ // header only
+ } else if (extractFlags & EXTRACT_HEADER) {
+
+ bodyDesc << ".MIME"; // "MIME" not "HEADER" for parts
+ }
+ }
+
+ bodyDesc << "]";
+
+ if (start != 0 || length != static_cast <size_t>(-1)) {
+
+ if (length == static_cast <size_t>(-1)) {
+ bodyDesc << "<" << start << "." << static_cast <unsigned int>(-1) << ">";
+ } else {
+ bodyDesc << "<" << start << "." << length << ">";
+ }
+ }
+
+ std::vector <std::string> fetchParams;
+ fetchParams.push_back(bodyDesc.str());
+
+ // Send the request
+ IMAPCommand::FETCH(
+ m_uid.empty() ? messageSet::byNumber(m_num) : messageSet::byUID(m_uid),
+ fetchParams
+ )->send(folder->m_connection);
+
+ // Get the response
+ scoped_ptr <IMAPParser::response> resp(folder->m_connection->readResponse(&literalHandler));
+
+ if (resp->isBad() || resp->response_done->response_tagged->
+ resp_cond_state->status != IMAPParser::resp_cond_state::OK) {
+
+ throw exceptions::command_error("FETCH", resp->getErrorLog(), "bad response");
+ }
+
+
+ if (extractFlags & EXTRACT_BODY) {
+ // TODO: update the flags (eg. flag "\Seen" may have been set)
+ }
+
+ return literalHandler.getTarget()->getBytesWritten();
+}
+
+
+int IMAPMessage::processFetchResponse(
+ const fetchAttributes& options,
+ const IMAPParser::message_data& msgData
+) {
+
+ shared_ptr <IMAPFolder> folder = m_folder.lock();
+
+ // Get message attributes
+ int changes = 0;
+
+ for (auto &att : msgData.msg_att->items) {
+
+ switch (att->type) {
+
+ case IMAPParser::msg_att_item::FLAGS: {
+
+ int flags = IMAPUtils::messageFlagsFromFlags(*att->flag_list);
+
+ if (m_flags != flags) {
+ m_flags = flags;
+ changes |= events::messageChangedEvent::TYPE_FLAGS;
+ }
+
+ break;
+ }
+ case IMAPParser::msg_att_item::UID: {
+
+ m_uid = att->uniqueid->value;
+ break;
+ }
+ case IMAPParser::msg_att_item::MODSEQ: {
+
+ m_modseq = att->mod_sequence_value->value;
+ break;
+ }
+ case IMAPParser::msg_att_item::ENVELOPE: {
+
+ if (!options.has(fetchAttributes::FULL_HEADER)) {
+
+ auto* env = att->envelope.get();
+ shared_ptr <vmime::header> hdr = getOrCreateHeader();
+
+ // Date
+ hdr->Date()->setValue(env->env_date->value);
+
+ // Subject
+ text subject;
+ text::decodeAndUnfold(env->env_subject->value, &subject);
+
+ hdr->Subject()->setValue(subject);
+
+ // From
+ mailboxList from;
+ IMAPUtils::convertAddressList(*(env->env_from), from);
+
+ if (!from.isEmpty()) {
+ hdr->From()->setValue(*(from.getMailboxAt(0)));
+ }
+
+ // To
+ mailboxList to;
+ IMAPUtils::convertAddressList(*(env->env_to), to);
+
+ hdr->To()->setValue(to.toAddressList());
+
+ // Sender
+ mailboxList sender;
+ IMAPUtils::convertAddressList(*(env->env_sender), sender);
+
+ if (!sender.isEmpty()) {
+ hdr->Sender()->setValue(*(sender.getMailboxAt(0)));
+ }
+
+ // Reply-to
+ mailboxList replyTo;
+ IMAPUtils::convertAddressList(*(env->env_reply_to), replyTo);
+
+ if (!replyTo.isEmpty()) {
+ hdr->ReplyTo()->setValue(*(replyTo.getMailboxAt(0)));
+ }
+
+ // Cc
+ mailboxList cc;
+ IMAPUtils::convertAddressList(*(env->env_cc), cc);
+
+ if (!cc.isEmpty()) {
+ hdr->Cc()->setValue(cc.toAddressList());
+ }
+
+ // Bcc
+ mailboxList bcc;
+ IMAPUtils::convertAddressList(*(env->env_bcc), bcc);
+
+ if (!bcc.isEmpty()) {
+ hdr->Bcc()->setValue(bcc.toAddressList());
+ }
+ }
+
+ break;
+ }
+ case IMAPParser::msg_att_item::BODY_STRUCTURE: {
+
+ m_structure = make_shared <IMAPMessageStructure>(att->body.get());
+ break;
+ }
+ case IMAPParser::msg_att_item::RFC822_HEADER: {
+
+ getOrCreateHeader()->parse(att->nstring->value);
+ break;
+ }
+ case IMAPParser::msg_att_item::RFC822_SIZE: {
+
+ m_size = static_cast <size_t>(att->number->value);
+ break;
+ }
+ case IMAPParser::msg_att_item::BODY_SECTION: {
+
+ if (!options.has(fetchAttributes::FULL_HEADER)) {
+
+ if (att->section->section_text1 &&
+ att->section->section_text1->type
+ == IMAPParser::section_text::HEADER_FIELDS) {
+
+ header tempHeader;
+ tempHeader.parse(att->nstring->value);
+
+ vmime::header& hdr = *getOrCreateHeader();
+
+ for (auto& fld : tempHeader.getFieldList()) {
+ hdr.appendField(vmime::clone(fld));
+ }
+ }
+ }
+
+ break;
+ }
+ case IMAPParser::msg_att_item::INTERNALDATE:
+ case IMAPParser::msg_att_item::RFC822:
+ case IMAPParser::msg_att_item::RFC822_TEXT:
+ case IMAPParser::msg_att_item::BODY: {
+
+ break;
+ }
+
+ }
+ }
+
+ return changes;
+}
+
+
+shared_ptr <header> IMAPMessage::getOrCreateHeader() {
+
+ if (m_header != NULL) {
+ return m_header;
+ } else {
+ return m_header = make_shared <header>();
+ }
+}
+
+
+void IMAPMessage::setFlags(const int flags, const int mode) {
+
+ shared_ptr <IMAPFolder> folder = m_folder.lock();
+
+ if (!folder) {
+ throw exceptions::folder_not_found();
+ }
+
+ if (!m_uid.empty()) {
+ folder->setMessageFlags(messageSet::byUID(m_uid), flags, mode);
+ } else {
+ folder->setMessageFlags(messageSet::byNumber(m_num), flags, mode);
+ }
+}
+
+
+void IMAPMessage::constructParsedMessage(
+ const shared_ptr <bodyPart>& parentPart,
+ const shared_ptr <messageStructure>& str,
+ int level
+) {
+
+ if (level == 0) {
+
+ shared_ptr <messagePart> part = str->getPartAt(0);
+
+ // Copy header
+ shared_ptr <const header> hdr = part->getHeader();
+ parentPart->getHeader()->copyFrom(*hdr);
+
+ // Initialize body
+ parentPart->getBody()->setContents(
+ make_shared <IMAPMessagePartContentHandler>(
+ dynamicCast <IMAPMessage>(shared_from_this()),
+ part, parentPart->getBody()->getEncoding()
+ )
+ );
+
+ constructParsedMessage(parentPart, part->getStructure(), 1);
+
+ } else {
+
+ for (size_t i = 0, n = str->getPartCount() ; i < n ; ++i) {
+
+ shared_ptr <messagePart> part = str->getPartAt(i);
+
+ shared_ptr <bodyPart> childPart = make_shared <bodyPart>();
+
+ // Copy header
+ shared_ptr <const header> hdr = part->getHeader();
+ childPart->getHeader()->copyFrom(*hdr);
+
+ // Initialize body
+ childPart->getBody()->setContents(
+ make_shared <IMAPMessagePartContentHandler>(
+ dynamicCast <IMAPMessage>(shared_from_this()),
+ part, childPart->getBody()->getEncoding()
+ )
+ );
+
+ // Add child part
+ parentPart->getBody()->appendPart(childPart);
+
+ // Construct sub parts
+ constructParsedMessage(childPart, part->getStructure(), ++level);
+ }
+ }
+}
+
+
+shared_ptr <vmime::message> IMAPMessage::getParsedMessage() {
+
+ // Fetch structure
+ shared_ptr <messageStructure> structure;
+
+ try {
+
+ structure = getStructure();
+
+ } catch (exceptions::unfetched_object&) {
+
+ std::vector <shared_ptr <message> > msgs;
+ msgs.push_back(dynamicCast <IMAPMessage>(shared_from_this()));
+
+ m_folder.lock()->fetchMessages(
+ msgs, fetchAttributes(fetchAttributes::STRUCTURE), /* progress */ NULL
+ );
+
+ structure = getStructure();
+ }
+
+ // Fetch header for each part
+ fetchPartHeaderForStructure(structure);
+
+ // Construct message from structure
+ shared_ptr <vmime::message> msg = make_shared <vmime::message>();
+
+ constructParsedMessage(msg, structure);
+
+ return msg;
+}
+
+
+void IMAPMessage::renumber(const size_t number) {
+
+ m_num = number;
+}
+
+
+void IMAPMessage::setExpunged() {
+
+ m_expunged = true;
+}
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
diff --git a/vmime-master/src/vmime/net/imap/IMAPMessage.hpp b/vmime-master/src/vmime/net/imap/IMAPMessage.hpp
new file mode 100644
index 0000000..6d82a3e
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPMessage.hpp
@@ -0,0 +1,200 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_IMAP_IMAPMESSAGE_HPP_INCLUDED
+#define VMIME_NET_IMAP_IMAPMESSAGE_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/net/message.hpp"
+#include "vmime/net/folder.hpp"
+
+#include "vmime/net/imap/IMAPParser.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+class IMAPFolder;
+
+
+/** IMAP message implementation.
+ */
+class VMIME_EXPORT IMAPMessage : public message {
+
+private:
+
+ friend class IMAPFolder;
+ friend class IMAPMessagePartContentHandler;
+
+ IMAPMessage(const IMAPMessage&) : message() { }
+
+public:
+
+ IMAPMessage(const shared_ptr <IMAPFolder>& folder, const size_t num);
+ IMAPMessage(const shared_ptr <IMAPFolder>& folder, const size_t num, const uid& uid);
+
+ ~IMAPMessage();
+
+ size_t getNumber() const;
+
+ const uid getUID() const;
+
+ /** Returns the modification sequence for this message.
+ *
+ * Every time metadata for this message changes, the modification
+ * sequence is updated, and is greater than the previous one. The
+ * server must support the CONDSTORE extension for this to be
+ * available.
+ *
+ * @return modification sequence, or zero if not supported by
+ * the underlying protocol
+ */
+ vmime_uint64 getModSequence() const;
+
+ size_t getSize() const;
+
+ bool isExpunged() const;
+
+ shared_ptr <const messageStructure> getStructure() const;
+ shared_ptr <messageStructure> getStructure();
+
+ shared_ptr <const header> getHeader() const;
+
+ int getFlags() const;
+ void setFlags(const int flags, const int mode = FLAG_MODE_SET);
+
+ void extract(
+ utility::outputStream& os,
+ utility::progressListener* progress = NULL,
+ const size_t start = 0,
+ const size_t length = -1,
+ const bool peek = false
+ ) const;
+
+ void extractPart(
+ const shared_ptr <const messagePart>& p,
+ utility::outputStream& os,
+ utility::progressListener* progress = NULL,
+ const size_t start = 0,
+ const size_t length = -1,
+ const bool peek = false
+ ) const;
+
+ void fetchPartHeader(const shared_ptr <messagePart>& p);
+
+ shared_ptr <vmime::message> getParsedMessage();
+
+private:
+
+ /** Renumbers the message.
+ *
+ * @param number new sequence number
+ */
+ void renumber(const size_t number);
+
+ /** Marks the message as expunged.
+ */
+ void setExpunged();
+
+ /** Processes the parsed response to fill in the attributes
+ * and metadata of this message.
+ *
+ * @param options one or more fetch options (see folder::fetchAttributes)
+ * @param msgData pointer to message_data component of the parsed response
+ * @return a combination of flags that specify what changed exactly on
+ * this message (see events::messageChangedEvent::Types)
+ */
+ int processFetchResponse(const fetchAttributes& options, const IMAPParser::message_data& msgData);
+
+ /** Recursively fetch part header for all parts in the structure.
+ *
+ * @param str structure for which to fetch parts headers
+ */
+ void fetchPartHeaderForStructure(const shared_ptr <messageStructure>& str);
+
+ /** Recursively contruct parsed message from structure.
+ * Called by getParsedMessage().
+ *
+ * @param parentPart root body part (the message)
+ * @param str structure for which to construct part
+ * @param level current nesting level (0 is root)
+ */
+ void constructParsedMessage(
+ const shared_ptr <bodyPart>& parentPart,
+ const shared_ptr <messageStructure>& str,
+ int level = 0
+ );
+
+
+ enum ExtractFlags
+ {
+ EXTRACT_HEADER = 0x1,
+ EXTRACT_BODY = 0x2,
+ EXTRACT_PEEK = 0x10
+ };
+
+ size_t extractImpl(
+ const shared_ptr <const messagePart>& p,
+ utility::outputStream& os,
+ utility::progressListener* progress,
+ const size_t start,
+ const size_t length,
+ const int extractFlags
+ ) const;
+
+
+ shared_ptr <header> getOrCreateHeader();
+
+
+ void onFolderClosed();
+
+ weak_ptr <IMAPFolder> m_folder;
+
+ size_t m_num;
+ size_t m_size;
+ int m_flags;
+ bool m_expunged;
+ uid m_uid;
+ vmime_uint64 m_modseq;
+
+ shared_ptr <header> m_header;
+ shared_ptr <messageStructure> m_structure;
+};
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+#endif // VMIME_NET_IMAP_IMAPMESSAGE_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/imap/IMAPMessagePart.cpp b/vmime-master/src/vmime/net/imap/IMAPMessagePart.cpp
new file mode 100644
index 0000000..ed2c0bd
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPMessagePart.cpp
@@ -0,0 +1,225 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/net/imap/IMAPMessagePart.hpp"
+#include "vmime/net/imap/IMAPMessageStructure.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+IMAPMessagePart::IMAPMessagePart(
+ const shared_ptr <IMAPMessagePart>& parent,
+ const size_t number,
+ const IMAPParser::body_type_mpart* mpart
+)
+ : m_parent(parent),
+ m_header(null),
+ m_number(number),
+ m_size(0) {
+
+ m_mediaType = vmime::mediaType(
+ "multipart",
+ mpart->media_subtype->value
+ );
+}
+
+namespace {
+ template<typename T>
+ vmime::string getPartName(const T& body_type) {
+ if (const auto* pparam = body_type->body_fields->body_fld_param.get()) {
+ for (const auto& param : pparam->items) {
+ if (param->string1->value == "NAME") {
+ return param->string2->value;
+ }
+ }
+ }
+
+ return {};
+ }
+}
+
+
+IMAPMessagePart::IMAPMessagePart(
+ const shared_ptr <IMAPMessagePart>& parent,
+ const size_t number,
+ const IMAPParser::body_type_1part* part
+)
+ : m_parent(parent),
+ m_header(null),
+ m_number(number),
+ m_size(0) {
+
+ if (part->body_type_text) {
+
+ m_mediaType = vmime::mediaType(
+ "text",
+ part->body_type_text->media_text->media_subtype->value
+ );
+
+ m_size = part->body_type_text->body_fields->body_fld_octets->value;
+
+ m_name = getPartName(part->body_type_text);
+
+ } else if (part->body_type_msg) {
+
+ m_mediaType = vmime::mediaType(
+ "message",
+ part->body_type_msg->media_message->media_subtype->value
+ );
+
+ } else {
+
+ m_mediaType = vmime::mediaType(
+ part->body_type_basic->media_basic->media_type->value,
+ part->body_type_basic->media_basic->media_subtype->value
+ );
+
+ m_size = part->body_type_basic->body_fields->body_fld_octets->value;
+
+ m_name = getPartName(part->body_type_basic);
+ }
+
+ if (part->body_ext_1part && part->body_ext_1part->body_fld_dsp) {
+ auto *cdisp = part->body_ext_1part->body_fld_dsp->str();
+ if (cdisp) {
+ m_dispType = contentDisposition(cdisp->value);
+ }
+ }
+
+ m_structure = null;
+}
+
+
+shared_ptr <const messageStructure> IMAPMessagePart::getStructure() const {
+
+ if (m_structure) {
+ return m_structure;
+ } else {
+ return IMAPMessageStructure::emptyStructure();
+ }
+}
+
+
+shared_ptr <messageStructure> IMAPMessagePart::getStructure() {
+
+ if (m_structure) {
+ return m_structure;
+ } else {
+ return IMAPMessageStructure::emptyStructure();
+ }
+}
+
+
+shared_ptr <const IMAPMessagePart> IMAPMessagePart::getParent() const {
+
+ return m_parent.lock();
+}
+
+
+const mediaType& IMAPMessagePart::getType() const {
+
+ return m_mediaType;
+}
+
+
+const contentDisposition &IMAPMessagePart::getDisposition() const {
+
+ return m_dispType;
+}
+
+
+size_t IMAPMessagePart::getSize() const {
+
+ return m_size;
+}
+
+
+size_t IMAPMessagePart::getNumber() const {
+
+ return m_number;
+}
+
+
+string IMAPMessagePart::getName() const {
+
+ return m_name;
+}
+
+
+shared_ptr <const header> IMAPMessagePart::getHeader() const {
+
+ if (!m_header) {
+ throw exceptions::unfetched_object();
+ } else {
+ return m_header;
+ }
+}
+
+
+// static
+shared_ptr <IMAPMessagePart> IMAPMessagePart::create(
+ const shared_ptr <IMAPMessagePart>& parent,
+ const size_t number,
+ const IMAPParser::body* body
+) {
+
+ if (body->body_type_mpart) {
+
+ auto part = make_shared <IMAPMessagePart>(parent, number, body->body_type_mpart.get());
+ part->m_structure = make_shared <IMAPMessageStructure>(part, body->body_type_mpart->list);
+
+ return part;
+
+ } else {
+
+ return make_shared <IMAPMessagePart>(parent, number, body->body_type_1part.get());
+ }
+}
+
+
+header& IMAPMessagePart::getOrCreateHeader() {
+
+ if (m_header) {
+ return *m_header;
+ } else {
+ return *(m_header = make_shared <header>());
+ }
+}
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
diff --git a/vmime-master/src/vmime/net/imap/IMAPMessagePart.hpp b/vmime-master/src/vmime/net/imap/IMAPMessagePart.hpp
new file mode 100644
index 0000000..34ea172
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPMessagePart.hpp
@@ -0,0 +1,108 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_IMAP_IMAPMESSAGEPART_HPP_INCLUDED
+#define VMIME_NET_IMAP_IMAPMESSAGEPART_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/net/message.hpp"
+
+#include "vmime/net/imap/IMAPParser.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+class IMAPMessageStructure;
+
+
+class VMIME_EXPORT IMAPMessagePart : public messagePart {
+
+public:
+
+ IMAPMessagePart(
+ const shared_ptr <IMAPMessagePart>& parent,
+ const size_t number,
+ const IMAPParser::body_type_mpart* mpart
+ );
+
+ IMAPMessagePart(
+ const shared_ptr <IMAPMessagePart>& parent,
+ const size_t number,
+ const IMAPParser::body_type_1part* part
+ );
+
+ shared_ptr <const messageStructure> getStructure() const;
+ shared_ptr <messageStructure> getStructure();
+
+ shared_ptr <const IMAPMessagePart> getParent() const;
+
+ const mediaType& getType() const;
+ const contentDisposition &getDisposition() const;
+ size_t getSize() const;
+ size_t getNumber() const;
+ string getName() const;
+
+ shared_ptr <const header> getHeader() const;
+
+
+ static shared_ptr <IMAPMessagePart> create(
+ const shared_ptr <IMAPMessagePart>& parent,
+ const size_t number,
+ const IMAPParser::body* body
+ );
+
+
+ header& getOrCreateHeader();
+
+private:
+
+ shared_ptr <IMAPMessageStructure> m_structure;
+ weak_ptr <IMAPMessagePart> m_parent;
+ shared_ptr <header> m_header;
+
+ size_t m_number;
+ size_t m_size;
+ string m_name;
+ mediaType m_mediaType;
+ contentDisposition m_dispType;
+};
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+#endif // VMIME_NET_IMAP_IMAPMESSAGEPART_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/imap/IMAPMessagePartContentHandler.cpp b/vmime-master/src/vmime/net/imap/IMAPMessagePartContentHandler.cpp
new file mode 100644
index 0000000..85f6cb6
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPMessagePartContentHandler.cpp
@@ -0,0 +1,227 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/net/imap/IMAPMessagePartContentHandler.hpp"
+#include "vmime/net/imap/IMAPFolder.hpp"
+#include "vmime/net/imap/IMAPConnection.hpp"
+#include "vmime/net/imap/IMAPFolderStatus.hpp"
+#include "vmime/net/imap/IMAPStore.hpp"
+
+#include "vmime/utility/outputStreamAdapter.hpp"
+#include "vmime/utility/inputStreamStringAdapter.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+IMAPMessagePartContentHandler::IMAPMessagePartContentHandler(
+ const shared_ptr <IMAPMessage>& msg,
+ const shared_ptr <messagePart>& part,
+ const vmime::encoding& encoding
+)
+ : m_message(msg),
+ m_part(part),
+ m_encoding(encoding) {
+
+}
+
+
+shared_ptr <contentHandler> IMAPMessagePartContentHandler::clone() const {
+
+ return make_shared <IMAPMessagePartContentHandler>(
+ m_message.lock(), m_part.lock(), m_encoding
+ );
+}
+
+
+void IMAPMessagePartContentHandler::generate(
+ utility::outputStream& os,
+ const vmime::encoding& enc,
+ const size_t maxLineLength
+) const {
+
+ shared_ptr <IMAPMessage> msg = m_message.lock();
+ shared_ptr <messagePart> part = m_part.lock();
+
+ // Data is already encoded
+ if (isEncoded()) {
+
+ // The data is already encoded but the encoding specified for
+ // the generation is different from the current one. We need
+ // to re-encode data: decode from input buffer to temporary
+ // buffer, and then re-encode to output stream...
+ if (m_encoding != enc) {
+
+ // Extract part contents to temporary buffer
+ std::ostringstream oss;
+ utility::outputStreamAdapter tmp(oss);
+
+ msg->extractPart(part, tmp, NULL);
+
+ // Decode to another temporary buffer
+ utility::inputStreamStringAdapter in(oss.str());
+
+ std::ostringstream oss2;
+ utility::outputStreamAdapter tmp2(oss2);
+
+ shared_ptr <utility::encoder::encoder> theDecoder = m_encoding.getEncoder();
+ theDecoder->decode(in, tmp2);
+
+ // Reencode to output stream
+ string str = oss2.str();
+ utility::inputStreamStringAdapter tempIn(str);
+
+ shared_ptr <utility::encoder::encoder> theEncoder = enc.getEncoder();
+ theEncoder->getProperties()["maxlinelength"] = maxLineLength;
+ theEncoder->getProperties()["text"] = (m_contentType.getType() == mediaTypes::TEXT);
+
+ theEncoder->encode(tempIn, os);
+
+ // No encoding to perform
+ } else {
+
+ msg->extractPart(part, os);
+ }
+
+ // Need to encode data before
+ } else {
+
+ // Extract part contents to temporary buffer
+ std::ostringstream oss;
+ utility::outputStreamAdapter tmp(oss);
+
+ msg->extractPart(part, tmp, NULL);
+
+ // Encode temporary buffer to output stream
+ shared_ptr <utility::encoder::encoder> theEncoder = enc.getEncoder();
+ theEncoder->getProperties()["maxlinelength"] = maxLineLength;
+ theEncoder->getProperties()["text"] = (m_contentType.getType() == mediaTypes::TEXT);
+
+ utility::inputStreamStringAdapter is(oss.str());
+
+ theEncoder->encode(is, os);
+ }
+}
+
+
+void IMAPMessagePartContentHandler::extract(
+ utility::outputStream& os,
+ utility::progressListener* progress
+) const {
+
+ shared_ptr <IMAPMessage> msg = m_message.lock();
+ shared_ptr <messagePart> part = m_part.lock();
+
+ // No decoding to perform
+ if (!isEncoded()) {
+
+ msg->extractImpl(part, os, progress, 0, -1, IMAPMessage::EXTRACT_BODY);
+
+ // Need to decode data
+ } else {
+
+ // Extract part contents to temporary buffer
+ std::ostringstream oss;
+ utility::outputStreamAdapter tmp(oss);
+
+ msg->extractImpl(part, tmp, NULL, 0, -1, IMAPMessage::EXTRACT_BODY);
+
+ // Encode temporary buffer to output stream
+ utility::inputStreamStringAdapter is(oss.str());
+ utility::progressListenerSizeAdapter plsa(progress, getLength());
+
+ shared_ptr <utility::encoder::encoder> theDecoder = m_encoding.getEncoder();
+ theDecoder->decode(is, os, &plsa);
+ }
+}
+
+
+void IMAPMessagePartContentHandler::extractRaw(
+ utility::outputStream& os,
+ utility::progressListener* progress
+) const {
+
+ shared_ptr <IMAPMessage> msg = m_message.lock();
+ shared_ptr <messagePart> part = m_part.lock();
+
+ msg->extractPart(part, os, progress);
+}
+
+
+size_t IMAPMessagePartContentHandler::getLength() const {
+
+ return m_part.lock()->getSize();
+}
+
+
+bool IMAPMessagePartContentHandler::isEncoded() const {
+
+ return m_encoding != NO_ENCODING;
+}
+
+
+const vmime::encoding& IMAPMessagePartContentHandler::getEncoding() const {
+
+ return m_encoding;
+}
+
+
+bool IMAPMessagePartContentHandler::isEmpty() const {
+
+ return getLength() == 0;
+}
+
+
+bool IMAPMessagePartContentHandler::isBuffered() const {
+
+ return true;
+}
+
+
+void IMAPMessagePartContentHandler::setContentTypeHint(const mediaType& type) {
+
+ m_contentType = type;
+}
+
+
+const mediaType IMAPMessagePartContentHandler::getContentTypeHint() const {
+
+ return m_contentType;
+}
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
diff --git a/vmime-master/src/vmime/net/imap/IMAPMessagePartContentHandler.hpp b/vmime-master/src/vmime/net/imap/IMAPMessagePartContentHandler.hpp
new file mode 100644
index 0000000..17f53e3
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPMessagePartContentHandler.hpp
@@ -0,0 +1,95 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_IMAP_IMAPMESSAGEPARTCONTENTHANDLER_HPP_INCLUDED
+#define VMIME_NET_IMAP_IMAPMESSAGEPARTCONTENTHANDLER_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/contentHandler.hpp"
+#include "vmime/net/imap/IMAPMessage.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+class VMIME_EXPORT IMAPMessagePartContentHandler : public contentHandler {
+
+public:
+
+ IMAPMessagePartContentHandler(
+ const shared_ptr <IMAPMessage>& msg,
+ const shared_ptr <messagePart>& part,
+ const vmime::encoding& encoding
+ );
+
+ shared_ptr <contentHandler> clone() const;
+
+ void generate(
+ utility::outputStream& os,
+ const vmime::encoding& enc,
+ const size_t maxLineLength = lineLengthLimits::infinite
+ ) const;
+
+ void extract(utility::outputStream& os, utility::progressListener* progress = NULL) const;
+ void extractRaw(utility::outputStream& os, utility::progressListener* progress = NULL) const;
+
+ size_t getLength() const;
+
+ bool isEncoded() const;
+
+ const vmime::encoding& getEncoding() const;
+
+ bool isEmpty() const;
+
+ bool isBuffered() const;
+
+ void setContentTypeHint(const mediaType& type);
+ const mediaType getContentTypeHint() const;
+
+private:
+
+ weak_ptr <IMAPMessage> m_message;
+ weak_ptr <messagePart> m_part;
+
+ vmime::encoding m_encoding;
+ vmime::mediaType m_contentType;
+};
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+#endif // VMIME_NET_IMAP_IMAPMESSAGEPARTCONTENTHANDLER_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/imap/IMAPMessageStructure.cpp b/vmime-master/src/vmime/net/imap/IMAPMessageStructure.cpp
new file mode 100644
index 0000000..c7ee809
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPMessageStructure.cpp
@@ -0,0 +1,94 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/net/imap/IMAPMessageStructure.hpp"
+#include "vmime/net/imap/IMAPMessagePart.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+IMAPMessageStructure::IMAPMessageStructure() {
+}
+
+
+IMAPMessageStructure::IMAPMessageStructure(const IMAPParser::body* body) {
+
+ m_parts.push_back(IMAPMessagePart::create(null, 0, body));
+}
+
+
+IMAPMessageStructure::IMAPMessageStructure(
+ const shared_ptr <IMAPMessagePart>& parent,
+ const std::vector <std::unique_ptr <IMAPParser::body>>& list
+) {
+
+ size_t number = 0;
+
+ for (auto it = list.begin() ; it != list.end() ; ++it, ++number) {
+ m_parts.push_back(IMAPMessagePart::create(parent, number, it->get()));
+ }
+}
+
+
+shared_ptr <const messagePart> IMAPMessageStructure::getPartAt(const size_t x) const {
+
+ return m_parts[x];
+}
+
+
+shared_ptr <messagePart> IMAPMessageStructure::getPartAt(const size_t x) {
+
+ return m_parts[x];
+}
+
+
+size_t IMAPMessageStructure::getPartCount() const {
+
+ return m_parts.size();
+}
+
+
+// static
+shared_ptr <IMAPMessageStructure> IMAPMessageStructure::emptyStructure() {
+
+ static shared_ptr <IMAPMessageStructure> emptyStructure = make_shared <IMAPMessageStructure>();
+ return emptyStructure;
+}
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
diff --git a/vmime-master/src/vmime/net/imap/IMAPMessageStructure.hpp b/vmime-master/src/vmime/net/imap/IMAPMessageStructure.hpp
new file mode 100644
index 0000000..ee1eac4
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPMessageStructure.hpp
@@ -0,0 +1,75 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_IMAP_IMAPMESSAGESTRUCTURE_HPP_INCLUDED
+#define VMIME_NET_IMAP_IMAPMESSAGESTRUCTURE_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/net/message.hpp"
+
+#include "vmime/net/imap/IMAPParser.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+class IMAPMessagePart;
+
+
+class VMIME_EXPORT IMAPMessageStructure : public messageStructure {
+
+public:
+
+ IMAPMessageStructure();
+ IMAPMessageStructure(const IMAPParser::body* body);
+ IMAPMessageStructure(const shared_ptr <IMAPMessagePart>& parent, const std::vector <std::unique_ptr <IMAPParser::body>>& list);
+
+ shared_ptr <const messagePart> getPartAt(const size_t x) const;
+ shared_ptr <messagePart> getPartAt(const size_t x);
+ size_t getPartCount() const;
+
+ static shared_ptr <IMAPMessageStructure> emptyStructure();
+
+private:
+
+ std::vector <shared_ptr <IMAPMessagePart> > m_parts;
+};
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+#endif // VMIME_NET_IMAP_IMAPMESSAGESTRUCTURE_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/imap/IMAPParser.hpp b/vmime-master/src/vmime/net/imap/IMAPParser.hpp
new file mode 100644
index 0000000..281fcb6
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPParser.hpp
@@ -0,0 +1,4986 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_IMAP_IMAPPARSER_HPP_INCLUDED
+#define VMIME_NET_IMAP_IMAPPARSER_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/base.hpp"
+#include "vmime/dateTime.hpp"
+#include "vmime/charset.hpp"
+#include "vmime/exception.hpp"
+
+#include "vmime/utility/stringUtils.hpp"
+#include "vmime/utility/progressListener.hpp"
+
+#include "vmime/utility/encoder/b64Encoder.hpp"
+#include "vmime/utility/encoder/qpEncoder.hpp"
+
+#include "vmime/utility/inputStreamStringAdapter.hpp"
+#include "vmime/utility/outputStreamStringAdapter.hpp"
+
+#include "vmime/platform.hpp"
+
+#include "vmime/net/timeoutHandler.hpp"
+#include "vmime/net/socket.hpp"
+#include "vmime/net/tracer.hpp"
+
+#include "vmime/net/imap/IMAPTag.hpp"
+
+#include <vector>
+#include <stdexcept>
+#include <memory>
+
+
+//#define DEBUG_RESPONSE 1
+
+
+#if DEBUG_RESPONSE
+# include <iostream>
+#endif
+
+
+/** Make the parsing of a component fail.
+ */
+#define VIMAP_PARSER_FAIL() \
+ { \
+ parser.m_errorResponseLine = makeResponseLine(getComponentName(), line, pos); \
+ return false; \
+ }
+
+/** Make the parsing of a component fail if a condition is not matched.
+ * If the specified expression does not resolve to "true", the parsing
+ * will fail.
+ *
+ * @param cond condition expression
+ */
+#define VIMAP_PARSER_FAIL_UNLESS(cond) \
+ if (!(cond)) \
+ { \
+ VIMAP_PARSER_FAIL(); \
+ }
+
+/** Check for a token and advance.
+ * If the token is not matched, parsing will fail.
+ *
+ * @param type token class
+ */
+#define VIMAP_PARSER_CHECK(type) \
+ VIMAP_PARSER_FAIL_UNLESS(parser.check <type>(line, &pos))
+
+/** Check for an optional token and advance.
+ * If the token is not matched, parsing will continue anyway.
+ *
+ * @param type token class
+ */
+#define VIMAP_PARSER_TRY_CHECK(type) \
+ (parser.check <type>(line, &pos))
+
+/** Get a token and advance.
+ * If the token is not matched, parsing will fail.
+ *
+ * @param type token class
+ * @param variable variable which will receive pointer to the retrieved token
+ */
+#define VIMAP_PARSER_GET(type, variable) \
+ { \
+ variable.reset(parser.get <type>(line, &pos)); \
+ VIMAP_PARSER_FAIL_UNLESS(variable.get()); \
+ }
+
+/** Get an optional token and advance.
+ * If the token is not matched, parsing will continue anyway.
+ */
+#define VIMAP_PARSER_TRY_GET(type, variable) \
+ (variable.reset(parser.get <type>(line, &pos)), variable.get())
+
+/** Get an optional token and advance. If found, token will be pushed back
+ * to a vector. If the token is not matched, stopInstr will be executed.
+ *
+ * @param type token class
+ * @param variable variable of type std::vector<> to which the retrieved
+ * token will be pushed
+ * @param stopInstr instruction to execute if token is not found
+ */
+#define VIMAP_PARSER_TRY_GET_PUSHBACK_OR_ELSE(type, variable, stopInstr) \
+ { \
+ std::unique_ptr <type> v; \
+ try \
+ { \
+ v.reset(parser.get <type>(line, &pos)); \
+ if (!v) \
+ { \
+ stopInstr; \
+ } \
+ variable.push_back(std::move(v)); \
+ } \
+ catch (...) \
+ { \
+ throw; \
+ } \
+ }
+
+/** Get a token and advance. Token will be pushed back to a vector.
+ * If the token is not matched, parsing will fail.
+ *
+ * @param type token class
+ * @param variable variable of type std::vector<> to which the retrieved
+ * token will be pushed
+ */
+#define VIMAP_PARSER_GET_PUSHBACK(type, variable) \
+ VIMAP_PARSER_TRY_GET_PUSHBACK_OR_ELSE(type, variable, VIMAP_PARSER_FAIL())
+
+
+/** Check for a token which takes an argument and advance.
+ * If the token is not matched, parsing will fail.
+ *
+ * @param type token class
+ */
+#define VIMAP_PARSER_CHECK_WITHARG(type, arg) \
+ VIMAP_PARSER_FAIL_UNLESS(parser.checkWithArg <type>(line, &pos, arg))
+
+/** Check for an optional token which takes an argument and advance.
+ * If the token is not matched, parsing will continue anyway.
+ *
+ * @param type token class
+ */
+#define VIMAP_PARSER_TRY_CHECK_WITHARG(type, arg) \
+ (parser.checkWithArg <type>(line, &pos, arg))
+
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+#if DEBUG_RESPONSE
+ static int IMAPParserDebugResponse_level = 0;
+ static std::vector <string> IMAPParserDebugResponse_stack;
+
+ class IMAPParserDebugResponse {
+
+ public:
+
+ IMAPParserDebugResponse(
+ const string& name,
+ string& line,
+ const size_t currentPos,
+ const bool &result
+ )
+ : m_name(name),
+ m_line(line),
+ m_pos(currentPos),
+ m_result(result) {
+
+ ++IMAPParserDebugResponse_level;
+ IMAPParserDebugResponse_stack.push_back(name);
+
+ for (int i = 0 ; i < IMAPParserDebugResponse_level ; ++i) {
+ std::cout << " ";
+ }
+
+ std::cout << "ENTER(" << m_name << "), pos=" << m_pos;
+ std::cout << std::endl;
+
+ for (std::vector <string>::iterator it = IMAPParserDebugResponse_stack.begin() ;
+ it != IMAPParserDebugResponse_stack.end() ; ++it) {
+
+ std::cout << "> " << *it << " ";
+ }
+
+ std::cout << std::endl;
+ std::cout << string(m_line.begin() + (m_pos < 30 ? 0U : m_pos - 30),
+ m_line.begin() + std::min(m_line.length(), m_pos + 30)) << std::endl;
+
+ for (size_t i = (m_pos < 30 ? m_pos : (m_pos - (m_pos - 30))) ; i != 0 ; --i) {
+ std::cout << " ";
+ }
+
+ std::cout << "^" << std::endl;
+ }
+
+ ~IMAPParserDebugResponse() {
+
+ for (int i = 0 ; i < IMAPParserDebugResponse_level ; ++i) {
+ std::cout << " ";
+ }
+
+ std::cout << "LEAVE(" << m_name << "), result=";
+ std::cout << (m_result ? "TRUE" : "FALSE") << ", pos=" << m_pos;
+ std::cout << std::endl;
+
+ --IMAPParserDebugResponse_level;
+ IMAPParserDebugResponse_stack.pop_back();
+ }
+
+ private:
+
+ const string m_name;
+ string m_line;
+ size_t m_pos;
+ const bool& m_result;
+ };
+
+
+ #define DEBUG_ENTER_COMPONENT(x, result) \
+ IMAPParserDebugResponse dbg(x, line, *currentPos, result)
+
+ #define DEBUG_FOUND(x, y) \
+ std::cout << "FOUND: " << x << ": " << y << std::endl;
+#else
+ #define DEBUG_ENTER_COMPONENT(x, result)
+ #define DEBUG_FOUND(x, y)
+#endif
+
+
+class VMIME_EXPORT IMAPParser : public object {
+
+public:
+
+ IMAPParser()
+ : m_progress(NULL),
+ m_strict(false),
+ m_literalHandler(NULL) {
+
+ }
+
+ ~IMAPParser() {
+
+ for (auto it = m_pendingResponses.begin() ; it != m_pendingResponses.end() ; ++it) {
+ delete it->second;
+ }
+ }
+
+
+ /** Set the socket currently used by this parser to receive data
+ * from server.
+ *
+ * @param sok socket
+ */
+ void setSocket(const shared_ptr <socket>& sok) {
+
+ m_socket = sok;
+ }
+
+ /** Set the timeout handler currently used by this parser.
+ *
+ * @param toh timeout handler
+ */
+ void setTimeoutHandler(const shared_ptr <timeoutHandler>& toh) {
+
+ m_timeoutHandler = toh;
+ }
+
+ /** Set the tracer currently used by this parser.
+ *
+ * @param tr tracer
+ */
+ void setTracer(const shared_ptr <tracer>& tr) {
+
+ m_tracer = tr;
+ }
+
+ /** Set whether we operate in strict mode (this may not work
+ * with some servers which are not fully standard-compliant).
+ *
+ * @param strict true to operate in strict mode, or false
+ * to operate in default, relaxed mode
+ */
+ void setStrict(const bool strict) {
+
+ m_strict = strict;
+ }
+
+ /** Return true if the parser operates in strict mode, or
+ * false otherwise.
+ *
+ * @return true if we are in strict mode, false otherwise
+ */
+ bool isStrict() const {
+
+ return m_strict;
+ }
+
+
+
+ //
+ // literalHandler : literal content handler
+ //
+
+ class component;
+
+ class literalHandler {
+
+ public:
+
+ virtual ~literalHandler() { }
+
+
+ // Abstract target class
+ class target {
+
+ protected:
+
+ target(utility::progressListener* progress) : m_progress(progress) {}
+ target(const target&) {}
+
+ public:
+
+ virtual ~target() { }
+
+
+ utility::progressListener* progressListener() { return (m_progress); }
+
+ virtual void putData(const string& chunk) = 0;
+
+ virtual size_t getBytesWritten() const = 0;
+
+ private:
+
+ utility::progressListener* m_progress;
+ };
+
+
+ // Target: put in a string
+ class targetString : public target {
+
+ public:
+
+ targetString(utility::progressListener* progress, vmime::string& str)
+ : target(progress), m_string(str), m_bytesWritten(0) { }
+
+ const vmime::string& string() const { return (m_string); }
+ vmime::string& string() { return (m_string); }
+
+
+ void putData(const vmime::string& chunk) {
+
+ m_string += chunk;
+ m_bytesWritten += chunk.length();
+ }
+
+ size_t getBytesWritten() const {
+
+ return m_bytesWritten;
+ }
+
+ private:
+
+ vmime::string& m_string;
+ size_t m_bytesWritten;
+ };
+
+
+ // Target: redirect to an output stream
+ class targetStream : public target {
+
+ public:
+
+ targetStream(
+ utility::progressListener* progress,
+ utility::outputStream& stream
+ )
+ : target(progress),
+ m_stream(stream),
+ m_bytesWritten(0) {
+
+ }
+
+ const utility::outputStream& stream() const { return (m_stream); }
+ utility::outputStream& stream() { return (m_stream); }
+
+
+ void putData(const string& chunk) {
+
+ m_stream.write(chunk.data(), chunk.length());
+ m_bytesWritten += chunk.length();
+ }
+
+ size_t getBytesWritten() const {
+
+ return m_bytesWritten;
+ }
+
+ private:
+
+ utility::outputStream& m_stream;
+ size_t m_bytesWritten;
+ };
+
+
+ // Called when the parser needs to know what to do with a literal
+ // . comp: the component in which we are at this moment
+ // . data: data specific to the component (may not be used)
+ //
+ // Returns :
+ // . == NULL to put the literal into the response
+ // . != NULL to redirect the literal to the specified target
+
+ virtual shared_ptr <target> targetFor(const component& comp, const int data) = 0;
+ };
+
+
+ //
+ // Base class for a terminal or a non-terminal
+ //
+
+ class component {
+
+ public:
+
+ component() { }
+ virtual ~component() { }
+
+ virtual const string getComponentName() const = 0;
+
+ bool parse(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ bool res = false;
+ DEBUG_ENTER_COMPONENT(getComponentName(), res);
+ res = parseImpl(parser, line, currentPos);
+ return res;
+ }
+
+ virtual bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) = 0;
+
+
+ const string makeResponseLine(
+ const string& comp,
+ const string& line,
+ const size_t pos
+ ) {
+
+#if DEBUG_RESPONSE
+ if (pos > line.length()) {
+ std::cout << "WARNING: component::makeResponseLine(): pos > line.length()" << std::endl;
+ }
+#endif
+
+ string result(line.substr(0, pos));
+ result += "[^]"; // indicates current parser position
+ result += line.substr(pos, line.length());
+ if (!comp.empty()) result += " [" + comp + "]";
+
+ return (result);
+ }
+ };
+
+
+#define COMPONENT_ALIAS(parent, name) \
+ class name : public parent { \
+ virtual const string getComponentName() const { return #name; } \
+ public: \
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) { \
+ return parent::parseImpl(parser, line, currentPos); \
+ } \
+ }
+
+#define DECLARE_COMPONENT(name) \
+ class name : public component { \
+ virtual const string getComponentName() const { return #name; } \
+ public:
+
+
+ //
+ // Parse one character
+ //
+
+ template <char C>
+ class one_char : public component {
+
+ public:
+
+ const string getComponentName() const {
+
+ return string("one_char <") + C + ">";
+ }
+
+ bool parseImpl(IMAPParser& /* parser */, string& line, size_t* currentPos) {
+
+ const size_t pos = *currentPos;
+
+ if (pos < line.length() && line[pos] == C) {
+ *currentPos = pos + 1;
+ return true;
+ } else {
+ return false;
+ }
+ }
+ };
+
+
+ //
+ // SPACE ::= <ASCII SP, space, 0x20>
+ //
+
+ DECLARE_COMPONENT(SPACE)
+
+ bool parseImpl(IMAPParser& /* parser */, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ while (pos < line.length() && (line[pos] == ' ' || line[pos] == '\t')) {
+ ++pos;
+ }
+
+ if (pos > *currentPos) {
+ *currentPos = pos;
+ return true;
+ } else {
+ return false;
+ }
+ }
+ };
+
+
+ //
+ // CR ::= <ASCII CR, carriage return, 0x0D>
+ // LF ::= <ASCII LF, line feed, 0x0A>
+ // CRLF ::= CR LF
+ //
+
+ DECLARE_COMPONENT(CRLF)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_TRY_CHECK(SPACE);
+
+ if (pos + 1 < line.length() &&
+ line[pos] == 0x0d && line[pos + 1] == 0x0a) {
+
+ *currentPos = pos + 2;
+ return true;
+
+ } else {
+
+ return false;
+ }
+ }
+ };
+
+
+ //
+ // SPACE ::= <ASCII SP, space, 0x20>
+ // CTL ::= <any ASCII control character and DEL, 0x00 - 0x1f, 0x7f>
+ // CHAR ::= <any 7-bit US-ASCII character except NUL, 0x01 - 0x7f>
+ // ATOM_CHAR ::= <any CHAR except atom_specials>
+ // atom_specials ::= "(" / ")" / "{" / SPACE / CTL / list_wildcards / quoted_specials
+ // list_wildcards ::= "%" / "*"
+ // quoted_specials ::= <"> / "\"
+ //
+ // tag ::= 1*<any ATOM_CHAR except "+"> (named "xtag")
+ //
+
+ DECLARE_COMPONENT(xtag)
+
+ bool parseImpl(IMAPParser& /* parser */, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ bool end = false;
+
+ tagString.reserve(10);
+
+ while (!end && pos < line.length()) {
+
+ const unsigned char c = line[pos];
+
+ switch (c) {
+
+ case '+':
+ case '(':
+ case ')':
+ case '{':
+ case 0x20: // SPACE
+ case '%': // list_wildcards
+ case '*': // list_wildcards
+ case '"': // quoted_specials
+ case '\\': // quoted_specials
+
+ end = true;
+ break;
+
+ default:
+
+ if (c <= 0x1f || c >= 0x7f) {
+ end = true;
+ } else {
+ tagString += c;
+ ++pos;
+ }
+
+ break;
+ }
+ }
+
+ *currentPos = pos;
+ return true;
+ }
+
+ string tagString;
+ };
+
+
+ //
+ // digit ::= "0" / digit_nz
+ // digit_nz ::= "1" / "2" / "3" / "4" / "5" / "6" / "7" / "8" / "9"
+ //
+ // number ::= 1*digit
+ // ;; Unsigned 32-bit integer
+ // ;; (0 <= n < 4,294,967,296)
+ //
+
+ DECLARE_COMPONENT(number)
+
+ number(const bool nonZero = false)
+ : value(0),
+ m_nonZero(nonZero) {
+
+ }
+
+ bool parseImpl(IMAPParser& /* parser */, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ bool valid = true;
+ unsigned int val = 0;
+
+ while (valid && pos < line.length()) {
+
+ const char c = line[pos];
+
+ if (c >= '0' && c <= '9') {
+ val = (val * 10) + (c - '0');
+ ++pos;
+ } else {
+ valid = false;
+ }
+ }
+
+ // Check for non-null length (and for non-zero number)
+ if (!(m_nonZero && val == 0) && pos != *currentPos) {
+ value = val;
+ *currentPos = pos;
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+
+ unsigned long value;
+
+ private:
+
+ const bool m_nonZero;
+ };
+
+
+ // nz_number ::= digit_nz *digit
+ // ;; Non-zero unsigned 32-bit integer
+ // ;; (0 < n < 4,294,967,296)
+ //
+
+ class nz_number : public number {
+
+ public:
+
+ nz_number()
+ : number(true) {
+
+ }
+ };
+
+
+ //
+ // uniqueid ::= nz_number
+ // ;; Strictly ascending
+ //
+
+ class uniqueid : public nz_number {
+
+ public:
+
+ uniqueid()
+ : nz_number() {
+
+ }
+ };
+
+
+ // uid-range = (uniqueid ":" uniqueid)
+ // ; two uniqueid values and all values
+ // ; between these two regards of order.
+ // ; Example: 2:4 and 4:2 are equivalent.
+
+ DECLARE_COMPONENT(uid_range)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_GET(uniqueid, uniqueid1);
+ VIMAP_PARSER_CHECK(one_char <':'>);
+ VIMAP_PARSER_GET(uniqueid, uniqueid2);
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <uniqueid> uniqueid1;
+ std::unique_ptr <uniqueid> uniqueid2;
+ };
+
+
+ //
+ // uid-set = (uniqueid / uid-range) *("," uid-set)
+ //
+
+ DECLARE_COMPONENT(uid_set)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ // We have either a 'uid_range' or a 'uniqueid'
+ if (!VIMAP_PARSER_TRY_GET(IMAPParser::uid_range, uid_range)) {
+ VIMAP_PARSER_GET(IMAPParser::uniqueid, uniqueid);
+ }
+
+ // And maybe another 'uid-set' following
+ if (VIMAP_PARSER_TRY_CHECK(one_char <','>)) {
+ VIMAP_PARSER_GET(IMAPParser::uid_set, next_uid_set);
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::uniqueid> uniqueid;
+ std::unique_ptr <IMAPParser::uid_range> uid_range;
+
+ std::unique_ptr <IMAPParser::uid_set> next_uid_set;
+ };
+
+
+ //
+ // text ::= 1*TEXT_CHAR
+ //
+ // CHAR ::= <any 7-bit US-ASCII character except NUL, 0x01 - 0x7f>
+ // TEXT_CHAR ::= <any CHAR except CR and LF>
+ //
+
+ DECLARE_COMPONENT(text)
+
+ text(bool allow8bits = false, const char except = 0)
+ : m_allow8bits(allow8bits),
+ m_except(except) {
+ }
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+ size_t len = 0;
+
+ if (m_allow8bits || !parser.isStrict()) {
+
+ const unsigned char except = m_except;
+
+ for (bool end = false ; !end && pos < line.length() ; ) {
+
+ const unsigned char c = line[pos];
+
+ if (c == 0x00 || c == 0x0d || c == 0x0a || c == except) {
+ end = true;
+ } else {
+ ++pos;
+ ++len;
+ }
+ }
+
+ } else {
+
+ const unsigned char except = m_except;
+
+ for (bool end = false ; !end && pos < line.length() ; ) {
+
+ const unsigned char c = line[pos];
+
+ if (c < 0x01 || c > 0x7f || c == 0x0d || c == 0x0a || c == except) {
+ end = true;
+ } else {
+ ++pos;
+ ++len;
+ }
+ }
+ }
+
+ if (len == 0) {
+ VIMAP_PARSER_FAIL();
+ }
+
+ value.resize(len);
+ std::copy(line.begin() + *currentPos, line.begin() + pos, value.begin());
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ string value;
+
+ private:
+
+ const bool m_allow8bits;
+ const char m_except;
+ };
+
+
+ class text8 : public text {
+
+ public:
+
+ text8() : text(true) {
+
+ }
+ };
+
+
+ template <char C>
+ class text_except : public text {
+
+ public:
+
+ text_except() : text(false, C) {
+
+ }
+ };
+
+
+ template <char C>
+ class text8_except : public text {
+
+ public:
+
+ text8_except() : text(true, C) {
+
+ }
+ };
+
+
+ //
+ // QUOTED_CHAR ::= <any TEXT_CHAR except quoted_specials> / "\" quoted_specials
+ // quoted_specials ::= <"> / "\"
+ // TEXT_CHAR ::= <any CHAR except CR and LF>
+ // CHAR ::= <any 7-bit US-ASCII character except NUL, 0x01 - 0x7f>
+ //
+
+ DECLARE_COMPONENT(QUOTED_CHAR)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ const unsigned char c = static_cast <unsigned char>(pos < line.length() ? line[pos] : 0);
+
+ if (c >= 0x01 && c <= 0x7f && // 0x01 - 0x7f
+ c != '"' && c != '\\' && // quoted_specials
+ c != '\r' && c != '\n') { // CR and LF
+
+ value = c;
+ *currentPos = pos + 1;
+
+ } else if (c == '\\' && pos + 1 < line.length() &&
+ (line[pos + 1] == '"' || line[pos + 1] == '\\')) {
+
+ value = line[pos + 1];
+ *currentPos = pos + 2;
+
+ } else {
+
+ VIMAP_PARSER_FAIL();
+ }
+
+ return true;
+ }
+
+
+ char value;
+ };
+
+
+ //
+ // quoted ::= <"> *QUOTED_CHAR <">
+ // QUOTED_CHAR ::= <any TEXT_CHAR except quoted_specials> / "\" quoted_specials
+ // quoted_specials ::= <"> / "\"
+ // TEXT_CHAR ::= <any CHAR except CR and LF>
+ // CHAR ::= <any 7-bit US-ASCII character except NUL, 0x01 - 0x7f>
+ //
+
+ DECLARE_COMPONENT(quoted_text)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+ size_t len = 0;
+ bool valid = false;
+
+ value.reserve(line.length() - pos);
+
+ for (bool end = false, quoted = false ; !end && pos < line.length() ; ) {
+
+ const unsigned char c = line[pos];
+
+ if (quoted) {
+
+ if (c == '"' || c == '\\') {
+ value += c;
+ } else {
+ value += '\\';
+ value += c;
+ }
+
+ quoted = false;
+
+ ++pos;
+ ++len;
+
+ } else {
+
+ if (c == '\\') {
+
+ quoted = true;
+
+ ++pos;
+ ++len;
+
+ } else if (c == '"') {
+
+ valid = true;
+ end = true;
+
+ } else if (c >= 0x01 && c <= 0x7f && // CHAR
+ c != 0x0a && c != 0x0d) { // CR and LF
+
+ value += c;
+
+ ++pos;
+ ++len;
+
+ } else {
+
+ valid = false;
+ end = true;
+ }
+ }
+ }
+
+ if (!valid) {
+ VIMAP_PARSER_FAIL();
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ string value;
+ };
+
+
+ //
+ // nil ::= "NIL"
+ //
+
+ DECLARE_COMPONENT(NIL)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_CHECK_WITHARG(special_atom, "nil");
+
+ *currentPos = pos;
+
+ return true;
+ }
+ };
+
+
+ //
+ // string ::= quoted / literal ----> named 'xstring'
+ //
+ // nil ::= "NIL"
+ // quoted ::= <"> *QUOTED_CHAR <">
+ // QUOTED_CHAR ::= <any TEXT_CHAR except quoted_specials> / "\" quoted_specials
+ // quoted_specials ::= <"> / "\"
+ // TEXT_CHAR ::= <any CHAR except CR and LF>
+ // CHAR ::= <any 7-bit US-ASCII character except NUL, 0x01 - 0x7f>
+ // literal ::= "{" number "}" CRLF *CHAR8
+ // ;; Number represents the number of CHAR8 octets
+ // CHAR8 ::= <any 8-bit octet except NUL, 0x01 - 0xff>
+ //
+
+ DECLARE_COMPONENT(xstring)
+
+ xstring(
+ const bool canBeNIL = false,
+ component* comp = NULL,
+ const int data = 0
+ )
+ : isNIL(true),
+ m_canBeNIL(canBeNIL),
+ m_component(comp),
+ m_data(data) {
+
+ }
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ if (m_canBeNIL &&
+ VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "nil")) {
+
+ // NIL
+ isNIL = true;
+
+ } else {
+
+ pos = *currentPos;
+
+ isNIL = false;
+
+ // quoted ::= <"> *QUOTED_CHAR <">
+ if (VIMAP_PARSER_TRY_CHECK(one_char <'"'>)) {
+
+ shared_ptr <quoted_text> text;
+ VIMAP_PARSER_GET(quoted_text, text);
+ VIMAP_PARSER_CHECK(one_char <'"'>);
+
+ if (parser.m_literalHandler != NULL) {
+
+ shared_ptr <literalHandler::target> target =
+ parser.m_literalHandler->targetFor(*m_component, m_data);
+
+ if (target != NULL) {
+
+ value = "[literal-handler]";
+
+ const size_t length = text->value.length();
+ utility::progressListener* progress = target->progressListener();
+
+ if (progress) {
+ progress->start(length);
+ }
+
+ target->putData(text->value);
+
+ if (progress) {
+ progress->progress(length, length);
+ progress->stop(length);
+ }
+
+ } else {
+
+ value = text->value;
+ }
+
+ } else {
+
+ value = text->value;
+ }
+
+ DEBUG_FOUND("string[quoted]", "<length=" << value.length() << ", value='" << value << "'>");
+
+ // literal ::= "{" number "}" CRLF *CHAR8
+ } else {
+
+ VIMAP_PARSER_CHECK(one_char <'{'>);
+
+ shared_ptr <number> num;
+ VIMAP_PARSER_GET(number, num);
+
+ const size_t length = num->value;
+
+ VIMAP_PARSER_CHECK(one_char <'}'> );
+
+ VIMAP_PARSER_CHECK(CRLF);
+
+
+ if (parser.m_literalHandler != NULL) {
+
+ shared_ptr <literalHandler::target> target =
+ parser.m_literalHandler->targetFor(*m_component, m_data);
+
+ if (target != NULL) {
+
+ value = "[literal-handler]";
+
+ parser.m_progress = target->progressListener();
+ parser.readLiteral(*target, length);
+ parser.m_progress = NULL;
+
+ } else {
+
+ literalHandler::targetString target(NULL, value);
+ parser.readLiteral(target, length);
+ }
+
+ } else {
+
+ literalHandler::targetString target(NULL, value);
+ parser.readLiteral(target, length);
+ }
+
+ line += parser.readLine();
+
+ DEBUG_FOUND("string[literal]", "<length=" << length << ", value='" << value << "'>");
+ }
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ bool isNIL;
+ string value;
+
+ private:
+
+ bool m_canBeNIL;
+
+ component* m_component;
+ const int m_data;
+ };
+
+
+ //
+ // nstring ::= string / nil
+ //
+
+ class nstring : public xstring {
+
+ public:
+
+ const string getComponentName() const {
+
+ return "nstring";
+ }
+
+ nstring(component* comp = NULL, const int data = 0)
+ : xstring(true, comp, data) {
+
+ }
+ };
+
+
+ //
+ // astring ::= atom / string
+ //
+
+ DECLARE_COMPONENT(astring)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ std::unique_ptr <xstring> str;
+ VIMAP_PARSER_TRY_GET(xstring, str);
+
+ if (str) {
+ value = str->value;
+ } else {
+ std::unique_ptr <atom> at;
+ VIMAP_PARSER_GET(atom, at);
+ value = at->value;
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ string value;
+ };
+
+
+ //
+ // atom ::= 1*ATOM_CHAR
+ //
+ // ATOM_CHAR ::= <any CHAR except atom_specials>
+ // atom_specials ::= "(" / ")" / "{" / SPACE / CTL / list_wildcards / quoted_specials
+ // CHAR ::= <any 7-bit US-ASCII character except NUL, 0x01 - 0x7f>
+ // CTL ::= <any ASCII control character and DEL, 0x00 - 0x1f, 0x7f>
+ // list_wildcards ::= "%" / "*"
+ // quoted_specials ::= <"> / "\"
+ // SPACE ::= <ASCII SP, space, 0x20>
+ //
+
+ DECLARE_COMPONENT(atom)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+ size_t len = 0;
+
+ for (bool end = false ; !end && pos < line.length() ; ) {
+
+ const unsigned char c = line[pos];
+
+ switch (c) {
+
+ case '(':
+ case ')':
+ case '{':
+ case 0x20: // SPACE
+ case '%': // list_wildcards
+ case '*': // list_wildcards
+ case '"': // quoted_specials
+ case '\\': // quoted_specials
+
+ case '[':
+ case ']': // for "special_atom"
+
+ end = true;
+ break;
+
+ default:
+
+ if (c <= 0x1f || c >= 0x7f) {
+ end = true;
+ } else {
+ ++pos;
+ ++len;
+ }
+ }
+ }
+
+ if (len != 0) {
+
+ value.resize(len);
+ std::copy(line.begin() + *currentPos, line.begin() + pos, value.begin());
+
+ *currentPos = pos;
+
+ } else {
+
+ VIMAP_PARSER_FAIL();
+ }
+
+ return true;
+ }
+
+
+ string value;
+ };
+
+
+ //
+ // special atom (eg. "CAPABILITY", "FLAGS", "STATUS"...)
+ //
+ // " Except as noted otherwise, all alphabetic characters are case-
+ // insensitive. The use of upper or lower case characters to define
+ // token strings is for editorial clarity only. Implementations MUST
+ // accept these strings in a case-insensitive fashion. "
+ //
+
+ class special_atom : public atom {
+
+ public:
+
+ const std::string getComponentName() const {
+
+ return string("special_atom <") + m_string + ">";
+ }
+
+ special_atom(const char* str)
+ : m_string(str) { // 'string' must be in lower-case
+
+ }
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ if (!atom::parseImpl(parser, line, &pos)) {
+ return false;
+ }
+
+ const char* cmp = value.c_str();
+ const char* with = m_string;
+
+ bool ok = true;
+
+ while (ok && *cmp && *with) {
+
+ ok = (std::tolower(*cmp, std::locale()) == *with);
+
+ ++cmp;
+ ++with;
+ }
+
+ if (!ok || *cmp || *with) {
+ VIMAP_PARSER_FAIL();
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+ private:
+
+ const char* m_string;
+ };
+
+
+ //
+ // text_mime2 ::= "=?" <charset> "?" <encoding> "?" <encoded-text> "?="
+ // ;; Syntax defined in [MIME-HDRS]
+ //
+
+ DECLARE_COMPONENT(text_mime2)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ std::unique_ptr <atom> theCharset, theEncoding;
+ std::unique_ptr <text> theText;
+
+ VIMAP_PARSER_CHECK(one_char <'='> );
+ VIMAP_PARSER_CHECK(one_char <'?'> );
+
+ VIMAP_PARSER_GET(atom, theCharset);
+
+ VIMAP_PARSER_CHECK(one_char <'?'> );
+
+ VIMAP_PARSER_GET(atom, theEncoding);
+
+ VIMAP_PARSER_CHECK(one_char <'?'> );
+
+ VIMAP_PARSER_GET(text8_except <'?'> , theText);
+
+ VIMAP_PARSER_CHECK(one_char <'?'> );
+ VIMAP_PARSER_CHECK(one_char <'='> );
+
+ charset = theCharset->value;
+
+ // Decode text
+ scoped_ptr <utility::encoder::encoder> theEncoder;
+
+ if (theEncoding->value[0] == 'q' || theEncoding->value[0] == 'Q') {
+
+ // Quoted-printable
+ theEncoder.reset(new utility::encoder::qpEncoder());
+ theEncoder->getProperties()["rfc2047"] = true;
+
+ } else if (theEncoding->value[0] == 'b' || theEncoding->value[0] == 'B') {
+
+ // Base64
+ theEncoder.reset(new utility::encoder::b64Encoder());
+ }
+
+ if (theEncoder.get()) {
+
+ utility::inputStreamStringAdapter in(theText->value);
+ utility::outputStreamStringAdapter out(value);
+
+ theEncoder->decode(in, out);
+
+ // No decoder available
+ } else {
+
+ value = theText->value;
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ vmime::charset charset;
+ string value;
+ };
+
+
+ // seq-number = nz-number / "*"
+ // ; message sequence number (COPY, FETCH, STORE
+ // ; commands) or unique identifier (UID COPY,
+ // ; UID FETCH, UID STORE commands).
+
+ DECLARE_COMPONENT(seq_number)
+
+ seq_number()
+ : star(false) {
+
+ }
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ if (VIMAP_PARSER_TRY_CHECK(one_char <'*'> )) {
+
+ star = true;
+ number.reset();
+
+ } else {
+
+ star = false;
+ VIMAP_PARSER_GET(IMAPParser::number, number);
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::number> number;
+ bool star;
+ };
+
+
+ // seq-range = seq-number ":" seq-number
+ // ; two seq-number values and all values between
+ // ; these two regardless of order.
+ // ; Example: 2:4 and 4:2 are equivalent and indicate
+ // ; values 2, 3, and 4.
+
+ DECLARE_COMPONENT(seq_range)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_GET(seq_number, first);
+
+ VIMAP_PARSER_CHECK(one_char <'*'> );
+
+ VIMAP_PARSER_GET(seq_number, last);
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::seq_number> first;
+ std::unique_ptr <IMAPParser::seq_number> last;
+ };
+
+
+ // sequence-set = (seq-number / seq-range) *("," sequence-set)
+ // ; set of seq-number values, regardless of order.
+ // ; Servers MAY coalesce overlaps and/or execute the
+ // ; sequence in any order.
+ // ; Example: a message sequence number set of
+ // ; 2,4:7,9,12:* for a mailbox with 15 messages is
+ // ; equivalent to 2,4,5,6,7,9,12,13,14,15
+
+ DECLARE_COMPONENT(sequence_set)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ if (!VIMAP_PARSER_TRY_GET(IMAPParser::seq_range, range)) {
+ VIMAP_PARSER_GET(IMAPParser::seq_number, number);
+ }
+
+ if (VIMAP_PARSER_TRY_CHECK(one_char <','> )) {
+ VIMAP_PARSER_GET(sequence_set, nextSet);
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::seq_number> number;
+ std::unique_ptr <IMAPParser::seq_range> range;
+ std::unique_ptr <IMAPParser::sequence_set> nextSet;
+ };
+
+
+ // mod-sequence-value = 1*DIGIT
+ // ;; Positive unsigned 64-bit integer
+ // ;; (mod-sequence)
+ // ;; (1 <= n < 18,446,744,073,709,551,615)
+
+ DECLARE_COMPONENT(mod_sequence_value)
+
+ mod_sequence_value()
+ : value(0) {
+
+ }
+
+ bool parseImpl(IMAPParser& /* parser */, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ bool valid = true;
+ vmime_uint64 val = 0;
+
+ while (valid && pos < line.length()) {
+
+ const char c = line[pos];
+
+ if (c >= '0' && c <= '9') {
+ val = (val * 10) + (c - '0');
+ ++pos;
+ } else {
+ valid = false;
+ }
+ }
+
+ value = val;
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ vmime_uint64 value;
+ };
+
+
+ //
+ // flag ::= "\Answered" / "\Flagged" / "\Deleted" /
+ // "\Seen" / "\Draft" / flag_keyword / flag_extension
+ //
+ // flag_extension ::= "\" atom
+ // ;; Future expansion. Client implementations
+ // ;; MUST accept flag_extension flags. Server
+ // ;; implementations MUST NOT generate
+ // ;; flag_extension flags except as defined by
+ // ;; future standard or standards-track
+ // ;; revisions of this specification.
+ //
+ // flag_keyword ::= atom
+ //
+
+ DECLARE_COMPONENT(flag)
+
+ flag()
+ : type(UNKNOWN) {
+
+ }
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ if (VIMAP_PARSER_TRY_CHECK(one_char <'\\'> )) {
+
+ if (VIMAP_PARSER_TRY_CHECK(one_char <'*'> )) {
+
+ type = STAR;
+
+ } else {
+
+ shared_ptr <atom> at;
+ VIMAP_PARSER_GET(atom, at);
+
+ const string tname = utility::stringUtils::toLower(at->value);
+
+ if (tname == "answered") {
+ type = ANSWERED;
+ } else if (tname == "flagged") {
+ type = FLAGGED;
+ } else if (tname == "deleted") {
+ type = DELETED;
+ } else if (tname == "seen") {
+ type = SEEN;
+ } else if (tname == "draft") {
+ type = DRAFT;
+ } else {
+ type = UNKNOWN;
+ name = tname;
+ }
+ }
+
+ } else {
+
+ if (!parser.isStrict() && VIMAP_PARSER_TRY_CHECK(one_char <'*'> )) {
+ type = STAR; // map "*" to "\*"
+ } else {
+ type = KEYWORD_OR_EXTENSION;
+ VIMAP_PARSER_GET(atom, flag_keyword);
+ }
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ enum Type {
+ UNKNOWN,
+ ANSWERED,
+ FLAGGED,
+ DELETED,
+ SEEN,
+ DRAFT,
+ KEYWORD_OR_EXTENSION,
+ STAR // * = custom flags allowed
+ };
+
+
+ Type type;
+ string name;
+
+ std::unique_ptr <IMAPParser::atom> flag_keyword;
+ };
+
+
+ //
+ // flag_list ::= "(" #flag ")"
+ //
+
+ DECLARE_COMPONENT(flag_list)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_CHECK(one_char <'('> );
+
+ while (!VIMAP_PARSER_TRY_CHECK(one_char <')'> )) {
+ VIMAP_PARSER_GET_PUSHBACK(flag, flags);
+ VIMAP_PARSER_TRY_CHECK(SPACE);
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::vector <std::unique_ptr <flag>> flags;
+ };
+
+
+ //
+ // mailbox ::= "INBOX" / astring
+ // ;; INBOX is case-insensitive. All case variants of
+ // ;; INBOX (e.g. "iNbOx") MUST be interpreted as INBOX
+ // ;; not as an astring. Refer to section 5.1 for
+ // ;; further semantic details of mailbox names.
+ //
+
+ DECLARE_COMPONENT(mailbox)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "inbox")) {
+
+ type = INBOX;
+ name = "INBOX";
+
+ } else {
+
+ type = OTHER;
+
+ std::unique_ptr <astring> astr;
+ VIMAP_PARSER_GET(astring, astr);
+ name = astr->value;
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ enum Type {
+ INBOX,
+ OTHER
+ };
+
+
+ Type type;
+ string name;
+ };
+
+
+ //
+ // mailbox_flag := "\Marked" / "\Noinferiors" /
+ // "\Noselect" / "\Unmarked" / flag_extension
+ //
+
+ DECLARE_COMPONENT(mailbox_flag)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ if (VIMAP_PARSER_TRY_CHECK(one_char <'\\'> )) {
+
+ std::unique_ptr <atom> at;
+ VIMAP_PARSER_GET(atom, at);
+
+ const string tname = utility::stringUtils::toLower(at->value);
+
+ type = UNKNOWN; // default
+
+ switch (tname[0]) {
+
+ case 'a':
+
+ if (tname == "all") {
+ type = SPECIALUSE_ALL;
+ } else if (tname == "archive") {
+ type = SPECIALUSE_ARCHIVE;
+ }
+
+ break;
+
+ case 'd':
+
+ if (tname == "drafts") {
+ type = SPECIALUSE_DRAFTS;
+ }
+
+ break;
+
+ case 'f':
+
+ if (tname == "flagged") {
+ type = SPECIALUSE_FLAGGED;
+ }
+
+ break;
+
+ case 'h':
+
+ if (tname == "haschildren") {
+ type = HASCHILDREN;
+ } else if (tname == "hasnochildren") {
+ type = HASNOCHILDREN;
+ }
+
+ break;
+
+ case 'i':
+
+ if (tname == "important") {
+ type = SPECIALUSE_IMPORTANT;
+ }
+
+ break;
+
+ case 'j':
+
+ if (tname == "junk") {
+ type = SPECIALUSE_JUNK;
+ }
+
+ break;
+
+ case 'm':
+
+ if (tname == "marked") {
+ type = MARKED;
+ }
+
+ break;
+
+ case 'n':
+
+ if (tname == "noinferiors") {
+ type = NOINFERIORS;
+ } else if (tname == "noselect") {
+ type = NOSELECT;
+ }
+
+ break;
+
+ case 's':
+
+ if (tname == "sent") {
+ type = SPECIALUSE_SENT;
+ }
+
+ break;
+
+ case 't':
+
+ if (tname == "trash") {
+ type = SPECIALUSE_TRASH;
+ }
+
+ break;
+
+ case 'u':
+
+ if (tname == "unmarked") {
+ type = UNMARKED;
+ }
+
+ break;
+ }
+
+ if (type == UNKNOWN) {
+ name = "\\" + tname;
+ }
+
+ } else {
+
+ std::unique_ptr <atom> at;
+ VIMAP_PARSER_GET(atom, at);
+ const string tname = utility::stringUtils::toLower(at->value);
+
+ type = UNKNOWN;
+ name = tname;
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ enum Type {
+ // RFC-3348 - Child Mailbox Extension
+ HASCHILDREN,
+ HASNOCHILDREN,
+
+ // RFC-6154 - Special-Use Mailboxes
+ SPECIALUSE_ALL,
+ SPECIALUSE_ARCHIVE,
+ SPECIALUSE_DRAFTS,
+ SPECIALUSE_FLAGGED,
+ SPECIALUSE_JUNK,
+ SPECIALUSE_SENT,
+ SPECIALUSE_TRASH,
+ SPECIALUSE_IMPORTANT, // draft
+
+ // Standard mailbox flags
+ UNKNOWN,
+ MARKED,
+ NOINFERIORS,
+ NOSELECT,
+ UNMARKED
+ };
+
+
+ Type type;
+ string name;
+ };
+
+
+ //
+ // mailbox_flag_list ::= "(" #(mailbox_flag) ")"
+ //
+
+ DECLARE_COMPONENT(mailbox_flag_list)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_CHECK(one_char <'('> );
+
+ while (!VIMAP_PARSER_TRY_CHECK(one_char <')'> )) {
+ VIMAP_PARSER_GET_PUSHBACK(mailbox_flag, flags);
+ VIMAP_PARSER_TRY_CHECK(SPACE);
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::vector <std::unique_ptr <mailbox_flag>> flags;
+ };
+
+
+ //
+ // mailbox_list ::= mailbox_flag_list SPACE
+ // (<"> QUOTED_CHAR <"> / nil) SPACE mailbox
+ //
+
+ DECLARE_COMPONENT(mailbox_list)
+
+ mailbox_list()
+ : quoted_char('\0') {
+
+ }
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_GET(IMAPParser::mailbox_flag_list, mailbox_flag_list);
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ if (!VIMAP_PARSER_TRY_CHECK(NIL)) {
+
+ VIMAP_PARSER_CHECK(one_char <'"'> );
+
+ std::unique_ptr <QUOTED_CHAR> qc;
+ VIMAP_PARSER_GET(QUOTED_CHAR, qc);
+ quoted_char = qc->value;
+
+ VIMAP_PARSER_CHECK(one_char <'"'> );
+ }
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::mailbox, mailbox);
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::mailbox_flag_list> mailbox_flag_list;
+ std::unique_ptr <IMAPParser::mailbox> mailbox;
+
+ char quoted_char;
+ };
+
+
+ //
+ // auth_type ::= atom
+ // ;; Defined by [IMAP-AUTH]
+ //
+
+ DECLARE_COMPONENT(auth_type)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ std::unique_ptr <atom> at;
+ VIMAP_PARSER_GET(atom, at);
+
+ name = utility::stringUtils::toLower(at->value);
+
+ if (name == "kerberos_v4") {
+ type = KERBEROS_V4;
+ } else if (name == "gssapi") {
+ type = GSSAPI;
+ } else if (name == "skey") {
+ type = SKEY;
+ } else {
+ type = UNKNOWN;
+ }
+
+ return true;
+ }
+
+
+ enum Type {
+ UNKNOWN,
+
+ // RFC 1731 - IMAP4 Authentication Mechanisms
+ KERBEROS_V4,
+ GSSAPI,
+ SKEY
+ };
+
+
+ Type type;
+ string name;
+ };
+
+
+ //
+ // status-att-val = ("MESSAGES" SP number) /
+ // ("RECENT" SP number) /
+ // ("UIDNEXT" SP nz-number) /
+ // ("UIDVALIDITY" SP nz-number) /
+ // ("UNSEEN" SP number)
+ //
+ // IMAP Extension for Conditional STORE (RFC-4551):
+ //
+ // status-att-val =/ "HIGHESTMODSEQ" SP mod-sequence-valzer
+ // ;; extends non-terminal defined in [IMAPABNF].
+ // ;; Value 0 denotes that the mailbox doesn't
+ // ;; support persistent mod-sequences
+ //
+
+ DECLARE_COMPONENT(status_att_val)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ // "HIGHESTMODSEQ" SP mod-sequence-valzer
+ if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "highestmodseq")) {
+
+ type = HIGHESTMODSEQ;
+
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::mod_sequence_value, value);
+
+ } else {
+
+ if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "messages")) {
+ type = MESSAGES;
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "recent")) {
+ type = RECENT;
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "uidnext")) {
+ type = UIDNEXT;
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "uidvalidity")) {
+ type = UIDVALIDITY;
+ } else {
+ VIMAP_PARSER_CHECK_WITHARG(special_atom, "unseen");
+ type = UNSEEN;
+ }
+
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::number, value);
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ enum Type {
+ // Extensions
+ HIGHESTMODSEQ,
+
+ // Standard IMAP
+ MESSAGES,
+ RECENT,
+ UIDNEXT,
+ UIDVALIDITY,
+ UNSEEN
+ };
+
+
+ Type type;
+ std::unique_ptr <IMAPParser::component> value;
+
+
+ const IMAPParser::number* value_as_number() const {
+ return dynamic_cast <IMAPParser::number *>(value.get());
+ }
+
+ const IMAPParser::mod_sequence_value* value_as_mod_sequence_value() const {
+ return dynamic_cast <IMAPParser::mod_sequence_value *>(value.get());
+ }
+ };
+
+
+ // status-att-list = status-att-val *(SP status-att-val)
+
+ DECLARE_COMPONENT(status_att_list)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_GET_PUSHBACK(IMAPParser::status_att_val, values);
+
+ while (VIMAP_PARSER_TRY_CHECK(SPACE)) {
+ VIMAP_PARSER_GET_PUSHBACK(IMAPParser::status_att_val, values);
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::vector <std::unique_ptr <status_att_val>> values;
+ };
+
+
+ //
+ // capability ::= "AUTH=" auth_type / atom
+ // ;; New capabilities MUST begin with "X" or be
+ // ;; registered with IANA as standard or standards-track
+ //
+
+ DECLARE_COMPONENT(capability)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_GET(IMAPParser::atom, atom);
+
+ string value = atom->value;
+ const char* str = value.c_str();
+
+ if ((str[0] == 'a' || str[0] == 'A') &&
+ (str[1] == 'u' || str[1] == 'U') &&
+ (str[2] == 't' || str[2] == 'T') &&
+ (str[3] == 'h' || str[3] == 'H') &&
+ (str[4] == '=')) {
+
+ size_t pos = 5;
+ auth_type.reset(parser.get <IMAPParser::auth_type>(value, &pos));
+
+ atom.reset();
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::auth_type> auth_type;
+ std::unique_ptr <IMAPParser::atom> atom;
+ };
+
+
+ //
+ // capability_data ::= "CAPABILITY" SPACE [1#capability SPACE] "IMAP4rev1"
+ // [SPACE 1#capability]
+ // ;; IMAP4rev1 servers which offer RFC 1730
+ // ;; compatibility MUST list "IMAP4" as the first
+ // ;; capability.
+ //
+
+ DECLARE_COMPONENT(capability_data)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_CHECK_WITHARG(special_atom, "capability");
+
+ while (VIMAP_PARSER_TRY_CHECK(SPACE)) {
+
+ std::unique_ptr <capability> cap;
+
+ if (parser.isStrict() || capabilities.empty()) {
+ VIMAP_PARSER_GET(capability, cap);
+ } else {
+ VIMAP_PARSER_TRY_GET(capability, cap); // allow SPACE at end of line (Apple iCloud IMAP server)
+ }
+
+ if (!cap) {
+ break;
+ }
+
+ capabilities.push_back(std::move(cap));
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::vector <std::unique_ptr <capability>> capabilities;
+ };
+
+
+ //
+ // date_day_fixed ::= (SPACE digit) / 2digit
+ // ;; Fixed-format version of date_day
+ //
+ // date_month ::= "Jan" / "Feb" / "Mar" / "Apr" / "May" / "Jun" /
+ // "Jul" / "Aug" / "Sep" / "Oct" / "Nov" / "Dec"
+ //
+ // date_year ::= 4digit
+ //
+ // time ::= 2digit ":" 2digit ":" 2digit
+ // ;; Hours minutes seconds
+ //
+ // zone ::= ("+" / "-") 4digit
+ // ;; Signed four-digit value of hhmm representing
+ // ;; hours and minutes west of Greenwich (that is,
+ // ;; (the amount that the given time differs from
+ // ;; Universal Time). Subtracting the timezone
+ // ;; from the given time will give the UT form.
+ // ;; The Universal Time zone is "+0000".
+ //
+ // date_time ::= <"> date_day_fixed "-" date_month "-" date_year
+ // SPACE time SPACE zone <">
+ //
+
+ DECLARE_COMPONENT(date_time)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ // <"> date_day_fixed "-" date_month "-" date_year
+ VIMAP_PARSER_CHECK(one_char <'"'> );
+ VIMAP_PARSER_TRY_CHECK(SPACE);
+
+ shared_ptr <number> nd;
+ VIMAP_PARSER_GET(number, nd);
+
+ VIMAP_PARSER_CHECK(one_char <'-'> );
+
+ shared_ptr <atom> amo;
+ VIMAP_PARSER_GET(atom, amo);
+
+ VIMAP_PARSER_CHECK(one_char <'-'> );
+
+ shared_ptr <number> ny;
+ VIMAP_PARSER_GET(number, ny);
+
+ VIMAP_PARSER_TRY_CHECK(SPACE);
+
+ // 2digit ":" 2digit ":" 2digit
+ shared_ptr <number> nh;
+ VIMAP_PARSER_GET(number, nh);
+
+ VIMAP_PARSER_CHECK(one_char <':'> );
+
+ shared_ptr <number> nmi;
+ VIMAP_PARSER_GET(number, nmi);
+
+ VIMAP_PARSER_CHECK(one_char <':'> );
+
+ shared_ptr <number> ns;
+ VIMAP_PARSER_GET(number, ns);
+
+ VIMAP_PARSER_TRY_CHECK(SPACE);
+
+ // ("+" / "-") 4digit
+ int sign = 1;
+
+ if (!(VIMAP_PARSER_TRY_CHECK(one_char <'+'> ))) {
+ VIMAP_PARSER_CHECK(one_char <'-'> );
+ }
+
+ shared_ptr <number> nz;
+ VIMAP_PARSER_GET(number, nz);
+
+ VIMAP_PARSER_CHECK(one_char <'"'> );
+
+
+ m_datetime.setHour(static_cast <int>(std::min(std::max(nh->value, 0ul), 23ul)));
+ m_datetime.setMinute(static_cast <int>(std::min(std::max(nmi->value, 0ul), 59ul)));
+ m_datetime.setSecond(static_cast <int>(std::min(std::max(ns->value, 0ul), 59ul)));
+
+ const int zone = static_cast <int>(nz->value);
+ const int zh = zone / 100; // hour offset
+ const int zm = zone % 100; // minute offset
+
+ m_datetime.setZone(((zh * 60) + zm) * sign);
+
+ m_datetime.setDay(static_cast <int>(std::min(std::max(nd->value, 1ul), 31ul)));
+ m_datetime.setYear(static_cast <int>(ny->value));
+
+ const string month(utility::stringUtils::toLower(amo->value));
+ int mon = vmime::datetime::JANUARY;
+
+ if (month.length() >= 3) {
+
+ switch (month[0]) {
+
+ case 'j': {
+
+ switch (month[1]) {
+
+ case 'a': mon = vmime::datetime::JANUARY; break;
+ case 'u': {
+
+ switch (month[2]) {
+
+ case 'n': mon = vmime::datetime::JUNE; break;
+ default: mon = vmime::datetime::JULY; break;
+ }
+
+ break;
+ }
+
+ }
+
+ break;
+ }
+ case 'f': mon = vmime::datetime::FEBRUARY; break;
+ case 'm': {
+
+ switch (month[2]) {
+ case 'r': mon = vmime::datetime::MARCH; break;
+ default: mon = vmime::datetime::MAY; break;
+ }
+
+ break;
+ }
+ case 'a':
+ {
+ switch (month[1]) {
+ case 'p': mon = vmime::datetime::APRIL; break;
+ default: mon = vmime::datetime::AUGUST; break;
+ }
+
+ break;
+ }
+ case 's': mon = vmime::datetime::SEPTEMBER; break;
+ case 'o': mon = vmime::datetime::OCTOBER; break;
+ case 'n': mon = vmime::datetime::NOVEMBER; break;
+ case 'd': mon = vmime::datetime::DECEMBER; break;
+ }
+ }
+
+ m_datetime.setMonth(mon);
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+ private:
+
+ vmime::datetime m_datetime;
+ };
+
+
+ //
+ // header_fld_name ::= astring
+ //
+
+ COMPONENT_ALIAS(astring, header_fld_name);
+
+
+ //
+ // header_list ::= "(" 1#header_fld_name ")"
+ //
+
+ DECLARE_COMPONENT(header_list)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_CHECK(one_char <'('> );
+
+ while (!VIMAP_PARSER_TRY_CHECK(one_char <')'> )) {
+ VIMAP_PARSER_GET_PUSHBACK(header_fld_name, fld_names);
+ VIMAP_PARSER_TRY_CHECK(SPACE);
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::vector <std::unique_ptr <header_fld_name>> fld_names;
+ };
+
+
+ //
+ // body_extension ::= nstring / number / "(" 1#body_extension ")"
+ // ;; Future expansion. Client implementations
+ // ;; MUST accept body_extension fields. Server
+ // ;; implementations MUST NOT generate
+ // ;; body_extension fields except as defined by
+ // ;; future standard or standards-track
+ // ;; revisions of this specification.
+ //
+
+ DECLARE_COMPONENT(body_extension)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ if (VIMAP_PARSER_TRY_CHECK(one_char <'('> )) {
+
+ VIMAP_PARSER_GET_PUSHBACK(body_extension, body_extensions);
+
+ while (!VIMAP_PARSER_TRY_CHECK(one_char <')'> )) {
+ VIMAP_PARSER_GET_PUSHBACK(body_extension, body_extensions);
+ VIMAP_PARSER_TRY_CHECK(SPACE);
+ }
+
+ } else {
+
+ if (!VIMAP_PARSER_TRY_GET(IMAPParser::nstring, nstring)) {
+ VIMAP_PARSER_GET(IMAPParser::number, number);
+ }
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::nstring> nstring;
+ std::unique_ptr <IMAPParser::number> number;
+
+ std::vector <std::unique_ptr <body_extension>> body_extensions;
+ };
+
+
+ //
+ // section_text ::= "HEADER" / "HEADER.FIELDS" [".NOT"]
+ // SPACE header_list / "TEXT" / "MIME"
+ //
+
+ DECLARE_COMPONENT(section_text)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ // "HEADER.FIELDS" [".NOT"] SPACE header_list
+ const bool b1 = VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "header.fields.not");
+ const bool b2 = (b1 ? false : VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "header.fields"));
+
+ if (b1 || b2) {
+
+ type = b1 ? HEADER_FIELDS_NOT : HEADER_FIELDS;
+
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::header_list, header_list);
+
+ // "HEADER"
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "header")) {
+
+ type = HEADER;
+
+ // "MIME"
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "mime")) {
+
+ type = MIME;
+
+ // "TEXT"
+ } else {
+
+ type = TEXT;
+
+ VIMAP_PARSER_CHECK_WITHARG(special_atom, "text");
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ enum Type {
+ HEADER,
+ HEADER_FIELDS,
+ HEADER_FIELDS_NOT,
+ MIME,
+ TEXT
+ };
+
+
+ Type type;
+ std::unique_ptr <IMAPParser::header_list> header_list;
+ };
+
+
+ //
+ // section ::= "[" [section_text / (nz_number *["." nz_number]
+ // ["." (section_text / "MIME")])] "]"
+ //
+
+ DECLARE_COMPONENT(section)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_CHECK(one_char <'['> );
+
+ if (!VIMAP_PARSER_TRY_CHECK(one_char <']'> )) {
+
+ if (!VIMAP_PARSER_TRY_GET(section_text, section_text1)) {
+
+ std::unique_ptr <nz_number> num;
+ VIMAP_PARSER_GET(nz_number, num);
+ nz_numbers.push_back(static_cast <unsigned int>(num->value));
+
+ while (VIMAP_PARSER_TRY_CHECK(one_char <'.'> )) {
+
+ if (VIMAP_PARSER_TRY_GET(nz_number, num)) {
+ nz_numbers.push_back(static_cast <unsigned int>(num->value));
+ } else {
+ VIMAP_PARSER_GET(section_text, section_text2);
+ break;
+ }
+ }
+ }
+
+ VIMAP_PARSER_CHECK(one_char <']'> );
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <section_text> section_text1;
+ std::unique_ptr <section_text> section_text2;
+ std::vector <unsigned int> nz_numbers;
+ };
+
+
+ //
+ // addr_adl ::= nstring
+ // ;; Holds route from [RFC-822] route-addr if
+ // ;; non-NIL
+ //
+ // addr_host ::= nstring
+ // ;; NIL indicates [RFC-822] group syntax.
+ // ;; Otherwise, holds [RFC-822] domain name
+ //
+ // addr_mailbox ::= nstring
+ // ;; NIL indicates end of [RFC-822] group; if
+ // ;; non-NIL and addr_host is NIL, holds
+ // ;; [RFC-822] group name.
+ // ;; Otherwise, holds [RFC-822] local-part
+ //
+ // addr_name ::= nstring
+ // ;; Holds phrase from [RFC-822] mailbox if
+ // ;; non-NIL
+ //
+ // address ::= "(" addr_name SPACE addr_adl SPACE addr_mailbox
+ // SPACE addr_host ")"
+ //
+
+ DECLARE_COMPONENT(address)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_CHECK(one_char <'('> );
+ VIMAP_PARSER_GET(nstring, addr_name);
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(nstring, addr_adl);
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(nstring, addr_mailbox);
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(nstring, addr_host);
+ VIMAP_PARSER_CHECK(one_char <')'> );
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <nstring> addr_name;
+ std::unique_ptr <nstring> addr_adl;
+ std::unique_ptr <nstring> addr_mailbox;
+ std::unique_ptr <nstring> addr_host;
+ };
+
+
+ //
+ // address_list ::= "(" 1*address ")" / nil
+ //
+
+ DECLARE_COMPONENT(address_list)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ if (!VIMAP_PARSER_TRY_CHECK(NIL)) {
+
+ VIMAP_PARSER_CHECK(one_char <'('> );
+
+ while (!VIMAP_PARSER_TRY_CHECK(one_char <')'> )) {
+ VIMAP_PARSER_GET_PUSHBACK(address, addresses);
+ VIMAP_PARSER_TRY_CHECK(SPACE);
+ }
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::vector <std::unique_ptr <address>> addresses;
+ };
+
+
+ //
+ // env_bcc ::= "(" 1*address ")" / nil
+ //
+
+ COMPONENT_ALIAS(address_list, env_bcc);
+
+
+ //
+ // env_cc ::= "(" 1*address ")" / nil
+ //
+
+ COMPONENT_ALIAS(address_list, env_cc);
+
+
+ //
+ // env_date ::= nstring
+ //
+
+ COMPONENT_ALIAS(nstring, env_date);
+
+
+ //
+ // env_from ::= "(" 1*address ")" / nil
+ //
+
+ COMPONENT_ALIAS(address_list, env_from);
+
+
+ //
+ // env_in_reply_to ::= nstring
+ //
+
+ COMPONENT_ALIAS(nstring, env_in_reply_to);
+
+
+ //
+ // env_message_id ::= nstring
+ //
+
+ COMPONENT_ALIAS(nstring, env_message_id);
+
+
+ //
+ // env_reply_to ::= "(" 1*address ")" / nil
+ //
+
+ COMPONENT_ALIAS(address_list, env_reply_to);
+
+
+ //
+ // env_sender ::= "(" 1*address ")" / nil
+ //
+
+ COMPONENT_ALIAS(address_list, env_sender);
+
+
+ //
+ // env_subject ::= nstring
+ //
+
+ COMPONENT_ALIAS(nstring, env_subject);
+
+
+ //
+ // env_to ::= "(" 1*address ")" / nil
+ //
+
+ COMPONENT_ALIAS(address_list, env_to);
+
+
+ //
+ // envelope ::= "(" env_date SPACE env_subject SPACE env_from
+ // SPACE env_sender SPACE env_reply_to SPACE env_to
+ // SPACE env_cc SPACE env_bcc SPACE env_in_reply_to
+ // SPACE env_message_id ")"
+ //
+
+ DECLARE_COMPONENT(envelope)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_CHECK(one_char <'('> );
+
+ VIMAP_PARSER_GET(IMAPParser::env_date, env_date);
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::env_subject, env_subject);
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::env_from, env_from);
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::env_sender, env_sender);
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::env_reply_to, env_reply_to);
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::env_to, env_to);
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::env_cc, env_cc);
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::env_bcc, env_bcc);
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::env_in_reply_to, env_in_reply_to);
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::env_message_id, env_message_id);
+
+ VIMAP_PARSER_CHECK(one_char <')'> );
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::env_date> env_date;
+ std::unique_ptr <IMAPParser::env_subject> env_subject;
+ std::unique_ptr <IMAPParser::env_from> env_from;
+ std::unique_ptr <IMAPParser::env_sender> env_sender;
+ std::unique_ptr <IMAPParser::env_reply_to> env_reply_to;
+ std::unique_ptr <IMAPParser::env_to> env_to;
+ std::unique_ptr <IMAPParser::env_cc> env_cc;
+ std::unique_ptr <IMAPParser::env_bcc> env_bcc;
+ std::unique_ptr <IMAPParser::env_in_reply_to> env_in_reply_to;
+ std::unique_ptr <IMAPParser::env_message_id> env_message_id;
+ };
+
+
+ //
+ // body_fld_desc ::= nstring
+ //
+
+ COMPONENT_ALIAS(nstring, body_fld_desc);
+
+
+ //
+ // body_fld_id ::= nstring
+ //
+
+ COMPONENT_ALIAS(nstring, body_fld_id);
+
+
+ //
+ // body_fld_md5 ::= nstring
+ //
+
+ COMPONENT_ALIAS(nstring, body_fld_md5);
+
+
+ //
+ // body_fld_octets ::= number
+ //
+
+ COMPONENT_ALIAS(number, body_fld_octets);
+
+
+ //
+ // body_fld_lines ::= number
+ //
+
+ COMPONENT_ALIAS(number, body_fld_lines);
+
+
+ //
+ // body_fld_enc ::= (<"> ("7BIT" / "8BIT" / "BINARY" / "BASE64"/
+ // "QUOTED-PRINTABLE") <">) / string
+ //
+
+ class body_fld_enc : public nstring {
+
+ public:
+
+ const string getComponentName() const {
+
+ return "body_fld_enc";
+ }
+
+ body_fld_enc() {
+
+ }
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ if (!xstring::parseImpl(parser, line, &pos)) {
+ return false;
+ }
+
+ // " When an IMAP4 client sends a FETCH (bodystructure) request
+ // to a server that is running the Exchange Server 2007 IMAP4
+ // service, a corrupted response is sent as a reply "
+ // (see http://support.microsoft.com/kb/975918/en-us)
+ //
+ // Fail in strict mode
+ if (isNIL && parser.isStrict()) {
+ VIMAP_PARSER_FAIL();
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+ };
+
+
+ //
+ // body_fld_param_item ::= string SPACE string
+ //
+
+ DECLARE_COMPONENT(body_fld_param_item)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ if (!parser.isStrict()) {
+
+ // Some servers send an <atom> instead of a <string> here:
+ // eg. ... (CHARSET "X-UNKNOWN") ...
+ if (!VIMAP_PARSER_TRY_GET(xstring, string1)) {
+
+ std::unique_ptr <atom> at;
+ VIMAP_PARSER_GET(atom, at);
+
+ string1.reset(new xstring());
+ string1->value = at->value;
+ }
+
+ } else {
+
+ VIMAP_PARSER_GET(xstring, string1);
+ }
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ if (!parser.isStrict()) {
+
+ // In non-strict mode, allow NIL in value
+ std::unique_ptr <nstring> nstr;
+ VIMAP_PARSER_GET(nstring, nstr);
+
+ string2.reset(new xstring());
+ string2->value = nstr->value;
+
+ } else {
+
+ VIMAP_PARSER_GET(xstring, string2);
+ }
+
+ DEBUG_FOUND("body_fld_param_item", "<" << string1->value << ", " << string2->value << ">");
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <xstring> string1;
+ std::unique_ptr <xstring> string2;
+ };
+
+
+ //
+ // body_fld_param ::= "(" 1#(body_fld_param_item) ")" / nil
+ //
+
+ DECLARE_COMPONENT(body_fld_param)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ if (VIMAP_PARSER_TRY_CHECK(one_char <'('> )) {
+
+ bool isNIL = false;
+
+ if (!parser.isStrict()) {
+
+ // In non-strict mode, allow "()" instead of "NIL"
+ if (VIMAP_PARSER_TRY_CHECK(one_char <')'> )) {
+ isNIL = true;
+ }
+ }
+
+ if (!isNIL) {
+
+ VIMAP_PARSER_GET_PUSHBACK(body_fld_param_item, items);
+
+ while (!VIMAP_PARSER_TRY_CHECK(one_char <')'> )) {
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET_PUSHBACK(body_fld_param_item, items);
+ }
+ }
+
+ } else {
+
+ VIMAP_PARSER_CHECK(NIL);
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::vector <std::unique_ptr <body_fld_param_item>> items;
+ };
+
+
+ //
+ // body_fld_dsp ::= "(" string SPACE body_fld_param ")" / nil
+ //
+
+ DECLARE_COMPONENT(body_fld_dsp)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ if (VIMAP_PARSER_TRY_CHECK(one_char <'('> )) {
+
+ VIMAP_PARSER_GET(xstring, m_string);
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(class body_fld_param, m_body_fld_param);
+ VIMAP_PARSER_CHECK(one_char <')'> );
+
+ } else {
+
+ VIMAP_PARSER_CHECK(NIL);
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+ private:
+
+ std::unique_ptr <class xstring> m_string;
+ std::unique_ptr <class body_fld_param> m_body_fld_param;
+
+ public:
+
+ const class xstring* str() const { return m_string.get(); }
+ const class body_fld_param* body_fld_param() const { return m_body_fld_param.get(); }
+ };
+
+
+ //
+ // body_fld_lang ::= nstring / "(" 1#string ")"
+ //
+
+ DECLARE_COMPONENT(body_fld_lang)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ if (VIMAP_PARSER_TRY_CHECK(one_char <'('> )) {
+
+ VIMAP_PARSER_GET_PUSHBACK(xstring, strings);
+
+ while (!VIMAP_PARSER_TRY_CHECK(one_char <')'> )) {
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET_PUSHBACK(xstring, strings);
+ }
+
+ } else {
+
+ VIMAP_PARSER_GET_PUSHBACK(nstring, strings);
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::vector <std::unique_ptr <xstring>> strings;
+ };
+
+
+ //
+ // body_fields ::= body_fld_param SPACE body_fld_id SPACE
+ // body_fld_desc SPACE body_fld_enc SPACE
+ // body_fld_octets
+ //
+
+ DECLARE_COMPONENT(body_fields)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_GET(IMAPParser::body_fld_param, body_fld_param);
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::body_fld_id, body_fld_id);
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::body_fld_desc, body_fld_desc);
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::body_fld_enc, body_fld_enc);
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::body_fld_octets, body_fld_octets);
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::body_fld_param> body_fld_param;
+ std::unique_ptr <IMAPParser::body_fld_id> body_fld_id;
+ std::unique_ptr <IMAPParser::body_fld_desc> body_fld_desc;
+ std::unique_ptr <IMAPParser::body_fld_enc> body_fld_enc;
+ std::unique_ptr <IMAPParser::body_fld_octets> body_fld_octets;
+ };
+
+
+ //
+ // media_subtype ::= string
+ // ;; Defined in [MIME-IMT]
+ //
+
+ COMPONENT_ALIAS(xstring, media_subtype);
+
+
+ //
+ // media_text ::= <"> "TEXT" <"> SPACE media_subtype
+ // ;; Defined in [MIME-IMT]
+ //
+
+ DECLARE_COMPONENT(media_text)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_CHECK(one_char <'"'> );
+ VIMAP_PARSER_CHECK_WITHARG(special_atom, "text");
+ VIMAP_PARSER_CHECK(one_char <'"'> );
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::media_subtype, media_subtype);
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::media_subtype> media_subtype;
+ };
+
+
+ //
+ // media_message ::= <"> "MESSAGE" <"> SPACE <"> "RFC822" <">
+ // ;; Defined in [MIME-IMT]
+ //
+
+ DECLARE_COMPONENT(media_message)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_CHECK(one_char <'"'> );
+ VIMAP_PARSER_CHECK_WITHARG(special_atom, "message");
+ VIMAP_PARSER_CHECK(one_char <'"'> );
+ VIMAP_PARSER_CHECK(SPACE);
+
+ //VIMAP_PARSER_CHECK(one_char <'"'> );
+ //VIMAP_PARSER_CHECK_WITHARG(special_atom, "rfc822");
+ //VIMAP_PARSER_CHECK(one_char <'"'> );
+
+ VIMAP_PARSER_GET(IMAPParser::media_subtype, media_subtype);
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::media_subtype> media_subtype;
+ };
+
+
+ //
+ // media_basic ::= (<"> ("APPLICATION" / "AUDIO" / "IMAGE" /
+ // "MESSAGE" / "VIDEO") <">) / string)
+ // SPACE media_subtype
+ // ;; Defined in [MIME-IMT]
+
+ DECLARE_COMPONENT(media_basic)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_GET(xstring, media_type);
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::media_subtype, media_subtype);
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::xstring> media_type;
+ std::unique_ptr <IMAPParser::media_subtype> media_subtype;
+ };
+
+
+ //
+ // body_ext_1part ::= body_fld_md5 [SPACE body_fld_dsp
+ // [SPACE body_fld_lang
+ // [SPACE 1#body_extension]]]
+ // ;; MUST NOT be returned on non-extensible
+ // ;; "BODY" fetch
+ //
+
+ DECLARE_COMPONENT(body_ext_1part)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos)
+ {
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_GET(IMAPParser::body_fld_md5, body_fld_md5);
+
+ // [SPACE body_fld_dsp
+ if (VIMAP_PARSER_TRY_CHECK(SPACE)) {
+
+ VIMAP_PARSER_GET(IMAPParser::body_fld_dsp, body_fld_dsp);
+
+ // [SPACE body_fld_lang
+ if (VIMAP_PARSER_TRY_CHECK(SPACE)) {
+
+ VIMAP_PARSER_GET(IMAPParser::body_fld_lang, body_fld_lang);
+
+ // [SPACE 1#body_extension]
+ if (VIMAP_PARSER_TRY_CHECK(SPACE)) {
+
+ VIMAP_PARSER_GET_PUSHBACK(body_extension, body_extensions);
+
+ while (VIMAP_PARSER_TRY_CHECK(SPACE)) {
+ VIMAP_PARSER_GET_PUSHBACK(body_extension, body_extensions);
+ }
+ }
+ }
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::body_fld_md5> body_fld_md5;
+ std::unique_ptr <IMAPParser::body_fld_dsp> body_fld_dsp;
+ std::unique_ptr <IMAPParser::body_fld_lang> body_fld_lang;
+
+ std::vector <std::unique_ptr <body_extension>> body_extensions;
+ };
+
+
+ //
+ // body_ext_mpart ::= body_fld_param
+ // [SPACE body_fld_dsp [SPACE body_fld_lang
+ // [SPACE 1#body_extension]]]
+ // ;; MUST NOT be returned on non-extensible
+ // ;; "BODY" fetch
+
+ DECLARE_COMPONENT(body_ext_mpart)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_GET(IMAPParser::body_fld_param, body_fld_param);
+
+ // [SPACE body_fld_dsp [SPACE body_fld_lang [SPACE 1#body_extension]]]
+ if (VIMAP_PARSER_TRY_CHECK(SPACE)) {
+
+ VIMAP_PARSER_GET(IMAPParser::body_fld_dsp, body_fld_dsp);
+
+ if (VIMAP_PARSER_TRY_CHECK(SPACE)) {
+
+ VIMAP_PARSER_GET(IMAPParser::body_fld_lang, body_fld_lang);
+
+ // [SPACE 1#body_extension]
+ if (VIMAP_PARSER_TRY_CHECK(SPACE)) {
+
+ VIMAP_PARSER_GET_PUSHBACK(body_extension, body_extensions);
+
+ while (VIMAP_PARSER_TRY_CHECK(SPACE)) {
+ VIMAP_PARSER_GET_PUSHBACK(body_extension, body_extensions);
+ }
+ }
+ }
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::body_fld_param> body_fld_param;
+ std::unique_ptr <IMAPParser::body_fld_dsp> body_fld_dsp;
+ std::unique_ptr <IMAPParser::body_fld_lang> body_fld_lang;
+
+ std::vector <std::unique_ptr <body_extension>> body_extensions;
+ };
+
+
+ //
+ // body_type_basic ::= media_basic SPACE body_fields
+ // ;; MESSAGE subtype MUST NOT be "RFC822"
+ //
+
+ DECLARE_COMPONENT(body_type_basic)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_GET(IMAPParser::media_basic, media_basic);
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::body_fields, body_fields);
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::media_basic> media_basic;
+ std::unique_ptr <IMAPParser::body_fields> body_fields;
+ };
+
+
+ //
+ // body_type_msg ::= media_message SPACE body_fields SPACE envelope
+ // SPACE body SPACE body_fld_lines
+ //
+
+ class xbody;
+ typedef xbody body;
+
+ DECLARE_COMPONENT(body_type_msg)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_GET(IMAPParser::media_message, media_message);
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::body_fields, body_fields);
+ VIMAP_PARSER_CHECK(SPACE);
+
+ // BUGFIX: made SPACE optional. This is not standard, but some servers
+ // seem to return responses like that...
+ VIMAP_PARSER_GET(IMAPParser::envelope, envelope);
+ VIMAP_PARSER_TRY_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::xbody, body);
+ VIMAP_PARSER_TRY_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::body_fld_lines, body_fld_lines);
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::media_message> media_message;
+ std::unique_ptr <IMAPParser::body_fields> body_fields;
+ std::unique_ptr <IMAPParser::envelope> envelope;
+ std::unique_ptr <IMAPParser::xbody> body;
+ std::unique_ptr <IMAPParser::body_fld_lines> body_fld_lines;
+ };
+
+
+ //
+ // body_type_text ::= media_text SPACE body_fields SPACE body_fld_lines
+ //
+
+ DECLARE_COMPONENT(body_type_text)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_GET(IMAPParser::media_text, media_text);
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::body_fields, body_fields);
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::body_fld_lines, body_fld_lines);
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::media_text> media_text;
+ std::unique_ptr <IMAPParser::body_fields> body_fields;
+ std::unique_ptr <IMAPParser::body_fld_lines> body_fld_lines;
+ };
+
+
+ //
+ // body_type_1part ::= (body_type_basic / body_type_msg / body_type_text)
+ // [SPACE body_ext_1part]
+ //
+
+ DECLARE_COMPONENT(body_type_1part)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ if (!VIMAP_PARSER_TRY_GET(IMAPParser::body_type_text, body_type_text)) {
+ if (!VIMAP_PARSER_TRY_GET(IMAPParser::body_type_msg, body_type_msg)) {
+ VIMAP_PARSER_GET(IMAPParser::body_type_basic, body_type_basic);
+ }
+ }
+
+ if (VIMAP_PARSER_TRY_CHECK(SPACE)) {
+ if (!VIMAP_PARSER_TRY_GET(IMAPParser::body_ext_1part, body_ext_1part)) {
+ --pos;
+ }
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::body_type_basic> body_type_basic;
+ std::unique_ptr <IMAPParser::body_type_msg> body_type_msg;
+ std::unique_ptr <IMAPParser::body_type_text> body_type_text;
+
+ std::unique_ptr <IMAPParser::body_ext_1part> body_ext_1part;
+ };
+
+
+ //
+ // body_type_mpart ::= 1*body SPACE media_subtype
+ // [SPACE body_ext_mpart]
+ //
+
+ DECLARE_COMPONENT(body_type_mpart)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_GET_PUSHBACK(xbody, list);
+
+ while (true) {
+ VIMAP_PARSER_TRY_GET_PUSHBACK_OR_ELSE(xbody, list, break);
+ }
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::media_subtype, media_subtype);
+
+ if (VIMAP_PARSER_TRY_CHECK(SPACE)) {
+ VIMAP_PARSER_GET(IMAPParser::body_ext_mpart, body_ext_mpart);
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::media_subtype> media_subtype;
+ std::unique_ptr <IMAPParser::body_ext_mpart> body_ext_mpart;
+
+ std::vector <std::unique_ptr <xbody>> list;
+ };
+
+
+ //
+ // xbody ::= "(" body_type_1part / body_type_mpart ")"
+ //
+
+ DECLARE_COMPONENT(xbody)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_CHECK(one_char <'('> );
+
+ if (!VIMAP_PARSER_TRY_GET(IMAPParser::body_type_mpart, body_type_mpart)) {
+ VIMAP_PARSER_GET(IMAPParser::body_type_1part, body_type_1part);
+ }
+
+ VIMAP_PARSER_CHECK(one_char <')'> );
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::body_type_1part> body_type_1part;
+ std::unique_ptr <IMAPParser::body_type_mpart> body_type_mpart;
+ };
+
+
+ // msg_att_item ::= "ENVELOPE" SPACE envelope /
+ // "FLAGS" SPACE "(" #(flag / "\Recent") ")" /
+ // "INTERNALDATE" SPACE date_time /
+ // "RFC822" [".HEADER" / ".TEXT"] SPACE nstring /
+ // "RFC822.SIZE" SPACE number /
+ // "BODY" ["STRUCTURE"] SPACE body /
+ // "BODY" section ["<" number ">"] SPACE nstring /
+ // "UID" SPACE uniqueid
+ //
+ // IMAP Extension for Conditional STORE (RFC-4551):
+ //
+ // msg_att_item /= "MODSEQ" SP "(" mod_sequence_value ")"
+
+ DECLARE_COMPONENT(msg_att_item)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ // "ENVELOPE" SPACE envelope
+ if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "envelope")) {
+
+ type = ENVELOPE;
+
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::envelope, envelope);
+
+ // "FLAGS" SPACE "(" #(flag / "\Recent") ")"
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "flags")) {
+
+ type = FLAGS;
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::flag_list, flag_list);
+
+ // "INTERNALDATE" SPACE date_time
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "internaldate")) {
+
+ type = INTERNALDATE;
+
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::date_time, date_time);
+
+ // "RFC822" ".HEADER" SPACE nstring
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "rfc822.header")) {
+
+ type = RFC822_HEADER;
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::nstring, nstring);
+
+ // "RFC822" ".TEXT" SPACE nstring
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "rfc822.text")) {
+
+ type = RFC822_TEXT;
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ nstring.reset(parser.getWithArgs <IMAPParser::nstring>(line, &pos, this, RFC822_TEXT));
+
+ VIMAP_PARSER_FAIL_UNLESS(nstring);
+
+ // "RFC822.SIZE" SPACE number
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "rfc822.size")) {
+
+ type = RFC822_SIZE;
+
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::number, number);
+
+ // "RFC822" SPACE nstring
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "rfc822")) {
+
+ type = RFC822;
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::nstring, nstring);
+
+ // "BODY" "STRUCTURE" SPACE body
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "bodystructure")) {
+
+ type = BODY_STRUCTURE;
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::body, body);
+
+ // "BODY" section ["<" number ">"] SPACE nstring
+ // "BODY" SPACE body
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "body")) {
+
+ VIMAP_PARSER_TRY_GET(IMAPParser::section, section);
+
+ // "BODY" section ["<" number ">"] SPACE nstring
+ if (section != NULL) {
+
+ type = BODY_SECTION;
+
+ if (VIMAP_PARSER_TRY_CHECK(one_char <'<'> )) {
+ VIMAP_PARSER_GET(IMAPParser::number, number);
+ VIMAP_PARSER_CHECK(one_char <'>'> );
+ }
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ nstring.reset(parser.getWithArgs <IMAPParser::nstring>(line, &pos, this, BODY_SECTION));
+
+ VIMAP_PARSER_FAIL_UNLESS(nstring);
+
+ // "BODY" SPACE body
+ } else {
+
+ type = BODY;
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::body, body);
+ }
+
+ // "MODSEQ" SP "(" mod_sequence_value ")"
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "modseq")) {
+
+ type = MODSEQ;
+
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_CHECK(one_char <'('> );
+
+ VIMAP_PARSER_GET(IMAPParser::mod_sequence_value, mod_sequence_value);
+
+ VIMAP_PARSER_CHECK(one_char <')'> );
+
+ // "UID" SPACE uniqueid
+ } else {
+
+ type = UID;
+
+ VIMAP_PARSER_CHECK_WITHARG(special_atom, "uid");
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::uniqueid, uniqueid);
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ enum Type {
+ ENVELOPE,
+ FLAGS,
+ INTERNALDATE,
+ RFC822,
+ RFC822_SIZE,
+ RFC822_HEADER,
+ RFC822_TEXT,
+ BODY,
+ BODY_SECTION,
+ BODY_STRUCTURE,
+ UID,
+ MODSEQ
+ };
+
+
+ Type type;
+
+ std::unique_ptr <IMAPParser::date_time> date_time;
+ std::unique_ptr <IMAPParser::number> number;
+ std::unique_ptr <IMAPParser::envelope> envelope;
+ std::unique_ptr <IMAPParser::uniqueid> uniqueid;
+ std::unique_ptr <IMAPParser::nstring> nstring;
+ std::unique_ptr <IMAPParser::xbody> body;
+ std::unique_ptr <IMAPParser::flag_list> flag_list;
+ std::unique_ptr <IMAPParser::section> section;
+ std::unique_ptr <IMAPParser::mod_sequence_value> mod_sequence_value;
+ };
+
+
+ //
+ // msg_att ::= "(" 1#(msg_att_item) ")"
+ //
+
+ DECLARE_COMPONENT(msg_att)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_CHECK(one_char <'('> );
+
+ items.push_back(std::move(std::unique_ptr <msg_att_item>(parser.get <msg_att_item>(line, &pos))));
+
+ while (!VIMAP_PARSER_TRY_CHECK(one_char <')'> )) {
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET_PUSHBACK(msg_att_item, items);
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::vector <std::unique_ptr <msg_att_item>> items;
+ };
+
+
+ //
+ // message_data ::= nz_number SPACE ("EXPUNGE" /
+ // ("FETCH" SPACE msg_att))
+ //
+
+ DECLARE_COMPONENT(message_data)
+
+ message_data()
+ : number(0) {
+
+ }
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ scoped_ptr <nz_number> num;
+ VIMAP_PARSER_GET(nz_number, num);
+ number = static_cast <unsigned int>(num->value);
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "expunge")) {
+
+ type = EXPUNGE;
+
+ } else {
+
+ type = FETCH;
+
+ VIMAP_PARSER_CHECK_WITHARG(special_atom, "fetch");
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::msg_att, msg_att);
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ enum Type {
+ EXPUNGE,
+ FETCH
+ };
+
+
+ Type type;
+ unsigned int number;
+ std::unique_ptr <IMAPParser::msg_att> msg_att;
+ };
+
+
+ //
+ // resp_text_code ::= "ALERT" / "PARSE" /
+ // capability-data /
+ // "PERMANENTFLAGS" SPACE "(" #(flag / "\*") ")" /
+ // "READ-ONLY" / "READ-WRITE" / "TRYCREATE" /
+ // "UIDVALIDITY" SPACE nz_number /
+ // "UNSEEN" SPACE nz_number /
+ // "UIDNEXT" SPACE nz-number /
+ // atom [SPACE 1*<any TEXT_CHAR except "]">]
+ //
+ // IMAP Extension for Conditional STORE (RFC-4551):
+ //
+ // resp-text-code =/ "HIGHESTMODSEQ" SP mod-sequence-value /
+ // "NOMODSEQ" /
+ // "MODIFIED" SP set
+ //
+ // IMAP UIDPLUS Extension (RFC-4315):
+ //
+ // resp-text-code =/ "APPENDUID" SP nz-number SP append-uid /
+ // "COPYUID" SP nz-number SP uid-set SP uid-set /
+ // "UIDNOTSTICKY"
+
+ DECLARE_COMPONENT(resp_text_code)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ // "ALERT"
+ if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "alert")) {
+
+ type = ALERT;
+
+ // "PARSE"
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "parse")) {
+
+ type = PARSE;
+
+ // capability_data
+ } else if (VIMAP_PARSER_TRY_GET(IMAPParser::capability_data, capability_data)) {
+
+ type = CAPABILITY;
+
+ // "PERMANENTFLAGS" SPACE flag_list
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "permanentflags")) {
+
+ type = PERMANENTFLAGS;
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::flag_list, flag_list);
+
+ // "READ-ONLY"
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "read-only")) {
+
+ type = READ_ONLY;
+
+ // "READ-WRITE"
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "read-write")) {
+
+ type = READ_WRITE;
+
+ // "TRYCREATE"
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "trycreate")) {
+
+ type = TRYCREATE;
+
+ // "UIDVALIDITY" SPACE nz_number
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "uidvalidity")) {
+
+ type = UIDVALIDITY;
+
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::nz_number, nz_number);
+
+ // "UIDNEXT" SPACE nz_number
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "uidnext")) {
+
+ type = UIDNEXT;
+
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::nz_number, nz_number);
+
+ // "UNSEEN" SPACE nz_number
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "unseen")) {
+
+ type = UNSEEN;
+
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::nz_number, nz_number);
+
+ // "HIGHESTMODSEQ" SP mod-sequence-value
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "highestmodseq")) {
+
+ type = HIGHESTMODSEQ;
+
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::mod_sequence_value, mod_sequence_value);
+
+ // "NOMODSEQ"
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "nomodseq")) {
+
+ type = NOMODSEQ;
+
+ // "MODIFIED" SP sequence-set
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "modified")) {
+
+ type = MODIFIED;
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::sequence_set, sequence_set);
+
+ // "APPENDUID" SP nz-number SP append-uid
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "appenduid")) {
+
+ type = APPENDUID;
+
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::nz_number, nz_number);
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::uid_set, uid_set);
+
+ // "COPYUID" SP nz-number SP uid-set SP uid-set
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "copyuid")) {
+
+ type = COPYUID;
+
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::nz_number, nz_number);
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::uid_set, uid_set);
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::uid_set, uid_set2);
+
+ // "UIDNOTSTICKY"
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "uidnotsticky")) {
+
+ type = UIDNOTSTICKY;
+
+ // atom [SPACE 1*<any TEXT_CHAR except "]">]
+ } else {
+
+ type = OTHER;
+
+ VIMAP_PARSER_GET(IMAPParser::atom, atom);
+
+ if (VIMAP_PARSER_TRY_CHECK(SPACE)) {
+ VIMAP_PARSER_GET(text_except <']'> , text);
+ }
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ enum Type {
+ // Extensions
+ HIGHESTMODSEQ,
+ NOMODSEQ,
+ MODIFIED,
+ APPENDUID,
+ COPYUID,
+ UIDNOTSTICKY,
+
+ // Standard IMAP
+ ALERT,
+ PARSE,
+ CAPABILITY,
+ PERMANENTFLAGS,
+ READ_ONLY,
+ READ_WRITE,
+ TRYCREATE,
+ UIDVALIDITY,
+ UIDNEXT,
+ UNSEEN,
+ OTHER
+ };
+
+
+ Type type;
+
+ std::unique_ptr <IMAPParser::nz_number> nz_number;
+ std::unique_ptr <IMAPParser::atom> atom;
+ std::unique_ptr <IMAPParser::flag_list> flag_list;
+ std::unique_ptr <IMAPParser::text> text;
+ std::unique_ptr <IMAPParser::mod_sequence_value> mod_sequence_value;
+ std::unique_ptr <IMAPParser::sequence_set> sequence_set;
+ std::unique_ptr <IMAPParser::capability_data> capability_data;
+ std::unique_ptr <IMAPParser::uid_set> uid_set;
+ std::unique_ptr <IMAPParser::uid_set> uid_set2;
+ };
+
+
+ //
+ // resp_text ::= ["[" resp_text_code "]" SPACE] (text_mime2 / text)
+ // ;; text SHOULD NOT begin with "[" or "="
+
+ DECLARE_COMPONENT(resp_text)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ if (VIMAP_PARSER_TRY_CHECK(one_char <'['> )) {
+
+ VIMAP_PARSER_GET(IMAPParser::resp_text_code, resp_text_code);
+
+ VIMAP_PARSER_CHECK(one_char <']'> );
+ VIMAP_PARSER_TRY_CHECK(SPACE);
+ }
+
+ std::unique_ptr <text_mime2> text1;
+ VIMAP_PARSER_TRY_GET(text_mime2, text1);
+
+ if (text1.get()) {
+
+ text = text1->value;
+
+ } else {
+
+ std::unique_ptr <IMAPParser::text> text2;
+ VIMAP_PARSER_TRY_GET(IMAPParser::text, text2);
+
+ if (text2.get()) {
+ text = text2->value;
+ } else {
+ // Empty response text
+ }
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::resp_text_code> resp_text_code;
+ string text;
+ };
+
+
+ //
+ // continue_req ::= "+" SPACE (resp_text / base64)
+ //
+
+ DECLARE_COMPONENT(continue_req)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_CHECK(one_char <'+'> );
+
+ if (!parser.isStrict()) {
+
+ // Some servers do not send SPACE when response text is empty
+ if (VIMAP_PARSER_TRY_CHECK(SPACE)) {
+ VIMAP_PARSER_GET(IMAPParser::resp_text, resp_text);
+ } else {
+ resp_text.reset(new IMAPParser::resp_text()); // empty
+ }
+
+ } else {
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::resp_text, resp_text);
+ }
+
+ VIMAP_PARSER_CHECK(CRLF);
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::resp_text> resp_text;
+ };
+
+
+ //
+ // resp_cond_state ::= ("OK" / "NO" / "BAD") SPACE resp_text
+ // ;; Status condition
+ //
+
+ DECLARE_COMPONENT(resp_cond_state)
+
+ resp_cond_state()
+ : status(BAD) {
+
+ }
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "ok")) {
+ status = OK;
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "no")) {
+ status = NO;
+ } else {
+ VIMAP_PARSER_CHECK_WITHARG(special_atom, "bad");
+ status = BAD;
+ }
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::resp_text, resp_text);
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ enum Status {
+ OK,
+ NO,
+ BAD
+ };
+
+
+ std::unique_ptr <IMAPParser::resp_text> resp_text;
+ Status status;
+ };
+
+
+ //
+ // resp_cond_bye ::= "BYE" SPACE resp_text
+ //
+
+ DECLARE_COMPONENT(resp_cond_bye)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_CHECK_WITHARG(special_atom, "bye");
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::resp_text, resp_text);
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::resp_text> resp_text;
+ };
+
+
+ //
+ // resp_cond_auth ::= ("OK" / "PREAUTH") SPACE resp_text
+ // ;; Authentication condition
+ //
+
+ DECLARE_COMPONENT(resp_cond_auth)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "ok")) {
+ condition = OK;
+ } else {
+ VIMAP_PARSER_CHECK_WITHARG(special_atom, "preauth");
+ condition = PREAUTH;
+ }
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::resp_text, resp_text);
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ enum Condition {
+ OK,
+ PREAUTH
+ };
+
+
+ Condition condition;
+ std::unique_ptr <IMAPParser::resp_text> resp_text;
+ };
+
+
+ //
+ // mailbox_data ::= "FLAGS" SPACE mailbox_flag_list /
+ // "LIST" SPACE mailbox_list /
+ // "LSUB" SPACE mailbox_list /
+ // "MAILBOX" SPACE text /
+ // "SEARCH" [SPACE 1#nz_number] /
+ // "STATUS" SPACE mailbox SPACE
+ // "(" [status-att-list] ")" /
+ // number SPACE "EXISTS" /
+ // number SPACE "RECENT"
+ //
+
+ DECLARE_COMPONENT(mailbox_data)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ if (VIMAP_PARSER_TRY_GET(IMAPParser::number, number)) {
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "exists")) {
+ type = EXISTS;
+ } else {
+ VIMAP_PARSER_CHECK_WITHARG(special_atom, "recent");
+ type = RECENT;
+ }
+
+ } else {
+
+ // "FLAGS" SPACE mailbox_flag_list
+ if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "flags")) {
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::mailbox_flag_list, mailbox_flag_list);
+
+ type = FLAGS;
+
+ // "LIST" SPACE mailbox_list
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "list")) {
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::mailbox_list, mailbox_list);
+
+ type = LIST;
+
+ // "LSUB" SPACE mailbox_list
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "lsub")) {
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::mailbox_list, mailbox_list);
+
+ type = LSUB;
+
+ // "MAILBOX" SPACE text
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "mailbox")) {
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::text, text);
+
+ type = MAILBOX;
+
+ // "SEARCH" [SPACE 1#nz_number]
+ } else if (VIMAP_PARSER_TRY_CHECK_WITHARG(special_atom, "search")) {
+
+ if (VIMAP_PARSER_TRY_CHECK(SPACE)) {
+
+ VIMAP_PARSER_GET_PUSHBACK(nz_number, search_nz_number_list);
+
+ while (VIMAP_PARSER_TRY_CHECK(SPACE)) {
+ VIMAP_PARSER_GET_PUSHBACK(nz_number, search_nz_number_list);
+ }
+ }
+
+ type = SEARCH;
+
+ // "STATUS" SPACE mailbox SPACE
+ // "(" [status_att_list] ")"
+ } else {
+
+ VIMAP_PARSER_CHECK_WITHARG(special_atom, "status");
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::mailbox, mailbox);
+
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_CHECK(one_char <'('> );
+ VIMAP_PARSER_TRY_GET(IMAPParser::status_att_list, status_att_list);
+ VIMAP_PARSER_CHECK(one_char <')'> );
+
+ type = STATUS;
+ }
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ enum Type {
+
+ FLAGS,
+ LIST,
+ LSUB,
+ MAILBOX,
+ SEARCH,
+ STATUS,
+ EXISTS,
+ RECENT
+ };
+
+
+ Type type;
+
+ std::unique_ptr <IMAPParser::number> number;
+ std::unique_ptr <IMAPParser::mailbox_flag_list> mailbox_flag_list;
+ std::unique_ptr <IMAPParser::mailbox_list> mailbox_list;
+ std::unique_ptr <IMAPParser::mailbox> mailbox;
+ std::unique_ptr <IMAPParser::text> text;
+ std::vector <std::unique_ptr <nz_number>> search_nz_number_list;
+ std::unique_ptr <IMAPParser::status_att_list> status_att_list;
+ };
+
+
+ //
+ // response_data ::= "*" SPACE (resp_cond_state / resp_cond_bye /
+ // mailbox_data / message_data / capability_data) CRLF
+ //
+
+ DECLARE_COMPONENT(response_data)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_CHECK(one_char <'*'> );
+ VIMAP_PARSER_CHECK(SPACE);
+
+ if (!VIMAP_PARSER_TRY_GET(IMAPParser::resp_cond_state, resp_cond_state)) {
+ if (!VIMAP_PARSER_TRY_GET(IMAPParser::resp_cond_bye, resp_cond_bye)) {
+ if (!VIMAP_PARSER_TRY_GET(IMAPParser::mailbox_data, mailbox_data)) {
+ if (!VIMAP_PARSER_TRY_GET(IMAPParser::message_data, message_data)) {
+ VIMAP_PARSER_GET(IMAPParser::capability_data, capability_data);
+ }
+ }
+ }
+ }
+
+ if (!parser.isStrict()) {
+
+ // Allow SPACEs at end of line
+ while (VIMAP_PARSER_TRY_CHECK(SPACE)) {
+ ;
+ }
+ }
+
+ VIMAP_PARSER_CHECK(CRLF);
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::resp_cond_state> resp_cond_state;
+ std::unique_ptr <IMAPParser::resp_cond_bye> resp_cond_bye;
+ std::unique_ptr <IMAPParser::mailbox_data> mailbox_data;
+ std::unique_ptr <IMAPParser::message_data> message_data;
+ std::unique_ptr <IMAPParser::capability_data> capability_data;
+ };
+
+
+ DECLARE_COMPONENT(continue_req_or_response_data)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ if (!VIMAP_PARSER_TRY_GET(IMAPParser::continue_req, continue_req)) {
+ VIMAP_PARSER_GET(IMAPParser::response_data, response_data);
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::continue_req> continue_req;
+ std::unique_ptr <IMAPParser::response_data> response_data;
+ };
+
+
+ //
+ // response_fatal ::= "*" SPACE resp_cond_bye CRLF
+ // ;; Server closes connection immediately
+ //
+
+ DECLARE_COMPONENT(response_fatal)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_CHECK(one_char <'*'> );
+ VIMAP_PARSER_CHECK(SPACE);
+
+ VIMAP_PARSER_GET(IMAPParser::resp_cond_bye, resp_cond_bye);
+
+ if (!parser.isStrict()) {
+
+ // Allow SPACEs at end of line
+ while (VIMAP_PARSER_TRY_CHECK(SPACE)) {
+ ;
+ }
+ }
+
+ VIMAP_PARSER_CHECK(CRLF);
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::resp_cond_bye> resp_cond_bye;
+ };
+
+
+ //
+ // response_tagged ::= tag SPACE resp_cond_state CRLF
+ //
+
+ DECLARE_COMPONENT(response_tagged)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_GET(IMAPParser::xtag, tag);
+ VIMAP_PARSER_CHECK(SPACE);
+ VIMAP_PARSER_GET(IMAPParser::resp_cond_state, resp_cond_state);
+
+ if (!parser.isStrict()) {
+
+ // Allow SPACEs at end of line
+ while (VIMAP_PARSER_TRY_CHECK(SPACE)) {
+ ;
+ }
+ }
+
+ VIMAP_PARSER_CHECK(CRLF);
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::xtag> tag;
+ std::unique_ptr <IMAPParser::resp_cond_state> resp_cond_state;
+ };
+
+
+ //
+ // response_done ::= response_tagged / response_fatal
+ //
+
+ DECLARE_COMPONENT(response_done)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ if (!VIMAP_PARSER_TRY_GET(IMAPParser::response_tagged, response_tagged)) {
+ VIMAP_PARSER_GET(IMAPParser::response_fatal, response_fatal);
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ std::unique_ptr <IMAPParser::response_tagged> response_tagged;
+ std::unique_ptr <IMAPParser::response_fatal> response_fatal;
+ };
+
+
+ //
+ // response ::= *(continue_req / response_data) response_done
+ //
+
+ DECLARE_COMPONENT(response)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+ string curLine = line;
+ bool partial = false; // partial response
+
+ IMAPParser::continue_req_or_response_data* resp = NULL;
+
+ while ((resp = parser.get <IMAPParser::continue_req_or_response_data>(curLine, &pos))) {
+
+ continue_req_or_response_data.push_back(
+ std::move(
+ std::unique_ptr <IMAPParser::continue_req_or_response_data>(resp)
+ )
+ );
+
+ // Partial response (continue_req)
+ if (resp->continue_req) {
+ partial = true;
+ break;
+ }
+
+ // We have read a CRLF, read another line
+ curLine = parser.readLine();
+ pos = 0;
+ }
+
+ if (!partial) {
+ response_done.reset(parser.get <IMAPParser::response_done>(curLine, &pos));
+ VIMAP_PARSER_FAIL_UNLESS(response_done);
+ }
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+
+ bool isBad() const {
+
+ if (!response_done) { // incomplete (partial) response
+ return true;
+ }
+
+ if (response_done->response_fatal) {
+ return true;
+ }
+
+ if (response_done->response_tagged->resp_cond_state->status == IMAPParser::resp_cond_state::BAD) {
+
+ return true;
+ }
+
+ return false;
+ }
+
+ void setErrorLog(const string& errorLog) {
+
+ m_errorLog = errorLog;
+ }
+
+ const string& getErrorLog() const {
+
+ return m_errorLog;
+ }
+
+
+ std::vector <std::unique_ptr <IMAPParser::continue_req_or_response_data>> continue_req_or_response_data;
+ std::unique_ptr <IMAPParser::response_done> response_done;
+
+ private:
+
+ string m_errorLog;
+ };
+
+
+ //
+ // greeting ::= "*" SPACE (resp_cond_auth / resp_cond_bye) CRLF
+ //
+
+ DECLARE_COMPONENT(greeting)
+
+ bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) {
+
+ size_t pos = *currentPos;
+
+ VIMAP_PARSER_CHECK(one_char <'*'> );
+ VIMAP_PARSER_CHECK(SPACE);
+
+ if (!VIMAP_PARSER_TRY_GET(IMAPParser::resp_cond_auth, resp_cond_auth)) {
+ VIMAP_PARSER_GET(IMAPParser::resp_cond_bye, resp_cond_bye);
+ }
+
+ VIMAP_PARSER_CHECK(CRLF);
+
+ *currentPos = pos;
+
+ return true;
+ }
+
+ void setErrorLog(const string& errorLog) {
+
+ m_errorLog = errorLog;
+ }
+
+ const string& getErrorLog() const {
+
+ return m_errorLog;
+ }
+
+
+ std::unique_ptr <IMAPParser::resp_cond_auth> resp_cond_auth;
+ std::unique_ptr <IMAPParser::resp_cond_bye> resp_cond_bye;
+
+ private:
+
+ string m_errorLog;
+ };
+
+
+
+ //
+ // The main functions used to parse a response
+ //
+
+ response* readResponse(const IMAPTag& tag, literalHandler* lh = NULL) {
+
+ while (true) {
+
+ auto it = m_pendingResponses.find(std::string(tag));
+
+ if (it != m_pendingResponses.end()) {
+ auto* resp = it->second;
+ m_pendingResponses.erase(it);
+ return resp;
+ }
+
+ size_t pos = 0;
+ string line = readLine();
+
+ m_literalHandler = lh;
+ response* resp = get <response>(line, &pos);
+ m_literalHandler = NULL;
+
+ if (!resp) {
+ throw exceptions::invalid_response("", m_errorResponseLine);
+ }
+
+ resp->setErrorLog(lastLine());
+
+ // If there is a continue_req, return the response immediately
+ for (auto &respData : resp->continue_req_or_response_data) {
+ if (respData->continue_req) {
+ return resp;
+ }
+ }
+
+ // Else, return response if the tag is the one we expect
+ if (resp->response_done && resp->response_done->response_tagged &&
+ resp->response_done->response_tagged->tag) {
+
+ if (tag == resp->response_done->response_tagged->tag->tagString) {
+ return resp;
+ } else {
+ // Not our response tag, cache it for later
+ m_pendingResponses[resp->response_done->response_tagged->tag->tagString] = resp;
+ }
+ } else {
+ // Untagged response
+ return resp;
+ }
+ }
+ }
+
+
+ greeting* readGreeting() {
+
+ size_t pos = 0;
+ string line = readLine();
+
+ greeting* greet = get <greeting>(line, &pos);
+
+ if (!greet) {
+ throw exceptions::invalid_response("", m_errorResponseLine);
+ }
+
+ greet->setErrorLog(lastLine());
+
+ return greet;
+ }
+
+
+ /** Parse a token and advance.
+ * If the token has been parsed successfully, a raw pointer to it
+ * will be returned. The caller is responsible to free the memory.
+ *
+ * @param TYPE token type (class)
+ * @param line line which is currently being parsed
+ * @param currentPos current position in the line (will be updated
+ * when the function returns)
+ * @return a raw pointer to the parsed token, or NULL otherwise
+ */
+ template <class TYPE>
+ TYPE* get(string& line, size_t* currentPos) {
+
+ component* resp = new TYPE;
+ return internalGet <TYPE>(resp, line, currentPos);
+ }
+
+ /** Parse a token which takes 2 arguments and advance.
+ * If the token has been parsed successfully, a raw pointer to it
+ * will be returned. The caller is responsible to free the memory.
+ *
+ * @param TYPE token type (class)
+ * @param ARG1_TYPE type of argument #1 (class)
+ * @param ARG2_TYPE type of argument #2 (class)
+ * @param line line which is currently being parsed
+ * @param currentPos current position in the line (will be updated
+ * when the function returns)
+ * @param arg1 value of argument 1 to be passed to the token
+ * @param arg2 value of argument 2 to be passed to the token
+ * @return a raw pointer to the parsed token, or NULL otherwise
+ */
+ template <class TYPE, class ARG1_TYPE, class ARG2_TYPE>
+ TYPE* getWithArgs(string& line, size_t* currentPos, ARG1_TYPE arg1, ARG2_TYPE arg2) {
+
+ component* resp = new TYPE(arg1, arg2);
+ return internalGet <TYPE>(resp, line, currentPos);
+ }
+
+private:
+
+ template <class TYPE>
+ TYPE* internalGet(component* resp, string& line, size_t* currentPos) {
+
+ const size_t oldPos = *currentPos;
+
+ if (!resp->parse(*this, line, currentPos)) {
+
+ *currentPos = oldPos;
+
+ delete resp;
+
+ return NULL;
+ }
+
+ return static_cast <TYPE*>(resp);
+ }
+
+ const string lastLine() const {
+
+ // Remove blanks and new lines at the end of the line.
+ string line(m_lastLine);
+
+ string::const_iterator it = line.end();
+ int count = 0;
+
+ while (it != line.begin()) {
+
+ const unsigned char c = *(it - 1);
+
+ if (!(c == ' ' || c == '\t' || c == '\n' || c == '\r')) {
+ break;
+ }
+
+ ++count;
+ --it;
+ }
+
+ line.resize(line.length() - count);
+
+ return (line);
+ }
+
+public:
+
+ /** Check for a token and advance.
+ *
+ * @param TYPE token type (class)
+ * @param line line which is currently being parsed
+ * @param currentPos current position in the line (will be updated
+ * when the function returns)
+ * @return true if the token has been parsed, or false otherwise
+ */
+ template <class TYPE>
+ bool check(string& line, size_t* currentPos) {
+
+ const size_t oldPos = *currentPos;
+
+ TYPE term;
+
+ if (!term.parse(*this, line, currentPos)) {
+ *currentPos = oldPos;
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+ /** Check for a token which takes an argument and advance.
+ *
+ * @param TYPE token type (class)
+ * @param ARG_TYPE argument type (class)
+ * @param line line which is currently being parsed
+ * @param currentPos current position in the line (will be updated
+ * when the function returns)
+ * @param arg argument to be passed to the token
+ * @return true if the token has been parsed, or false otherwise
+ */
+ template <class TYPE, class ARG_TYPE>
+ bool checkWithArg(string& line, size_t* currentPos, const ARG_TYPE arg) {
+
+ const size_t oldPos = *currentPos;
+
+ TYPE term(arg);
+
+ if (!term.parse(*this, line, currentPos)) {
+ *currentPos = oldPos;
+ return false;
+ } else {
+ return true;
+ }
+ }
+
+
+private:
+
+ weak_ptr <socket> m_socket;
+ shared_ptr <tracer> m_tracer;
+
+ utility::progressListener* m_progress;
+
+ bool m_strict;
+
+ literalHandler* m_literalHandler;
+
+ weak_ptr <timeoutHandler> m_timeoutHandler;
+
+
+ string m_buffer;
+
+ string m_lastLine;
+ string m_errorResponseLine;
+
+ std::map <std::string, response*> m_pendingResponses;
+
+public:
+
+ /** Read a line from the input buffer. The function blocks until a
+ * complete line is read from the buffer. Position in input buffer
+ * will be updated.
+ *
+ * @return next line
+ */
+ const string readLine() {
+
+ size_t pos;
+
+ while ((pos = m_buffer.find('\n')) == string::npos) {
+ read();
+ }
+
+ string line;
+ line.resize(pos + 1);
+ std::copy(m_buffer.begin(), m_buffer.begin() + pos + 1, line.begin());
+
+ m_buffer.erase(m_buffer.begin(), m_buffer.begin() + pos + 1);
+
+ m_lastLine = line;
+
+#if DEBUG_RESPONSE
+ std::cout << std::endl << "Read line:" << std::endl << line << std::endl;
+#endif
+
+ if (m_tracer) {
+ string::size_type len = line.length();
+ while (len != 0 && (line[len - 1] == '\r' || line[len - 1] == '\n')) --len;
+ m_tracer->traceReceive(line.substr(0, len));
+ }
+
+ return (line);
+ }
+
+ /** Fill in the input buffer with data available from the socket stream.
+ * The function blocks until some data is available.
+ */
+ void read() {
+
+ string receiveBuffer;
+
+ shared_ptr <timeoutHandler> toh = m_timeoutHandler.lock();
+ shared_ptr <socket> sok = m_socket.lock();
+
+ if (toh) {
+ toh->resetTimeOut();
+ }
+
+ while (receiveBuffer.empty()) {
+
+ // Check whether the time-out delay is elapsed
+ if (toh && toh->isTimeOut()) {
+ if (!toh->handleTimeOut()) {
+ throw exceptions::operation_timed_out();
+ }
+ }
+
+ // We have received data: reset the time-out counter
+ sok->receive(receiveBuffer);
+
+ if (receiveBuffer.empty()) { // buffer is empty
+
+ if (sok->getStatus() & socket::STATUS_WANT_WRITE) {
+ sok->waitForWrite();
+ } else {
+ sok->waitForRead();
+ }
+
+ continue;
+ }
+
+ // We have received data ...
+ if (toh) {
+ toh->resetTimeOut();
+ }
+ }
+
+ m_buffer += receiveBuffer;
+ }
+
+
+ void readLiteral(literalHandler::target& buffer, size_t count) {
+
+ size_t len = 0;
+ string receiveBuffer;
+
+ shared_ptr <timeoutHandler> toh = m_timeoutHandler.lock();
+ shared_ptr <socket> sok = m_socket.lock();
+
+ if (m_progress) {
+ m_progress->start(count);
+ }
+
+ if (toh) {
+ toh->resetTimeOut();
+ }
+
+ if (!m_buffer.empty()) {
+
+ if (m_buffer.length() > count) {
+
+ buffer.putData(string(m_buffer.begin(), m_buffer.begin() + count));
+ m_buffer.erase(m_buffer.begin(), m_buffer.begin() + count);
+ len = count;
+
+ } else {
+
+ len += m_buffer.length();
+ buffer.putData(m_buffer);
+ m_buffer.clear();
+ }
+ }
+
+ while (len < count) {
+
+ // Check whether the time-out delay is elapsed
+ if (toh && toh->isTimeOut()) {
+
+ if (!toh->handleTimeOut()) {
+ throw exceptions::operation_timed_out();
+ }
+
+ toh->resetTimeOut();
+ }
+
+ // Receive data from the socket
+ sok->receive(receiveBuffer);
+
+ if (receiveBuffer.empty()) { // buffer is empty
+
+ if (sok->getStatus() & socket::STATUS_WANT_WRITE) {
+ sok->waitForWrite();
+ } else {
+ sok->waitForRead();
+ }
+
+ continue;
+ }
+
+ // We have received data: reset the time-out counter
+ if (toh) {
+ toh->resetTimeOut();
+ }
+
+ if (len + receiveBuffer.length() > count) {
+
+ const size_t remaining = count - len;
+
+ // Get the needed amount of data
+ buffer.putData(string(receiveBuffer.begin(), receiveBuffer.begin() + remaining));
+
+ // Put the remaining data into the internal response buffer
+ receiveBuffer.erase(receiveBuffer.begin(), receiveBuffer.begin() + remaining);
+ m_buffer += receiveBuffer;
+
+ len = count;
+
+ } else {
+
+ buffer.putData(receiveBuffer);
+ len += receiveBuffer.length();
+ }
+
+ // Notify progress
+ if (m_progress) {
+ m_progress->progress(len, count);
+ }
+ }
+
+ if (m_tracer) {
+ m_tracer->traceReceiveBytes(count);
+ }
+
+ if (m_progress) {
+ m_progress->stop(count);
+ }
+ }
+};
+
+
+} // imap
+} // net
+} // vmime
+
+
+#undef VIMAP_PARSER_FAIL
+#undef VIMAP_PARSER_FAIL_UNLESS
+#undef VIMAP_PARSER_CHECK
+#undef VIMAP_PARSER_TRY_CHECK
+#undef VIMAP_PARSER_GET
+#undef VIMAP_PARSER_GET
+#undef VIMAP_PARSER_TRY_GET
+#undef VIMAP_PARSER_TRY_GET
+#undef VIMAP_PARSER_GET_PUSHBACK
+#undef VIMAP_PARSER_CHECK_WITHARG
+#undef VIMAP_PARSER_TRY_CHECK_WITHARG
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+#endif // VMIME_NET_IMAP_IMAPPARSER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/imap/IMAPSStore.cpp b/vmime-master/src/vmime/net/imap/IMAPSStore.cpp
new file mode 100644
index 0000000..dd9c318
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPSStore.cpp
@@ -0,0 +1,82 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/net/imap/IMAPSStore.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+IMAPSStore::IMAPSStore(
+ const shared_ptr <session>& sess,
+ const shared_ptr <security::authenticator>& auth
+)
+ : IMAPStore(sess, auth, true) {
+
+}
+
+
+IMAPSStore::~IMAPSStore() {
+
+}
+
+
+const string IMAPSStore::getProtocolName() const {
+
+ return "imaps";
+}
+
+
+
+// Service infos
+
+IMAPServiceInfos IMAPSStore::sm_infos(true);
+
+
+const serviceInfos& IMAPSStore::getInfosInstance() {
+
+ return sm_infos;
+}
+
+
+const serviceInfos& IMAPSStore::getInfos() const {
+
+ return sm_infos;
+}
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
diff --git a/vmime-master/src/vmime/net/imap/IMAPSStore.hpp b/vmime-master/src/vmime/net/imap/IMAPSStore.hpp
new file mode 100644
index 0000000..e18a067
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPSStore.hpp
@@ -0,0 +1,70 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_IMAP_IMAPSSTORE_HPP_INCLUDED
+#define VMIME_NET_IMAP_IMAPSSTORE_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/net/imap/IMAPStore.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+/** IMAPS store service.
+ */
+class VMIME_EXPORT IMAPSStore : public IMAPStore {
+
+public:
+
+ IMAPSStore(const shared_ptr <session>& sess, const shared_ptr <security::authenticator>& auth);
+ ~IMAPSStore();
+
+ const string getProtocolName() const;
+
+ static const serviceInfos& getInfosInstance();
+ const serviceInfos& getInfos() const;
+
+private:
+
+ static IMAPServiceInfos sm_infos;
+};
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+#endif // VMIME_NET_IMAP_IMAPSSTORE_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/imap/IMAPServiceInfos.cpp b/vmime-master/src/vmime/net/imap/IMAPServiceInfos.cpp
new file mode 100644
index 0000000..baed6ba
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPServiceInfos.cpp
@@ -0,0 +1,135 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/net/imap/IMAPServiceInfos.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+IMAPServiceInfos::IMAPServiceInfos(const bool imaps)
+ : m_imaps(imaps) {
+
+}
+
+
+const string IMAPServiceInfos::getPropertyPrefix() const {
+
+ if (m_imaps) {
+ return "store.imaps.";
+ } else {
+ return "store.imap.";
+ }
+}
+
+
+const IMAPServiceInfos::props& IMAPServiceInfos::getProperties() const {
+
+ static props imapProps = {
+ // IMAP-specific options
+#if VMIME_HAVE_SASL_SUPPORT
+ property("options.sasl", serviceInfos::property::TYPE_BOOLEAN, "true"),
+ property("options.sasl.fallback", serviceInfos::property::TYPE_BOOLEAN, "true"),
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+ // Common properties
+ property(serviceInfos::property::AUTH_USERNAME, serviceInfos::property::FLAG_REQUIRED),
+ property(serviceInfos::property::AUTH_PASSWORD, serviceInfos::property::FLAG_REQUIRED),
+
+#if VMIME_HAVE_TLS_SUPPORT
+ property(serviceInfos::property::CONNECTION_TLS),
+ property(serviceInfos::property::CONNECTION_TLS_REQUIRED),
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+ property(serviceInfos::property::SERVER_ADDRESS, serviceInfos::property::FLAG_REQUIRED),
+ property(serviceInfos::property::SERVER_PORT, "143"),
+ };
+
+ static props imapsProps = {
+ // IMAP-specific options
+#if VMIME_HAVE_SASL_SUPPORT
+ property("options.sasl", serviceInfos::property::TYPE_BOOLEAN, "true"),
+ property("options.sasl.fallback", serviceInfos::property::TYPE_BOOLEAN, "true"),
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+ // Common properties
+ property(serviceInfos::property::AUTH_USERNAME, serviceInfos::property::FLAG_REQUIRED),
+ property(serviceInfos::property::AUTH_PASSWORD, serviceInfos::property::FLAG_REQUIRED),
+
+#if VMIME_HAVE_TLS_SUPPORT
+ property(serviceInfos::property::CONNECTION_TLS),
+ property(serviceInfos::property::CONNECTION_TLS_REQUIRED),
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+ property(serviceInfos::property::SERVER_ADDRESS, serviceInfos::property::FLAG_REQUIRED),
+ property(serviceInfos::property::SERVER_PORT, "993"),
+ };
+
+ return m_imaps ? imapsProps : imapProps;
+}
+
+
+const std::vector <serviceInfos::property> IMAPServiceInfos::getAvailableProperties() const {
+
+ std::vector <property> list;
+ const props& p = getProperties();
+
+ // IMAP-specific options
+#if VMIME_HAVE_SASL_SUPPORT
+ list.push_back(p.PROPERTY_OPTIONS_SASL);
+ list.push_back(p.PROPERTY_OPTIONS_SASL_FALLBACK);
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+ // Common properties
+ list.push_back(p.PROPERTY_AUTH_USERNAME);
+ list.push_back(p.PROPERTY_AUTH_PASSWORD);
+
+#if VMIME_HAVE_TLS_SUPPORT
+ if (!m_imaps) {
+ list.push_back(p.PROPERTY_CONNECTION_TLS);
+ list.push_back(p.PROPERTY_CONNECTION_TLS_REQUIRED);
+ }
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+ list.push_back(p.PROPERTY_SERVER_ADDRESS);
+ list.push_back(p.PROPERTY_SERVER_PORT);
+
+ return list;
+}
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
diff --git a/vmime-master/src/vmime/net/imap/IMAPServiceInfos.hpp b/vmime-master/src/vmime/net/imap/IMAPServiceInfos.hpp
new file mode 100644
index 0000000..73fca7a
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPServiceInfos.hpp
@@ -0,0 +1,89 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_IMAP_IMAPSERVICEINFOS_HPP_INCLUDED
+#define VMIME_NET_IMAP_IMAPSERVICEINFOS_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/net/serviceInfos.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+/** Information about IMAP service.
+ */
+class VMIME_EXPORT IMAPServiceInfos : public serviceInfos {
+
+public:
+
+ IMAPServiceInfos(const bool imaps);
+
+ struct props {
+ // IMAP-specific options
+#if VMIME_HAVE_SASL_SUPPORT
+ serviceInfos::property PROPERTY_OPTIONS_SASL;
+ serviceInfos::property PROPERTY_OPTIONS_SASL_FALLBACK;
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+ // Common properties
+ serviceInfos::property PROPERTY_AUTH_USERNAME;
+ serviceInfos::property PROPERTY_AUTH_PASSWORD;
+
+#if VMIME_HAVE_TLS_SUPPORT
+ serviceInfos::property PROPERTY_CONNECTION_TLS;
+ serviceInfos::property PROPERTY_CONNECTION_TLS_REQUIRED;
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+ serviceInfos::property PROPERTY_SERVER_ADDRESS;
+ serviceInfos::property PROPERTY_SERVER_PORT;
+ };
+
+ const props& getProperties() const;
+
+ const string getPropertyPrefix() const;
+ const std::vector <serviceInfos::property> getAvailableProperties() const;
+
+private:
+
+ const bool m_imaps;
+};
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+#endif // VMIME_NET_IMAP_IMAPSERVICEINFOS_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/imap/IMAPStore.cpp b/vmime-master/src/vmime/net/imap/IMAPStore.cpp
new file mode 100644
index 0000000..eafa444
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPStore.cpp
@@ -0,0 +1,287 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/net/imap/IMAPStore.hpp"
+#include "vmime/net/imap/IMAPFolder.hpp"
+#include "vmime/net/imap/IMAPConnection.hpp"
+#include "vmime/net/imap/IMAPFolderStatus.hpp"
+#include "vmime/net/imap/IMAPCommand.hpp"
+
+#include "vmime/exception.hpp"
+#include "vmime/platform.hpp"
+
+#include <map>
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+IMAPStore::IMAPStore(
+ const shared_ptr <session>& sess,
+ const shared_ptr <security::authenticator>& auth,
+ const bool secured
+)
+ : store(sess, getInfosInstance(), auth),
+ m_connection(null),
+ m_isIMAPS(secured) {
+
+}
+
+
+IMAPStore::~IMAPStore() {
+
+ try {
+
+ if (isConnected()) {
+ disconnect();
+ }
+
+ } catch (...) {
+
+ // Don't throw in destructor
+ }
+}
+
+
+const string IMAPStore::getProtocolName() const {
+
+ return "imap";
+}
+
+
+shared_ptr <folder> IMAPStore::getRootFolder() {
+
+ if (!isConnected()) {
+ throw exceptions::illegal_state("Not connected");
+ }
+
+ return make_shared <IMAPFolder>(
+ folder::path(),
+ dynamicCast <IMAPStore>(shared_from_this()),
+ shared_ptr <folderAttributes>()
+ );
+}
+
+
+shared_ptr <folder> IMAPStore::getDefaultFolder() {
+
+ if (!isConnected()) {
+ throw exceptions::illegal_state("Not connected");
+ }
+
+ return make_shared <IMAPFolder>(
+ folder::path::component("INBOX"),
+ dynamicCast <IMAPStore>(shared_from_this()),
+ shared_ptr <folderAttributes>()
+ );
+}
+
+
+shared_ptr <folder> IMAPStore::getFolder(const folder::path& path) {
+
+ if (!isConnected()) {
+ throw exceptions::illegal_state("Not connected");
+ }
+
+ return make_shared <IMAPFolder>(
+ path,
+ dynamicCast <IMAPStore>(shared_from_this()),
+ shared_ptr <folderAttributes>()
+ );
+}
+
+
+bool IMAPStore::isValidFolderName(const folder::path::component& /* name */) const {
+
+ return true;
+}
+
+
+void IMAPStore::connect() {
+
+ if (isConnected()) {
+ throw exceptions::already_connected();
+ }
+
+ m_connection = make_shared <IMAPConnection>(
+ dynamicCast <IMAPStore>(shared_from_this()), getAuthenticator()
+ );
+
+ m_connection->connect();
+}
+
+
+bool IMAPStore::isConnected() const {
+
+ return m_connection && m_connection->isConnected();
+}
+
+
+bool IMAPStore::isIMAPS() const {
+
+ return m_isIMAPS;
+}
+
+
+bool IMAPStore::isSecuredConnection() const {
+
+ if (!m_connection) {
+ return false;
+ }
+
+ return m_connection->isSecuredConnection();
+}
+
+
+shared_ptr <connectionInfos> IMAPStore::getConnectionInfos() const {
+
+ if (!m_connection) {
+ return null;
+ }
+
+ return m_connection->getConnectionInfos();
+}
+
+
+shared_ptr <IMAPConnection> IMAPStore::getConnection() {
+
+ return m_connection;
+}
+
+
+void IMAPStore::disconnect() {
+
+ if (!isConnected()) {
+ throw exceptions::not_connected();
+ }
+
+ for (std::list <IMAPFolder*>::iterator it = m_folders.begin() ;
+ it != m_folders.end() ; ++it) {
+
+ (*it)->onStoreDisconnected();
+ }
+
+ m_folders.clear();
+
+
+ m_connection->disconnect();
+
+ m_connection = null;
+}
+
+
+void IMAPStore::noop() {
+
+ if (!isConnected()) {
+ throw exceptions::not_connected();
+ }
+
+ IMAPCommand::NOOP()->send(m_connection);
+
+ scoped_ptr <IMAPParser::response> resp(m_connection->readResponse());
+
+ if (resp->isBad() || resp->response_done->response_tagged->
+ resp_cond_state->status != IMAPParser::resp_cond_state::OK) {
+
+ throw exceptions::command_error("NOOP", resp->getErrorLog());
+ }
+
+
+ for (std::list <IMAPFolder*>::iterator it = m_folders.begin() ;
+ it != m_folders.end() ; ++it) {
+
+ if ((*it)->isOpen()) {
+ (*it)->noop();
+ }
+ }
+}
+
+
+shared_ptr <IMAPConnection> IMAPStore::connection() {
+
+ return m_connection;
+}
+
+
+void IMAPStore::registerFolder(IMAPFolder* folder) {
+
+ m_folders.push_back(folder);
+}
+
+
+void IMAPStore::unregisterFolder(IMAPFolder* folder) {
+
+ std::list <IMAPFolder*>::iterator it = std::find(m_folders.begin(), m_folders.end(), folder);
+
+ if (it != m_folders.end()) {
+ m_folders.erase(it);
+ }
+}
+
+
+int IMAPStore::getCapabilities() const {
+
+ return CAPABILITY_CREATE_FOLDER |
+ CAPABILITY_RENAME_FOLDER |
+ CAPABILITY_ADD_MESSAGE |
+ CAPABILITY_COPY_MESSAGE |
+ CAPABILITY_DELETE_MESSAGE |
+ CAPABILITY_PARTIAL_FETCH |
+ CAPABILITY_MESSAGE_FLAGS |
+ CAPABILITY_EXTRACT_PART;
+}
+
+
+
+// Service infos
+
+IMAPServiceInfos IMAPStore::sm_infos(false);
+
+
+const serviceInfos& IMAPStore::getInfosInstance() {
+
+ return sm_infos;
+}
+
+
+const serviceInfos& IMAPStore::getInfos() const {
+
+ return sm_infos;
+}
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
diff --git a/vmime-master/src/vmime/net/imap/IMAPStore.hpp b/vmime-master/src/vmime/net/imap/IMAPStore.hpp
new file mode 100644
index 0000000..018c195
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPStore.hpp
@@ -0,0 +1,124 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_IMAP_IMAPSTORE_HPP_INCLUDED
+#define VMIME_NET_IMAP_IMAPSTORE_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/net/store.hpp"
+#include "vmime/net/socket.hpp"
+#include "vmime/net/folder.hpp"
+
+#include "vmime/net/imap/IMAPServiceInfos.hpp"
+#include "vmime/net/imap/IMAPConnection.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+class IMAPParser;
+class IMAPTag;
+class IMAPFolder;
+
+
+/** IMAP store service.
+ */
+class VMIME_EXPORT IMAPStore : public store {
+
+ friend class IMAPFolder;
+ friend class IMAPMessage;
+ friend class IMAPConnection;
+
+public:
+
+ IMAPStore(
+ const shared_ptr <session>& sess,
+ const shared_ptr <security::authenticator>& auth,
+ const bool secured = false
+ );
+
+ ~IMAPStore();
+
+ const string getProtocolName() const;
+
+ shared_ptr <folder> getDefaultFolder();
+ shared_ptr <folder> getRootFolder();
+ shared_ptr <folder> getFolder(const folder::path& path);
+
+ bool isValidFolderName(const folder::path::component& name) const;
+
+ static const serviceInfos& getInfosInstance();
+ const serviceInfos& getInfos() const;
+
+ void connect();
+ bool isConnected() const;
+ void disconnect();
+
+ void noop();
+
+ int getCapabilities() const;
+
+ bool isIMAPS() const;
+
+ bool isSecuredConnection() const;
+ shared_ptr <connectionInfos> getConnectionInfos() const;
+ shared_ptr <IMAPConnection> getConnection();
+
+protected:
+
+ // Connection
+ shared_ptr <IMAPConnection> m_connection;
+
+
+
+ shared_ptr <IMAPConnection> connection();
+
+
+ void registerFolder(IMAPFolder* folder);
+ void unregisterFolder(IMAPFolder* folder);
+
+ std::list <IMAPFolder*> m_folders;
+
+ const bool m_isIMAPS; // Use IMAPS
+
+
+ static IMAPServiceInfos sm_infos;
+};
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+#endif // VMIME_NET_IMAP_IMAPSTORE_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/imap/IMAPTag.cpp b/vmime-master/src/vmime/net/imap/IMAPTag.cpp
new file mode 100644
index 0000000..52cd212
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPTag.cpp
@@ -0,0 +1,148 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/net/imap/IMAPTag.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+const int IMAPTag::sm_maxNumber = 52 * 10 * 10 * 10;
+
+
+IMAPTag::IMAPTag(const int number)
+ : m_number(number) {
+
+ m_tag.resize(4);
+ generate();
+}
+
+
+IMAPTag::IMAPTag(const IMAPTag& tag)
+ : object(),
+ m_number(tag.m_number) {
+
+ m_tag.resize(4);
+ generate();
+}
+
+
+IMAPTag::IMAPTag()
+ : m_number(1) {
+
+ m_tag.resize(4);
+ generate();
+}
+
+
+IMAPTag& IMAPTag::operator++() {
+
+ ++m_number;
+
+ if (m_number >= sm_maxNumber) {
+ m_number = 1;
+ }
+
+ generate();
+
+ return *this;
+}
+
+
+const IMAPTag IMAPTag::operator++(int) {
+
+ IMAPTag old(*this);
+ operator++();
+ return old;
+}
+
+
+bool IMAPTag::operator<(const IMAPTag &other) const {
+
+ return m_number < other.m_number;
+}
+
+
+bool IMAPTag::operator==(const IMAPTag &other) const {
+
+ return m_number == other.m_number;
+}
+
+
+bool IMAPTag::operator!=(const IMAPTag &other) const {
+
+ return m_number != other.m_number;
+}
+
+
+bool IMAPTag::operator==(const std::string &tag) const {
+
+ return m_tag == tag;
+}
+
+
+int IMAPTag::maximumNumber() const {
+
+ return sm_maxNumber - 1;
+}
+
+
+int IMAPTag::number() const {
+
+ return m_number;
+}
+
+
+IMAPTag::operator string() const
+{
+ return m_tag;
+}
+
+
+void IMAPTag::generate() {
+
+ static const char prefixChars[53] =
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
+
+ m_tag[0] = prefixChars[m_number / 1000];
+ m_tag[1] = static_cast <char>('0' + (m_number % 1000) / 100);
+ m_tag[2] = static_cast <char>('0' + (m_number % 100) / 10);
+ m_tag[3] = static_cast <char>('0' + m_number % 10);
+}
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
diff --git a/vmime-master/src/vmime/net/imap/IMAPTag.hpp b/vmime-master/src/vmime/net/imap/IMAPTag.hpp
new file mode 100644
index 0000000..cbab942
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPTag.hpp
@@ -0,0 +1,85 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_IMAP_IMAPTAG_HPP_INCLUDED
+#define VMIME_NET_IMAP_IMAPTAG_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/types.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+class VMIME_EXPORT IMAPTag : public object {
+
+private:
+
+ IMAPTag(const int number);
+
+public:
+
+ IMAPTag();
+ IMAPTag(const IMAPTag& tag);
+
+ IMAPTag& operator++(); // ++IMAPTag
+ const IMAPTag operator++(int); // IMAPTag++
+
+ int maximumNumber() const;
+ int number() const;
+
+ operator string() const;
+
+ bool operator<(const IMAPTag &other) const;
+ bool operator==(const IMAPTag &other) const;
+ bool operator!=(const IMAPTag &other) const;
+
+ bool operator==(const std::string &tag) const;
+
+private:
+
+ void generate();
+
+ static const int sm_maxNumber;
+
+ int m_number;
+ string m_tag;
+};
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+#endif // VMIME_NET_IMAP_IMAPTAG_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/imap/IMAPUtils.cpp b/vmime-master/src/vmime/net/imap/IMAPUtils.cpp
new file mode 100644
index 0000000..59b1e18
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPUtils.cpp
@@ -0,0 +1,854 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/net/imap/IMAPUtils.hpp"
+#include "vmime/net/imap/IMAPStore.hpp"
+
+#include "vmime/net/message.hpp"
+#include "vmime/net/folder.hpp"
+
+#include <sstream>
+#include <iterator>
+#include <algorithm>
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+// static
+const string IMAPUtils::quoteString(const string& text) {
+
+ //
+ // ATOM_CHAR ::= <any CHAR except atom_specials>
+ //
+ // atom_specials ::= "(" / ")" / "{" / SPACE / CTL /
+ // list_wildcards / quoted_specials
+ //
+ // list_wildcards ::= "%" / "*"
+ //
+ // quoted_specials ::= <"> / "\"
+ //
+ // CHAR ::= <any 7-bit US-ASCII character except NUL,
+ // 0x01 - 0x7f>
+ //
+ // CTL ::= <any ASCII control character and DEL,
+ // 0x00 - 0x1f, 0x7f>
+ //
+
+ bool needQuoting = text.empty();
+
+ for (string::const_iterator it = text.begin() ;
+ !needQuoting && it != text.end() ; ++it) {
+
+ const unsigned char c = *it;
+
+ switch (c) {
+
+ case '(':
+ case ')':
+ case '{':
+ case 0x20: // SPACE
+ case '%':
+ case '*':
+ case '"':
+ case '\\':
+
+ needQuoting = true;
+ break;
+
+ default:
+
+ if (c <= 0x1f || c >= 0x7f) {
+ needQuoting = true;
+ }
+ }
+ }
+
+ if (needQuoting) {
+
+ string quoted;
+ quoted.reserve((text.length() * 3) / 2 + 2);
+
+ quoted += '"';
+
+ for (string::const_iterator it = text.begin() ; it != text.end() ; ++it) {
+
+ const unsigned char c = *it;
+
+ if (c == '\\' || c == '"') {
+ quoted += '\\';
+ }
+
+ quoted += c;
+ }
+
+ quoted += '"';
+
+ return quoted;
+
+ } else {
+
+ return text;
+ }
+}
+
+
+const string IMAPUtils::pathToString(
+ const char hierarchySeparator,
+ const folder::path& path
+) {
+
+ string result;
+
+ for (size_t i = 0 ; i < path.getSize() ; ++i) {
+
+ if (i > 0) result += hierarchySeparator;
+ result += toModifiedUTF7(hierarchySeparator, path[i]);
+ }
+
+ return (result);
+}
+
+
+const folder::path IMAPUtils::stringToPath(
+ const char hierarchySeparator,
+ const string& str
+) {
+
+ folder::path result;
+ string::const_iterator begin = str.begin();
+
+ for (string::const_iterator it = str.begin() ; it != str.end() ; ++it) {
+
+ if (*it == hierarchySeparator) {
+ result /= fromModifiedUTF7(string(begin, it));
+ begin = it + 1;
+ }
+ }
+
+ if (begin != str.end()) {
+ result /= fromModifiedUTF7(string(begin, str.end()));
+ }
+
+ return result;
+}
+
+
+const string IMAPUtils::toModifiedUTF7(
+ const char hierarchySeparator,
+ const folder::path::component& text
+) {
+
+ // We will replace the hierarchy separator with an equivalent
+ // UTF-7 sequence, so we compute it here...
+ const char base64alphabet[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+,=";
+
+ const unsigned int hs = static_cast <unsigned int>(static_cast <unsigned char>(hierarchySeparator));
+
+ string hsUTF7;
+ hsUTF7.resize(3);
+
+ hsUTF7[0] = base64alphabet[0];
+ hsUTF7[1] = base64alphabet[(hs & 0xF0) >> 4];
+ hsUTF7[2] = base64alphabet[(hs & 0x0F) << 2];
+
+ // iconv() is buggy with UTF-8 to UTF-7 conversion, so we do it "by hand".
+ // This code is largely inspired from "imap/utf7.c", in mutt 1.4.
+ // Copyright (C) 2000 Edmund Grimley Evans <edmundo@rano.org>
+
+ // WARNING: This may throw "exceptions::charset_conv_error"
+ const string cvt = text.getConvertedText(charset(charsets::UTF_8));
+
+ // In the worst case we convert 2 chars to 7 chars.
+ // For example: "\x10&\x10&..." -> "&ABA-&-&ABA-&-...".
+ string out;
+ out.reserve((cvt.length() / 2) * 7 + 6);
+
+ int b = 0, k = 0;
+ bool base64 = false;
+
+ size_t remaining = cvt.length();
+
+ for (size_t i = 0, len = cvt.length() ; i < len ; ) {
+
+ const unsigned char c = cvt[i];
+
+ // Replace hierarchy separator with an equivalent UTF-7 Base64 sequence
+ if (!base64 && c == hierarchySeparator) {
+
+ out += "&" + hsUTF7 + "-";
+
+ ++i;
+ --remaining;
+ continue;
+ }
+
+ size_t n = 0;
+ int ch = 0;
+
+ if (c < 0x80) {
+ ch = c, n = 0;
+ } else if (c < 0xc2) {
+ return "";
+ } else if (c < 0xe0) {
+ ch = c & 0x1f, n = 1;
+ } else if (c < 0xf0) {
+ ch = c & 0x0f, n = 2;
+ } else if (c < 0xf8) {
+ ch = c & 0x07, n = 3;
+ } else if (c < 0xfc) {
+ ch = c & 0x03, n = 4;
+ } else if (c < 0xfe) {
+ ch = c & 0x01, n = 5;
+ } else {
+ return "";
+ }
+
+ if (n > remaining) {
+ return ""; // error
+ }
+
+ ++i;
+ --remaining;
+
+ for (size_t j = 0 ; j < n ; j++) {
+
+ if ((cvt[i + j] & 0xc0) != 0x80) {
+ return ""; // error
+ }
+
+ ch = (ch << 6) | (cvt[i + j] & 0x3f);
+ }
+
+ if (n > 1 && !(ch >> (n * 5 + 1))) {
+ return ""; // error
+ }
+
+ i += n;
+ remaining -= n;
+
+ if (ch < 0x20 || ch >= 0x7f) {
+
+ if (!base64) {
+ out += '&';
+ base64 = true;
+ b = 0;
+ k = 10;
+ }
+
+ if (ch & ~0xffff) {
+ ch = 0xfffe;
+ }
+
+ out += base64alphabet[b | ch >> k];
+
+ k -= 6;
+
+ for ( ; k >= 0 ; k -= 6) {
+ out += base64alphabet[(ch >> k) & 0x3f];
+ }
+
+ b = (ch << (-k)) & 0x3f;
+ k += 16;
+
+ } else {
+
+ if (base64) {
+
+ if (k > 10) {
+ out += base64alphabet[b];
+ }
+
+ out += '-';
+ base64 = false;
+ }
+
+ out += static_cast <char>(ch);
+
+ if (ch == '&') {
+ out += '-';
+ }
+ }
+ }
+
+ if (base64) {
+
+ if (k > 10) {
+ out += base64alphabet[b];
+ }
+
+ out += '-';
+ }
+
+ return (out);
+}
+
+
+const folder::path::component IMAPUtils::fromModifiedUTF7(const string& text) {
+
+ // Transcode from modified UTF-7 (RFC-2060).
+ string out;
+ out.reserve(text.length());
+
+ bool inB64sequence = false;
+ bool plusOutput = false;
+ unsigned char prev = 0;
+
+ for (string::const_iterator it = text.begin() ; it != text.end() ; ++it) {
+
+ const unsigned char c = *it;
+
+ switch (c) {
+
+ // Start of Base64 sequence
+ case '&': {
+
+ if (!inB64sequence) {
+ inB64sequence = true;
+ plusOutput = false;
+ } else {
+ out += '&';
+ }
+
+ break;
+ }
+ // End of Base64 sequence (or "&-" --> "&")
+ case '-': {
+
+ if (inB64sequence && prev == '&') { // special case "&-" --> "&"
+ out += '&';
+ } else {
+ out += '-';
+ }
+
+ inB64sequence = false;
+ break;
+ }
+ // ',' is used instead of '/' in modified Base64
+ case ',': {
+
+ if (inB64sequence && !plusOutput) {
+ out += '+';
+ plusOutput = true;
+ }
+
+ out += (inB64sequence ? '/' : ',');
+ break;
+ }
+ default: {
+
+ if (inB64sequence && !plusOutput) {
+ out += '+';
+ plusOutput = true;
+ }
+
+ out += c;
+ break;
+ }
+ }
+
+ prev = c;
+ }
+
+ // Store it as UTF-8 by default
+ string cvt;
+ charset::convert(out, cvt, charset(charsets::UTF_7), charset(charsets::UTF_8));
+
+ return folder::path::component(cvt, charset(charsets::UTF_8));
+}
+
+
+// static
+void IMAPUtils::mailboxFlagsToFolderAttributes(
+ const shared_ptr <const IMAPConnection>& cnt,
+ const folder::path &path,
+ const IMAPParser::mailbox_flag_list& list,
+ folderAttributes& attribs
+) {
+
+ int specialUse = folderAttributes::SPECIALUSE_NONE;
+ int type = folderAttributes::TYPE_CONTAINS_MESSAGES | folderAttributes::TYPE_CONTAINS_FOLDERS;
+ int flags = 0;
+
+ // If CHILDREN extension (RFC-3348) is not supported, assume folder has children
+ // as we have no hint about it
+ if (!cnt->hasCapability("CHILDREN")) {
+ flags |= folderAttributes::FLAG_HAS_CHILDREN;
+ }
+
+ for (auto it = list.flags.begin() ; it != list.flags.end() ; ++it) {
+
+ switch ((*it)->type) {
+
+ case IMAPParser::mailbox_flag::NOSELECT:
+
+ type &= ~folderAttributes::TYPE_CONTAINS_MESSAGES;
+ flags |= folderAttributes::FLAG_NO_OPEN;
+ break;
+
+ case IMAPParser::mailbox_flag::NOINFERIORS:
+ case IMAPParser::mailbox_flag::HASNOCHILDREN:
+
+ flags &= ~folderAttributes::FLAG_HAS_CHILDREN;
+ break;
+
+ case IMAPParser::mailbox_flag::HASCHILDREN:
+
+ flags |= folderAttributes::FLAG_HAS_CHILDREN;
+ break;
+
+ case IMAPParser::mailbox_flag::SPECIALUSE_ALL:
+
+ specialUse = folderAttributes::SPECIALUSE_ALL;
+ break;
+
+ case IMAPParser::mailbox_flag::SPECIALUSE_ARCHIVE:
+
+ specialUse = folderAttributes::SPECIALUSE_ARCHIVE;
+ break;
+
+ case IMAPParser::mailbox_flag::SPECIALUSE_DRAFTS:
+
+ specialUse = folderAttributes::SPECIALUSE_DRAFTS;
+ break;
+
+ case IMAPParser::mailbox_flag::SPECIALUSE_FLAGGED:
+
+ specialUse = folderAttributes::SPECIALUSE_FLAGGED;
+ break;
+
+ case IMAPParser::mailbox_flag::SPECIALUSE_JUNK:
+
+ specialUse = folderAttributes::SPECIALUSE_JUNK;
+ break;
+
+ case IMAPParser::mailbox_flag::SPECIALUSE_SENT:
+
+ specialUse = folderAttributes::SPECIALUSE_SENT;
+ break;
+
+ case IMAPParser::mailbox_flag::SPECIALUSE_TRASH:
+
+ specialUse = folderAttributes::SPECIALUSE_TRASH;
+ break;
+
+ case IMAPParser::mailbox_flag::SPECIALUSE_IMPORTANT:
+
+ specialUse = folderAttributes::SPECIALUSE_IMPORTANT;
+ break;
+
+ default:
+
+ break;
+ }
+ }
+
+ if (path.getSize() == 1 && path.getLastComponent().getBuffer() == "INBOX") {
+ specialUse = folderAttributes::SPECIALUSE_INBOX;
+ }
+
+ attribs.setSpecialUse(specialUse);
+ attribs.setType(type);
+ attribs.setFlags(flags);
+}
+
+
+int IMAPUtils::messageFlagsFromFlags(const IMAPParser::flag_list& list) {
+
+ int flags = 0;
+
+ for (auto &flag : list.flags) {
+
+ switch (flag->type) {
+
+ case IMAPParser::flag::ANSWERED:
+
+ flags |= message::FLAG_REPLIED;
+ break;
+
+ case IMAPParser::flag::FLAGGED:
+
+ flags |= message::FLAG_MARKED;
+ break;
+
+ case IMAPParser::flag::DELETED:
+
+ flags |= message::FLAG_DELETED;
+ break;
+
+ case IMAPParser::flag::SEEN:
+
+ flags |= message::FLAG_SEEN;
+ break;
+
+ case IMAPParser::flag::DRAFT:
+
+ flags |= message::FLAG_DRAFT;
+ break;
+
+ default:
+ //case IMAPParser::flag::UNKNOWN:
+
+ break;
+ }
+ }
+
+ return flags;
+}
+
+
+// static
+const std::vector <string> IMAPUtils::messageFlagList(const int flags) {
+
+ std::vector <string> flagList;
+
+ if (flags == -1) {
+ return flagList; // default flags
+ }
+
+ if (flags & message::FLAG_REPLIED) flagList.push_back("\\Answered");
+ if (flags & message::FLAG_MARKED) flagList.push_back("\\Flagged");
+ if (flags & message::FLAG_DELETED) flagList.push_back("\\Deleted");
+ if (flags & message::FLAG_SEEN) flagList.push_back("\\Seen");
+ if (flags & message::FLAG_DRAFT) flagList.push_back("\\Draft");
+
+ return flagList;
+}
+
+
+// static
+const string IMAPUtils::dateTime(const vmime::datetime& date) {
+
+ std::ostringstream res;
+ res.imbue(std::locale::classic());
+
+ // date_time ::= <"> date_day_fixed "-" date_month "-" date_year
+ // SPACE time SPACE zone <">
+ //
+ // time ::= 2digit ":" 2digit ":" 2digit
+ // ;; Hours minutes seconds
+ // zone ::= ("+" / "-") 4digit
+ // ;; Signed four-digit value of hhmm representing
+ // ;; hours and minutes west of Greenwich
+ res << '"';
+
+ // Date
+ if (date.getDay() < 10) res << ' ';
+ res << date.getDay();
+
+ res << '-';
+
+ static const char* monthNames[12] = {
+ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
+ "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
+ };
+
+ res << monthNames[std::min(std::max(date.getMonth() - 1, 0), 11)];
+
+ res << '-';
+
+ if (date.getYear() < 10) res << '0';
+ if (date.getYear() < 100) res << '0';
+ if (date.getYear() < 1000) res << '0';
+ res << date.getYear();
+
+ res << ' ';
+
+ // Time
+ if (date.getHour() < 10) res << '0';
+ res << date.getHour() << ':';
+
+ if (date.getMinute() < 10) res << '0';
+ res << date.getMinute() << ':';
+
+ if (date.getSecond() < 10) res << '0';
+ res << date.getSecond();
+
+ res << ' ';
+
+ // Zone
+ const int zs = (date.getZone() < 0 ? -1 : 1);
+ const int zh = (date.getZone() * zs) / 60;
+ const int zm = (date.getZone() * zs) % 60;
+
+ res << (zs < 0 ? '-' : '+');
+
+ if (zh < 10) res << '0';
+ res << zh;
+
+ if (zm < 10) res << '0';
+ res << zm;
+
+ res << '"';
+
+ return res.str();
+}
+
+
+// static
+shared_ptr <IMAPCommand> IMAPUtils::buildFetchCommand(
+ const shared_ptr <IMAPConnection>& cnt,
+ const messageSet& msgs,
+ const fetchAttributes& options
+) {
+
+ // Example:
+ // C: A654 FETCH 2:4 (FLAGS BODY[HEADER.FIELDS (DATE FROM)])
+ // S: * 2 FETCH ....
+ // S: * 3 FETCH ....
+ // S: * 4 FETCH ....
+ // S: A654 OK FETCH completed
+
+ std::vector <string> items;
+
+ if (options.has(fetchAttributes::SIZE)) {
+ items.push_back("RFC822.SIZE");
+ }
+
+ if (options.has(fetchAttributes::FLAGS)) {
+ items.push_back("FLAGS");
+ }
+
+ if (options.has(fetchAttributes::STRUCTURE)) {
+ items.push_back("BODYSTRUCTURE");
+ }
+
+ if (options.has(fetchAttributes::UID)) {
+
+ items.push_back("UID");
+
+ // Also fetch MODSEQ if CONDSTORE is supported
+ if (cnt && cnt->hasCapability("CONDSTORE") && !cnt->isMODSEQDisabled()) {
+ items.push_back("MODSEQ");
+ }
+ }
+
+ if (options.has(fetchAttributes::FULL_HEADER)) {
+
+ items.push_back("RFC822.HEADER");
+
+ } else {
+
+ if (options.has(fetchAttributes::ENVELOPE)) {
+ items.push_back("ENVELOPE");
+ }
+
+ std::vector <string> headerFields;
+
+ if (options.has(fetchAttributes::CONTENT_INFO)) {
+ headerFields.push_back("CONTENT_TYPE");
+ }
+
+ if (options.has(fetchAttributes::IMPORTANCE)) {
+ headerFields.push_back("IMPORTANCE");
+ headerFields.push_back("X-PRIORITY");
+ }
+
+ // Also add custom header fields to fetch, if any
+ const std::vector <string> customHeaderFields = options.getHeaderFields();
+ std::copy(customHeaderFields.begin(), customHeaderFields.end(), std::back_inserter(headerFields));
+
+ if (!headerFields.empty()) {
+
+ string list;
+
+ for (std::vector <string>::iterator it = headerFields.begin() ;
+ it != headerFields.end() ; ++it) {
+
+ if (it != headerFields.begin()) {
+ list += " ";
+ }
+
+ list += *it;
+ }
+
+ items.push_back("BODY[HEADER.FIELDS (" + list + ")]");
+ }
+ }
+
+ return IMAPCommand::FETCH(msgs, items);
+}
+
+
+// static
+void IMAPUtils::convertAddressList(
+ const IMAPParser::address_list& src,
+ mailboxList& dest
+) {
+
+ for (auto& addr : src.addresses) {
+
+ text name;
+ text::decodeAndUnfold(addr->addr_name->value, &name);
+
+ string email = addr->addr_mailbox->value
+ + "@" + addr->addr_host->value;
+
+ dest.appendMailbox(make_shared <mailbox>(name, email));
+ }
+}
+
+
+
+class IMAPUIDMessageSetEnumerator : public messageSetEnumerator {
+
+public:
+
+ IMAPUIDMessageSetEnumerator()
+ : m_first(true) {
+
+ m_oss.imbue(std::locale::classic());
+ }
+
+ void enumerateNumberMessageRange(const vmime::net::numberMessageRange& range) {
+
+ if (!m_first) {
+ m_oss << ",";
+ }
+
+ if (range.getFirst() == range.getLast()) {
+ m_oss << range.getFirst();
+ } else if (range.getLast() == size_t(-1)) {
+ m_oss << range.getFirst() << ":*";
+ } else {
+ m_oss << range.getFirst() << ":" << range.getLast();
+ }
+
+ m_first = false;
+ }
+
+ void enumerateUIDMessageRange(const vmime::net::UIDMessageRange& range) {
+
+ if (!m_first) {
+ m_oss << ",";
+ }
+
+ if (range.getFirst() == range.getLast()) {
+ m_oss << range.getFirst();
+ } else if (range.getLast() == size_t(-1)) {
+ m_oss << range.getFirst() << ":*";
+ } else {
+ m_oss << range.getFirst() << ":" << range.getLast();
+ }
+
+ m_first = false;
+ }
+
+ const std::string str() const {
+
+ return m_oss.str();
+ }
+
+private:
+
+ std::ostringstream m_oss;
+ bool m_first;
+};
+
+
+class IMAPMessageSetEnumerator : public messageSetEnumerator {
+
+public:
+
+ void enumerateNumberMessageRange(const vmime::net::numberMessageRange& range) {
+
+ for (size_t i = range.getFirst(), last = range.getLast() ; i <= last ; ++i) {
+ m_list.push_back(i);
+ }
+ }
+
+ void enumerateUIDMessageRange(const vmime::net::UIDMessageRange& /* range */) {
+
+ // Not used
+ }
+
+ const std::vector <size_t>& list() const {
+
+ return m_list;
+ }
+
+public:
+
+ std::vector <size_t> m_list;
+};
+
+
+
+// static
+const string IMAPUtils::messageSetToSequenceSet(const messageSet& msgs) {
+
+ IMAPUIDMessageSetEnumerator en;
+ msgs.enumerate(en);
+
+ return en.str();
+}
+
+
+// static
+messageSet IMAPUtils::buildMessageSet(const IMAPParser::uid_set& uidSetRef) {
+
+ messageSet set = messageSet::empty();
+
+ const IMAPParser::uid_set* uidSet = &uidSetRef;
+
+ for ( ; uidSet ; uidSet = uidSet->next_uid_set.get()) {
+
+ if (uidSet->uid_range) {
+
+ set.addRange(
+ UIDMessageRange(
+ message::uid(uidSet->uid_range->uniqueid1->value),
+ message::uid(uidSet->uid_range->uniqueid2->value)
+ )
+ );
+
+ } else {
+
+ set.addRange(
+ UIDMessageRange(
+ message::uid(uidSet->uniqueid->value)
+ )
+ );
+ }
+ }
+
+ return set;
+}
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
diff --git a/vmime-master/src/vmime/net/imap/IMAPUtils.hpp b/vmime-master/src/vmime/net/imap/IMAPUtils.hpp
new file mode 100644
index 0000000..d4bd135
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/IMAPUtils.hpp
@@ -0,0 +1,144 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_IMAP_IMAPUTILS_HPP_INCLUDED
+#define VMIME_NET_IMAP_IMAPUTILS_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+
+#include "vmime/types.hpp"
+#include "vmime/dateTime.hpp"
+
+#include "vmime/net/folder.hpp"
+#include "vmime/net/message.hpp"
+#include "vmime/net/imap/IMAPParser.hpp"
+#include "vmime/net/imap/IMAPConnection.hpp"
+#include "vmime/net/imap/IMAPCommand.hpp"
+
+#include "vmime/mailboxList.hpp"
+
+#include <vector>
+
+
+namespace vmime {
+namespace net {
+namespace imap {
+
+
+class VMIME_EXPORT IMAPUtils
+{
+public:
+
+ static const string pathToString(const char hierarchySeparator, const folder::path& path);
+ static const folder::path stringToPath(const char hierarchySeparator, const string& str);
+
+ static const string toModifiedUTF7(const char hierarchySeparator, const folder::path::component& text);
+ static const folder::path::component fromModifiedUTF7(const string& text);
+
+ /** Quote string if it contains IMAP-special characters.
+ *
+ * @param text string to quote
+ * @return quoted string
+ */
+ static const string quoteString(const string& text);
+
+ /** Parse mailbox flags and fill in folder attributes.
+ *
+ * @param cnt reference to current IMAP connection (for testing capabilities)
+ * @param path folder full path
+ * @param list list of mailbox flags
+ * @param attribs reference to an object holding folder attributes
+ */
+ static void mailboxFlagsToFolderAttributes(
+ const shared_ptr <const IMAPConnection>& cnt,
+ const folder::path &path,
+ const IMAPParser::mailbox_flag_list& list,
+ folderAttributes& attribs
+ );
+
+ static int messageFlagsFromFlags(const IMAPParser::flag_list& list);
+
+ static const std::vector <string> messageFlagList(const int flags);
+
+ /** Format a date/time to IMAP date/time format.
+ *
+ * @param date date/time to format
+ * @return IMAP-formatted date/time
+ */
+ static const string dateTime(const vmime::datetime& date);
+
+ /** Construct a fetch request for the specified messages, designated
+ * either by their sequence numbers or their UIDs.
+ *
+ * @param cnt connection
+ * @param msgs message set
+ * @param options fetch options
+ * @return fetch request
+ */
+ static shared_ptr <IMAPCommand> buildFetchCommand(
+ const shared_ptr <IMAPConnection>& cnt,
+ const messageSet& msgs,
+ const fetchAttributes& options
+ );
+
+ /** Convert a parser-style address list to a mailbox list.
+ *
+ * @param src input address list
+ * @param dest output mailbox list
+ */
+ static void convertAddressList(const IMAPParser::address_list& src, mailboxList& dest);
+
+ /** Returns an IMAP-formatted sequence set given a message set.
+ *
+ * @param msgs message set
+ * @return IMAP sequence set (eg. "1:5,7,15:*")
+ */
+ static const string messageSetToSequenceSet(const messageSet& msgs);
+
+ /** Constructs a message set from a parser 'uid_set' structure.
+ *
+ * @param uidSet UID set, as returned by the parser
+ * @return message set
+ */
+ static messageSet buildMessageSet(const IMAPParser::uid_set& uidSet);
+
+private:
+
+ static const string buildFetchRequestImpl
+ (const shared_ptr <IMAPConnection>& cnt, const string& mode, const string& set, const int options);
+};
+
+
+} // imap
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_IMAP
+
+#endif // VMIME_NET_IMAP_IMAPUTILS_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/imap/imap.hpp b/vmime-master/src/vmime/net/imap/imap.hpp
new file mode 100644
index 0000000..f25baa4
--- /dev/null
+++ b/vmime-master/src/vmime/net/imap/imap.hpp
@@ -0,0 +1,35 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_IMAP_IMAP_HPP_INCLUDED
+#define VMIME_NET_IMAP_IMAP_HPP_INCLUDED
+
+
+#include "vmime/net/imap/IMAPFolder.hpp"
+#include "vmime/net/imap/IMAPFolderStatus.hpp"
+#include "vmime/net/imap/IMAPMessage.hpp"
+#include "vmime/net/imap/IMAPStore.hpp"
+#include "vmime/net/imap/IMAPSStore.hpp"
+
+
+#endif // VMIME_NET_IMAP_IMAP_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/maildir/format/courierMaildirFormat.cpp b/vmime-master/src/vmime/net/maildir/format/courierMaildirFormat.cpp
new file mode 100644
index 0000000..e611949
--- /dev/null
+++ b/vmime-master/src/vmime/net/maildir/format/courierMaildirFormat.cpp
@@ -0,0 +1,569 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+
+#include "vmime/net/maildir/format/courierMaildirFormat.hpp"
+
+#include "vmime/net/maildir/maildirStore.hpp"
+#include "vmime/net/maildir/maildirUtils.hpp"
+
+#include "vmime/platform.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace maildir {
+namespace format {
+
+
+courierMaildirFormat::courierMaildirFormat(const shared_ptr <context>& ctx)
+ : maildirFormat(ctx) {
+
+}
+
+
+const string courierMaildirFormat::getName() const {
+
+ return "courier";
+}
+
+
+void courierMaildirFormat::createFolder(const folder::path& path) {
+
+ shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory();
+
+ if (!fsf->isValidPath(folderPathToFileSystemPath(path, ROOT_DIRECTORY))) {
+ throw exceptions::invalid_folder_name();
+ }
+
+ shared_ptr <utility::file> rootDir = fsf->create(
+ folderPathToFileSystemPath(path, ROOT_DIRECTORY)
+ );
+
+ shared_ptr <utility::file> newDir = fsf->create(
+ folderPathToFileSystemPath(path, NEW_DIRECTORY)
+ );
+ shared_ptr <utility::file> tmpDir = fsf->create(
+ folderPathToFileSystemPath(path, TMP_DIRECTORY)
+ );
+ shared_ptr <utility::file> curDir = fsf->create(
+ folderPathToFileSystemPath(path, CUR_DIRECTORY)
+ );
+
+ rootDir->createDirectory(true);
+
+ newDir->createDirectory(false);
+ tmpDir->createDirectory(false);
+ curDir->createDirectory(false);
+
+ shared_ptr <utility::file> maildirFile = fsf->create(
+ folderPathToFileSystemPath(path, ROOT_DIRECTORY)
+ / utility::file::path::component("maildirfolder")
+ );
+
+ maildirFile->createFile();
+}
+
+
+void courierMaildirFormat::destroyFolder(const folder::path& path) {
+
+ shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory();
+
+ // Recursively delete directories of subfolders
+ const std::vector <folder::path> folders = listFolders(path, true);
+
+ for (std::vector <folder::path>::size_type i = 0, n = folders.size() ; i < n ; ++i) {
+
+ maildirUtils::recursiveFSDelete(
+ fsf->create(folderPathToFileSystemPath(folders[i], ROOT_DIRECTORY))
+ );
+ }
+
+ // Recursively delete the directory of this folder
+ maildirUtils::recursiveFSDelete(
+ fsf->create(folderPathToFileSystemPath(path, ROOT_DIRECTORY))
+ );
+}
+
+
+void courierMaildirFormat::renameFolder(
+ const folder::path& oldPath,
+ const folder::path& newPath
+) {
+
+ const std::vector <folder::path> folders = listFolders(oldPath, true);
+
+ for (std::vector <folder::path>::size_type i = 0, n = folders.size() ; i < n ; ++i) {
+
+ const folder::path folderOldPath = folders[i];
+
+ folder::path folderNewPath = folderOldPath;
+ folderNewPath.renameParent(oldPath, newPath);
+
+ renameFolderImpl(folderOldPath, folderNewPath);
+ }
+
+ renameFolderImpl(oldPath, newPath);
+}
+
+
+void courierMaildirFormat::renameFolderImpl(
+ const folder::path& oldPath,
+ const folder::path& newPath
+) {
+
+ shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory();
+
+ const utility::file::path oldFSPath =
+ folderPathToFileSystemPath(oldPath, ROOT_DIRECTORY);
+
+ const utility::file::path newFSPath =
+ folderPathToFileSystemPath(newPath, ROOT_DIRECTORY);
+
+ shared_ptr <utility::file> rootDir = fsf->create(oldFSPath);
+ rootDir->rename(newFSPath);
+}
+
+
+bool courierMaildirFormat::folderExists(const folder::path& path) const {
+
+ shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory();
+
+ shared_ptr <utility::file> rootDir = fsf->create(
+ folderPathToFileSystemPath(path, ROOT_DIRECTORY)
+ );
+
+ shared_ptr <utility::file> newDir = fsf->create(
+ folderPathToFileSystemPath(path, NEW_DIRECTORY)
+ );
+ shared_ptr <utility::file> tmpDir = fsf->create(
+ folderPathToFileSystemPath(path, TMP_DIRECTORY)
+ );
+ shared_ptr <utility::file> curDir = fsf->create(
+ folderPathToFileSystemPath(path, CUR_DIRECTORY)
+ );
+
+ shared_ptr <utility::file> maildirFile = fsf->create(
+ folderPathToFileSystemPath(path, ROOT_DIRECTORY)
+ / utility::file::path::component("maildirfolder")
+ );
+
+ bool exists = rootDir->exists() && rootDir->isDirectory() &&
+ newDir->exists() && newDir->isDirectory() &&
+ tmpDir->exists() && tmpDir->isDirectory() &&
+ curDir->exists() && curDir->isDirectory();
+
+ // If this is not the root folder, then a file named "maildirfolder"
+ // must also be present in the directory
+ if (!path.isRoot()) {
+ exists = exists && maildirFile->exists() && maildirFile->isFile();
+ }
+
+ return exists;
+}
+
+
+bool courierMaildirFormat::folderHasSubfolders(const folder::path& path) const {
+
+ std::vector <string> dirs;
+ return listDirectories(path, dirs, true);
+}
+
+
+const utility::file::path courierMaildirFormat::folderPathToFileSystemPath(
+ const folder::path& path,
+ const DirectoryType type
+) const {
+
+ // Virtual folder "/MyFolder/SubFolder" corresponds to physical
+ // directory "[store root]/.MyFolder.SubFolder"
+ utility::file::path fsPath = getContext()->getStore()->getFileSystemPath();
+
+ if (!path.isRoot()) {
+
+ string folderComp;
+
+ for (size_t i = 0, n = path.getSize() ; i < n ; ++i) {
+ folderComp += "." + toModifiedUTF7(path[i]);
+ }
+
+ fsPath /= utility::file::path::component(folderComp);
+ }
+
+ // Last component
+ switch (type) {
+
+ case ROOT_DIRECTORY:
+
+ // Nothing to add
+ break;
+
+ case NEW_DIRECTORY:
+
+ fsPath /= NEW_DIR;
+ break;
+
+ case CUR_DIRECTORY:
+
+ fsPath /= CUR_DIR;
+ break;
+
+ case TMP_DIRECTORY:
+
+ fsPath /= TMP_DIR;
+ break;
+
+ case CONTAINER_DIRECTORY:
+
+ // Not used
+ break;
+ }
+
+ return fsPath;
+}
+
+
+const std::vector <folder::path> courierMaildirFormat::listFolders(
+ const folder::path& root,
+ const bool recursive
+) const {
+
+ // First, list directories
+ std::vector <string> dirs;
+ listDirectories(root, dirs, false);
+
+ // Then, map directories to folders
+ std::vector <folder::path> folders;
+
+ for (std::vector <string>::size_type i = 0, n = dirs.size() ; i < n ; ++i) {
+
+ const string dir = dirs[i].substr(1) + ".";
+ folder::path path;
+
+ for (size_t pos = dir.find("."), prev = 0 ;
+ pos != string::npos ; prev = pos + 1, pos = dir.find(".", pos + 1)) {
+
+ const string comp = dir.substr(prev, pos - prev);
+ path /= fromModifiedUTF7(comp);
+ }
+
+ if (recursive || path.getSize() == root.getSize() + 1) {
+ folders.push_back(path);
+ }
+ }
+
+ return folders;
+}
+
+
+bool courierMaildirFormat::listDirectories(
+ const folder::path& root,
+ std::vector <string>& dirs,
+ const bool onlyTestForExistence
+) const {
+
+ shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory();
+
+ shared_ptr <utility::file> rootDir = fsf->create(
+ getContext()->getStore()->getFileSystemPath()
+ );
+
+ if (rootDir->exists()) {
+
+ // To speed up things, and if we are not searching in root folder,
+ // search for directories with a common prefix
+ string base;
+
+ if (!root.isRoot()) {
+ for (size_t i = 0, n = root.getSize() ; i < n ; ++i) {
+ base += "." + toModifiedUTF7(root[i]);
+ }
+ }
+
+ // Enumerate directories
+ shared_ptr <utility::fileIterator> it = rootDir->getFiles();
+
+ while (it->hasMoreElements()) {
+
+ shared_ptr <utility::file> file = it->nextElement();
+
+ if (isSubfolderDirectory(*file)) {
+
+ const string dir = file->getFullPath().getLastComponent().getBuffer();
+
+ if (base.empty() || (dir.length() > base.length() && dir.substr(0, base.length()) == base)) {
+
+ dirs.push_back(dir);
+
+ if (onlyTestForExistence) {
+ return true;
+ }
+ }
+ }
+ }
+
+ } else {
+
+ // No sub-folder
+ }
+
+ std::sort(dirs.begin(), dirs.end());
+
+ return !dirs.empty();
+}
+
+
+// static
+bool courierMaildirFormat::isSubfolderDirectory(const utility::file& file) {
+
+ // A directory which names starts with '.' may be a subfolder
+ if (file.isDirectory() &&
+ file.getFullPath().getLastComponent().getBuffer().length() >= 1 &&
+ file.getFullPath().getLastComponent().getBuffer()[0] == '.') {
+
+ return true;
+ }
+
+ return false;
+}
+
+
+// static
+const string courierMaildirFormat::toModifiedUTF7(const folder::path::component& text) {
+
+ // From http://www.courier-mta.org/?maildir.html:
+ //
+ // Folder names can contain any Unicode character, except for control
+ // characters. US-ASCII characters, U+0x0020 - U+0x007F, except for the
+ // period, forward-slash, and ampersand characters (U+0x002E, U+0x002F,
+ // and U+0x0026) represent themselves. The ampersand is represented by
+ // the two character sequence "&-". The period, forward slash, and non
+ // US-ASCII Unicode characters are represented using the UTF-7 character
+ // set, and encoded with a modified form of base64-encoding.
+ //
+ // The "&" character starts the modified base64-encoded sequence; the
+ // sequence is terminated by the "-" character. The sequence of 16-bit
+ // Unicode characters is written in big-endian order, and encoded using
+ // the base64-encoding method described in section 5.2 of RFC 1521, with
+ // the following modifications:
+ //
+ // * The "=" padding character is omitted. When decoding, an incomplete
+ // 16-bit character is discarded.
+ //
+ // * The comma character, "," is used in place of the "/" character in
+ // the base64 alphabet.
+ //
+ // For example, the word "Resume" with both "e"s being the e-acute
+ // character, U+0x00e9, is encoded as "R&AOk-sum&AOk-" (so a folder of
+ // that name would be a maildir subdirectory called ".R&AOk-sum&AOk-").
+ //
+
+ // Transcode path component to UTF-7 charset.
+ // WARNING: This may throw "exceptions::charset_conv_error"
+ const string cvt = text.getConvertedText(charset(charsets::UTF_7));
+
+ // Transcode to modified UTF-7 (RFC-2060).
+ string out;
+ out.reserve((cvt.length() * 3) / 2);
+
+ bool inB64sequence = false;
+
+ for (string::const_iterator it = cvt.begin() ; it != cvt.end() ; ++it) {
+
+ const unsigned char c = *it;
+
+ switch (c) {
+
+ // Beginning of Base64 sequence: replace '+' with '&'
+ case '+': {
+
+ if (!inB64sequence) {
+ inB64sequence = true;
+ out += '&';
+ } else {
+ out += '+';
+ }
+
+ break;
+ }
+ // End of Base64 sequence
+ case '-': {
+
+ inB64sequence = false;
+ out += '-';
+ break;
+ }
+ // ',' is used instead of '/' in modified Base64,
+ // and simply UTF7-encoded out of a Base64 sequence
+ case '/': {
+
+ if (inB64sequence) {
+ out += ',';
+ } else {
+ out += "&Lw-";
+ }
+
+ break;
+ }
+ // Encode period (should not happen in a Base64 sequence)
+ case '.': {
+
+ out += "&Lg-";
+ break;
+ }
+ // '&' (0x26) is represented by the two-octet sequence "&-"
+ case '&': {
+
+ if (!inB64sequence) {
+ out += "&-";
+ } else {
+ out += '&';
+ }
+
+ break;
+ }
+ default: {
+
+ out += c;
+ break;
+ }
+ }
+ }
+
+ return out;
+}
+
+
+// static
+const folder::path::component courierMaildirFormat::fromModifiedUTF7(const string& text) {
+
+ // Transcode from modified UTF-7
+ string out;
+ out.reserve(text.length());
+
+ bool inB64sequence = false;
+ unsigned char prev = 0;
+
+ for (string::const_iterator it = text.begin() ; it != text.end() ; ++it) {
+
+ const unsigned char c = *it;
+
+ switch (c) {
+
+ // Start of Base64 sequence
+ case '&': {
+
+ if (!inB64sequence) {
+ inB64sequence = true;
+ out += '+';
+ } else {
+ out += '&';
+ }
+
+ break;
+ }
+ // End of Base64 sequence (or "&-" --> "&")
+ case '-': {
+
+ if (inB64sequence && prev == '&') {
+ out += '&';
+ } else {
+ out += '-';
+ }
+
+ inB64sequence = false;
+ break;
+ }
+ // ',' is used instead of '/' in modified Base64
+ case ',': {
+
+ out += (inB64sequence ? '/' : ',');
+ break;
+ }
+ default: {
+
+ out += c;
+ break;
+ }
+
+ }
+
+ prev = c;
+ }
+
+ // Store it as UTF-8 by default
+ string cvt;
+ charset::convert(out, cvt, charset(charsets::UTF_7), charset(charsets::UTF_8));
+
+ return folder::path::component(cvt, charset(charsets::UTF_8));
+}
+
+
+bool courierMaildirFormat::supports() const {
+
+ shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory();
+
+ shared_ptr <utility::file> rootDir = fsf->create(
+ getContext()->getStore()->getFileSystemPath()
+ );
+
+ if (rootDir->exists()) {
+
+ // Try to find a file named "maildirfolder", which indicates
+ // the Maildir is in Courier format
+ shared_ptr <utility::fileIterator> it = rootDir->getFiles();
+
+ while (it->hasMoreElements()) {
+
+ shared_ptr <utility::file> file = it->nextElement();
+
+ if (isSubfolderDirectory(*file)) {
+
+ shared_ptr <utility::file> folderFile = fsf->create(
+ file->getFullPath() / utility::file::path::component("maildirfolder")
+ );
+
+ if (folderFile->exists() && folderFile->isFile()) {
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+}
+
+
+} // format
+} // maildir
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
diff --git a/vmime-master/src/vmime/net/maildir/format/courierMaildirFormat.hpp b/vmime-master/src/vmime/net/maildir/format/courierMaildirFormat.hpp
new file mode 100644
index 0000000..7db1a83
--- /dev/null
+++ b/vmime-master/src/vmime/net/maildir/format/courierMaildirFormat.hpp
@@ -0,0 +1,127 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_MAILDIR_FORMAT_COURIERMAILDIRFORMAT_HPP_INCLUDED
+#define VMIME_NET_MAILDIR_FORMAT_COURIERMAILDIRFORMAT_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+
+#include "vmime/net/maildir/maildirFormat.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace maildir {
+namespace format {
+
+
+/** Reads Courier/QMail Maildir format.
+ */
+class VMIME_EXPORT courierMaildirFormat : public maildirFormat {
+
+public:
+
+ courierMaildirFormat(const shared_ptr <context>& ctx);
+
+
+ /* Folder types:
+ *
+ * - ROOT_DIRECTORY: ~/Mail/.MyFolder
+ * - NEW_DIRECTORY: ~/Mail/.MyFolder/new
+ * - CUR_DIRECTORY: ~/Mail/.MyFolder/cur
+ * - TMP_DIRECTORY: ~/Mail/.MyFolder/tmp
+ * - CONTAINER_DIRECTORY: not used
+ */
+
+ const string getName() const;
+
+ void createFolder(const folder::path& path);
+ void destroyFolder(const folder::path& path);
+ void renameFolder(const folder::path& oldPath, const folder::path& newPath);
+
+ bool folderExists(const folder::path& path) const;
+ bool folderHasSubfolders(const folder::path& path) const;
+
+ const utility::file::path folderPathToFileSystemPath(
+ const folder::path& path,
+ const DirectoryType type
+ ) const;
+
+ const std::vector <folder::path> listFolders(
+ const folder::path& root,
+ const bool recursive
+ ) const;
+
+protected:
+
+ bool supports() const;
+
+
+ static const string toModifiedUTF7(const folder::path::component& text);
+ static const folder::path::component fromModifiedUTF7(const string& text);
+
+ void renameFolderImpl(const folder::path& oldPath, const folder::path& newPath);
+
+ /** Test whether the specified file system directory corresponds to
+ * a maildir subfolder. The name of the directory should start
+ * with a '.' to be listed as a subfolder.
+ *
+ * @param file reference to a file system directory
+ * @return true if the specified directory is a maildir subfolder,
+ * false otherwise
+ */
+ static bool isSubfolderDirectory(const utility::file& file);
+
+ /** List directories corresponding to folders which are (direct or
+ * indirect) children of specified folder.
+ *
+ * @param root root folder
+ * @param dirs list in which found directories will be added
+ * @param onlyTestForExistence if true, the function returns as soon
+ * as the first directory is found
+ * @return true if at least one directory has been found,
+ * false otherwise
+ */
+ bool listDirectories(
+ const folder::path& root,
+ std::vector <string>& dirs,
+ const bool onlyTestForExistence
+ ) const;
+};
+
+
+} // format
+} // maildir
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+#endif // VMIME_NET_MAILDIR_FORMAT_COURIERMAILDIRFORMAT_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/maildir/format/kmailMaildirFormat.cpp b/vmime-master/src/vmime/net/maildir/format/kmailMaildirFormat.cpp
new file mode 100644
index 0000000..4eb89e8
--- /dev/null
+++ b/vmime-master/src/vmime/net/maildir/format/kmailMaildirFormat.cpp
@@ -0,0 +1,337 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+
+#include "vmime/net/maildir/format/kmailMaildirFormat.hpp"
+
+#include "vmime/net/maildir/maildirStore.hpp"
+#include "vmime/net/maildir/maildirUtils.hpp"
+
+#include "vmime/platform.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace maildir {
+namespace format {
+
+
+kmailMaildirFormat::kmailMaildirFormat(const shared_ptr <context>& ctx)
+ : maildirFormat(ctx) {
+
+}
+
+
+const string kmailMaildirFormat::getName() const {
+
+ return "kmail";
+}
+
+
+void kmailMaildirFormat::createFolder(const folder::path& path) {
+
+ shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory();
+
+ if (!fsf->isValidPath(folderPathToFileSystemPath(path, ROOT_DIRECTORY))) {
+ throw exceptions::invalid_folder_name();
+ }
+
+ shared_ptr <utility::file> rootDir = fsf->create(
+ folderPathToFileSystemPath(path, ROOT_DIRECTORY)
+ );
+
+ shared_ptr <utility::file> newDir = fsf->create(
+ folderPathToFileSystemPath(path, NEW_DIRECTORY)
+ );
+ shared_ptr <utility::file> tmpDir = fsf->create(
+ folderPathToFileSystemPath(path, TMP_DIRECTORY)
+ );
+ shared_ptr <utility::file> curDir = fsf->create(
+ folderPathToFileSystemPath(path, CUR_DIRECTORY)
+ );
+
+ rootDir->createDirectory(true);
+
+ newDir->createDirectory(false);
+ tmpDir->createDirectory(false);
+ curDir->createDirectory(false);
+}
+
+
+void kmailMaildirFormat::destroyFolder(const folder::path& path) {
+
+ // Delete 'folder' and '.folder.directory' directories
+ shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory();
+
+ maildirUtils::recursiveFSDelete(
+ fsf->create(folderPathToFileSystemPath(path, ROOT_DIRECTORY)) // root
+ );
+
+ maildirUtils::recursiveFSDelete(
+ fsf->create(folderPathToFileSystemPath(path, CONTAINER_DIRECTORY)) // container
+ );
+}
+
+
+bool kmailMaildirFormat::folderExists(const folder::path& path) const {
+
+ shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory();
+
+ shared_ptr <utility::file> rootDir = fsf->create(
+ folderPathToFileSystemPath(path, ROOT_DIRECTORY)
+ );
+
+ shared_ptr <utility::file> newDir = fsf->create(
+ folderPathToFileSystemPath(path, NEW_DIRECTORY)
+ );
+ shared_ptr <utility::file> tmpDir = fsf->create(
+ folderPathToFileSystemPath(path, TMP_DIRECTORY)
+ );
+ shared_ptr <utility::file> curDir = fsf->create(
+ folderPathToFileSystemPath(path, CUR_DIRECTORY)
+ );
+
+ return rootDir->exists() && rootDir->isDirectory() &&
+ newDir->exists() && newDir->isDirectory() &&
+ tmpDir->exists() && tmpDir->isDirectory() &&
+ curDir->exists() && curDir->isDirectory();
+}
+
+
+const utility::file::path kmailMaildirFormat::folderPathToFileSystemPath(
+ const folder::path& path,
+ const DirectoryType type
+) const {
+
+ // Root path
+ utility::file::path fsPath = getContext()->getStore()->getFileSystemPath();
+
+ const size_t pathSize = path.getSize();
+ const size_t count = (type == CONTAINER_DIRECTORY
+ ? pathSize : (pathSize >= 1 ? pathSize - 1 : 0));
+
+ // Parent folders
+ for (size_t i = 0 ; i < count ; ++i) {
+
+ utility::file::path::component comp(path[i]);
+
+ // TODO: may not work with all encodings...
+ comp.setBuffer("." + comp.getBuffer() + ".directory");
+
+ fsPath /= comp;
+ }
+
+ // Last component
+ if (path.getSize() != 0 && type != CONTAINER_DIRECTORY) {
+
+ fsPath /= path.getLastComponent();
+
+ switch (type) {
+
+ case ROOT_DIRECTORY:
+
+ // Nothing to add
+ break;
+
+ case NEW_DIRECTORY:
+
+ fsPath /= NEW_DIR;
+ break;
+
+ case CUR_DIRECTORY:
+
+ fsPath /= CUR_DIR;
+ break;
+
+ case TMP_DIRECTORY:
+
+ fsPath /= TMP_DIR;
+ break;
+
+ case CONTAINER_DIRECTORY:
+
+ // Can't happen...
+ break;
+ }
+ }
+
+ return fsPath;
+}
+
+
+const std::vector <folder::path> kmailMaildirFormat::listFolders(
+ const folder::path& root,
+ const bool recursive
+) const {
+
+ std::vector <folder::path> list;
+ listFoldersImpl(list, root, recursive);
+
+ return list;
+}
+
+
+void kmailMaildirFormat::listFoldersImpl(
+ std::vector <folder::path>& list,
+ const folder::path& root,
+ const bool recursive
+) const {
+
+ shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory();
+
+ shared_ptr <utility::file> rootDir = fsf->create(
+ folderPathToFileSystemPath(root, root.isEmpty() ? ROOT_DIRECTORY : CONTAINER_DIRECTORY)
+ );
+
+ if (rootDir->exists()) {
+
+ shared_ptr <utility::fileIterator> it = rootDir->getFiles();
+
+ while (it->hasMoreElements()) {
+
+ shared_ptr <utility::file> file = it->nextElement();
+
+ if (isSubfolderDirectory(*file)) {
+
+ const utility::path subPath = root / file->getFullPath().getLastComponent();
+
+ list.push_back(subPath);
+
+ if (recursive) {
+ listFoldersImpl(list, subPath, true);
+ }
+ }
+ }
+
+ } else {
+
+ // No sub-folder
+ }
+}
+
+
+// static
+bool kmailMaildirFormat::isSubfolderDirectory(const utility::file& file) {
+
+ // A directory which name does not start with '.' is listed as a sub-folder
+ if (file.isDirectory() &&
+ file.getFullPath().getLastComponent().getBuffer().length() >= 1 &&
+ file.getFullPath().getLastComponent().getBuffer()[0] != '.') {
+
+ return true;
+ }
+
+ return false;
+}
+
+
+void kmailMaildirFormat::renameFolder(const folder::path& oldPath, const folder::path& newPath) {
+
+ shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory();
+
+ shared_ptr <utility::file> rootDir = fsf->create(
+ folderPathToFileSystemPath(oldPath, ROOT_DIRECTORY)
+ );
+ shared_ptr <utility::file> contDir = fsf->create(
+ folderPathToFileSystemPath(oldPath, CONTAINER_DIRECTORY)
+ );
+
+ try {
+
+ const utility::file::path newRootPath =
+ folderPathToFileSystemPath(newPath, ROOT_DIRECTORY);
+ const utility::file::path newContPath =
+ folderPathToFileSystemPath(newPath, CONTAINER_DIRECTORY);
+
+ rootDir->rename(newRootPath);
+
+ // Container directory may not exist, so ignore error when trying to rename it
+ try {
+ contDir->rename(newContPath);
+ } catch (exceptions::filesystem_exception& e) {
+ // Ignore
+ }
+
+ } catch (exceptions::filesystem_exception& e) {
+
+ // Revert to old location
+ const utility::file::path rootPath =
+ folderPathToFileSystemPath(oldPath, ROOT_DIRECTORY);
+ const utility::file::path contPath =
+ folderPathToFileSystemPath(oldPath, CONTAINER_DIRECTORY);
+
+ try {
+ rootDir->rename(rootPath);
+ contDir->rename(contPath);
+ } catch (exceptions::filesystem_exception& e) {
+ // Ignore (not recoverable)
+ }
+
+ throw;
+ }
+}
+
+
+bool kmailMaildirFormat::folderHasSubfolders(const folder::path& path) const {
+
+ shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory();
+
+ shared_ptr <utility::file> rootDir = fsf->create(
+ folderPathToFileSystemPath(path, CONTAINER_DIRECTORY)
+ );
+
+ shared_ptr <utility::fileIterator> it = rootDir->getFiles();
+
+ while (it->hasMoreElements()) {
+
+ shared_ptr <utility::file> file = it->nextElement();
+
+ if (isSubfolderDirectory(*file)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+
+bool kmailMaildirFormat::supports() const {
+
+ // This is the default
+ return true;
+}
+
+
+} // format
+} // maildir
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
diff --git a/vmime-master/src/vmime/net/maildir/format/kmailMaildirFormat.hpp b/vmime-master/src/vmime/net/maildir/format/kmailMaildirFormat.hpp
new file mode 100644
index 0000000..26b557a
--- /dev/null
+++ b/vmime-master/src/vmime/net/maildir/format/kmailMaildirFormat.hpp
@@ -0,0 +1,115 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_MAILDIR_FORMAT_KMAILMAILDIRFORMAT_HPP_INCLUDED
+#define VMIME_NET_MAILDIR_FORMAT_KMAILMAILDIRFORMAT_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+
+#include "vmime/net/maildir/maildirFormat.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace maildir {
+namespace format {
+
+
+/** Reads KMail Maildir format.
+ */
+class VMIME_EXPORT kmailMaildirFormat : public maildirFormat {
+
+public:
+
+ kmailMaildirFormat(const shared_ptr <context>& ctx);
+
+
+ /* Folder types:
+ *
+ * - ROOT_DIRECTORY: ~/Mail/MyFolder
+ * - NEW_DIRECTORY: ~/Mail/MyFolder/new
+ * - CUR_DIRECTORY: ~/Mail/MyFolder/cur
+ * - TMP_DIRECTORY: ~/Mail/MyFolder/tmp
+ * - CONTAINER_DIRECTORY: ~/Mail/.MyFolder.directory
+ */
+
+ const string getName() const;
+
+ void createFolder(const folder::path& path);
+ void destroyFolder(const folder::path& path);
+ void renameFolder(const folder::path& oldPath, const folder::path& newPath);
+
+ bool folderExists(const folder::path& path) const;
+ bool folderHasSubfolders(const folder::path& path) const;
+
+ const utility::file::path folderPathToFileSystemPath(
+ const folder::path& path,
+ const DirectoryType type
+ ) const;
+
+ const std::vector <folder::path> listFolders(
+ const folder::path& root,
+ const bool recursive
+ ) const;
+
+protected:
+
+ bool supports() const;
+
+
+ /** Recursive implementation of listFolders().
+ */
+ void listFoldersImpl(
+ std::vector <folder::path>& list,
+ const folder::path& root,
+ const bool recursive
+ ) const;
+
+ /** Test whether the specified file system directory corresponds to
+ * a maildir subfolder. The name of the directory should not start
+ * with '.' to be listed as a subfolder.
+ *
+ * @param file reference to a file system directory
+ * @return true if the specified directory is a maildir subfolder,
+ * false otherwise
+ */
+ static bool isSubfolderDirectory(const utility::file& file);
+};
+
+
+} // format
+} // maildir
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+
+#endif // VMIME_NET_MAILDIR_FORMAT_KMAILMAILDIRFORMAT_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/maildir/maildir.hpp b/vmime-master/src/vmime/net/maildir/maildir.hpp
new file mode 100644
index 0000000..8835bf4
--- /dev/null
+++ b/vmime-master/src/vmime/net/maildir/maildir.hpp
@@ -0,0 +1,34 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_MAILDIR_MAILDIR_HPP_INCLUDED
+#define VMIME_NET_MAILDIR_MAILDIR_HPP_INCLUDED
+
+
+#include "vmime/net/maildir/maildirFolder.hpp"
+#include "vmime/net/maildir/maildirFolderStatus.hpp"
+#include "vmime/net/maildir/maildirMessage.hpp"
+#include "vmime/net/maildir/maildirStore.hpp"
+
+
+#endif // VMIME_NET_MAILDIR_MAILDIR_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/maildir/maildirFolder.cpp b/vmime-master/src/vmime/net/maildir/maildirFolder.cpp
new file mode 100644
index 0000000..8c02025
--- /dev/null
+++ b/vmime-master/src/vmime/net/maildir/maildirFolder.cpp
@@ -0,0 +1,1365 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+
+#include "vmime/net/maildir/maildirFolder.hpp"
+
+#include "vmime/net/maildir/maildirStore.hpp"
+#include "vmime/net/maildir/maildirMessage.hpp"
+#include "vmime/net/maildir/maildirUtils.hpp"
+#include "vmime/net/maildir/maildirFormat.hpp"
+#include "vmime/net/maildir/maildirFolderStatus.hpp"
+
+#include "vmime/message.hpp"
+
+#include "vmime/exception.hpp"
+#include "vmime/platform.hpp"
+
+#include "vmime/utility/outputStreamAdapter.hpp"
+#include "vmime/utility/inputStreamStringAdapter.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace maildir {
+
+
+maildirFolder::maildirFolder(
+ const folder::path& path,
+ const shared_ptr <maildirStore>& store
+)
+ : m_store(store),
+ m_path(path),
+ m_name(path.isEmpty() ? folder::path::component("") : path.getLastComponent()),
+ m_mode(-1),
+ m_open(false),
+ m_unreadMessageCount(0),
+ m_messageCount(0) {
+
+ store->registerFolder(this);
+}
+
+
+maildirFolder::~maildirFolder() {
+
+ try {
+
+ shared_ptr <maildirStore> store = m_store.lock();
+
+ if (store) {
+
+ if (m_open) {
+ close(false);
+ }
+
+ store->unregisterFolder(this);
+
+ } else if (m_open) {
+
+ close(false);
+ }
+
+ } catch (...) {
+
+ // Don't throw in destructor
+ }
+}
+
+
+void maildirFolder::onStoreDisconnected() {
+
+ m_store.reset();
+}
+
+
+int maildirFolder::getMode() const {
+
+ if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ }
+
+ return m_mode;
+}
+
+
+const folderAttributes maildirFolder::getAttributes() {
+
+ folderAttributes attribs;
+
+ if (m_path.isEmpty()) {
+ attribs.setType(folderAttributes::TYPE_CONTAINS_FOLDERS);
+ } else {
+ attribs.setType(folderAttributes::TYPE_CONTAINS_FOLDERS | folderAttributes::TYPE_CONTAINS_MESSAGES);
+ }
+
+ if (m_store.lock()->getFormat()->folderHasSubfolders(m_path)) {
+ attribs.setFlags(folderAttributes::FLAG_HAS_CHILDREN); // contains at least one sub-folder
+ }
+
+ return attribs;
+}
+
+
+const folder::path::component maildirFolder::getName() const {
+
+ return m_name;
+}
+
+
+const folder::path maildirFolder::getFullPath() const {
+
+ return m_path;
+}
+
+
+void maildirFolder::open(const int mode, bool /* failIfModeIsNotAvailable */) {
+
+ shared_ptr <maildirStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ } else if (isOpen()) {
+ throw exceptions::illegal_state("Folder is already open");
+ } else if (!exists()) {
+ throw exceptions::illegal_state("Folder does not exist");
+ }
+
+ scanFolder();
+
+ m_open = true;
+ m_mode = mode;
+}
+
+
+void maildirFolder::close(const bool expunge) {
+
+ shared_ptr <maildirStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ }
+
+ if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ }
+
+ if (expunge) {
+ this->expunge();
+ }
+
+ m_open = false;
+ m_mode = -1;
+
+ onClose();
+}
+
+
+void maildirFolder::onClose() {
+
+ for (std::vector <maildirMessage*>::iterator it = m_messages.begin() ;
+ it != m_messages.end() ; ++it) {
+
+ (*it)->onFolderClosed();
+ }
+
+ m_messages.clear();
+}
+
+
+void maildirFolder::registerMessage(maildirMessage* msg) {
+
+ m_messages.push_back(msg);
+}
+
+
+void maildirFolder::unregisterMessage(maildirMessage* msg) {
+
+ std::vector <maildirMessage*>::iterator it =
+ std::find(m_messages.begin(), m_messages.end(), msg);
+
+ if (it != m_messages.end()) {
+ m_messages.erase(it);
+ }
+}
+
+
+void maildirFolder::create(const folderAttributes& /* attribs */) {
+
+ shared_ptr <maildirStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ } else if (isOpen()) {
+ throw exceptions::illegal_state("Folder is open");
+ } else if (exists()) {
+ throw exceptions::illegal_state("Folder already exists");
+ } else if (!store->isValidFolderName(m_name)) {
+ throw exceptions::invalid_folder_name();
+ }
+
+ // Create directory on file system
+ try {
+ store->getFormat()->createFolder(m_path);
+ } catch (exceptions::filesystem_exception& e) {
+ throw exceptions::command_error("CREATE", "", "File system exception", e);
+ }
+
+ // Notify folder created
+ shared_ptr <events::folderEvent> event =
+ make_shared <events::folderEvent>(
+ dynamicCast <folder>(shared_from_this()),
+ events::folderEvent::TYPE_CREATED,
+ m_path, m_path
+ );
+
+ notifyFolder(event);
+}
+
+
+void maildirFolder::destroy() {
+
+ shared_ptr <maildirStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ } else if (isOpen()) {
+ throw exceptions::illegal_state("Folder is open");
+ }
+
+ // Delete folder
+ try {
+ store->getFormat()->destroyFolder(m_path);
+ } catch (std::exception&) {
+ // Ignore exception: anyway, we can't recover from this...
+ }
+
+ // Notify folder deleted
+ shared_ptr <events::folderEvent> event =
+ make_shared <events::folderEvent>(
+ dynamicCast <folder>(shared_from_this()),
+ events::folderEvent::TYPE_DELETED,
+ m_path, m_path
+ );
+
+ notifyFolder(event);
+}
+
+
+bool maildirFolder::exists() {
+
+ shared_ptr <maildirStore> store = m_store.lock();
+
+ return store->getFormat()->folderExists(m_path);
+}
+
+
+bool maildirFolder::isOpen() const {
+
+ return m_open;
+}
+
+
+void maildirFolder::scanFolder() {
+
+ shared_ptr <maildirStore> store = m_store.lock();
+
+ try {
+
+ m_messageCount = 0;
+ m_unreadMessageCount = 0;
+
+ shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory();
+
+ utility::file::path newDirPath =
+ store->getFormat()->folderPathToFileSystemPath(m_path, maildirFormat::NEW_DIRECTORY);
+ shared_ptr <utility::file> newDir = fsf->create(newDirPath);
+
+ utility::file::path curDirPath =
+ store->getFormat()->folderPathToFileSystemPath(m_path, maildirFormat::CUR_DIRECTORY);
+ shared_ptr <utility::file> curDir = fsf->create(curDirPath);
+
+ // New received messages (new/)
+ shared_ptr <utility::fileIterator> nit = newDir->getFiles();
+ std::vector <utility::file::path::component> newMessageFilenames;
+
+ while (nit->hasMoreElements()) {
+
+ shared_ptr <utility::file> file = nit->nextElement();
+
+ if (maildirUtils::isMessageFile(*file)) {
+ newMessageFilenames.push_back(file->getFullPath().getLastComponent());
+ }
+ }
+
+ // Current messages (cur/)
+ shared_ptr <utility::fileIterator> cit = curDir->getFiles();
+ std::vector <utility::file::path::component> curMessageFilenames;
+
+ while (cit->hasMoreElements()) {
+
+ shared_ptr <utility::file> file = cit->nextElement();
+
+ if (maildirUtils::isMessageFile(*file)) {
+ curMessageFilenames.push_back(file->getFullPath().getLastComponent());
+ }
+ }
+
+ // Update/delete existing messages (found in previous scan)
+ for (size_t i = 0 ; i < m_messageInfos.size() ; ++i) {
+
+ messageInfos& msgInfos = m_messageInfos[i];
+
+ // NOTE: the flags may have changed (eg. moving from 'new' to 'cur'
+ // may imply the 'S' flag) and so the filename. That's why we use
+ // "maildirUtils::messageIdComparator" to compare only the 'unique'
+ // portion of the filename...
+
+ if (msgInfos.type == messageInfos::TYPE_CUR) {
+
+ const std::vector <utility::file::path::component>::iterator pos =
+ std::find_if(
+ curMessageFilenames.begin(),
+ curMessageFilenames.end(),
+ maildirUtils::messageIdComparator(msgInfos.path)
+ );
+
+ // If we cannot find this message in the 'cur' directory,
+ // it means it has been deleted (and expunged).
+ if (pos == curMessageFilenames.end()) {
+
+ msgInfos.type = messageInfos::TYPE_DELETED;
+
+ // Otherwise, update its information.
+ } else {
+
+ msgInfos.path = *pos;
+ curMessageFilenames.erase(pos);
+ }
+ }
+ }
+
+ m_messageInfos.reserve(m_messageInfos.size()
+ + newMessageFilenames.size() + curMessageFilenames.size());
+
+ // Add new messages from 'new': we are responsible to move the files
+ // from the 'new' directory to the 'cur' directory, and append them
+ // to our message list.
+ for (std::vector <utility::file::path::component>::const_iterator
+ it = newMessageFilenames.begin() ; it != newMessageFilenames.end() ; ++it) {
+
+ const utility::file::path::component newFilename =
+ maildirUtils::buildFilename(maildirUtils::extractId(*it), 0);
+
+ // Move messages from 'new' to 'cur'
+ shared_ptr <utility::file> file = fsf->create(newDirPath / *it);
+ file->rename(curDirPath / newFilename);
+
+ // Append to message list
+ messageInfos msgInfos;
+ msgInfos.path = newFilename;
+
+ if (maildirUtils::extractFlags(msgInfos.path) & message::FLAG_DELETED) {
+ msgInfos.type = messageInfos::TYPE_DELETED;
+ } else {
+ msgInfos.type = messageInfos::TYPE_CUR;
+ }
+
+ m_messageInfos.push_back(msgInfos);
+ }
+
+ // Add new messages from 'cur': the files have already been moved
+ // from 'new' to 'cur'. Just append them to our message list.
+ for (std::vector <utility::file::path::component>::const_iterator
+ it = curMessageFilenames.begin() ; it != curMessageFilenames.end() ; ++it) {
+
+ // Append to message list
+ messageInfos msgInfos;
+ msgInfos.path = *it;
+
+ if (maildirUtils::extractFlags(msgInfos.path) & message::FLAG_DELETED) {
+ msgInfos.type = messageInfos::TYPE_DELETED;
+ } else {
+ msgInfos.type = messageInfos::TYPE_CUR;
+ }
+
+ m_messageInfos.push_back(msgInfos);
+ }
+
+ // Update message count
+ size_t unreadMessageCount = 0;
+
+ for (std::vector <messageInfos>::const_iterator
+ it = m_messageInfos.begin() ; it != m_messageInfos.end() ; ++it) {
+
+ if ((maildirUtils::extractFlags((*it).path) & message::FLAG_SEEN) == 0) {
+ ++unreadMessageCount;
+ }
+ }
+
+ m_unreadMessageCount = unreadMessageCount;
+ m_messageCount = static_cast <size_t>(m_messageInfos.size());
+
+ } catch (exceptions::filesystem_exception&) {
+
+ // Should not happen...
+ }
+}
+
+
+shared_ptr <message> maildirFolder::getMessage(const size_t num) {
+
+ if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ }
+
+ if (num < 1 || num > m_messageCount) {
+ throw exceptions::message_not_found();
+ }
+
+ return make_shared <maildirMessage>(dynamicCast <maildirFolder>(shared_from_this()), num);
+}
+
+
+std::vector <shared_ptr <message> > maildirFolder::getMessages(const messageSet& msgs) {
+
+ if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ }
+
+ if (msgs.isNumberSet()) {
+
+ const std::vector <size_t> numbers = maildirUtils::messageSetToNumberList(msgs, m_messageCount);
+
+ std::vector <shared_ptr <message> > messages;
+ shared_ptr <maildirFolder> thisFolder = dynamicCast <maildirFolder>(shared_from_this());
+
+ for (std::vector <size_t>::const_iterator it = numbers.begin() ; it != numbers.end() ; ++it) {
+
+ if (*it < 1|| *it > m_messageCount) {
+ throw exceptions::message_not_found();
+ }
+
+ messages.push_back(make_shared <maildirMessage>(thisFolder, *it));
+ }
+
+ return messages;
+
+ } else {
+
+ throw exceptions::operation_not_supported();
+ }
+}
+
+
+size_t maildirFolder::getMessageCount() {
+
+ return m_messageCount;
+}
+
+
+shared_ptr <folder> maildirFolder::getFolder(const folder::path::component& name) {
+
+ shared_ptr <maildirStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ }
+
+ return shared_ptr <maildirFolder>(new maildirFolder(m_path / name, store));
+}
+
+
+std::vector <shared_ptr <folder> > maildirFolder::getFolders(const bool recursive) {
+
+ shared_ptr <maildirStore> store = m_store.lock();
+
+ if (!isOpen() && !store) {
+ throw exceptions::illegal_state("Store disconnected");
+ }
+
+ std::vector <shared_ptr <folder> > list;
+
+ listFolders(list, recursive);
+
+ return list;
+}
+
+
+void maildirFolder::listFolders(std::vector <shared_ptr <folder> >& list, const bool recursive) {
+
+ shared_ptr <maildirStore> store = m_store.lock();
+
+ try {
+
+ std::vector <folder::path> pathList =
+ store->getFormat()->listFolders(m_path, recursive);
+
+ list.reserve(pathList.size());
+
+ for (std::vector <folder::path>::size_type i = 0, n = pathList.size() ; i < n ; ++i) {
+
+ shared_ptr <maildirFolder> subFolder(
+ new maildirFolder(pathList[i], store)
+ );
+
+ list.push_back(subFolder);
+ }
+
+ } catch (exceptions::filesystem_exception& e) {
+
+ throw exceptions::command_error("LIST", "", "", e);
+ }
+}
+
+
+void maildirFolder::rename(const folder::path& newPath) {
+
+ shared_ptr <maildirStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ } else if (m_path.isEmpty() || newPath.isEmpty()) {
+ throw exceptions::illegal_operation("Cannot rename root folder");
+ } else if (!store->isValidFolderName(newPath.getLastComponent())) {
+ throw exceptions::invalid_folder_name();
+ }
+
+ // Rename the directory on the file system
+ try {
+ store->getFormat()->renameFolder(m_path, newPath);
+ } catch (vmime::exception& e) {
+ throw exceptions::command_error("RENAME", "", "", e);
+ }
+
+ // Notify folder renamed
+ folder::path oldPath(m_path);
+
+ m_path = newPath;
+ m_name = newPath.getLastComponent();
+
+ shared_ptr <events::folderEvent> event =
+ make_shared <events::folderEvent>(
+ dynamicCast <folder>(shared_from_this()),
+ events::folderEvent::TYPE_RENAMED,
+ oldPath, newPath
+ );
+
+ notifyFolder(event);
+
+ // Notify folders with the same path
+ for (std::list <maildirFolder*>::iterator it = store->m_folders.begin() ;
+ it != store->m_folders.end() ; ++it) {
+
+ if ((*it) != this && (*it)->getFullPath() == oldPath) {
+
+ (*it)->m_path = newPath;
+ (*it)->m_name = newPath.getLastComponent();
+
+ shared_ptr <events::folderEvent> event =
+ make_shared <events::folderEvent>(
+ dynamicCast <folder>((*it)->shared_from_this()),
+ events::folderEvent::TYPE_RENAMED,
+ oldPath, newPath
+ );
+
+ (*it)->notifyFolder(event);
+
+ } else if ((*it) != this && oldPath.isParentOf((*it)->getFullPath())) {
+
+ folder::path oldPath((*it)->m_path);
+
+ (*it)->m_path.renameParent(oldPath, newPath);
+
+ shared_ptr <events::folderEvent> event =
+ make_shared <events::folderEvent>(
+ dynamicCast <folder>((*it)->shared_from_this()),
+ events::folderEvent::TYPE_RENAMED,
+ oldPath, (*it)->m_path
+ );
+
+ (*it)->notifyFolder(event);
+ }
+ }
+}
+
+
+void maildirFolder::deleteMessages(const messageSet& msgs) {
+
+ // Mark messages as deleted
+ setMessageFlags(msgs, message::FLAG_DELETED, message::FLAG_MODE_ADD);
+}
+
+
+void maildirFolder::setMessageFlags(
+ const messageSet& msgs,
+ const int flags,
+ const int mode
+) {
+
+ shared_ptr <maildirStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ } else if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ } else if (m_mode == MODE_READ_ONLY) {
+ throw exceptions::illegal_state("Folder is read-only");
+ }
+
+ if (msgs.isNumberSet()) {
+
+ const std::vector <size_t> nums = maildirUtils::messageSetToNumberList(msgs, m_messageCount);
+
+ // Change message flags
+ shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory();
+
+ utility::file::path curDirPath = store->getFormat()->
+ folderPathToFileSystemPath(m_path, maildirFormat::CUR_DIRECTORY);
+
+ for (std::vector <size_t>::const_iterator it =
+ nums.begin() ; it != nums.end() ; ++it) {
+
+ const size_t num = *it - 1;
+
+ try {
+
+ const utility::file::path::component path = m_messageInfos[num].path;
+ shared_ptr <utility::file> file = fsf->create(curDirPath / path);
+
+ int newFlags = maildirUtils::extractFlags(path);
+
+ switch (mode) {
+ case message::FLAG_MODE_ADD: newFlags |= flags; break;
+ case message::FLAG_MODE_REMOVE: newFlags &= ~flags; break;
+ default:
+ case message::FLAG_MODE_SET: newFlags = flags; break;
+ }
+
+ const utility::file::path::component newPath =
+ maildirUtils::buildFilename(maildirUtils::extractId(path), newFlags);
+
+ file->rename(curDirPath / newPath);
+
+ if (flags & message::FLAG_DELETED) {
+ m_messageInfos[num].type = messageInfos::TYPE_DELETED;
+ } else {
+ m_messageInfos[num].type = messageInfos::TYPE_CUR;
+ }
+
+ m_messageInfos[num].path = newPath;
+
+ } catch (exceptions::filesystem_exception& e) {
+
+ // Ignore (not important)
+ }
+ }
+
+ // Update local flags
+ switch (mode) {
+
+ case message::FLAG_MODE_ADD: {
+
+ for (std::vector <maildirMessage*>::iterator it =
+ m_messages.begin() ; it != m_messages.end() ; ++it) {
+
+ if (std::binary_search(nums.begin(), nums.end(), (*it)->getNumber()) &&
+ (*it)->m_flags != maildirMessage::FLAG_UNDEFINED) {
+
+ (*it)->m_flags |= flags;
+ }
+ }
+
+ break;
+ }
+ case message::FLAG_MODE_REMOVE: {
+
+ for (std::vector <maildirMessage*>::iterator it =
+ m_messages.begin() ; it != m_messages.end() ; ++it) {
+
+ if (std::binary_search(nums.begin(), nums.end(), (*it)->getNumber()) &&
+ (*it)->m_flags != maildirMessage::FLAG_UNDEFINED) {
+
+ (*it)->m_flags &= ~flags;
+ }
+ }
+
+ break;
+ }
+ default:
+ case message::FLAG_MODE_SET: {
+
+ for (std::vector <maildirMessage*>::iterator it =
+ m_messages.begin() ; it != m_messages.end() ; ++it) {
+
+ if (std::binary_search(nums.begin(), nums.end(), (*it)->getNumber()) &&
+ (*it)->m_flags != maildirMessage::FLAG_UNDEFINED) {
+
+ (*it)->m_flags = flags;
+ }
+ }
+
+ break;
+ }
+
+ }
+
+ // Notify message flags changed
+ shared_ptr <events::messageChangedEvent> event =
+ make_shared <events::messageChangedEvent>(
+ dynamicCast <folder>(shared_from_this()),
+ events::messageChangedEvent::TYPE_FLAGS,
+ nums
+ );
+
+ notifyMessageChanged(event);
+
+ // TODO: notify other folders with the same path
+
+ } else {
+
+ throw exceptions::operation_not_supported();
+ }
+}
+
+
+messageSet maildirFolder::addMessage(
+ const shared_ptr <vmime::message>& msg,
+ const int flags,
+ vmime::datetime* date,
+ utility::progressListener* progress
+) {
+
+ std::ostringstream oss;
+ utility::outputStreamAdapter ossAdapter(oss);
+
+ msg->generate(ossAdapter);
+
+ const string& str = oss.str();
+ utility::inputStreamStringAdapter strAdapter(str);
+
+ return addMessage(strAdapter, str.length(), flags, date, progress);
+}
+
+
+messageSet maildirFolder::addMessage(
+ utility::inputStream& is,
+ const size_t size,
+ const int flags,
+ vmime::datetime* /* date */,
+ utility::progressListener* progress
+) {
+
+ shared_ptr <maildirStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ } else if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ } else if (m_mode == MODE_READ_ONLY) {
+ throw exceptions::illegal_state("Folder is read-only");
+ }
+
+ shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory();
+
+ utility::file::path tmpDirPath = store->getFormat()->
+ folderPathToFileSystemPath(m_path,maildirFormat::TMP_DIRECTORY);
+ utility::file::path dstDirPath = store->getFormat()->
+ folderPathToFileSystemPath(
+ m_path,
+ flags == message::FLAG_RECENT ?
+ maildirFormat::NEW_DIRECTORY :
+ maildirFormat::CUR_DIRECTORY
+ );
+
+ const utility::file::path::component filename =
+ maildirUtils::buildFilename(maildirUtils::generateId(), ((flags == -1) ? 0 : flags));
+
+ try {
+ shared_ptr <utility::file> tmpDir = fsf->create(tmpDirPath);
+ tmpDir->createDirectory(true);
+ } catch (exceptions::filesystem_exception&) {
+ // Don't throw now, it will fail later...
+ }
+
+ try {
+ shared_ptr <utility::file> curDir = fsf->create(dstDirPath);
+ curDir->createDirectory(true);
+ } catch (exceptions::filesystem_exception&) {
+ // Don't throw now, it will fail later...
+ }
+
+ // Actually add the message
+ copyMessageImpl(tmpDirPath, dstDirPath, filename, is, size, progress);
+
+ // Append the message to the cache list
+ messageInfos msgInfos;
+ msgInfos.path = filename;
+ msgInfos.type = messageInfos::TYPE_CUR;
+
+ m_messageInfos.push_back(msgInfos);
+ m_messageCount++;
+
+ if ((flags == -1) || !(flags & message::FLAG_SEEN)) {
+ m_unreadMessageCount++;
+ }
+
+ // Notification
+ std::vector <size_t> nums;
+ nums.push_back(m_messageCount);
+
+ shared_ptr <events::messageCountEvent> event =
+ make_shared <events::messageCountEvent>(
+ dynamicCast <folder>(shared_from_this()),
+ events::messageCountEvent::TYPE_ADDED,
+ nums
+ );
+
+ notifyMessageCount(event);
+
+ // Notify folders with the same path
+ for (std::list <maildirFolder*>::iterator it = store->m_folders.begin() ;
+ it != store->m_folders.end() ; ++it) {
+
+ if ((*it) != this && (*it)->getFullPath() == m_path) {
+
+ (*it)->m_messageCount = m_messageCount;
+ (*it)->m_unreadMessageCount = m_unreadMessageCount;
+
+ (*it)->m_messageInfos.resize(m_messageInfos.size());
+ std::copy(m_messageInfos.begin(), m_messageInfos.end(), (*it)->m_messageInfos.begin());
+
+ shared_ptr <events::messageCountEvent> event =
+ make_shared <events::messageCountEvent>(
+ dynamicCast <folder>((*it)->shared_from_this()),
+ events::messageCountEvent::TYPE_ADDED,
+ nums
+ );
+
+ (*it)->notifyMessageCount(event);
+ }
+ }
+
+ return messageSet::empty();
+}
+
+
+void maildirFolder::copyMessageImpl(
+ const utility::file::path& tmpDirPath,
+ const utility::file::path& dstDirPath,
+ const utility::file::path::component& filename,
+ utility::inputStream& is, const size_t size,
+ utility::progressListener* progress
+) {
+
+ shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory();
+
+ shared_ptr <utility::file> file = fsf->create(tmpDirPath / filename);
+
+ if (progress) {
+ progress->start(size);
+ }
+
+ // First, write the message into 'tmp'...
+ try {
+
+ file->createFile();
+
+ shared_ptr <utility::fileWriter> fw = file->getFileWriter();
+ shared_ptr <utility::outputStream> os = fw->getOutputStream();
+
+ byte_t buffer[65536];
+ size_t total = 0;
+
+ while (!is.eof()) {
+
+ const size_t read = is.read(buffer, sizeof(buffer));
+
+ if (read != 0) {
+ os->write(buffer, read);
+ total += read;
+ }
+
+ if (progress) {
+ progress->progress(total, size);
+ }
+ }
+
+ os->flush();
+
+ } catch (exception& e) {
+
+ if (progress) {
+ progress->stop(size);
+ }
+
+ // Delete temporary file
+ try {
+ shared_ptr <utility::file> file = fsf->create(tmpDirPath / filename);
+ file->remove();
+ } catch (exceptions::filesystem_exception&) {
+ // Ignore
+ }
+
+ throw exceptions::command_error("ADD", "", "", e);
+ }
+
+ // ...then, move it to 'cur'
+ try {
+
+ file->rename(dstDirPath / filename);
+
+ } catch (exception& e) {
+
+ if (progress) {
+ progress->stop(size);
+ }
+
+ // Delete temporary file
+ try {
+
+ file->remove();
+ shared_ptr <utility::file> file = fsf->create(dstDirPath / filename);
+ file->remove();
+
+ } catch (exceptions::filesystem_exception&) {
+
+ // Ignore
+ }
+
+ throw exceptions::command_error("ADD", "", "", e);
+ }
+
+ if (progress) {
+ progress->stop(size);
+ }
+}
+
+
+messageSet maildirFolder::copyMessages(const folder::path& dest, const messageSet& msgs) {
+
+ shared_ptr <maildirStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ } else if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ }
+
+ shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory();
+
+ utility::file::path curDirPath =
+ store->getFormat()->folderPathToFileSystemPath(m_path, maildirFormat::CUR_DIRECTORY);
+
+ utility::file::path destCurDirPath = store->getFormat()->
+ folderPathToFileSystemPath(dest, maildirFormat::CUR_DIRECTORY);
+ utility::file::path destTmpDirPath = store->getFormat()->
+ folderPathToFileSystemPath(dest, maildirFormat::TMP_DIRECTORY);
+
+ // Create destination directories
+ try {
+
+ shared_ptr <utility::file> destTmpDir = fsf->create(destTmpDirPath);
+ destTmpDir->createDirectory(true);
+
+ } catch (exceptions::filesystem_exception&) {
+
+ // Don't throw now, it will fail later...
+ }
+
+ try {
+
+ shared_ptr <utility::file> destCurDir = fsf->create(destCurDirPath);
+ destCurDir->createDirectory(true);
+
+ } catch (exceptions::filesystem_exception&) {
+
+ // Don't throw now, it will fail later...
+ }
+
+ // Copy messages
+ const std::vector <size_t> nums = maildirUtils::messageSetToNumberList(msgs, m_messageCount);
+
+ try {
+
+ for (std::vector <size_t>::const_iterator it =
+ nums.begin() ; it != nums.end() ; ++it) {
+
+ const size_t num = *it;
+ const messageInfos& msg = m_messageInfos[num - 1];
+ const int flags = maildirUtils::extractFlags(msg.path);
+
+ const utility::file::path::component filename =
+ maildirUtils::buildFilename(maildirUtils::generateId(), flags);
+
+ shared_ptr <utility::file> file = fsf->create(curDirPath / msg.path);
+ shared_ptr <utility::fileReader> fr = file->getFileReader();
+ shared_ptr <utility::inputStream> is = fr->getInputStream();
+
+ copyMessageImpl(destTmpDirPath, destCurDirPath,
+ filename, *is, file->getLength(), NULL);
+ }
+
+ } catch (exception& e) {
+
+ notifyMessagesCopied(dest);
+ throw exceptions::command_error("COPY", "", "", e);
+ }
+
+ notifyMessagesCopied(dest);
+
+ return messageSet::empty();
+}
+
+
+void maildirFolder::notifyMessagesCopied(const folder::path& dest) {
+
+ shared_ptr <maildirStore> store = m_store.lock();
+
+ for (std::list <maildirFolder*>::iterator it = store->m_folders.begin() ;
+ it != store->m_folders.end() ; ++it) {
+
+ if ((*it) != this && (*it)->getFullPath() == dest) {
+
+ // We only need to update the first folder we found as calling
+ // status() will notify all the folders with the same path.
+ size_t count, unseen;
+ (*it)->status(count, unseen);
+
+ return;
+ }
+ }
+}
+
+
+void maildirFolder::status(size_t& count, size_t& unseen) {
+
+ count = 0;
+ unseen = 0;
+
+ shared_ptr <folderStatus> status = getStatus();
+
+ count = status->getMessageCount();
+ unseen = status->getUnseenCount();
+
+ m_messageCount = count;
+}
+
+
+shared_ptr <folderStatus> maildirFolder::getStatus() {
+
+ shared_ptr <maildirStore> store = m_store.lock();
+
+ const size_t oldCount = m_messageCount;
+
+ scanFolder();
+
+ shared_ptr <maildirFolderStatus> status = make_shared <maildirFolderStatus>();
+
+ status->setMessageCount(m_messageCount);
+ status->setUnseenCount(m_unreadMessageCount);
+
+ // Notify message count changed (new messages)
+ if (m_messageCount > oldCount) {
+
+ std::vector <size_t> nums;
+ nums.reserve(m_messageCount - oldCount);
+
+ for (size_t i = oldCount + 1, j = 0 ; i <= m_messageCount ; ++i, ++j) {
+ nums[j] = i;
+ }
+
+ shared_ptr <events::messageCountEvent> event =
+ make_shared <events::messageCountEvent>(
+ dynamicCast <folder>(shared_from_this()),
+ events::messageCountEvent::TYPE_ADDED,
+ nums
+ );
+
+ notifyMessageCount(event);
+
+ // Notify folders with the same path
+ for (std::list <maildirFolder*>::iterator it = store->m_folders.begin() ;
+ it != store->m_folders.end() ; ++it) {
+
+ if ((*it) != this && (*it)->getFullPath() == m_path) {
+
+ (*it)->m_messageCount = m_messageCount;
+ (*it)->m_unreadMessageCount = m_unreadMessageCount;
+
+ (*it)->m_messageInfos.resize(m_messageInfos.size());
+ std::copy(m_messageInfos.begin(), m_messageInfos.end(), (*it)->m_messageInfos.begin());
+
+ shared_ptr <events::messageCountEvent> event =
+ make_shared <events::messageCountEvent>(
+ dynamicCast <folder>((*it)->shared_from_this()),
+ events::messageCountEvent::TYPE_ADDED,
+ nums
+ );
+
+ (*it)->notifyMessageCount(event);
+ }
+ }
+ }
+
+ return status;
+}
+
+
+void maildirFolder::expunge() {
+
+ shared_ptr <maildirStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ } else if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ } else if (m_mode == MODE_READ_ONLY) {
+ throw exceptions::illegal_state("Folder is read-only");
+ }
+
+ shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory();
+
+ utility::file::path curDirPath = store->getFormat()->
+ folderPathToFileSystemPath(m_path, maildirFormat::CUR_DIRECTORY);
+
+ std::vector <size_t> nums;
+ size_t unreadCount = 0;
+
+ for (size_t num = 1 ; num <= m_messageCount ; ++num) {
+
+ messageInfos& infos = m_messageInfos[num - 1];
+
+ if (infos.type == messageInfos::TYPE_DELETED) {
+
+ nums.push_back(num);
+
+ for (std::vector <maildirMessage*>::iterator it =
+ m_messages.begin() ; it != m_messages.end() ; ++it) {
+
+ if ((*it)->m_num == num) {
+ (*it)->m_expunged = true;
+ } else if ((*it)->m_num > num) {
+ (*it)->m_num--;
+ }
+ }
+
+ if (maildirUtils::extractFlags(infos.path) & message::FLAG_SEEN) {
+ ++unreadCount;
+ }
+
+ // Delete file from file system
+ try {
+ shared_ptr <utility::file> file = fsf->create(curDirPath / infos.path);
+ file->remove();
+ } catch (exceptions::filesystem_exception& e) {
+ // Ignore (not important)
+ }
+ }
+ }
+
+ if (!nums.empty()) {
+
+ for (std::vector <size_t>::size_type i = nums.size() ; i != 0 ; --i) {
+ m_messageInfos.erase(m_messageInfos.begin() + (i - 1));
+ }
+ }
+
+ m_messageCount -= static_cast <size_t>(nums.size());
+ m_unreadMessageCount -= unreadCount;
+
+ // Notify message expunged
+ shared_ptr <events::messageCountEvent> event =
+ make_shared <events::messageCountEvent>(
+ dynamicCast <folder>(shared_from_this()),
+ events::messageCountEvent::TYPE_REMOVED,
+ nums
+ );
+
+ notifyMessageCount(event);
+
+ // Notify folders with the same path
+ for (std::list <maildirFolder*>::iterator it = store->m_folders.begin() ;
+ it != store->m_folders.end() ; ++it) {
+
+ if ((*it) != this && (*it)->getFullPath() == m_path) {
+
+ (*it)->m_messageCount = m_messageCount;
+ (*it)->m_unreadMessageCount = m_unreadMessageCount;
+
+ (*it)->m_messageInfos.resize(m_messageInfos.size());
+ std::copy(m_messageInfos.begin(), m_messageInfos.end(), (*it)->m_messageInfos.begin());
+
+ shared_ptr <events::messageCountEvent> event =
+ make_shared <events::messageCountEvent>(
+ dynamicCast <folder>((*it)->shared_from_this()),
+ events::messageCountEvent::TYPE_REMOVED,
+ nums
+ );
+
+ (*it)->notifyMessageCount(event);
+ }
+ }
+}
+
+
+shared_ptr <folder> maildirFolder::getParent() {
+
+ if (m_path.isEmpty()) {
+ return null;
+ } else {
+ return shared_ptr <maildirFolder>(new maildirFolder(m_path.getParent(), m_store.lock()));
+ }
+}
+
+
+shared_ptr <const store> maildirFolder::getStore() const {
+
+ return m_store.lock();
+}
+
+
+shared_ptr <store> maildirFolder::getStore() {
+
+ return m_store.lock();
+}
+
+
+void maildirFolder::fetchMessages(
+ std::vector <shared_ptr <message> >& msg,
+ const fetchAttributes& options,
+ utility::progressListener* progress
+) {
+
+ shared_ptr <maildirStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ } else if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ }
+
+ if (msg.empty()) {
+ return;
+ }
+
+ const size_t total = msg.size();
+ size_t current = 0;
+
+ if (progress) {
+ progress->start(total);
+ }
+
+ shared_ptr <maildirFolder> thisFolder = dynamicCast <maildirFolder>(shared_from_this());
+
+ for (std::vector <shared_ptr <message> >::iterator it = msg.begin() ;
+ it != msg.end() ; ++it) {
+
+ dynamicCast <maildirMessage>(*it)->fetch(thisFolder, options);
+
+ if (progress) {
+ progress->progress(++current, total);
+ }
+ }
+
+ if (progress) {
+ progress->stop(total);
+ }
+}
+
+
+void maildirFolder::fetchMessage(
+ const shared_ptr <message>& msg,
+ const fetchAttributes& options
+) {
+
+ shared_ptr <maildirStore> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ } else if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ }
+
+ dynamicCast <maildirMessage>(msg)->fetch(
+ dynamicCast <maildirFolder>(shared_from_this()),
+ options
+ );
+}
+
+
+std::vector <shared_ptr <message> > maildirFolder::getAndFetchMessages(
+ const messageSet& msgs,
+ const fetchAttributes& attribs
+) {
+
+ if (msgs.isEmpty()) {
+ return std::vector <shared_ptr <message> >();
+ }
+
+ std::vector <shared_ptr <message> > messages = getMessages(msgs);
+ fetchMessages(messages, attribs);
+
+ return messages;
+}
+
+
+int maildirFolder::getFetchCapabilities() const {
+
+ return fetchAttributes::ENVELOPE |
+ fetchAttributes::STRUCTURE |
+ fetchAttributes::CONTENT_INFO |
+ fetchAttributes::FLAGS |
+ fetchAttributes::SIZE |
+ fetchAttributes::FULL_HEADER |
+ fetchAttributes::UID |
+ fetchAttributes::IMPORTANCE;
+}
+
+
+const utility::file::path maildirFolder::getMessageFSPath(const size_t number) const {
+
+ utility::file::path curDirPath = m_store.lock()->getFormat()->
+ folderPathToFileSystemPath(m_path, maildirFormat::CUR_DIRECTORY);
+
+ return curDirPath / m_messageInfos[number - 1].path;
+}
+
+
+std::vector <size_t> maildirFolder::getMessageNumbersStartingOnUID(const message::uid& /* uid */) {
+
+ throw exceptions::operation_not_supported();
+}
+
+
+} // maildir
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
diff --git a/vmime-master/src/vmime/net/maildir/maildirFolder.hpp b/vmime-master/src/vmime/net/maildir/maildirFolder.hpp
new file mode 100644
index 0000000..24f2bf8
--- /dev/null
+++ b/vmime-master/src/vmime/net/maildir/maildirFolder.hpp
@@ -0,0 +1,211 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_MAILDIR_MAILDIRFOLDER_HPP_INCLUDED
+#define VMIME_NET_MAILDIR_MAILDIRFOLDER_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+
+#include <vector>
+#include <map>
+
+#include "vmime/types.hpp"
+
+#include "vmime/net/folder.hpp"
+
+#include "vmime/utility/file.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace maildir {
+
+
+class maildirStore;
+class maildirMessage;
+
+
+/** maildir folder implementation.
+ */
+class VMIME_EXPORT maildirFolder : public folder {
+
+private:
+
+ friend class maildirStore;
+ friend class maildirMessage;
+
+ maildirFolder(const maildirFolder&) : folder() { }
+ maildirFolder(const folder::path& path, const shared_ptr <maildirStore>& store);
+
+public:
+
+ ~maildirFolder();
+
+
+ int getMode() const;
+
+ const folderAttributes getAttributes();
+
+ const folder::path::component getName() const;
+ const folder::path getFullPath() const;
+
+ void open(const int mode, bool failIfModeIsNotAvailable = false);
+ void close(const bool expunge);
+ void create(const folderAttributes& attribs);
+
+ bool exists();
+
+ void destroy();
+
+ bool isOpen() const;
+
+ shared_ptr <message> getMessage(const size_t num);
+ std::vector <shared_ptr <message> > getMessages(const messageSet& msgs);
+
+ size_t getMessageCount();
+
+ shared_ptr <folder> getFolder(const folder::path::component& name);
+ std::vector <shared_ptr <folder> > getFolders(const bool recursive = false);
+
+ void rename(const folder::path& newPath);
+
+ void deleteMessages(const messageSet& msgs);
+
+ void setMessageFlags(
+ const messageSet& msgs,
+ const int flags,
+ const int mode = message::FLAG_MODE_SET
+ );
+
+ messageSet addMessage(
+ const shared_ptr <vmime::message>& msg,
+ const int flags = -1,
+ vmime::datetime* date = NULL,
+ utility::progressListener* progress = NULL
+ );
+
+ messageSet addMessage(
+ utility::inputStream& is,
+ const size_t size,
+ const int flags = -1,
+ vmime::datetime* date = NULL,
+ utility::progressListener* progress = NULL
+ );
+
+ messageSet copyMessages(const folder::path& dest, const messageSet& msgs);
+
+ void status(size_t& count, size_t& unseen);
+ shared_ptr <folderStatus> getStatus();
+
+ void expunge();
+
+ shared_ptr <folder> getParent();
+
+ shared_ptr <const store> getStore() const;
+ shared_ptr <store> getStore();
+
+
+ void fetchMessages(
+ std::vector <shared_ptr <message> >& msg,
+ const fetchAttributes& options,
+ utility::progressListener* progress = NULL
+ );
+
+ void fetchMessage(const shared_ptr <message>& msg, const fetchAttributes& options);
+
+ std::vector <shared_ptr <message> > getAndFetchMessages(
+ const messageSet& msgs,
+ const fetchAttributes& attribs
+ );
+
+ int getFetchCapabilities() const;
+
+ std::vector <size_t> getMessageNumbersStartingOnUID(const message::uid& uid);
+
+private:
+
+ void scanFolder();
+
+ void listFolders(std::vector <shared_ptr <folder> >& list, const bool recursive);
+
+ void registerMessage(maildirMessage* msg);
+ void unregisterMessage(maildirMessage* msg);
+
+ const utility::file::path getMessageFSPath(const size_t number) const;
+
+ void onStoreDisconnected();
+
+ void onClose();
+
+ void deleteMessagesImpl(const std::vector <size_t>& nums);
+ void setMessageFlagsImpl(const std::vector <size_t>& nums, const int flags, const int mode);
+
+ void copyMessagesImpl(const folder::path& dest, const std::vector <size_t>& nums);
+ void copyMessageImpl(const utility::file::path& tmpDirPath, const utility::file::path& curDirPath, const utility::file::path::component& filename, utility::inputStream& is, const size_t size, utility::progressListener* progress);
+
+ void notifyMessagesCopied(const folder::path& dest);
+
+
+ weak_ptr <maildirStore> m_store;
+
+ folder::path m_path;
+ folder::path::component m_name;
+
+ int m_mode;
+ bool m_open;
+
+ size_t m_unreadMessageCount;
+ size_t m_messageCount;
+
+ // Store information about scanned messages
+ struct messageInfos {
+
+ enum Type {
+ TYPE_CUR,
+ TYPE_DELETED
+ };
+
+ utility::file::path::component path; // filename
+ Type type; // current location
+ };
+
+ std::vector <messageInfos> m_messageInfos;
+
+ // Instanciated message objects
+ std::vector <maildirMessage*> m_messages;
+};
+
+
+} // maildir
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+#endif // VMIME_NET_MAILDIR_MAILDIRFOLDER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/maildir/maildirFolderStatus.cpp b/vmime-master/src/vmime/net/maildir/maildirFolderStatus.cpp
new file mode 100644
index 0000000..7438d8c
--- /dev/null
+++ b/vmime-master/src/vmime/net/maildir/maildirFolderStatus.cpp
@@ -0,0 +1,88 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+
+#include "vmime/net/maildir/maildirFolderStatus.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace maildir {
+
+
+maildirFolderStatus::maildirFolderStatus()
+ : m_count(0),
+ m_unseen(0) {
+
+}
+
+
+maildirFolderStatus::maildirFolderStatus(const maildirFolderStatus& other)
+ : folderStatus(),
+ m_count(other.m_count),
+ m_unseen(other.m_unseen) {
+
+}
+
+
+size_t maildirFolderStatus::getMessageCount() const {
+
+ return m_count;
+}
+
+
+size_t maildirFolderStatus::getUnseenCount() const {
+
+ return m_unseen;
+}
+
+
+void maildirFolderStatus::setMessageCount(const size_t count) {
+
+ m_count = count;
+}
+
+
+void maildirFolderStatus::setUnseenCount(const size_t unseen) {
+
+ m_unseen = unseen;
+}
+
+
+shared_ptr <folderStatus> maildirFolderStatus::clone() const {
+
+ return make_shared <maildirFolderStatus>(*this);
+}
+
+
+} // maildir
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
diff --git a/vmime-master/src/vmime/net/maildir/maildirFolderStatus.hpp b/vmime-master/src/vmime/net/maildir/maildirFolderStatus.hpp
new file mode 100644
index 0000000..3b69375
--- /dev/null
+++ b/vmime-master/src/vmime/net/maildir/maildirFolderStatus.hpp
@@ -0,0 +1,75 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_MAILDIR_MAILDIRFOLDERSTATUS_HPP_INCLUDED
+#define VMIME_NET_MAILDIR_MAILDIRFOLDERSTATUS_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+
+#include "vmime/net/folderStatus.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace maildir {
+
+
+/** Holds the status of a Maildir folder.
+ */
+class VMIME_EXPORT maildirFolderStatus : public folderStatus {
+
+public:
+
+ maildirFolderStatus();
+ maildirFolderStatus(const maildirFolderStatus& other);
+
+ // Inherited from folderStatus
+ size_t getMessageCount() const;
+ size_t getUnseenCount() const;
+
+ shared_ptr <folderStatus> clone() const;
+
+
+ void setMessageCount(const size_t count);
+ void setUnseenCount(const size_t unseen);
+
+private:
+
+ size_t m_count;
+ size_t m_unseen;
+};
+
+
+} // maildir
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+#endif // VMIME_NET_MAILDIR_MAILDIRFOLDERSTATUS_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/maildir/maildirFormat.cpp b/vmime-master/src/vmime/net/maildir/maildirFormat.cpp
new file mode 100644
index 0000000..914c078
--- /dev/null
+++ b/vmime-master/src/vmime/net/maildir/maildirFormat.cpp
@@ -0,0 +1,104 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+
+#include "vmime/net/maildir/maildirFormat.hpp"
+#include "vmime/net/maildir/maildirStore.hpp"
+
+#include "vmime/net/maildir/format/kmailMaildirFormat.hpp"
+#include "vmime/net/maildir/format/courierMaildirFormat.hpp"
+
+#include "vmime/utility/file.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace maildir {
+
+
+const utility::file::path::component maildirFormat::TMP_DIR("tmp", vmime::charset(vmime::charsets::US_ASCII));
+const utility::file::path::component maildirFormat::CUR_DIR("cur", vmime::charset(vmime::charsets::US_ASCII));
+const utility::file::path::component maildirFormat::NEW_DIR("new", vmime::charset(vmime::charsets::US_ASCII));
+
+
+//
+// maildirFormat::context
+//
+
+maildirFormat::context::context(const shared_ptr <maildirStore>& store)
+ : m_store(store) {
+
+}
+
+
+shared_ptr <maildirStore> maildirFormat::context::getStore() {
+
+ return m_store.lock();
+}
+
+
+//
+// maildirFormat
+//
+
+maildirFormat::maildirFormat(const shared_ptr <context>& ctx)
+ : m_context(ctx) {
+
+}
+
+
+shared_ptr <maildirFormat::context> maildirFormat::getContext() const {
+
+ return m_context;
+}
+
+
+// static
+shared_ptr <maildirFormat> maildirFormat::detect(const shared_ptr <maildirStore>& store) {
+
+ shared_ptr <context> ctx = make_shared <context>(store);
+
+ // Try Courier format
+ shared_ptr <maildirFormat> fmt = make_shared <format::courierMaildirFormat>(ctx);
+
+ if (fmt->supports()) {
+ return fmt;
+ }
+
+ // Default is KMail format
+ return make_shared <format::kmailMaildirFormat>(ctx);
+}
+
+
+} // maildir
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
diff --git a/vmime-master/src/vmime/net/maildir/maildirFormat.hpp b/vmime-master/src/vmime/net/maildir/maildirFormat.hpp
new file mode 100644
index 0000000..9b9e063
--- /dev/null
+++ b/vmime-master/src/vmime/net/maildir/maildirFormat.hpp
@@ -0,0 +1,192 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_MAILDIR_FORMAT_MAILDIRFORMAT_HPP_INCLUDED
+#define VMIME_NET_MAILDIR_FORMAT_MAILDIRFORMAT_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+
+#include "vmime/net/folder.hpp"
+
+#include "vmime/utility/file.hpp"
+#include "vmime/utility/path.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace maildir {
+
+
+class maildirStore;
+
+
+/** Interface for an object capable of reading a specific Maildir format.
+ */
+class VMIME_EXPORT maildirFormat : public object {
+
+public:
+
+ class context : public object {
+
+ public:
+
+ context(const shared_ptr <maildirStore>& store);
+
+ shared_ptr <maildirStore> getStore();
+
+ private:
+
+ weak_ptr <maildirStore> m_store;
+ };
+
+
+ /** Physical directory types. */
+ enum DirectoryType {
+ ROOT_DIRECTORY, /**< Root directory. */
+ NEW_DIRECTORY, /**< Directory containing unread messages. */
+ CUR_DIRECTORY, /**< Directory containing messages that have been seen. */
+ TMP_DIRECTORY, /**< Temporary directory used for reliable delivery. */
+ CONTAINER_DIRECTORY /**< Container for subfolders. */
+ };
+
+ /** Return the name of this Maildir format.
+ *
+ * @return format name
+ */
+ virtual const string getName() const = 0;
+
+ /** Create the specified folder.
+ *
+ * @param path virtual path of the folder
+ * @throw exceptions::filesystem_exception, invalid_folder_name
+ */
+ virtual void createFolder(const folder::path& path) = 0;
+
+ /** Destroy the specified folder.
+ *
+ * @param path virtual path of the folder
+ * @throw exceptions::filesystem_exception
+ */
+ virtual void destroyFolder(const folder::path& path) = 0;
+
+ /** Rename the specified folder.
+ *
+ * @param oldPath old virtual path of the folder
+ * @param newPath new virtual path of the folder
+ * @throw exceptions::filesystem_exception
+ */
+ virtual void renameFolder(const folder::path& oldPath, const folder::path& newPath) = 0;
+
+ /** Test whether the specified folder exists.
+ *
+ * @param path virtual path of the folder
+ * @return true if the folder exists, false otherwise
+ */
+ virtual bool folderExists(const folder::path& path) const = 0;
+
+ /** Test whether the specified folder has subfolders.
+ *
+ * @param path virtual path of the folder
+ * @return true if the folder has at least one subfolder,
+ * false otherwise
+ */
+ virtual bool folderHasSubfolders(const folder::path& path) const = 0;
+
+ /** Returns the directory which represents the specified
+ * folder on the file system.
+ *
+ * @param path virtual path of the folder
+ * @param type type of directory to return
+ * @return corresponding directory on the file system
+ */
+ virtual const utility::file::path folderPathToFileSystemPath(
+ const folder::path& path,
+ const DirectoryType type
+ ) const = 0;
+
+ /** List subfolders in the specified folder.
+ *
+ * @param root root folder in which to start the search
+ * @param recursive if set to true, all the descendant are
+ * returned; if set to false, only direct children are returned.
+ * @return list of subfolders
+ */
+ virtual const std::vector <folder::path> listFolders(
+ const folder::path& root,
+ const bool recursive
+ ) const = 0;
+
+
+ /** Try to detect the format of the specified Maildir store.
+ * If the format cannot be detected, a compatible implementation
+ * will be returned.
+ *
+ * @param store of which to detect format
+ * @return a Maildir format implementation for the specified store
+ */
+ static shared_ptr <maildirFormat> detect(const shared_ptr <maildirStore>& store);
+
+protected:
+
+ static const utility::file::path::component TMP_DIR; /**< Ensure reliable delivery (not to be listed). */
+ static const utility::file::path::component CUR_DIR; /**< No longer new messages. */
+ static const utility::file::path::component NEW_DIR; /**< Unread messages. */
+
+
+ maildirFormat(const shared_ptr <context>& ctx);
+
+
+ /** Returns the current context.
+ *
+ * @return current context
+ */
+ shared_ptr <context> getContext() const;
+
+ /** Quick checks whether this implementation can read the Maildir
+ * format in the specified directory.
+ *
+ * @return true if the implementation supports the specified
+ * Maildir, or false otherwise
+ */
+ virtual bool supports() const = 0;
+
+private:
+
+ shared_ptr <context> m_context;
+};
+
+
+} // maildir
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+#endif // VMIME_NET_MAILDIR_FORMAT_MAILDIRFORMAT_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/maildir/maildirMessage.cpp b/vmime-master/src/vmime/net/maildir/maildirMessage.cpp
new file mode 100644
index 0000000..ae99c59
--- /dev/null
+++ b/vmime-master/src/vmime/net/maildir/maildirMessage.cpp
@@ -0,0 +1,410 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+
+#include "vmime/net/maildir/maildirMessage.hpp"
+#include "vmime/net/maildir/maildirMessagePart.hpp"
+#include "vmime/net/maildir/maildirMessageStructure.hpp"
+#include "vmime/net/maildir/maildirFolder.hpp"
+#include "vmime/net/maildir/maildirUtils.hpp"
+#include "vmime/net/maildir/maildirStore.hpp"
+
+#include "vmime/message.hpp"
+
+#include "vmime/exception.hpp"
+#include "vmime/platform.hpp"
+
+#include "vmime/utility/outputStreamAdapter.hpp"
+#include "vmime/utility/stringUtils.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace maildir {
+
+
+maildirMessage::maildirMessage(const shared_ptr <maildirFolder>& folder, const size_t num)
+ : m_folder(folder),
+ m_num(num),
+ m_size(-1),
+ m_flags(FLAG_UNDEFINED),
+ m_expunged(false),
+ m_structure(null) {
+
+ folder->registerMessage(this);
+}
+
+
+maildirMessage::~maildirMessage() {
+
+ try {
+
+ shared_ptr <maildirFolder> folder = m_folder.lock();
+
+ if (folder) {
+ folder->unregisterMessage(this);
+ }
+
+ } catch (...) {
+
+ // Don't throw in destructor
+ }
+}
+
+
+void maildirMessage::onFolderClosed() {
+
+ m_folder.reset();
+}
+
+
+size_t maildirMessage::getNumber() const {
+
+ return m_num;
+}
+
+
+const message::uid maildirMessage::getUID() const {
+
+ return m_uid;
+}
+
+
+size_t maildirMessage::getSize() const {
+
+ if (m_size == static_cast <size_t>(-1)) {
+ throw exceptions::unfetched_object();
+ }
+
+ return m_size;
+}
+
+
+bool maildirMessage::isExpunged() const {
+
+ return m_expunged;
+}
+
+
+shared_ptr <const messageStructure> maildirMessage::getStructure() const {
+
+ if (!m_structure) {
+ throw exceptions::unfetched_object();
+ }
+
+ return m_structure;
+}
+
+
+shared_ptr <messageStructure> maildirMessage::getStructure() {
+
+ if (!m_structure) {
+ throw exceptions::unfetched_object();
+ }
+
+ return m_structure;
+}
+
+
+shared_ptr <const header> maildirMessage::getHeader() const {
+
+ if (!m_header) {
+ throw exceptions::unfetched_object();
+ }
+
+ return m_header;
+}
+
+
+int maildirMessage::getFlags() const {
+
+ if (m_flags == FLAG_UNDEFINED) {
+ throw exceptions::unfetched_object();
+ }
+
+ return m_flags;
+}
+
+
+void maildirMessage::setFlags(const int flags, const int mode) {
+
+ shared_ptr <maildirFolder> folder = m_folder.lock();
+
+ if (!folder) {
+ throw exceptions::folder_not_found();
+ }
+
+ folder->setMessageFlags(messageSet::byNumber(m_num), flags, mode);
+}
+
+
+void maildirMessage::extract(
+ utility::outputStream& os,
+ utility::progressListener* progress,
+ const size_t start,
+ const size_t length,
+ const bool peek
+) const {
+
+ extractImpl(os, progress, 0, m_size, start, length, peek);
+}
+
+
+void maildirMessage::extractPart(
+ const shared_ptr <const messagePart>& p,
+ utility::outputStream& os,
+ utility::progressListener* progress,
+ const size_t start,
+ const size_t length,
+ const bool peek
+) const {
+
+ shared_ptr <const maildirMessagePart> mp = dynamicCast <const maildirMessagePart>(p);
+
+ extractImpl(
+ os, progress, mp->getBodyParsedOffset(), mp->getBodyParsedLength(),
+ start, length, peek
+ );
+}
+
+
+void maildirMessage::extractImpl(
+ utility::outputStream& os,
+ utility::progressListener* progress,
+ const size_t start,
+ const size_t length,
+ const size_t partialStart,
+ const size_t partialLength,
+ const bool /* peek */
+) const {
+
+ shared_ptr <const maildirFolder> folder = m_folder.lock();
+
+ shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory();
+
+ const utility::file::path path = folder->getMessageFSPath(m_num);
+ shared_ptr <utility::file> file = fsf->create(path);
+
+ shared_ptr <utility::fileReader> reader = file->getFileReader();
+ shared_ptr <utility::inputStream> is = reader->getInputStream();
+
+ is->skip(start + partialStart);
+
+ byte_t buffer[8192];
+ size_t remaining =
+ (partialLength == static_cast <size_t>(-1)
+ ? length
+ : std::min(partialLength, length)
+ );
+
+ const size_t total = remaining;
+ size_t current = 0;
+
+ if (progress) {
+ progress->start(total);
+ }
+
+ while (!is->eof() && remaining > 0) {
+
+ const size_t read = is->read(buffer, std::min(remaining, sizeof(buffer)));
+
+ remaining -= read;
+ current += read;
+
+ os.write(buffer, read);
+
+ if (progress) {
+ progress->progress(current, total);
+ }
+ }
+
+ if (progress) {
+ progress->stop(total);
+ }
+
+ // TODO: mark as read unless 'peek' is set
+}
+
+
+void maildirMessage::fetchPartHeader(const shared_ptr <messagePart>& p) {
+
+ shared_ptr <maildirFolder> folder = m_folder.lock();
+
+ shared_ptr <maildirMessagePart> mp = dynamicCast <maildirMessagePart>(p);
+
+ shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory();
+
+ const utility::file::path path = folder->getMessageFSPath(m_num);
+ shared_ptr <utility::file> file = fsf->create(path);
+
+ shared_ptr <utility::fileReader> reader = file->getFileReader();
+ shared_ptr <utility::inputStream> is = reader->getInputStream();
+
+ is->skip(mp->getHeaderParsedOffset());
+
+ byte_t buffer[1024];
+ size_t remaining = mp->getHeaderParsedLength();
+
+ string contents;
+ contents.reserve(remaining);
+
+ while (!is->eof() && remaining > 0) {
+
+ const size_t read = is->read(buffer, std::min(remaining, sizeof(buffer)));
+
+ remaining -= read;
+
+ vmime::utility::stringUtils::appendBytesToString(contents, buffer, read);
+ }
+
+ mp->getOrCreateHeader().parse(contents);
+}
+
+
+void maildirMessage::fetch(const shared_ptr <maildirFolder>& msgFolder, const fetchAttributes& options) {
+
+ shared_ptr <maildirFolder> folder = m_folder.lock();
+
+ if (folder != msgFolder) {
+ throw exceptions::folder_not_found();
+ }
+
+ shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory();
+
+ const utility::file::path path = folder->getMessageFSPath(m_num);
+ shared_ptr <utility::file> file = fsf->create(path);
+
+ if (options.has(fetchAttributes::FLAGS)) {
+ m_flags = maildirUtils::extractFlags(path.getLastComponent());
+ }
+
+ if (options.has(fetchAttributes::SIZE)) {
+ m_size = file->getLength();
+ }
+
+ if (options.has(fetchAttributes::UID)) {
+ m_uid = maildirUtils::extractId(path.getLastComponent()).getBuffer();
+ }
+
+ if (options.has(fetchAttributes::ENVELOPE | fetchAttributes::CONTENT_INFO |
+ fetchAttributes::FULL_HEADER | fetchAttributes::STRUCTURE |
+ fetchAttributes::IMPORTANCE)) {
+
+ string contents;
+
+ shared_ptr <utility::fileReader> reader = file->getFileReader();
+ shared_ptr <utility::inputStream> is = reader->getInputStream();
+
+ // Need whole message contents for structure
+ if (options.has(fetchAttributes::STRUCTURE)) {
+
+ byte_t buffer[16384];
+
+ contents.reserve(file->getLength());
+
+ while (!is->eof()) {
+ const size_t read = is->read(buffer, sizeof(buffer));
+ vmime::utility::stringUtils::appendBytesToString(contents, buffer, read);
+ }
+
+ // Need only header
+ } else {
+
+ byte_t buffer[1024];
+
+ contents.reserve(4096);
+
+ while (!is->eof()) {
+
+ const size_t read = is->read(buffer, sizeof(buffer));
+ vmime::utility::stringUtils::appendBytesToString(contents, buffer, read);
+
+ const size_t sep1 = contents.rfind("\r\n\r\n");
+ const size_t sep2 = contents.rfind("\n\n");
+
+ if (sep1 != string::npos) {
+ contents.erase(contents.begin() + sep1 + 4, contents.end());
+ break;
+ } else if (sep2 != string::npos) {
+ contents.erase(contents.begin() + sep2 + 2, contents.end());
+ break;
+ }
+ }
+ }
+
+ vmime::message msg;
+ msg.parse(contents);
+
+ // Extract structure
+ if (options.has(fetchAttributes::STRUCTURE)) {
+ m_structure = make_shared <maildirMessageStructure>(shared_ptr <maildirMessagePart>(), msg);
+ }
+
+ // Extract some header fields or whole header
+ if (options.has(fetchAttributes::ENVELOPE |
+ fetchAttributes::CONTENT_INFO |
+ fetchAttributes::FULL_HEADER |
+ fetchAttributes::IMPORTANCE)) {
+
+ getOrCreateHeader()->copyFrom(*(msg.getHeader()));
+ }
+ }
+}
+
+
+shared_ptr <header> maildirMessage::getOrCreateHeader() {
+
+ if (m_header) {
+ return m_header;
+ } else {
+ return (m_header = make_shared <header>());
+ }
+}
+
+
+shared_ptr <vmime::message> maildirMessage::getParsedMessage() {
+
+ std::ostringstream oss;
+ utility::outputStreamAdapter os(oss);
+
+ extract(os);
+
+ shared_ptr <vmime::message> msg = make_shared <vmime::message>();
+ msg->parse(oss.str());
+
+ return msg;
+}
+
+
+} // maildir
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
diff --git a/vmime-master/src/vmime/net/maildir/maildirMessage.hpp b/vmime-master/src/vmime/net/maildir/maildirMessage.hpp
new file mode 100644
index 0000000..8cd0aac
--- /dev/null
+++ b/vmime-master/src/vmime/net/maildir/maildirMessage.hpp
@@ -0,0 +1,137 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_MAILDIR_MAILDIRMESSAGE_HPP_INCLUDED
+#define VMIME_NET_MAILDIR_MAILDIRMESSAGE_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+
+#include "vmime/net/message.hpp"
+#include "vmime/net/folder.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace maildir {
+
+
+class maildirFolder;
+
+
+/** maildir message implementation.
+ */
+class VMIME_EXPORT maildirMessage : public message {
+
+ friend class maildirFolder;
+
+ maildirMessage(const maildirMessage&) : message() { }
+
+public:
+
+ maildirMessage(const shared_ptr <maildirFolder>& folder, const size_t num);
+
+ ~maildirMessage();
+
+
+ size_t getNumber() const;
+
+ const uid getUID() const;
+
+ size_t getSize() const;
+
+ bool isExpunged() const;
+
+ shared_ptr <const messageStructure> getStructure() const;
+ shared_ptr <messageStructure> getStructure();
+
+ shared_ptr <const header> getHeader() const;
+
+ int getFlags() const;
+ void setFlags(const int flags, const int mode = FLAG_MODE_SET);
+
+ void extract(
+ utility::outputStream& os,
+ utility::progressListener* progress = NULL,
+ const size_t start = 0,
+ const size_t length = -1,
+ const bool peek = false
+ ) const;
+
+ void extractPart(
+ const shared_ptr <const messagePart>& p,
+ utility::outputStream& os,
+ utility::progressListener* progress = NULL,
+ const size_t start = 0,
+ const size_t length = -1,
+ const bool peek = false
+ ) const;
+
+ void fetchPartHeader(const shared_ptr <messagePart>& p);
+
+ shared_ptr <vmime::message> getParsedMessage();
+
+private:
+
+ void fetch(const shared_ptr <maildirFolder>& folder, const fetchAttributes& options);
+
+ void onFolderClosed();
+
+ shared_ptr <header> getOrCreateHeader();
+
+ void extractImpl(
+ utility::outputStream& os,
+ utility::progressListener* progress,
+ const size_t start,
+ const size_t length,
+ const size_t partialStart,
+ const size_t partialLength,
+ const bool peek
+ ) const;
+
+
+ weak_ptr <maildirFolder> m_folder;
+
+ size_t m_num;
+ size_t m_size;
+ int m_flags;
+ bool m_expunged;
+ uid m_uid;
+
+ shared_ptr <header> m_header;
+ shared_ptr <messageStructure> m_structure;
+};
+
+
+} // maildir
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+#endif // VMIME_NET_MAILDIR_MAILDIRMESSAGE_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/maildir/maildirMessagePart.cpp b/vmime-master/src/vmime/net/maildir/maildirMessagePart.cpp
new file mode 100644
index 0000000..7448d7e
--- /dev/null
+++ b/vmime-master/src/vmime/net/maildir/maildirMessagePart.cpp
@@ -0,0 +1,178 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+
+#include "vmime/net/maildir/maildirMessagePart.hpp"
+#include "vmime/net/maildir/maildirMessageStructure.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace maildir {
+
+
+maildirMessagePart::maildirMessagePart(
+ const shared_ptr <maildirMessagePart>& parent,
+ const size_t number,
+ const bodyPart& part
+)
+ : m_parent(parent),
+ m_header(null),
+ m_number(number) {
+
+ m_headerParsedOffset = part.getHeader()->getParsedOffset();
+ m_headerParsedLength = part.getHeader()->getParsedLength();
+
+ m_bodyParsedOffset = part.getBody()->getParsedOffset();
+ m_bodyParsedLength = part.getBody()->getParsedLength();
+
+ m_size = part.getBody()->getContents()->getLength();
+
+ m_mediaType = part.getBody()->getContentType();
+
+ auto cdispField = part.getHeader()->ContentDisposition();
+ if (cdispField) {
+ m_dispType = dynamic_cast <const contentDisposition&>(*cdispField->getValue());
+ }
+}
+
+
+maildirMessagePart::~maildirMessagePart() {
+
+}
+
+
+void maildirMessagePart::initStructure(const bodyPart& part) {
+
+ if (part.getBody()->getPartList().size() == 0) {
+
+ m_structure = null;
+
+ } else {
+
+ m_structure = make_shared <maildirMessageStructure>(
+ dynamicCast <maildirMessagePart>(shared_from_this()), part.getBody()->getPartList()
+ );
+ }
+}
+
+
+shared_ptr <const messageStructure> maildirMessagePart::getStructure() const {
+
+ if (m_structure) {
+ return m_structure;
+ } else {
+ return maildirMessageStructure::emptyStructure();
+ }
+}
+
+
+shared_ptr <messageStructure> maildirMessagePart::getStructure() {
+
+ if (m_structure) {
+ return m_structure;
+ } else {
+ return maildirMessageStructure::emptyStructure();
+ }
+}
+
+
+const mediaType& maildirMessagePart::getType() const {
+
+ return m_mediaType;
+}
+
+
+const contentDisposition &maildirMessagePart::getDisposition() const {
+
+ return m_dispType;
+}
+
+
+size_t maildirMessagePart::getSize() const {
+
+ return m_size;
+}
+
+
+size_t maildirMessagePart::getNumber() const {
+
+ return m_number;
+}
+
+
+shared_ptr <const header> maildirMessagePart::getHeader() const {
+
+ if (!m_header) {
+ throw exceptions::unfetched_object();
+ } else {
+ return m_header;
+ }
+}
+
+
+header& maildirMessagePart::getOrCreateHeader() {
+
+ if (m_header) {
+ return *m_header;
+ } else {
+ return *(m_header = make_shared <header>());
+ }
+}
+
+
+size_t maildirMessagePart::getHeaderParsedOffset() const {
+
+ return m_headerParsedOffset;
+}
+
+
+size_t maildirMessagePart::getHeaderParsedLength() const {
+
+ return m_headerParsedLength;
+}
+
+
+size_t maildirMessagePart::getBodyParsedOffset() const {
+
+ return m_bodyParsedOffset;
+}
+
+
+size_t maildirMessagePart::getBodyParsedLength() const {
+
+ return m_bodyParsedLength;
+}
+
+
+} // maildir
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
diff --git a/vmime-master/src/vmime/net/maildir/maildirMessagePart.hpp b/vmime-master/src/vmime/net/maildir/maildirMessagePart.hpp
new file mode 100644
index 0000000..5ecc739
--- /dev/null
+++ b/vmime-master/src/vmime/net/maildir/maildirMessagePart.hpp
@@ -0,0 +1,106 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_MAILDIR_MAILDIRMESSAGEPART_HPP_INCLUDED
+#define VMIME_NET_MAILDIR_MAILDIRMESSAGEPART_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+
+#include "vmime/net/message.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace maildir {
+
+
+class maildirMessageStructure;
+
+
+class maildirMessagePart : public messagePart
+{
+public:
+
+ maildirMessagePart(
+ const shared_ptr <maildirMessagePart>& parent,
+ const size_t number,
+ const bodyPart& part
+ );
+
+ ~maildirMessagePart();
+
+
+ shared_ptr <const messageStructure> getStructure() const;
+ shared_ptr <messageStructure> getStructure();
+
+ weak_ptr <const maildirMessagePart> getParent() const { return (m_parent); }
+
+ const mediaType& getType() const;
+ const contentDisposition &getDisposition() const;
+ size_t getSize() const;
+ size_t getNumber() const;
+
+ shared_ptr <const header> getHeader() const;
+
+ header& getOrCreateHeader();
+
+ size_t getHeaderParsedOffset() const;
+ size_t getHeaderParsedLength() const;
+
+ size_t getBodyParsedOffset() const;
+ size_t getBodyParsedLength() const;
+
+ void initStructure(const bodyPart& part);
+
+private:
+
+ shared_ptr <maildirMessageStructure> m_structure;
+ weak_ptr <maildirMessagePart> m_parent;
+ shared_ptr <header> m_header;
+
+ size_t m_number;
+ size_t m_size;
+ mediaType m_mediaType;
+ contentDisposition m_dispType;
+
+ size_t m_headerParsedOffset;
+ size_t m_headerParsedLength;
+
+ size_t m_bodyParsedOffset;
+ size_t m_bodyParsedLength;
+};
+
+
+} // maildir
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+#endif // VMIME_NET_MAILDIR_MAILDIRMESSAGEPART_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/maildir/maildirMessageStructure.cpp b/vmime-master/src/vmime/net/maildir/maildirMessageStructure.cpp
new file mode 100644
index 0000000..1e2f2cc
--- /dev/null
+++ b/vmime-master/src/vmime/net/maildir/maildirMessageStructure.cpp
@@ -0,0 +1,104 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+
+#include "vmime/net/maildir/maildirMessageStructure.hpp"
+#include "vmime/net/maildir/maildirMessagePart.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace maildir {
+
+
+shared_ptr <maildirMessageStructure> maildirMessageStructure::m_emptyStructure = make_shared <maildirMessageStructure>();
+
+
+maildirMessageStructure::maildirMessageStructure()
+{
+}
+
+
+maildirMessageStructure::maildirMessageStructure(
+ const shared_ptr <maildirMessagePart>& parent,
+ const bodyPart& part
+) {
+
+ shared_ptr <maildirMessagePart> mpart = make_shared <maildirMessagePart>(parent, 0, part);
+ mpart->initStructure(part);
+
+ m_parts.push_back(mpart);
+}
+
+
+maildirMessageStructure::maildirMessageStructure(
+ const shared_ptr <maildirMessagePart>& parent,
+ const std::vector <shared_ptr <const vmime::bodyPart> >& list
+) {
+
+ for (size_t i = 0 ; i < list.size() ; ++i) {
+
+ shared_ptr <maildirMessagePart> mpart = make_shared <maildirMessagePart>(parent, i, *list[i]);
+ mpart->initStructure(*list[i]);
+
+ m_parts.push_back(mpart);
+ }
+}
+
+
+shared_ptr <const messagePart> maildirMessageStructure::getPartAt(const size_t x) const {
+
+ return m_parts[x];
+}
+
+
+shared_ptr <messagePart> maildirMessageStructure::getPartAt(const size_t x) {
+
+ return m_parts[x];
+}
+
+
+size_t maildirMessageStructure::getPartCount() const {
+
+ return m_parts.size();
+}
+
+
+// static
+shared_ptr <maildirMessageStructure> maildirMessageStructure::emptyStructure() {
+
+ return m_emptyStructure;
+}
+
+
+} // maildir
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
diff --git a/vmime-master/src/vmime/net/maildir/maildirMessageStructure.hpp b/vmime-master/src/vmime/net/maildir/maildirMessageStructure.hpp
new file mode 100644
index 0000000..1a20ea4
--- /dev/null
+++ b/vmime-master/src/vmime/net/maildir/maildirMessageStructure.hpp
@@ -0,0 +1,82 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_MAILDIR_MAILDIRMESSAGESTRUCTURE_HPP_INCLUDED
+#define VMIME_NET_MAILDIR_MAILDIRMESSAGESTRUCTURE_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+
+#include "vmime/net/message.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace maildir {
+
+
+class maildirMessagePart;
+
+
+class maildirMessageStructure : public messageStructure {
+
+public:
+
+ maildirMessageStructure();
+ maildirMessageStructure(
+ const shared_ptr <maildirMessagePart>& parent,
+ const bodyPart& part
+ );
+ maildirMessageStructure(
+ const shared_ptr <maildirMessagePart>& parent,
+ const std::vector <shared_ptr <const vmime::bodyPart> >& list
+ );
+
+
+ shared_ptr <const messagePart> getPartAt(const size_t x) const;
+ shared_ptr <messagePart> getPartAt(const size_t x);
+
+ size_t getPartCount() const;
+
+ static shared_ptr <maildirMessageStructure> emptyStructure();
+
+private:
+
+ static shared_ptr <maildirMessageStructure> m_emptyStructure;
+
+ std::vector <shared_ptr <maildirMessagePart> > m_parts;
+};
+
+
+} // maildir
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+#endif // VMIME_NET_MAILDIR_MAILDIRMESSAGESTRUCTURE_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/maildir/maildirServiceInfos.cpp b/vmime-master/src/vmime/net/maildir/maildirServiceInfos.cpp
new file mode 100644
index 0000000..f9d92d3
--- /dev/null
+++ b/vmime-master/src/vmime/net/maildir/maildirServiceInfos.cpp
@@ -0,0 +1,76 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+
+#include "vmime/net/maildir/maildirServiceInfos.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace maildir {
+
+
+maildirServiceInfos::maildirServiceInfos() {
+
+}
+
+
+const string maildirServiceInfos::getPropertyPrefix() const {
+
+ return "store.maildir.";
+}
+
+
+const maildirServiceInfos::props& maildirServiceInfos::getProperties() const {
+
+ static props maildirProps = {
+ property(serviceInfos::property::SERVER_ROOTPATH, serviceInfos::property::FLAG_REQUIRED)
+ };
+
+ return maildirProps;
+}
+
+
+const std::vector <serviceInfos::property> maildirServiceInfos::getAvailableProperties() const {
+
+ std::vector <property> list;
+ const props& p = getProperties();
+
+ list.push_back(p.PROPERTY_SERVER_ROOTPATH);
+
+ return list;
+}
+
+
+} // maildir
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
diff --git a/vmime-master/src/vmime/net/maildir/maildirServiceInfos.hpp b/vmime-master/src/vmime/net/maildir/maildirServiceInfos.hpp
new file mode 100644
index 0000000..827a7d7
--- /dev/null
+++ b/vmime-master/src/vmime/net/maildir/maildirServiceInfos.hpp
@@ -0,0 +1,69 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_MAILDIR_MAILDIRSERVICEINFOS_HPP_INCLUDED
+#define VMIME_NET_MAILDIR_MAILDIRSERVICEINFOS_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+
+#include "vmime/net/serviceInfos.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace maildir {
+
+
+/** Information about maildir service.
+ */
+class VMIME_EXPORT maildirServiceInfos : public serviceInfos {
+
+public:
+
+ maildirServiceInfos();
+
+ struct props {
+ serviceInfos::property PROPERTY_SERVER_ROOTPATH;
+ };
+
+ const props& getProperties() const;
+
+ const string getPropertyPrefix() const;
+ const std::vector <serviceInfos::property> getAvailableProperties() const;
+};
+
+
+} // maildir
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+#endif // VMIME_NET_MAILDIR_MAILDIRSERVICEINFOS_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/maildir/maildirStore.cpp b/vmime-master/src/vmime/net/maildir/maildirStore.cpp
new file mode 100644
index 0000000..a994f45
--- /dev/null
+++ b/vmime-master/src/vmime/net/maildir/maildirStore.cpp
@@ -0,0 +1,294 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+
+#include "vmime/net/maildir/maildirStore.hpp"
+
+#include "vmime/net/maildir/maildirFolder.hpp"
+#include "vmime/net/maildir/maildirFormat.hpp"
+
+#include "vmime/exception.hpp"
+#include "vmime/platform.hpp"
+
+#include "vmime/net/defaultConnectionInfos.hpp"
+
+
+// Helpers for service properties
+#define GET_PROPERTY(type, prop) \
+ (getInfos().getPropertyValue <type>(getSession(), \
+ dynamic_cast <const maildirServiceInfos&>(getInfos()).getProperties().prop))
+#define HAS_PROPERTY(prop) \
+ (getInfos().hasProperty(getSession(), \
+ dynamic_cast <const maildirServiceInfos&>(getInfos()).getProperties().prop))
+
+
+namespace vmime {
+namespace net {
+namespace maildir {
+
+
+maildirStore::maildirStore(
+ const shared_ptr <session>& sess,
+ const shared_ptr <security::authenticator>& auth
+)
+ : store(sess, getInfosInstance(), auth),
+ m_connected(false) {
+
+}
+
+
+maildirStore::~maildirStore() {
+
+ try {
+
+ if (isConnected()) {
+ disconnect();
+ }
+
+ } catch (...) {
+
+ // Don't throw in destructor
+ }
+}
+
+
+const string maildirStore::getProtocolName() const {
+
+ return "maildir";
+}
+
+
+shared_ptr <folder> maildirStore::getRootFolder() {
+
+ if (!isConnected()) {
+ throw exceptions::illegal_state("Not connected");
+ }
+
+ return shared_ptr <maildirFolder>(
+ new maildirFolder(
+ folder::path(),
+ dynamicCast <maildirStore>(shared_from_this())
+ )
+ );
+}
+
+
+shared_ptr <folder> maildirStore::getDefaultFolder() {
+
+ if (!isConnected()) {
+ throw exceptions::illegal_state("Not connected");
+ }
+
+ return shared_ptr <maildirFolder>(
+ new maildirFolder(
+ folder::path::component("inbox"),
+ dynamicCast <maildirStore>(shared_from_this())
+ )
+ );
+}
+
+
+shared_ptr <folder> maildirStore::getFolder(const folder::path& path) {
+
+ if (!isConnected()) {
+ throw exceptions::illegal_state("Not connected");
+ }
+
+ return shared_ptr <maildirFolder>(
+ new maildirFolder(
+ path,
+ dynamicCast <maildirStore>(shared_from_this())
+ )
+ );
+}
+
+
+bool maildirStore::isValidFolderName(const folder::path::component& name) const {
+
+ if (!platform::getHandler()->getFileSystemFactory()->isValidPathComponent(name)) {
+ return false;
+ }
+
+ const string& buf = name.getBuffer();
+
+ // Name cannot start/end with spaces
+ if (utility::stringUtils::trim(buf) != buf) {
+ return false;
+ }
+
+ // Name cannot start with '.'
+ const size_t length = buf.length();
+ size_t pos = 0;
+
+ while ((pos < length) && (buf[pos] == '.')) {
+ ++pos;
+ }
+
+ return (pos == 0);
+}
+
+
+void maildirStore::connect() {
+
+ if (isConnected()) {
+ throw exceptions::already_connected();
+ }
+
+ // Get root directory
+ shared_ptr <utility::fileSystemFactory> fsf = platform::getHandler()->getFileSystemFactory();
+
+ m_fsPath = fsf->stringToPath(GET_PROPERTY(string, PROPERTY_SERVER_ROOTPATH));
+
+ shared_ptr <utility::file> rootDir = fsf->create(m_fsPath);
+
+ // Try to create the root directory if it does not exist
+ if (!(rootDir->exists() && rootDir->isDirectory())) {
+
+ try {
+ rootDir->createDirectory();
+ } catch (exceptions::filesystem_exception& e) {
+ throw exceptions::connection_error("Cannot create root directory.", e);
+ }
+ }
+
+ m_format = maildirFormat::detect(dynamicCast <maildirStore>(shared_from_this()));
+
+ m_connected = true;
+}
+
+
+bool maildirStore::isConnected() const {
+
+ return m_connected;
+}
+
+
+bool maildirStore::isSecuredConnection() const {
+
+ return false;
+}
+
+
+shared_ptr <connectionInfos> maildirStore::getConnectionInfos() const {
+
+ return make_shared <defaultConnectionInfos>("localhost", static_cast <port_t>(0));
+}
+
+
+void maildirStore::disconnect() {
+
+ for (std::list <maildirFolder*>::iterator it = m_folders.begin() ;
+ it != m_folders.end() ; ++it) {
+
+ (*it)->onStoreDisconnected();
+ }
+
+ m_folders.clear();
+
+ m_connected = false;
+}
+
+
+void maildirStore::noop() {
+
+ // Nothing to do.
+}
+
+
+shared_ptr <maildirFormat> maildirStore::getFormat() {
+
+ return m_format;
+}
+
+
+shared_ptr <const maildirFormat> maildirStore::getFormat() const {
+
+ return m_format;
+}
+
+
+void maildirStore::registerFolder(maildirFolder* folder) {
+
+ m_folders.push_back(folder);
+}
+
+
+void maildirStore::unregisterFolder(maildirFolder* folder) {
+
+ std::list <maildirFolder*>::iterator it = std::find(m_folders.begin(), m_folders.end(), folder);
+
+ if (it != m_folders.end()) {
+ m_folders.erase(it);
+ }
+}
+
+
+const utility::path& maildirStore::getFileSystemPath() const {
+
+ return m_fsPath;
+}
+
+
+int maildirStore::getCapabilities() const {
+
+ return CAPABILITY_CREATE_FOLDER |
+ CAPABILITY_RENAME_FOLDER |
+ CAPABILITY_ADD_MESSAGE |
+ CAPABILITY_COPY_MESSAGE |
+ CAPABILITY_DELETE_MESSAGE |
+ CAPABILITY_PARTIAL_FETCH |
+ CAPABILITY_MESSAGE_FLAGS |
+ CAPABILITY_EXTRACT_PART;
+}
+
+
+
+// Service infos
+
+maildirServiceInfos maildirStore::sm_infos;
+
+
+const serviceInfos& maildirStore::getInfosInstance() {
+
+ return sm_infos;
+}
+
+
+const serviceInfos& maildirStore::getInfos() const {
+
+ return sm_infos;
+}
+
+
+} // maildir
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
diff --git a/vmime-master/src/vmime/net/maildir/maildirStore.hpp b/vmime-master/src/vmime/net/maildir/maildirStore.hpp
new file mode 100644
index 0000000..13255c0
--- /dev/null
+++ b/vmime-master/src/vmime/net/maildir/maildirStore.hpp
@@ -0,0 +1,123 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_MAILDIR_MAILDIRSTORE_HPP_INCLUDED
+#define VMIME_NET_MAILDIR_MAILDIRSTORE_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+
+#include "vmime/net/store.hpp"
+#include "vmime/net/socket.hpp"
+#include "vmime/net/folder.hpp"
+
+#include "vmime/net/maildir/maildirFormat.hpp"
+#include "vmime/net/maildir/maildirServiceInfos.hpp"
+
+#include "vmime/utility/file.hpp"
+
+#include <ostream>
+
+
+namespace vmime {
+namespace net {
+namespace maildir {
+
+
+class maildirFolder;
+
+
+/** maildir store service.
+ */
+class VMIME_EXPORT maildirStore : public store {
+
+ friend class maildirFolder;
+
+public:
+
+ maildirStore(
+ const shared_ptr <session>& sess,
+ const shared_ptr <security::authenticator>& auth
+ );
+
+ ~maildirStore();
+
+ const string getProtocolName() const;
+
+ shared_ptr <folder> getDefaultFolder();
+ shared_ptr <folder> getRootFolder();
+ shared_ptr <folder> getFolder(const folder::path& path);
+
+ bool isValidFolderName(const folder::path::component& name) const;
+
+ static const serviceInfos& getInfosInstance();
+ const serviceInfos& getInfos() const;
+
+ void connect();
+ bool isConnected() const;
+ void disconnect();
+
+ void noop();
+
+ const utility::path& getFileSystemPath() const;
+
+ int getCapabilities() const;
+
+ bool isSecuredConnection() const;
+ shared_ptr <connectionInfos> getConnectionInfos() const;
+
+ shared_ptr <maildirFormat> getFormat();
+ shared_ptr <const maildirFormat> getFormat() const;
+
+private:
+
+ void registerFolder(maildirFolder* folder);
+ void unregisterFolder(maildirFolder* folder);
+
+
+ std::list <maildirFolder*> m_folders;
+
+ shared_ptr <maildirFormat> m_format;
+
+ bool m_connected;
+
+ utility::path m_fsPath;
+
+
+ // Service infos
+ static maildirServiceInfos sm_infos;
+};
+
+
+} // maildir
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+#endif // VMIME_NET_MAILDIR_MAILDIRSTORE_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/maildir/maildirUtils.cpp b/vmime-master/src/vmime/net/maildir/maildirUtils.cpp
new file mode 100644
index 0000000..9942e56
--- /dev/null
+++ b/vmime-master/src/vmime/net/maildir/maildirUtils.cpp
@@ -0,0 +1,288 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+
+#include "vmime/net/maildir/maildirUtils.hpp"
+#include "vmime/net/maildir/maildirStore.hpp"
+
+#include "vmime/utility/random.hpp"
+#include "vmime/platform.hpp"
+
+#include "vmime/exception.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace maildir {
+
+
+bool maildirUtils::isMessageFile(const utility::file& file) {
+
+ // Ignore files which name begins with '.'
+ if (file.isFile() &&
+ file.getFullPath().getLastComponent().getBuffer().length() >= 1 &&
+ file.getFullPath().getLastComponent().getBuffer()[0] != '.') {
+
+ return true;
+ }
+
+ return false;
+}
+
+
+// NOTE ABOUT ID/FLAGS SEPARATOR
+// -----------------------------
+// In the maildir specification, the character ':' is used to separate
+// the unique identifier and the message flags.
+//
+// On Windows (and particularly FAT file systems), ':' is not allowed
+// in a filename, so we use a dash ('-') instead. This is the solution
+// used by Mutt/Win32, so we also use it here.
+//
+// To be compatible between implementations, we check for both
+// characters when reading file names.
+
+
+const utility::file::path::component maildirUtils::extractId(
+ const utility::file::path::component& filename
+) {
+
+ size_t sep = filename.getBuffer().rfind(':'); // try colon
+
+ if (sep == string::npos) {
+ sep = filename.getBuffer().rfind('-'); // try dash (Windows)
+ if (sep == string::npos) return (filename);
+ }
+
+ return utility::path::component(
+ string(filename.getBuffer().begin(), filename.getBuffer().begin() + sep)
+ );
+}
+
+
+int maildirUtils::extractFlags(const utility::file::path::component& comp) {
+
+ size_t sep = comp.getBuffer().rfind(':'); // try colon
+
+ if (sep == string::npos) {
+ sep = comp.getBuffer().rfind('-'); // try dash (Windows)
+ if (sep == string::npos) return 0;
+ }
+
+ const string flagsString(comp.getBuffer().begin() + sep + 1, comp.getBuffer().end());
+ const size_t count = flagsString.length();
+
+ int flags = 0;
+
+ for (size_t i = 0 ; i < count ; ++i) {
+
+ switch (flagsString[i]) {
+ case 'R': case 'r': flags |= message::FLAG_REPLIED; break;
+ case 'S': case 's': flags |= message::FLAG_SEEN; break;
+ case 'T': case 't': flags |= message::FLAG_DELETED; break;
+ case 'F': case 'f': flags |= message::FLAG_MARKED; break;
+ case 'P': case 'p': flags |= message::FLAG_PASSED; break;
+ case 'D': case 'd': flags |= message::FLAG_DRAFT; break;
+ }
+ }
+
+ return flags;
+}
+
+
+const utility::file::path::component maildirUtils::buildFlags(const int flags) {
+
+ string str;
+ str.reserve(8);
+
+ str += "2,";
+
+ if (flags & message::FLAG_MARKED) str += "F";
+ if (flags & message::FLAG_PASSED) str += "P";
+ if (flags & message::FLAG_REPLIED) str += "R";
+ if (flags & message::FLAG_SEEN) str += "S";
+ if (flags & message::FLAG_DELETED) str += "T";
+ if (flags & message::FLAG_DRAFT) str += "D";
+
+ return utility::file::path::component(str);
+}
+
+
+const utility::file::path::component maildirUtils::buildFilename(
+ const utility::file::path::component& id,
+ const int flags
+) {
+
+ if (flags == message::FLAG_RECENT) {
+ return id;
+ } else {
+ return buildFilename(id, buildFlags(flags));
+ }
+}
+
+
+const utility::file::path::component maildirUtils::buildFilename(
+ const utility::file::path::component& id,
+ const utility::file::path::component& flags
+) {
+
+#if VMIME_PLATFORM_IS_WINDOWS
+ static const char DELIMITER[] = "-";
+#else
+ static const char DELIMITER[] = ":";
+#endif
+
+ return utility::path::component(id.getBuffer() + DELIMITER + flags.getBuffer());
+}
+
+
+const utility::file::path::component maildirUtils::generateId() {
+
+ std::ostringstream oss;
+ oss.imbue(std::locale::classic());
+
+ oss << utility::random::getTime();
+ oss << ".";
+ oss << utility::random::getProcess();
+ oss << ".";
+ oss << utility::random::getString(6);
+ oss << ".";
+ oss << platform::getHandler()->getHostName();
+
+ return utility::file::path::component(oss.str());
+}
+
+
+void maildirUtils::recursiveFSDelete(const shared_ptr <utility::file>& dir) {
+
+ shared_ptr <utility::fileIterator> files = dir->getFiles();
+
+ // First, delete files and subdirectories in this directory
+ while (files->hasMoreElements()) {
+
+ shared_ptr <utility::file> file = files->nextElement();
+
+ if (file->isDirectory()) {
+
+ maildirUtils::recursiveFSDelete(file);
+
+ } else {
+
+ try {
+ file->remove();
+ } catch (exceptions::filesystem_exception&) {
+ // Ignore
+ }
+ }
+ }
+
+ // Then, delete this (empty) directory
+ try {
+ dir->remove();
+ } catch (exceptions::filesystem_exception&) {
+ // Ignore
+ }
+}
+
+
+
+class maildirMessageSetEnumerator : public messageSetEnumerator {
+
+public:
+
+ maildirMessageSetEnumerator(const size_t msgCount)
+ : m_msgCount(msgCount) {
+
+ }
+
+ void enumerateNumberMessageRange(const vmime::net::numberMessageRange& range) {
+
+ size_t last = range.getLast();
+ if (last == size_t(-1)) last = m_msgCount;
+
+ for (size_t i = range.getFirst() ; i <= last ; ++i) {
+ list.push_back(i);
+ }
+ }
+
+ void enumerateUIDMessageRange(const vmime::net::UIDMessageRange& /* range */) {
+
+ // Not supported
+ }
+
+public:
+
+ std::vector <size_t> list;
+
+private:
+
+ size_t m_msgCount;
+};
+
+
+// static
+const std::vector <size_t> maildirUtils::messageSetToNumberList(
+ const messageSet& msgs,
+ const size_t msgCount
+) {
+
+ maildirMessageSetEnumerator en(msgCount);
+ msgs.enumerate(en);
+
+ return en.list;
+}
+
+
+
+//
+// messageIdComparator
+//
+
+maildirUtils::messageIdComparator::messageIdComparator(
+ const utility::file::path::component& comp
+)
+ : m_comp(maildirUtils::extractId(comp)) {
+
+}
+
+
+bool maildirUtils::messageIdComparator::operator()(
+ const utility::file::path::component& other
+) const {
+
+ return m_comp == maildirUtils::extractId(other);
+}
+
+
+} // maildir
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
diff --git a/vmime-master/src/vmime/net/maildir/maildirUtils.hpp b/vmime-master/src/vmime/net/maildir/maildirUtils.hpp
new file mode 100644
index 0000000..94ab998
--- /dev/null
+++ b/vmime-master/src/vmime/net/maildir/maildirUtils.hpp
@@ -0,0 +1,160 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_MAILDIR_MAILDIRUTILS_HPP_INCLUDED
+#define VMIME_NET_MAILDIR_MAILDIRUTILS_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+
+#include "vmime/utility/file.hpp"
+#include "vmime/utility/path.hpp"
+
+#include "vmime/net/messageSet.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace maildir {
+
+
+class maildirStore;
+
+
+/** Miscellaneous helpers functions for maildir messaging system.
+ */
+class VMIME_EXPORT maildirUtils {
+
+public:
+
+ /** Comparator for message filenames, based only on the
+ * unique identifier part of the filename.
+ */
+ class messageIdComparator {
+
+ public:
+
+ messageIdComparator(const utility::file::path::component& comp);
+
+ bool operator()(const utility::file::path::component& other) const;
+
+ private:
+
+ const utility::file::path::component m_comp;
+ };
+
+ /** Test whether the specified file-system object is a message.
+ *
+ * @param file reference to a file-system object
+ * @return true if the specified object is a message file,
+ * false otherwise
+ */
+ static bool isMessageFile(const utility::file& file);
+
+ /** Extract the unique identifier part of the message filename.
+ * Eg: for the filename "1071577232.28549.m03s:2,RS", it will
+ * return "1071577232.28549.m03s".
+ *
+ * @param filename filename part
+ * @return part of the filename that corresponds to the unique
+ * identifier of the message
+ */
+ static const utility::file::path::component extractId(const utility::file::path::component& filename);
+
+ /** Extract message flags from the specified message filename.
+ * Eg: for the filename "1071577232.28549.m03s:2,RS", it will
+ * return (message::FLAG_SEEN | message::FLAG_REPLIED).
+ *
+ * @param comp filename part
+ * @return message flags extracted from the specified filename
+ */
+ static int extractFlags(const utility::file::path::component& comp);
+
+ /** Return a string representing the specified message flags.
+ * Eg: for (message::FLAG_SEEN | message::FLAG_REPLIED), it will
+ * return "RS".
+ *
+ * @param flags set of flags
+ * @return message flags in a string representation
+ */
+ static const utility::file::path::component buildFlags(const int flags);
+
+ /** Build a filename with the specified id and flags.
+ *
+ * @param id id part of the filename
+ * @param flags flags part of the filename
+ * @return message filename
+ */
+ static const utility::file::path::component buildFilename(
+ const utility::file::path::component& id,
+ const utility::file::path::component& flags
+ );
+
+ /** Build a filename with the specified id and flags.
+ *
+ * @param id id part of the filename
+ * @param flags set of flags
+ * @return message filename
+ */
+ static const utility::file::path::component buildFilename(
+ const utility::file::path::component& id,
+ const int flags
+ );
+
+ /** Generate a new unique message identifier.
+ *
+ * @return unique message id
+ */
+ static const utility::file::path::component generateId();
+
+ /** Recursively delete a directory on the file system.
+ *
+ * @param dir directory to delete
+ */
+ static void recursiveFSDelete(const shared_ptr <utility::file>& dir);
+
+ /** Returns a list of message numbers given a message set.
+ *
+ * @param msgs message set
+ * @param msgCount number of messages in folder
+ * @return list of message numbers
+ */
+ static const std::vector <size_t> messageSetToNumberList(
+ const messageSet& msgs,
+ const size_t msgCount
+ );
+};
+
+
+} // maildir
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_MAILDIR
+
+#endif // VMIME_NET_MAILDIR_MAILDIRUTILS_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/message.cpp b/vmime-master/src/vmime/net/message.cpp
new file mode 100644
index 0000000..2d6f995
--- /dev/null
+++ b/vmime-master/src/vmime/net/message.cpp
@@ -0,0 +1,155 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/net/message.hpp"
+
+#include <sstream>
+
+
+namespace vmime {
+namespace net {
+
+
+string messagePart::getName() const
+{
+ return {};
+}
+
+shared_ptr <const messagePart> messagePart::getPartAt(const size_t pos) const {
+
+ return getStructure()->getPartAt(pos);
+}
+
+
+shared_ptr <messagePart> messagePart::getPartAt(const size_t pos) {
+
+ return getStructure()->getPartAt(pos);
+}
+
+
+size_t messagePart::getPartCount() const {
+
+ return getStructure()->getPartCount();
+}
+
+
+
+// message::uid
+
+
+message::uid::uid() {
+
+}
+
+
+message::uid::uid(const string& uid)
+ : m_str(uid) {
+
+}
+
+
+message::uid::uid(const unsigned long uid) {
+
+ std::ostringstream oss;
+ oss.imbue(std::locale::classic());
+ oss << uid;
+
+ m_str = oss.str();
+}
+
+
+message::uid::uid(const char* uid)
+ : m_str(uid) {
+
+}
+
+
+message::uid::uid(const uid& other) {
+
+ m_str = other.m_str;
+}
+
+
+message::uid& message::uid::operator=(const uid& other) {
+
+ m_str = other.m_str;
+ return *this;
+}
+
+
+message::uid& message::uid::operator=(const string& uid) {
+
+ m_str = uid;
+ return *this;
+}
+
+
+message::uid& message::uid::operator=(const unsigned long uid) {
+
+ std::ostringstream oss;
+ oss.imbue(std::locale::classic());
+ oss << uid;
+
+ m_str = oss.str();
+
+ return *this;
+}
+
+
+message::uid::operator string() const {
+
+ return m_str;
+}
+
+
+bool message::uid::empty() const {
+
+ return m_str.empty();
+}
+
+
+bool message::uid::operator==(const uid& other) const {
+
+ return m_str == other.m_str;
+}
+
+
+std::ostream& operator<<(std::ostream& os, const message::uid& uid) {
+
+ os << static_cast <string>(uid);
+ return os;
+}
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
diff --git a/vmime-master/src/vmime/net/message.hpp b/vmime-master/src/vmime/net/message.hpp
new file mode 100644
index 0000000..8679879
--- /dev/null
+++ b/vmime-master/src/vmime/net/message.hpp
@@ -0,0 +1,369 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_MESSAGE_HPP_INCLUDED
+#define VMIME_NET_MESSAGE_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/header.hpp"
+#include "vmime/mediaType.hpp"
+#include "vmime/contentDisposition.hpp"
+
+#include "vmime/utility/progressListener.hpp"
+#include "vmime/utility/stream.hpp"
+
+#include "vmime/message.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+class messageStructure;
+
+
+/** A MIME part in a message.
+ */
+class VMIME_EXPORT messagePart : public object, public enable_shared_from_this <messagePart> {
+
+protected:
+
+ messagePart() { }
+ messagePart(const messagePart&);
+
+ virtual ~messagePart() { }
+
+public:
+
+ /** Return the structure of this part.
+ *
+ * @return structure of the part
+ */
+ virtual shared_ptr <const messageStructure> getStructure() const = 0;
+
+ /** Return the structure of this part.
+ *
+ * @return structure of the part
+ */
+ virtual shared_ptr <messageStructure> getStructure() = 0;
+
+ /** Return the header section for this part (you must fetch header
+ * before using this function: see message::fetchPartHeader).
+ *
+ * @return header section
+ */
+ virtual shared_ptr <const header> getHeader() const = 0;
+
+ /** Return the media-type of the content in this part.
+ *
+ * @return content media type
+ */
+ virtual const mediaType& getType() const = 0;
+
+ /** Return the disposition type of the content in this part.
+ *
+ * @return content disposition type
+ */
+ virtual const contentDisposition &getDisposition() const = 0;
+
+ /** Return the size of this part.
+ *
+ * @return size of the part (in bytes)
+ */
+ virtual size_t getSize() const = 0;
+
+ /** Return the part sequence number (index).
+ * The first part is at index zero.
+ *
+ * @return part number
+ */
+ virtual size_t getNumber() const = 0;
+
+ /** Return the name of this part. In particular, this corresponds to
+ * the attachment file name for attachment parts.
+ *
+ * The part name may be empty if the part does not advertise it or
+ * if the underlying protocol does not support it.
+ *
+ * @return part name
+ */
+ virtual string getName() const;
+
+ /** Return the sub-part at the specified position (zero is the
+ * first part).
+ *
+ * @param pos index of the sub-part
+ * @return sub-part at position 'pos'
+ */
+ shared_ptr <const messagePart> getPartAt(const size_t pos) const;
+
+ /** Return the sub-part at the specified position (zero is the
+ * first part).
+ *
+ * @param pos index of the sub-part
+ * @return sub-part at position 'pos'
+ */
+ shared_ptr <messagePart> getPartAt(const size_t pos);
+
+ /** Return the number of sub-parts in this part.
+ *
+ * @return number of sub-parts
+ */
+ size_t getPartCount() const;
+};
+
+
+/** Structure of a MIME part/message.
+ */
+class VMIME_EXPORT messageStructure : public object, public enable_shared_from_this <messageStructure> {
+
+protected:
+
+ messageStructure() { }
+ messageStructure(const messageStructure&);
+
+public:
+
+ virtual ~messageStructure() { }
+
+ /** Return the part at the specified position (first
+ * part is at position 0).
+ *
+ * @param pos position
+ * @return part at position 'pos'
+ */
+ virtual shared_ptr <const messagePart> getPartAt(const size_t pos) const = 0;
+
+ /** Return the part at the specified position (first
+ * part is at position 0).
+ *
+ * @param pos position
+ * @return part at position 'pos'
+ */
+ virtual shared_ptr <messagePart> getPartAt(const size_t pos) = 0;
+
+ /** Return the number of parts in this part.
+ *
+ * @return number of parts
+ */
+ virtual size_t getPartCount() const = 0;
+};
+
+
+/** Abstract representation of a message in a store/transport service.
+ */
+class VMIME_EXPORT message : public object, public enable_shared_from_this <message> {
+
+protected:
+
+ message() { }
+ message(const message&);
+
+ enum PrivateConstants {
+ FLAG_UNDEFINED = 9999 /**< Used internally to indicate flags have not
+ been initialized yet. */
+ };
+
+public:
+
+ /** The type for an unique message identifier.
+ */
+ class VMIME_EXPORT uid {
+
+ public:
+
+ uid();
+ uid(const string& uid);
+ uid(const unsigned long uid);
+ uid(const char* uid);
+ uid(const uid& other);
+
+ uid& operator=(const uid& other);
+ uid& operator=(const string& uid);
+ uid& operator=(const unsigned long uid);
+
+ operator string() const;
+
+ bool empty() const;
+
+ bool operator==(const uid& other) const;
+
+ private:
+
+ string m_str;
+ };
+
+ /** Return the MIME structure of the message (must fetch before).
+ *
+ * @return MIME structure of the message
+ */
+ virtual shared_ptr <const messageStructure> getStructure() const = 0;
+
+ /** Return the MIME structure of the message (must fetch before).
+ *
+ * @return MIME structure of the message
+ */
+ virtual shared_ptr <messageStructure> getStructure() = 0;
+
+ /** Return a reference to the header fields of the message (must fetch before).
+ *
+ * @return header section of the message
+ */
+ virtual shared_ptr <const header> getHeader() const = 0;
+
+ /** Return the sequence number of this message. This number is
+ * used to reference the message in the folder.
+ *
+ * @return sequence number of the message
+ */
+ virtual size_t getNumber() const = 0;
+
+ /** Return the unique identifier (UID) of this message in its
+ * folder (must fetch before).
+ *
+ * @return UID of the message
+ */
+ virtual const uid getUID() const = 0;
+
+ /** Return the size of the message (must fetch before).
+ *
+ * @return size of the message (in bytes)
+ */
+ virtual size_t getSize() const = 0;
+
+ /** Check whether this message has been expunged (ie: definitively
+ * deleted) and does not exist in the folder anymore.
+ *
+ * @return true if the message is expunged, false otherwise
+ */
+ virtual bool isExpunged() const = 0;
+
+ /** Possible flags for a message.
+ */
+ enum Flags {
+ FLAG_SEEN = (1 << 0), /**< Message has been seen. */
+ FLAG_RECENT = (1 << 1), /**< Message has been recently received. */
+ FLAG_DELETED = (1 << 2), /**< Message is marked for deletion. */
+ FLAG_REPLIED = (1 << 3), /**< User replied to this message. */
+ FLAG_MARKED = (1 << 4), /**< Used-defined flag. */
+ FLAG_PASSED = (1 << 5), /**< Message has been resent/forwarded/bounced. */
+ FLAG_DRAFT = (1 << 6) /**< Message is marked as a 'draft'. */
+ };
+
+ /** Methods for setting the flags.
+ */
+ enum FlagsModes {
+ FLAG_MODE_SET, /**< Set (replace) the flags. */
+ FLAG_MODE_ADD, /**< Add the flags. */
+ FLAG_MODE_REMOVE /**< Remove the flags. */
+ };
+
+ /** Return the flags of this message.
+ *
+ * @return flags of the message
+ */
+ virtual int getFlags() const = 0;
+
+ /** Set the flags of this message.
+ *
+ * @param flags set of flags (see Flags)
+ * @param mode indicate how to treat old and new flags (see FlagsModes)
+ */
+ virtual void setFlags(const int flags, const int mode = FLAG_MODE_SET) = 0;
+
+ /** Extract the whole message data (header + contents).
+ *
+ * \warning Partial fetch might not be supported by the underlying protocol.
+ *
+ * @param os output stream in which to write message data
+ * @param progress progress listener, or NULL if not used
+ * @param start index of the first byte to retrieve (used for partial fetch)
+ * @param length number of bytes to retrieve (used for partial fetch)
+ * @param peek if true, try not to mark the message as read. This may not
+ * be supported by the protocol (IMAP supports this), but it will NOT throw
+ * an exception if not supported.
+ */
+ virtual void extract(
+ utility::outputStream& os,
+ utility::progressListener* progress = NULL,
+ const size_t start = 0,
+ const size_t length = -1,
+ const bool peek = false
+ ) const = 0;
+
+ /** Extract the specified MIME part of the message (header + contents).
+ *
+ * \warning Partial fetch might not be supported by the underlying protocol.
+ *
+ * @param p part to extract
+ * @param os output stream in which to write part data
+ * @param progress progress listener, or NULL if not used
+ * @param start index of the first byte to retrieve (used for partial fetch)
+ * @param length number of bytes to retrieve (used for partial fetch)
+ * @param peek if true, try not to mark the message as read. This may not
+ * be supported by the protocol (IMAP supports this), but it will NOT throw
+ * an exception if not supported.
+ */
+ virtual void extractPart(
+ const shared_ptr <const messagePart>& p,
+ utility::outputStream& os,
+ utility::progressListener* progress = NULL,
+ const size_t start = 0,
+ const size_t length = -1,
+ const bool peek = false
+ ) const = 0;
+
+ /** Fetch the MIME header for the specified part.
+ *
+ * @param p the part for which to fetch the header
+ */
+ virtual void fetchPartHeader(const shared_ptr <messagePart>& p) = 0;
+
+ /** Get the RFC-822 message for this abstract message.
+ * Warning: This may require getting some data (ie: structure and headers) from
+ * the server, which is done automatically. Actual message contents (ie: body)
+ * will not be fetched if possible (IMAP allows it, whereas POP3 will require
+ * to fetch the whole message).
+ *
+ * @return a RFC-822-parsed message
+ */
+ virtual shared_ptr <vmime::message> getParsedMessage() = 0;
+};
+
+
+VMIME_EXPORT std::ostream& operator<<(std::ostream& os, const message::uid& uid);
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+#endif // VMIME_NET_MESSAGE_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/messageSet.cpp b/vmime-master/src/vmime/net/messageSet.cpp
new file mode 100644
index 0000000..fe2d645
--- /dev/null
+++ b/vmime-master/src/vmime/net/messageSet.cpp
@@ -0,0 +1,430 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/net/messageSet.hpp"
+
+#include <iterator>
+#include <algorithm>
+#include <typeinfo>
+
+
+namespace vmime {
+namespace net {
+
+// messageSetEnumerator
+
+messageSetEnumerator::~messageSetEnumerator()
+{
+}
+
+// messageRange
+
+messageRange::messageRange() {
+
+}
+
+
+messageRange::~messageRange() {
+
+}
+
+
+// numberMessageRange
+
+numberMessageRange::numberMessageRange(const size_t number)
+ : m_first(number),
+ m_last(number) {
+
+ if (number < 1) {
+ throw std::invalid_argument("number");
+ }
+}
+
+
+numberMessageRange::numberMessageRange(const size_t first, const size_t last)
+ : m_first(first),
+ m_last(last) {
+
+ if (first < 1 || first == static_cast <size_t>(-1)) {
+ throw std::invalid_argument("first");
+ } else if (last != static_cast <size_t>(-1) && last < first) {
+ throw std::invalid_argument("last");
+ }
+}
+
+
+numberMessageRange::numberMessageRange(const numberMessageRange& other)
+ : messageRange(),
+ m_first(other.m_first),
+ m_last(other.m_last) {
+
+}
+
+
+size_t numberMessageRange::getFirst() const {
+
+ return m_first;
+}
+
+
+size_t numberMessageRange::getLast() const {
+
+ return m_last;
+}
+
+
+void numberMessageRange::enumerate(messageSetEnumerator& en) const {
+
+ en.enumerateNumberMessageRange(*this);
+}
+
+
+messageRange* numberMessageRange::clone() const {
+
+ return new numberMessageRange(*this);
+}
+
+
+// UIDMessageRange
+
+UIDMessageRange::UIDMessageRange(const message::uid& uid)
+ : m_first(uid),
+ m_last(uid) {
+
+}
+
+
+UIDMessageRange::UIDMessageRange(const message::uid& first, const message::uid& last)
+ : m_first(first),
+ m_last(last) {
+
+}
+
+
+UIDMessageRange::UIDMessageRange(const UIDMessageRange& other)
+ : messageRange(),
+ m_first(other.m_first),
+ m_last(other.m_last) {
+
+}
+
+
+const message::uid UIDMessageRange::getFirst() const {
+
+ return m_first;
+}
+
+
+const message::uid UIDMessageRange::getLast() const {
+
+ return m_last;
+}
+
+
+void UIDMessageRange::enumerate(messageSetEnumerator& en) const {
+
+ en.enumerateUIDMessageRange(*this);
+}
+
+
+messageRange* UIDMessageRange::clone() const {
+
+ return new UIDMessageRange(*this);
+}
+
+
+// messageSet
+
+
+messageSet::messageSet() {
+
+}
+
+
+messageSet::messageSet(const messageSet& other)
+ : object() {
+
+ m_ranges.resize(other.m_ranges.size());
+
+ for (size_t i = 0, n = other.m_ranges.size() ; i < n ; ++i) {
+ m_ranges[i] = other.m_ranges[i]->clone();
+ }
+}
+
+
+messageSet::~messageSet() {
+
+ for (size_t i = 0, n = m_ranges.size() ; i < n ; ++i) {
+ delete m_ranges[i];
+ }
+}
+
+
+// static
+messageSet messageSet::empty() {
+
+ return messageSet();
+}
+
+
+// static
+messageSet messageSet::byNumber(const size_t number) {
+
+ messageSet set;
+ set.m_ranges.push_back(new numberMessageRange(number));
+
+ return set;
+}
+
+
+// static
+messageSet messageSet::byNumber(const size_t first, const size_t last) {
+
+ messageSet set;
+ set.m_ranges.push_back(new numberMessageRange(first, last));
+
+ return set;
+}
+
+
+// static
+messageSet messageSet::byNumber(const std::vector <size_t>& numbers) {
+
+ // Sort a copy of the list
+ std::vector <size_t> sortedNumbers;
+
+ sortedNumbers.resize(numbers.size());
+
+ std::copy(numbers.begin(), numbers.end(), sortedNumbers.begin());
+ std::sort(sortedNumbers.begin(), sortedNumbers.end());
+
+ // Build the set by detecting ranges of continuous numbers
+ size_t previous = static_cast <size_t>(-1), rangeStart = static_cast <size_t>(-1);
+ messageSet set;
+
+ for (std::vector <size_t>::const_iterator it = sortedNumbers.begin() ;
+ it != sortedNumbers.end() ; ++it) {
+
+ const size_t current = *it;
+
+ if (current == previous) {
+ continue; // skip duplicates
+ }
+
+ if (current == static_cast <size_t>(-1)) {
+ throw std::invalid_argument("numbers");
+ }
+
+ if (previous == static_cast <size_t>(-1)) {
+
+ previous = current;
+ rangeStart = current;
+
+ } else {
+
+ if (current == previous + 1) {
+
+ previous = current;
+
+ } else {
+
+ set.m_ranges.push_back(new numberMessageRange(rangeStart, previous));
+
+ previous = current;
+ rangeStart = current;
+ }
+ }
+ }
+
+ set.m_ranges.push_back(new numberMessageRange(rangeStart, previous));
+
+ return set;
+}
+
+
+// static
+messageSet messageSet::byUID(const message::uid& uid) {
+
+ messageSet set;
+ set.m_ranges.push_back(new UIDMessageRange(uid));
+
+ return set;
+}
+
+
+messageSet messageSet::byUID(const message::uid& first, const message::uid& last) {
+
+ messageSet set;
+ set.m_ranges.push_back(new UIDMessageRange(first, last));
+
+ return set;
+}
+
+
+messageSet messageSet::byUID(const std::vector <message::uid>& uids) {
+
+ std::vector <vmime_uint32> numericUIDs;
+
+ for (size_t i = 0, n = uids.size() ; i < n ; ++i) {
+
+ const string uid = uids[i];
+ int numericUID = 0;
+
+ const char* p = uid.c_str();
+
+ for ( ; *p >= '0' && *p <= '9' ; ++p) {
+ numericUID = (numericUID * 10) + (*p - '0');
+ }
+
+ if (*p != '\0') {
+
+ messageSet set;
+
+ // Non-numeric UID, fall back to plain UID list (single-UID ranges)
+ for (size_t i = 0, n = uids.size() ; i < n ; ++i) {
+ set.m_ranges.push_back(new UIDMessageRange(uids[i]));
+ }
+
+ return set;
+ }
+
+ numericUIDs.push_back(numericUID);
+ }
+
+ // Sort a copy of the list
+ std::vector <vmime_uint32> sortedUIDs;
+
+ sortedUIDs.resize(numericUIDs.size());
+
+ std::copy(numericUIDs.begin(), numericUIDs.end(), sortedUIDs.begin());
+ std::sort(sortedUIDs.begin(), sortedUIDs.end());
+
+ // Build the set by detecting ranges of continuous numbers
+ vmime_uint32 previous = static_cast <vmime_uint32>(-1), rangeStart = static_cast <vmime_uint32>(-1);
+ messageSet set;
+
+ for (std::vector <vmime_uint32>::const_iterator it = sortedUIDs.begin() ;
+ it != sortedUIDs.end() ; ++it) {
+
+ const vmime_uint32 current = *it;
+
+ if (current == previous) {
+ continue; // skip duplicates
+ }
+
+ if (previous == static_cast <vmime_uint32>(-1)) {
+
+ previous = current;
+ rangeStart = current;
+
+ } else {
+
+ if (current == previous + 1) {
+
+ previous = current;
+
+ } else {
+
+ set.m_ranges.push_back(
+ new UIDMessageRange(
+ utility::stringUtils::toString(rangeStart),
+ utility::stringUtils::toString(previous)
+ )
+ );
+
+ previous = current;
+ rangeStart = current;
+ }
+ }
+ }
+
+ set.m_ranges.push_back(
+ new UIDMessageRange(
+ utility::stringUtils::toString(rangeStart),
+ utility::stringUtils::toString(previous)
+ )
+ );
+
+ return set;
+}
+
+
+void messageSet::addRange(const messageRange& range) {
+
+ if (!m_ranges.empty() && typeid(*m_ranges[0]) != typeid(range)) {
+ throw std::invalid_argument("range");
+ }
+
+ m_ranges.push_back(range.clone());
+}
+
+
+void messageSet::enumerate(messageSetEnumerator& en) const {
+
+ for (size_t i = 0, n = m_ranges.size() ; i < n ; ++i) {
+ m_ranges[i]->enumerate(en);
+ }
+}
+
+
+bool messageSet::isEmpty() const {
+
+ return m_ranges.empty();
+}
+
+
+bool messageSet::isNumberSet() const {
+
+ return !isEmpty() && dynamic_cast <numberMessageRange*>(m_ranges[0]) != NULL;
+}
+
+
+bool messageSet::isUIDSet() const {
+
+ return !isEmpty() && dynamic_cast <UIDMessageRange*>(m_ranges[0]) != NULL;
+}
+
+
+size_t messageSet::getRangeCount() const {
+
+ return m_ranges.size();
+}
+
+
+const messageRange& messageSet::getRangeAt(const size_t i) const {
+
+ return *m_ranges[i];
+}
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
diff --git a/vmime-master/src/vmime/net/messageSet.hpp b/vmime-master/src/vmime/net/messageSet.hpp
new file mode 100644
index 0000000..848c4c9
--- /dev/null
+++ b/vmime-master/src/vmime/net/messageSet.hpp
@@ -0,0 +1,358 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_MESSAGESET_HPP_INCLUDED
+#define VMIME_NET_MESSAGESET_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/net/message.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+// Forward references
+class numberMessageRange;
+class UIDMessageRange;
+
+
+/** Enumerator used to retrieve the message number/UID ranges contained
+ * in a messageSet object.
+ */
+class VMIME_EXPORT messageSetEnumerator {
+
+public:
+ virtual ~messageSetEnumerator();
+ virtual void enumerateNumberMessageRange(const numberMessageRange& range) = 0;
+ virtual void enumerateUIDMessageRange(const UIDMessageRange& range) = 0;
+};
+
+
+/** A range of (continuous) messages, designated either by their
+ * sequence number, or by their UID.
+ */
+class VMIME_EXPORT messageRange : public object {
+
+public:
+
+ virtual ~messageRange();
+
+ /** Enumerates this range with the specified enumerator.
+ *
+ * @param en enumerator that will receive the method calls while
+ * enumerating this range
+ */
+ virtual void enumerate(messageSetEnumerator& en) const = 0;
+
+ /** Clones this message range.
+ */
+ virtual messageRange* clone() const = 0;
+
+protected:
+
+ messageRange();
+ messageRange(const messageRange&);
+};
+
+
+/** A range of (continuous) messages designated by their sequence number.
+ */
+class VMIME_EXPORT numberMessageRange : public messageRange {
+
+public:
+
+ /** Constructs a message range containing a single message.
+ *
+ * @param number message number (numbering starts at 1, not 0)
+ */
+ numberMessageRange(const size_t number);
+
+ /** Constructs a message range for multiple messages.
+ *
+ * @param first number of the first message in the range (numbering
+ * starts at 1, not 0)
+ * @param last number of the last message in the range, or use the
+ * special value -1 to designate the last message in the folder
+ */
+ numberMessageRange(const size_t first, const size_t last);
+
+ /** Constructs a message range by copying from another range.
+ *
+ * @param other range to copy
+ */
+ numberMessageRange(const numberMessageRange& other);
+
+ /** Returns the number of the first message in the range.
+ *
+ * @return number of the first message
+ */
+ size_t getFirst() const;
+
+ /** Returns the number of the last message in the range, or -1
+ * to designate the last message in the folder
+ *
+ * @return number of the last message
+ */
+ size_t getLast() const;
+
+ void enumerate(messageSetEnumerator& en) const;
+
+ messageRange* clone() const;
+
+private:
+
+ size_t m_first, m_last;
+};
+
+
+/** A range of (continuous) messages represented by their UID.
+ */
+class VMIME_EXPORT UIDMessageRange : public messageRange {
+
+public:
+
+ /** Constructs a message range containing a single message.
+ *
+ * @param uid message UID
+ */
+ UIDMessageRange(const message::uid& uid);
+
+ /** Constructs a message range for multiple messages.
+ *
+ * @param first UID of the first message in the range
+ * @param last UID of the last message in the range, or use the
+ * special value '*' to designate the last message in the folder
+ */
+ UIDMessageRange(const message::uid& first, const message::uid& last);
+
+ /** Constructs a message range by copying from another range.
+ *
+ * @param other range to copy
+ */
+ UIDMessageRange(const UIDMessageRange& other);
+
+ /** Returns the UID of the first message in the range.
+ *
+ * @return UID of the first message
+ */
+ const message::uid getFirst() const;
+
+ /** Returns the UID of the last message in the range, or '*'
+ * to designate the last message in the folder
+ *
+ * @return UID of the last message
+ */
+ const message::uid getLast() const;
+
+ void enumerate(messageSetEnumerator& en) const;
+
+ messageRange* clone() const;
+
+private:
+
+ message::uid m_first, m_last;
+};
+
+
+/** Represents a set of messages, designated either by their sequence
+ * number, or by their UID (but not both).
+ *
+ * Following is example code to designate messages by their number:
+ * \code{.cpp}
+ * // Designate a single message with sequence number 42
+ * vmime::net::messageSet::byNumber(42)
+ *
+ * // Designate messages from sequence number 5 to sequence number 8 (including)
+ * vmime::net::messageSet::byNumber(5, 8)
+ *
+ * // Designate all messages in the folder, starting from number 42
+ * vmime::net::messageSet::byNumber(42, -1)
+ * \endcode
+ * Or, to designate messages by their UID, use:
+ * \code{.cpp}
+ * // Designate a single message with UID 1042
+ * vmime::net::messageSet::byUID(1042)
+ *
+ * // Designate messages from UID 1000 to UID 1042 (including)
+ * vmime::net::messageSet::byUID(1000, 1042)
+ *
+ * // Designate all messages in the folder, starting from UID 1000
+ * vmime::net::messageSet::byUID(1000, "*")
+ * \endcode
+ */
+class VMIME_EXPORT messageSet : public object {
+
+public:
+
+ ~messageSet();
+
+ messageSet(const messageSet& other);
+
+ /** Constructs an empty set.
+ *
+ * @return new empty message set
+ */
+ static messageSet empty();
+
+ /** Constructs a new message set and initializes it with a single
+ * message represented by its sequence number.
+ *
+ * @param number message number (numbering starts at 1, not 0)
+ * @return new message set
+ */
+ static messageSet byNumber(const size_t number);
+
+ /** Constructs a new message set and initializes it with a range
+ * of messages represented by their sequence number.
+ *
+ * @param first number of the first message in the range (numbering
+ * starts at 1, not 0)
+ * @param last number of the last message in the range, or use the
+ * special value -1 to designate the last message in the folder
+ * @return new message set
+ */
+ static messageSet byNumber(const size_t first, const size_t last);
+
+ /** Constructs a new message set and initializes it with a possibly
+ * unsorted list of messages represented by their sequence number.
+ * Please note that numbering starts at 1, not 0.
+ *
+ * The function tries to group consecutive message numbers into
+ * ranges to reduce the size of the resulting set.
+ *
+ * For example, given the list "1,2,3,4,5,7,8,13,15,16,17" it will
+ * result in the following ranges: "1:5,7:8,13,15:17".
+ *
+ * @param numbers a vector containing numbers of the messages
+ * @return new message set
+ */
+ static messageSet byNumber(const std::vector <size_t>& numbers);
+
+ /** Constructs a new message set and initializes it with a single
+ * message represented by its UID.
+ *
+ * @param uid message UID
+ * @return new message set
+ */
+ static messageSet byUID(const message::uid& uid);
+
+ /** Constructs a new message set and initializes it with a range
+ * of messages represented by their sequence number.
+ *
+ * @param first UID of the first message in the range
+ * @param last UID of the last message in the range, or use the
+ * special value '*' to designate the last message in the folder
+ * @return new message set
+ */
+ static messageSet byUID(const message::uid& first, const message::uid& last);
+
+ /** Constructs a new message set and initializes it with a possibly
+ * unsorted list of messages represented by their UID.
+ *
+ * For UIDs that actually are numbers (this is the case for IMAP), the
+ * function tries to group consecutive UIDs into ranges to reduce the
+ * size of the resulting set.
+ *
+ * For example, given the list "1,2,3,4,5,7,8,13,15,16,17" it will
+ * result in the following ranges: "1:5,7:8,13,15:17".
+ *
+ * @param uids a vector containing UIDs of the messages
+ * @return new message set
+ */
+ static messageSet byUID(const std::vector <message::uid>& uids);
+
+ /** Adds the specified range to this set. The type of message range
+ * (either number or UID) must match the type of the ranges already
+ * contained in this set (ie. it's not possible to have a message
+ * set which contains both number ranges and UID ranges).
+ *
+ * @param range range to add
+ * @throw std::invalid_argument exception if the range type does
+ * not match the type of the ranges in this set
+ */
+ void addRange(const messageRange& range);
+
+ /** Enumerates this set with the specified enumerator.
+ *
+ * @param en enumerator that will receive the method calls while
+ * enumerating the ranges in this set
+ */
+ void enumerate(messageSetEnumerator& en) const;
+
+ /** Returns whether this set is empty (contains no range).
+ *
+ * @return true if this set is empty, or false otherwise
+ */
+ bool isEmpty() const;
+
+ /** Returns whether this set references messages by their sequence
+ * number.
+ *
+ * @return true if this set references messages by their sequence
+ * number, or false otherwise
+ */
+ bool isNumberSet() const;
+
+ /** Returns whether this set references messages by their UID.
+ *
+ * @return true if this set references messages by their UID,
+ * or false otherwise
+ */
+ bool isUIDSet() const;
+
+ /** Returns the number of ranges contained in this set.
+ *
+ * @return range count
+ */
+ size_t getRangeCount() const;
+
+ /** Returns the message range at the specified index.
+ *
+ * @param i range index (from 0 to getRangeCount())
+ * @return a reference to the message range at the specified index
+ */
+ const messageRange& getRangeAt(const size_t i) const;
+
+private:
+
+ messageSet();
+
+ std::vector <messageRange*> m_ranges;
+};
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+
+#endif // VMIME_NET_MESSAGESET_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/pop3/POP3Command.cpp b/vmime-master/src/vmime/net/pop3/POP3Command.cpp
new file mode 100644
index 0000000..0e79888
--- /dev/null
+++ b/vmime-master/src/vmime/net/pop3/POP3Command.cpp
@@ -0,0 +1,267 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+
+#include "vmime/net/pop3/POP3Command.hpp"
+#include "vmime/net/pop3/POP3Connection.hpp"
+#include "vmime/net/pop3/POP3Store.hpp"
+
+#include "vmime/net/socket.hpp"
+
+#include "vmime/mailbox.hpp"
+#include "vmime/utility/outputStreamAdapter.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace pop3 {
+
+
+POP3Command::POP3Command(const string& text, const string& traceText)
+ : m_text(text),
+ m_traceText(traceText) {
+
+}
+
+
+// static
+shared_ptr <POP3Command> POP3Command::CAPA() {
+
+ return createCommand("CAPA");
+}
+
+
+// static
+shared_ptr <POP3Command> POP3Command::NOOP() {
+
+ return createCommand("NOOP");
+}
+
+
+// static
+shared_ptr <POP3Command> POP3Command::AUTH(const string& mechName) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "AUTH " << mechName;
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <POP3Command> POP3Command::AUTH(const string& mechName, const string& initialResponse) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "AUTH " << mechName << " " << initialResponse;
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <POP3Command> POP3Command::STLS() {
+
+ return createCommand("STLS");
+}
+
+
+// static
+shared_ptr <POP3Command> POP3Command::APOP(const string& username, const string& digest) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "APOP " << username << " " << digest;
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <POP3Command> POP3Command::USER(const string& username) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "USER " << username;
+
+ std::ostringstream trace;
+ trace.imbue(std::locale::classic());
+ trace << "USER {username}";
+
+ return createCommand(cmd.str(), trace.str());
+}
+
+
+// static
+shared_ptr <POP3Command> POP3Command::PASS(const string& password) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "PASS " << password;
+
+ std::ostringstream trace;
+ trace.imbue(std::locale::classic());
+ trace << "PASS {password}";
+
+ return createCommand(cmd.str(), trace.str());
+}
+
+
+// static
+shared_ptr <POP3Command> POP3Command::STAT() {
+
+ return createCommand("STAT");
+}
+
+
+// static
+shared_ptr <POP3Command> POP3Command::LIST() {
+
+ return createCommand("LIST");
+}
+
+
+// static
+shared_ptr <POP3Command> POP3Command::LIST(const unsigned long msg) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "LIST " << msg;
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <POP3Command> POP3Command::UIDL() {
+
+ return createCommand("UIDL");
+}
+
+
+// static
+shared_ptr <POP3Command> POP3Command::UIDL(const unsigned long msg) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "UIDL " << msg;
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <POP3Command> POP3Command::DELE(const unsigned long msg) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "DELE " << msg;
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <POP3Command> POP3Command::RETR(const unsigned long msg) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "RETR " << msg;
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <POP3Command> POP3Command::TOP(const unsigned long msg, const unsigned long lines) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "TOP " << msg << " " << lines;
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <POP3Command> POP3Command::RSET() {
+
+ return createCommand("RSET");
+}
+
+
+// static
+shared_ptr <POP3Command> POP3Command::QUIT() {
+
+ return createCommand("QUIT");
+}
+
+
+// static
+shared_ptr <POP3Command> POP3Command::createCommand(
+ const string& text,
+ const string& traceText
+) {
+
+ if (traceText.empty()) {
+ return shared_ptr <POP3Command>(new POP3Command(text, text));
+ } else {
+ return shared_ptr <POP3Command>(new POP3Command(text, traceText));
+ }
+}
+
+
+const string POP3Command::getText() const {
+
+ return m_text;
+}
+
+
+const string POP3Command::getTraceText() const {
+
+ return m_traceText;
+}
+
+
+void POP3Command::send(const shared_ptr <POP3Connection>& conn) {
+
+ conn->getSocket()->send(m_text + "\r\n");
+
+ if (conn->getTracer()) {
+ conn->getTracer()->traceSend(m_traceText);
+ }
+}
+
+
+} // pop3
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
diff --git a/vmime-master/src/vmime/net/pop3/POP3Command.hpp b/vmime-master/src/vmime/net/pop3/POP3Command.hpp
new file mode 100644
index 0000000..06a61b9
--- /dev/null
+++ b/vmime-master/src/vmime/net/pop3/POP3Command.hpp
@@ -0,0 +1,123 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_POP3_POP3COMMAND_HPP_INCLUDED
+#define VMIME_NET_POP3_POP3COMMAND_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+
+#include "vmime/object.hpp"
+#include "vmime/base.hpp"
+
+
+namespace vmime {
+
+
+class mailbox;
+
+
+namespace net {
+namespace pop3 {
+
+
+class POP3Connection;
+
+
+/** A POP3 command that will be sent to the server.
+ */
+class VMIME_EXPORT POP3Command : public object {
+
+public:
+
+ static shared_ptr <POP3Command> CAPA();
+ static shared_ptr <POP3Command> NOOP();
+ static shared_ptr <POP3Command> AUTH(const string& mechName);
+ static shared_ptr <POP3Command> AUTH(const string& mechName, const string& initialResponse);
+ static shared_ptr <POP3Command> STLS();
+ static shared_ptr <POP3Command> APOP(const string& username, const string& digest);
+ static shared_ptr <POP3Command> USER(const string& username);
+ static shared_ptr <POP3Command> PASS(const string& password);
+ static shared_ptr <POP3Command> STAT();
+ static shared_ptr <POP3Command> LIST();
+ static shared_ptr <POP3Command> LIST(const unsigned long msg);
+ static shared_ptr <POP3Command> UIDL();
+ static shared_ptr <POP3Command> UIDL(const unsigned long msg);
+ static shared_ptr <POP3Command> DELE(const unsigned long msg);
+ static shared_ptr <POP3Command> RETR(const unsigned long msg);
+ static shared_ptr <POP3Command> TOP(const unsigned long msg, const unsigned long lines);
+ static shared_ptr <POP3Command> RSET();
+ static shared_ptr <POP3Command> QUIT();
+
+ /** Creates a new POP3 command with the specified text.
+ *
+ * @param text command text
+ * @param traceText trace text (if empty, command text is used)
+ * @return a new POP3Command object
+ */
+ static shared_ptr <POP3Command> createCommand(const string& text, const string& traceText = "");
+
+ /** Sends this command over the specified connection.
+ *
+ * @param conn connection onto which the command will be sent
+ */
+ virtual void send(const shared_ptr <POP3Connection>& conn);
+
+ /** Returns the full text of the command, including command name
+ * and parameters (if any).
+ *
+ * @return command text (eg. "LIST 42")
+ */
+ virtual const string getText() const;
+
+ /** Returns the full text of the command, suitable for outputing
+ * to the tracer.
+ *
+ * @return trace text (eg. "USER myusername")
+ */
+ virtual const string getTraceText() const;
+
+protected:
+
+ POP3Command(const string& text, const string& traceText);
+ POP3Command(const POP3Command&);
+
+private:
+
+ string m_text;
+ string m_traceText;
+};
+
+
+} // pop3
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+#endif // VMIME_NET_POP3_POP3COMMAND_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/pop3/POP3Connection.cpp b/vmime-master/src/vmime/net/pop3/POP3Connection.cpp
new file mode 100644
index 0000000..749f7ef
--- /dev/null
+++ b/vmime-master/src/vmime/net/pop3/POP3Connection.cpp
@@ -0,0 +1,737 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+
+#include "vmime/net/pop3/POP3Connection.hpp"
+#include "vmime/net/pop3/POP3Store.hpp"
+
+#include "vmime/exception.hpp"
+#include "vmime/platform.hpp"
+
+#include "vmime/security/digest/messageDigestFactory.hpp"
+
+#include "vmime/net/defaultConnectionInfos.hpp"
+
+#if VMIME_HAVE_SASL_SUPPORT
+ #include "vmime/security/sasl/SASLContext.hpp"
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+#if VMIME_HAVE_TLS_SUPPORT
+ #include "vmime/net/tls/TLSSession.hpp"
+ #include "vmime/net/tls/TLSSecuredConnectionInfos.hpp"
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+
+
+// Helpers for service properties
+#define GET_PROPERTY(type, prop) \
+ (m_store.lock()->getInfos().getPropertyValue <type>(getSession(), \
+ dynamic_cast <const POP3ServiceInfos&>(m_store.lock()->getInfos()).getProperties().prop))
+#define HAS_PROPERTY(prop) \
+ (m_store.lock()->getInfos().hasProperty(getSession(), \
+ dynamic_cast <const POP3ServiceInfos&>(m_store.lock()->getInfos()).getProperties().prop))
+
+
+namespace vmime {
+namespace net {
+namespace pop3 {
+
+
+
+POP3Connection::POP3Connection(
+ const shared_ptr <POP3Store>& store,
+ const shared_ptr <security::authenticator>& auth
+)
+ : m_store(store),
+ m_auth(auth),
+ m_socket(null),
+ m_timeoutHandler(null),
+ m_authenticated(false),
+ m_secured(false),
+ m_capabilitiesFetched(false) {
+
+ static int connectionId = 0;
+
+ if (store->getTracerFactory()) {
+ m_tracer = store->getTracerFactory()->create(store, ++connectionId);
+ }
+}
+
+
+POP3Connection::~POP3Connection() {
+
+ try {
+
+ if (isConnected()) {
+ disconnect();
+ } else if (m_socket) {
+ internalDisconnect();
+ }
+
+ } catch (...) {
+
+ // Don't throw in destructor
+ }
+}
+
+
+void POP3Connection::connect() {
+
+ if (isConnected()) {
+ throw exceptions::already_connected();
+ }
+
+ const string address = GET_PROPERTY(string, PROPERTY_SERVER_ADDRESS);
+ const port_t port = GET_PROPERTY(port_t, PROPERTY_SERVER_PORT);
+
+ shared_ptr <POP3Store> store = m_store.lock();
+
+ // Create the time-out handler
+ if (store->getTimeoutHandlerFactory()) {
+ m_timeoutHandler = store->getTimeoutHandlerFactory()->create();
+ }
+
+ // Create and connect the socket
+ m_socket = store->getSocketFactory()->create(m_timeoutHandler);
+ m_socket->setTracer(m_tracer);
+
+#if VMIME_HAVE_TLS_SUPPORT
+ if (store->isPOP3S()) { // dedicated port/POP3S
+
+ shared_ptr <tls::TLSSession> tlsSession = tls::TLSSession::create
+ (store->getCertificateVerifier(),
+ store->getSession()->getTLSProperties());
+
+ shared_ptr <tls::TLSSocket> tlsSocket =
+ tlsSession->getSocket(m_socket);
+
+ m_socket = tlsSocket;
+
+ m_secured = true;
+ m_cntInfos = make_shared <tls::TLSSecuredConnectionInfos>(address, port, tlsSession, tlsSocket);
+ } else
+#endif // VMIME_HAVE_TLS_SUPPORT
+ {
+ m_cntInfos = make_shared <defaultConnectionInfos>(address, port);
+ }
+
+ m_socket->connect(address, port);
+
+ // Connection
+ //
+ // eg: C: <connection to server>
+ // --- S: +OK MailSite POP3 Server 5.3.4.0 Ready <36938848.1056800841.634@somewhere.com>
+
+ shared_ptr <POP3Response> response = POP3Response::readResponse(
+ dynamicCast <POP3Connection>(shared_from_this())
+ );
+
+ if (!response->isSuccess()) {
+
+ internalDisconnect();
+ throw exceptions::connection_greeting_error(response->getFirstLine());
+ }
+
+#if VMIME_HAVE_TLS_SUPPORT
+ // Setup secured connection, if requested
+ const bool tls = HAS_PROPERTY(PROPERTY_CONNECTION_TLS)
+ && GET_PROPERTY(bool, PROPERTY_CONNECTION_TLS);
+ const bool tlsRequired = HAS_PROPERTY(PROPERTY_CONNECTION_TLS_REQUIRED)
+ && GET_PROPERTY(bool, PROPERTY_CONNECTION_TLS_REQUIRED);
+
+ if (!store->isPOP3S() && tls) { // only if not POP3S
+
+ try {
+
+ startTLS();
+
+ // Non-fatal error
+ } catch (exceptions::command_error&) {
+
+ if (tlsRequired) {
+ throw;
+ } else {
+ // TLS is not required, so don't bother
+ }
+
+ // Fatal error
+ } catch (...) {
+ throw;
+ }
+ }
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+ // Start authentication process
+ authenticate(messageId(response->getText()));
+}
+
+
+void POP3Connection::disconnect() {
+
+ if (!isConnected()) {
+ throw exceptions::not_connected();
+ }
+
+ internalDisconnect();
+}
+
+
+void POP3Connection::internalDisconnect() {
+
+ if (m_socket) {
+
+ if (m_socket->isConnected()) {
+
+ try {
+
+ POP3Command::QUIT()->send(dynamicCast <POP3Connection>(shared_from_this()));
+ POP3Response::readResponse(dynamicCast <POP3Connection>(shared_from_this()));
+
+ } catch (exception&) {
+
+ // Not important
+ }
+
+ m_socket->disconnect();
+ }
+
+ m_socket = null;
+ }
+
+ m_timeoutHandler = null;
+
+ m_authenticated = false;
+ m_secured = false;
+
+ m_cntInfos = null;
+}
+
+
+void POP3Connection::authenticate(const messageId& randomMID) {
+
+ getAuthenticator()->setService(m_store.lock());
+
+#if VMIME_HAVE_SASL_SUPPORT
+ // First, try SASL authentication
+ if (GET_PROPERTY(bool, PROPERTY_OPTIONS_SASL)) {
+
+ try {
+
+ authenticateSASL();
+
+ m_authenticated = true;
+ return;
+
+ } catch (exceptions::authentication_error&) {
+
+ if (!GET_PROPERTY(bool, PROPERTY_OPTIONS_SASL_FALLBACK)) {
+
+ // Can't fallback on APOP/normal authentication
+ internalDisconnect();
+ throw;
+
+ } else {
+
+ // Ignore, will try APOP/normal authentication
+ }
+
+ } catch (exception&) {
+
+ internalDisconnect();
+ throw;
+ }
+ }
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+ // Secured authentication with APOP (if requested and if available)
+ //
+ // eg: C: APOP vincent <digest>
+ // --- S: +OK vincent is a valid mailbox
+
+ const string username = getAuthenticator()->getUsername();
+ const string password = getAuthenticator()->getPassword();
+
+ shared_ptr <POP3Connection> conn = dynamicCast <POP3Connection>(shared_from_this());
+ shared_ptr <POP3Response> response;
+
+ if (GET_PROPERTY(bool, PROPERTY_OPTIONS_APOP)) {
+
+ if (randomMID.getLeft().length() != 0 &&
+ randomMID.getRight().length() != 0) {
+
+ // <digest> is the result of MD5 applied to "<message-id>password"
+ shared_ptr <security::digest::messageDigest> md5 =
+ security::digest::messageDigestFactory::getInstance()->create("md5");
+
+ md5->update(randomMID.generate() + password);
+ md5->finalize();
+
+ POP3Command::APOP(username, md5->getHexDigest())->send(conn);
+ response = POP3Response::readResponse(conn);
+
+ if (response->isSuccess()) {
+
+ m_authenticated = true;
+ return;
+
+ } else {
+
+ // Some servers close the connection after an unsuccessful APOP
+ // command, so the fallback may not always work...
+ //
+ // S: +OK Qpopper (version 4.0.5) at xxx starting. <30396.1126730747@xxx>
+ // C: APOP plop c5e0a87d088ec71d60e32692d4c5bdf4
+ // S: -ERR [AUTH] Password supplied for "plop" is incorrect.
+ // S: +OK Pop server at xxx signing off.
+ // [Connection closed by foreign host.]
+
+ if (!GET_PROPERTY(bool, PROPERTY_OPTIONS_APOP_FALLBACK)) {
+
+ // Can't fallback on basic authentication
+ internalDisconnect();
+ throw exceptions::authentication_error(response->getFirstLine());
+ }
+
+ // Ensure connection is valid (cf. note above)
+ try {
+
+ POP3Command::NOOP()->send(conn);
+ POP3Response::readResponse(conn);
+
+ } catch (exceptions::socket_exception&) {
+
+ internalDisconnect();
+ throw exceptions::authentication_error(response->getFirstLine());
+ }
+ }
+
+ } else {
+
+ // APOP not supported
+ if (!GET_PROPERTY(bool, PROPERTY_OPTIONS_APOP_FALLBACK)) {
+
+ // Can't fallback on basic authentication
+ internalDisconnect();
+ throw exceptions::authentication_error("APOP not supported");
+ }
+ }
+ }
+
+ // Basic authentication
+ //
+ // eg: C: USER vincent
+ // --- S: +OK vincent is a valid mailbox
+ //
+ // C: PASS couic
+ // S: +OK vincent's maildrop has 2 messages (320 octets)
+ POP3Command::USER(username)->send(conn);
+ response = POP3Response::readResponse(conn);
+
+ if (!response->isSuccess()) {
+
+ internalDisconnect();
+ throw exceptions::authentication_error(response->getFirstLine());
+ }
+
+ POP3Command::PASS(password)->send(conn);
+ response = POP3Response::readResponse(conn);
+
+ if (!response->isSuccess()) {
+
+ internalDisconnect();
+ throw exceptions::authentication_error(response->getFirstLine());
+ }
+
+ m_authenticated = true;
+}
+
+
+#if VMIME_HAVE_SASL_SUPPORT
+
+void POP3Connection::authenticateSASL() {
+
+ if (!dynamicCast <security::sasl::SASLAuthenticator>(getAuthenticator())) {
+ throw exceptions::authentication_error("No SASL authenticator available.");
+ }
+
+ std::vector <string> capa = getCapabilities();
+ std::vector <string> saslMechs;
+
+ for (unsigned int i = 0 ; i < capa.size() ; ++i) {
+
+ const string& x = capa[i];
+
+ // C: CAPA
+ // S: +OK List of capabilities follows
+ // S: LOGIN-DELAY 0
+ // S: PIPELINING
+ // S: UIDL
+ // S: ...
+ // S: SASL DIGEST-MD5 CRAM-MD5 <-----
+ // S: EXPIRE NEVER
+ // S: ...
+
+ if (x.length() > 5 &&
+ (x[0] == 'S' || x[0] == 's') &&
+ (x[1] == 'A' || x[1] == 'a') &&
+ (x[2] == 'S' || x[2] == 's') &&
+ (x[3] == 'L' || x[3] == 'l') &&
+ (x[4] == ' ' || x[4] == '\t')) {
+
+ const string list(x.begin() + 5, x.end());
+
+ std::istringstream iss(list);
+ iss.imbue(std::locale::classic());
+
+ string mech;
+
+ while (iss >> mech) {
+ saslMechs.push_back(mech);
+ }
+ }
+ }
+
+ if (saslMechs.empty()) {
+ throw exceptions::authentication_error("No SASL mechanism available.");
+ }
+
+ std::vector <shared_ptr <security::sasl::SASLMechanism> > mechList;
+
+ shared_ptr <security::sasl::SASLContext> saslContext =
+ security::sasl::SASLContext::create();
+
+ for (unsigned int i = 0 ; i < saslMechs.size() ; ++i) {
+
+ try {
+ mechList.push_back(saslContext->createMechanism(saslMechs[i]));
+ } catch (exceptions::no_such_mechanism&) {
+ // Ignore mechanism
+ }
+ }
+
+ if (mechList.empty()) {
+ throw exceptions::authentication_error("No SASL mechanism available.");
+ }
+
+ // Try to suggest a mechanism among all those supported
+ shared_ptr <security::sasl::SASLMechanism> suggestedMech =
+ saslContext->suggestMechanism(mechList);
+
+ if (!suggestedMech) {
+ throw exceptions::authentication_error("Unable to suggest SASL mechanism.");
+ }
+
+ // Allow application to choose which mechanisms to use
+ mechList = dynamicCast <security::sasl::SASLAuthenticator>(getAuthenticator())->
+ getAcceptableMechanisms(mechList, suggestedMech);
+
+ if (mechList.empty()) {
+ throw exceptions::authentication_error("No SASL mechanism available.");
+ }
+
+ // Try each mechanism in the list in turn
+ for (unsigned int i = 0 ; i < mechList.size() ; ++i) {
+
+ shared_ptr <security::sasl::SASLMechanism> mech = mechList[i];
+
+ shared_ptr <security::sasl::SASLSession> saslSession =
+ saslContext->createSession("pop3", getAuthenticator(), mech);
+
+ saslSession->init();
+
+ shared_ptr <POP3Command> authCmd;
+
+ if (saslSession->getMechanism()->hasInitialResponse()) {
+
+ byte_t* initialResp = 0;
+ size_t initialRespLen = 0;
+
+ saslSession->evaluateChallenge(NULL, 0, &initialResp, &initialRespLen);
+
+ string encodedInitialResp(saslContext->encodeB64(initialResp, initialRespLen));
+ delete [] initialResp;
+
+ if (encodedInitialResp.empty()) {
+ authCmd = POP3Command::AUTH(mech->getName(), "=");
+ } else {
+ authCmd = POP3Command::AUTH(mech->getName(), encodedInitialResp);
+ }
+
+ } else {
+
+ authCmd = POP3Command::AUTH(mech->getName());
+ }
+
+ authCmd->send(dynamicCast <POP3Connection>(shared_from_this()));
+
+ for (bool cont = true ; cont ; ) {
+
+ shared_ptr <POP3Response> response =
+ POP3Response::readResponse(dynamicCast <POP3Connection>(shared_from_this()));
+
+ switch (response->getCode()) {
+
+ case POP3Response::CODE_OK: {
+
+ m_socket = saslSession->getSecuredSocket(m_socket);
+ return;
+ }
+
+ case POP3Response::CODE_READY: {
+
+ byte_t* challenge = 0;
+ size_t challengeLen = 0;
+
+ byte_t* resp = 0;
+ size_t respLen = 0;
+
+ try {
+
+ // Extract challenge
+ saslContext->decodeB64(response->getText(), &challenge, &challengeLen);
+
+ // Prepare response
+ saslSession->evaluateChallenge(challenge, challengeLen, &resp, &respLen);
+
+ // Send response
+ const string respB64 = saslContext->encodeB64(resp, respLen) + "\r\n";
+ m_socket->sendRaw(utility::stringUtils::bytesFromString(respB64), respB64.length());
+
+ if (m_tracer) {
+ m_tracer->traceSendBytes(respB64.length() - 2, "SASL exchange");
+ }
+
+ } catch (exceptions::sasl_exception& e) {
+
+ if (challenge) {
+ delete [] challenge;
+ challenge = NULL;
+ }
+
+ if (resp) {
+ delete [] resp;
+ resp = NULL;
+ }
+
+ // Cancel SASL exchange
+ m_socket->send("*\r\n");
+
+ if (m_tracer) {
+ m_tracer->traceSend("*");
+ }
+
+ } catch (...) {
+
+ if (challenge) {
+ delete [] challenge;
+ }
+
+ if (resp) {
+ delete [] resp;
+ }
+
+ throw;
+ }
+
+ if (challenge) {
+ delete [] challenge;
+ }
+
+ if (resp) {
+ delete [] resp;
+ }
+
+ break;
+ }
+
+ default:
+
+ cont = false;
+ break;
+ }
+ }
+ }
+
+ throw exceptions::authentication_error("Could not authenticate using SASL: all mechanisms failed.");
+}
+
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+
+#if VMIME_HAVE_TLS_SUPPORT
+
+void POP3Connection::startTLS() {
+
+ try {
+
+ POP3Command::STLS()->send(dynamicCast <POP3Connection>(shared_from_this()));
+
+ shared_ptr <POP3Response> response =
+ POP3Response::readResponse(dynamicCast <POP3Connection>(shared_from_this()));
+
+ if (!response->isSuccess()) {
+ throw exceptions::command_error("STLS", response->getFirstLine());
+ }
+
+ shared_ptr <tls::TLSSession> tlsSession = tls::TLSSession::create(
+ m_store.lock()->getCertificateVerifier(),
+ m_store.lock()->getSession()->getTLSProperties()
+ );
+
+ shared_ptr <tls::TLSSocket> tlsSocket = tlsSession->getSocket(m_socket);
+
+ tlsSocket->handshake();
+
+ m_socket = tlsSocket;
+
+ m_secured = true;
+ m_cntInfos = make_shared <tls::TLSSecuredConnectionInfos>(
+ m_cntInfos->getHost(), m_cntInfos->getPort(), tlsSession, tlsSocket
+ );
+
+ // " Once TLS has been started, the client MUST discard cached
+ // information about server capabilities and SHOULD re-issue
+ // the CAPA command. This is necessary to protect against
+ // man-in-the-middle attacks which alter the capabilities list
+ // prior to STLS. " (RFC-2595)
+ invalidateCapabilities();
+
+ } catch (exceptions::command_error&) {
+
+ // Non-fatal error
+ throw;
+
+ } catch (exception&) {
+
+ // Fatal error
+ internalDisconnect();
+ throw;
+ }
+}
+
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+
+const std::vector <string> POP3Connection::getCapabilities() {
+
+ if (!m_capabilitiesFetched) {
+ fetchCapabilities();
+ }
+
+ return m_capabilities;
+}
+
+
+void POP3Connection::invalidateCapabilities() {
+
+ m_capabilities.clear();
+ m_capabilitiesFetched = false;
+}
+
+
+void POP3Connection::fetchCapabilities() {
+
+ POP3Command::CAPA()->send(dynamicCast <POP3Connection>(shared_from_this()));
+
+ shared_ptr <POP3Response> response =
+ POP3Response::readMultilineResponse(dynamicCast <POP3Connection>(shared_from_this()));
+
+ std::vector <string> res;
+
+ if (response->isSuccess()) {
+
+ for (size_t i = 0, n = response->getLineCount() ; i < n ; ++i) {
+ res.push_back(response->getLineAt(i));
+ }
+ }
+
+ m_capabilities = res;
+ m_capabilitiesFetched = true;
+}
+
+
+bool POP3Connection::isConnected() const {
+
+ return m_socket && m_socket->isConnected() && m_authenticated;
+}
+
+
+bool POP3Connection::isSecuredConnection() const {
+
+ return m_secured;
+}
+
+
+shared_ptr <connectionInfos> POP3Connection::getConnectionInfos() const {
+
+ return m_cntInfos;
+}
+
+
+shared_ptr <POP3Store> POP3Connection::getStore() {
+
+ return m_store.lock();
+}
+
+
+shared_ptr <session> POP3Connection::getSession() {
+
+ return m_store.lock()->getSession();
+}
+
+
+shared_ptr <socket> POP3Connection::getSocket() {
+
+ return m_socket;
+}
+
+
+shared_ptr <tracer> POP3Connection::getTracer() {
+
+ return m_tracer;
+}
+
+
+shared_ptr <timeoutHandler> POP3Connection::getTimeoutHandler() {
+
+ return m_timeoutHandler;
+}
+
+
+shared_ptr <security::authenticator> POP3Connection::getAuthenticator() {
+
+ return m_auth;
+}
+
+
+} // pop3
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
diff --git a/vmime-master/src/vmime/net/pop3/POP3Connection.hpp b/vmime-master/src/vmime/net/pop3/POP3Connection.hpp
new file mode 100644
index 0000000..26b3f3c
--- /dev/null
+++ b/vmime-master/src/vmime/net/pop3/POP3Connection.hpp
@@ -0,0 +1,132 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_POP3_POP3CONNECTION_HPP_INCLUDED
+#define VMIME_NET_POP3_POP3CONNECTION_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+
+#include "vmime/messageId.hpp"
+
+#include "vmime/net/socket.hpp"
+#include "vmime/net/timeoutHandler.hpp"
+#include "vmime/net/session.hpp"
+#include "vmime/net/connectionInfos.hpp"
+#include "vmime/net/tracer.hpp"
+
+#include "vmime/net/pop3/POP3Command.hpp"
+#include "vmime/net/pop3/POP3Response.hpp"
+
+#include "vmime/security/authenticator.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+class socket;
+class timeoutHandler;
+
+
+namespace pop3 {
+
+
+class POP3Store;
+
+
+/** Manage connection to a POP3 server.
+ */
+class VMIME_EXPORT POP3Connection : public object, public enable_shared_from_this <POP3Connection> {
+
+public:
+
+ POP3Connection(
+ const shared_ptr <POP3Store>& store,
+ const shared_ptr <security::authenticator>& auth
+ );
+
+ virtual ~POP3Connection();
+
+
+ virtual void connect();
+ virtual bool isConnected() const;
+ virtual void disconnect();
+
+ bool isSecuredConnection() const;
+ shared_ptr <connectionInfos> getConnectionInfos() const;
+
+ virtual shared_ptr <POP3Store> getStore();
+ virtual shared_ptr <socket> getSocket();
+ virtual shared_ptr <timeoutHandler> getTimeoutHandler();
+ virtual shared_ptr <security::authenticator> getAuthenticator();
+ virtual shared_ptr <session> getSession();
+ virtual shared_ptr <tracer> getTracer();
+
+private:
+
+ void authenticate(const messageId& randomMID);
+#if VMIME_HAVE_SASL_SUPPORT
+ void authenticateSASL();
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+#if VMIME_HAVE_TLS_SUPPORT
+ void startTLS();
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+ void fetchCapabilities();
+ void invalidateCapabilities();
+ const std::vector <string> getCapabilities();
+
+ void internalDisconnect();
+
+
+ weak_ptr <POP3Store> m_store;
+
+ shared_ptr <security::authenticator> m_auth;
+ shared_ptr <socket> m_socket;
+ shared_ptr <timeoutHandler> m_timeoutHandler;
+ shared_ptr <tracer> m_tracer;
+
+ bool m_authenticated;
+ bool m_secured;
+
+ shared_ptr <connectionInfos> m_cntInfos;
+
+ std::vector <string> m_capabilities;
+ bool m_capabilitiesFetched;
+};
+
+
+} // pop3
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+#endif // VMIME_NET_POP3_POP3CONNECTION_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/pop3/POP3Folder.cpp b/vmime-master/src/vmime/net/pop3/POP3Folder.cpp
new file mode 100644
index 0000000..b69a483
--- /dev/null
+++ b/vmime-master/src/vmime/net/pop3/POP3Folder.cpp
@@ -0,0 +1,822 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+
+#include "vmime/net/pop3/POP3Folder.hpp"
+
+#include "vmime/net/pop3/POP3Store.hpp"
+#include "vmime/net/pop3/POP3Message.hpp"
+#include "vmime/net/pop3/POP3Command.hpp"
+#include "vmime/net/pop3/POP3Response.hpp"
+#include "vmime/net/pop3/POP3FolderStatus.hpp"
+
+#include "vmime/net/pop3/POP3Utils.hpp"
+
+#include "vmime/exception.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace pop3 {
+
+
+POP3Folder::POP3Folder(
+ const folder::path& path,
+ const shared_ptr <POP3Store>& store
+)
+ : m_store(store),
+ m_path(path),
+ m_name(path.isEmpty() ? folder::path::component("") : path.getLastComponent()),
+ m_mode(-1),
+ m_open(false) {
+
+ store->registerFolder(this);
+}
+
+
+POP3Folder::~POP3Folder() {
+
+ try {
+
+ shared_ptr <POP3Store> store = m_store.lock();
+
+ if (store) {
+
+ if (m_open) {
+ close(false);
+ }
+
+ store->unregisterFolder(this);
+
+ } else if (m_open) {
+
+ onClose();
+ }
+
+ } catch (...) {
+
+ // Don't throw in destructor
+ }
+}
+
+
+int POP3Folder::getMode() const {
+
+ if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ }
+
+ return m_mode;
+}
+
+
+const folderAttributes POP3Folder::getAttributes() {
+
+ folderAttributes attribs;
+
+ if (m_path.isEmpty()) {
+ attribs.setType(folderAttributes::TYPE_CONTAINS_FOLDERS);
+ } else if (m_path.getSize() == 1 && m_path[0].getBuffer() == "INBOX") {
+ attribs.setType(folderAttributes::TYPE_CONTAINS_MESSAGES);
+ attribs.setSpecialUse(folderAttributes::SPECIALUSE_INBOX);
+ } else {
+ throw exceptions::folder_not_found();
+ }
+
+ attribs.setFlags(0);
+
+ return attribs;
+}
+
+
+const folder::path::component POP3Folder::getName() const {
+
+ return m_name;
+}
+
+
+const folder::path POP3Folder::getFullPath() const {
+
+ return m_path;
+}
+
+
+void POP3Folder::open(const int mode, bool failIfModeIsNotAvailable) {
+
+ shared_ptr <POP3Store> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ }
+
+ if (m_path.isEmpty()) {
+
+ if (mode != MODE_READ_ONLY && failIfModeIsNotAvailable) {
+ throw exceptions::operation_not_supported();
+ }
+
+ m_open = true;
+ m_mode = mode;
+
+ m_messageCount = 0;
+
+ } else if (m_path.getSize() == 1 && m_path[0].getBuffer() == "INBOX") {
+
+ POP3Command::STAT()->send(store->getConnection());
+
+ shared_ptr <POP3Response> response = POP3Response::readResponse(store->getConnection());
+
+ if (!response->isSuccess()) {
+ throw exceptions::command_error("STAT", response->getFirstLine());
+ }
+
+ std::istringstream iss(response->getText());
+ iss.imbue(std::locale::classic());
+ iss >> m_messageCount;
+
+ if (iss.fail()) {
+ throw exceptions::invalid_response("STAT", response->getFirstLine());
+ }
+
+ m_open = true;
+ m_mode = mode;
+
+ } else {
+
+ throw exceptions::folder_not_found();
+ }
+}
+
+
+void POP3Folder::close(const bool expunge) {
+
+ shared_ptr <POP3Store> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ }
+
+ if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ }
+
+ if (!expunge) {
+ POP3Command::RSET()->send(store->getConnection());
+ POP3Response::readResponse(store->getConnection());
+ }
+
+ m_open = false;
+ m_mode = -1;
+
+ onClose();
+}
+
+
+void POP3Folder::onClose() {
+
+ for (MessageMap::iterator it = m_messages.begin() ; it != m_messages.end() ; ++it) {
+ (*it).first->onFolderClosed();
+ }
+
+ m_messages.clear();
+}
+
+
+void POP3Folder::create(const folderAttributes& /* attribs */) {
+
+ throw exceptions::operation_not_supported();
+}
+
+
+void POP3Folder::destroy() {
+
+ throw exceptions::operation_not_supported();
+}
+
+
+bool POP3Folder::exists() {
+
+ shared_ptr <POP3Store> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ }
+
+ return m_path.isEmpty() || (m_path.getSize() == 1 && m_path[0].getBuffer() == "INBOX");
+}
+
+
+bool POP3Folder::isOpen() const {
+
+ return m_open;
+}
+
+
+shared_ptr <message> POP3Folder::getMessage(const size_t num) {
+
+ shared_ptr <POP3Store> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ } else if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ } else if (num < 1 || num > m_messageCount) {
+ throw exceptions::message_not_found();
+ }
+
+ return make_shared <POP3Message>(dynamicCast <POP3Folder>(shared_from_this()), num);
+}
+
+
+std::vector <shared_ptr <message> > POP3Folder::getMessages(const messageSet& msgs) {
+
+ shared_ptr <POP3Store> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ } else if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ }
+
+ if (msgs.isNumberSet()) {
+
+ const std::vector <size_t> numbers = POP3Utils::messageSetToNumberList(msgs, m_messageCount);
+
+ std::vector <shared_ptr <message> > messages;
+ shared_ptr <POP3Folder> thisFolder(dynamicCast <POP3Folder>(shared_from_this()));
+
+ for (std::vector <size_t>::const_iterator it = numbers.begin() ; it != numbers.end() ; ++it) {
+
+ if (*it < 1|| *it > m_messageCount) {
+ throw exceptions::message_not_found();
+ }
+
+ messages.push_back(make_shared <POP3Message>(thisFolder, *it));
+ }
+
+ return messages;
+
+ } else {
+
+ throw exceptions::operation_not_supported();
+ }
+}
+
+
+size_t POP3Folder::getMessageCount() {
+
+ shared_ptr <POP3Store> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ } else if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ }
+
+ return m_messageCount;
+}
+
+
+shared_ptr <folder> POP3Folder::getFolder(const folder::path::component& name) {
+
+ shared_ptr <POP3Store> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ }
+
+ return shared_ptr <POP3Folder>(new POP3Folder(m_path / name, store));
+}
+
+
+std::vector <shared_ptr <folder> > POP3Folder::getFolders(const bool /* recursive */) {
+
+ shared_ptr <POP3Store> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ }
+
+ if (m_path.isEmpty()) {
+
+ std::vector <shared_ptr <folder> > v;
+ v.push_back(shared_ptr <POP3Folder>(new POP3Folder(folder::path::component("INBOX"), store)));
+ return v;
+
+ } else {
+
+ std::vector <shared_ptr <folder> > v;
+ return v;
+ }
+}
+
+
+void POP3Folder::fetchMessages(
+ std::vector <shared_ptr <message> >& msg,
+ const fetchAttributes& options,
+ utility::progressListener* progress
+) {
+
+ shared_ptr <POP3Store> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ } else if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ }
+
+ if (msg.empty()) {
+ return;
+ }
+
+ const size_t total = msg.size();
+ size_t current = 0;
+
+ if (progress) {
+ progress->start(total);
+ }
+
+ for (std::vector <shared_ptr <message> >::iterator it = msg.begin() ;
+ it != msg.end() ; ++it) {
+
+ dynamicCast <POP3Message>(*it)->fetch(
+ dynamicCast <POP3Folder>(shared_from_this()),
+ options
+ );
+
+ if (progress) {
+ progress->progress(++current, total);
+ }
+ }
+
+ if (options.has(fetchAttributes::SIZE)) {
+
+ // Send the "LIST" command
+ POP3Command::LIST()->send(store->getConnection());
+
+ // Get the response
+ shared_ptr <POP3Response> response =
+ POP3Response::readMultilineResponse(store->getConnection());
+
+ if (response->isSuccess()) {
+
+ // C: LIST
+ // S: +OK
+ // S: 1 47548
+ // S: 2 12653
+ // S: .
+ std::map <size_t, string> result;
+ POP3Utils::parseMultiListOrUidlResponse(response, result);
+
+ for (std::vector <shared_ptr <message> >::iterator it = msg.begin() ;
+ it != msg.end() ; ++it) {
+
+ shared_ptr <POP3Message> m = dynamicCast <POP3Message>(*it);
+
+ std::map <size_t, string>::const_iterator x = result.find(m->m_num);
+
+ if (x != result.end()) {
+
+ size_t size = 0;
+
+ std::istringstream iss((*x).second);
+ iss.imbue(std::locale::classic());
+ iss >> size;
+
+ m->m_size = size;
+ }
+ }
+ }
+ }
+
+ if (options.has(fetchAttributes::UID)) {
+
+ // Send the "UIDL" command
+ POP3Command::UIDL()->send(store->getConnection());
+
+ // Get the response
+ shared_ptr <POP3Response> response =
+ POP3Response::readMultilineResponse(store->getConnection());
+
+ if (response->isSuccess()) {
+
+ // C: UIDL
+ // S: +OK
+ // S: 1 whqtswO00WBw418f9t5JxYwZ
+ // S: 2 QhdPYR:00WBw1Ph7x7
+ // S: .
+ std::map <size_t, string> result;
+ POP3Utils::parseMultiListOrUidlResponse(response, result);
+
+ for (std::vector <shared_ptr <message> >::iterator it = msg.begin() ;
+ it != msg.end() ; ++it) {
+
+ shared_ptr <POP3Message> m = dynamicCast <POP3Message>(*it);
+
+ std::map <size_t, string>::const_iterator x = result.find(m->m_num);
+
+ if (x != result.end()) {
+ m->m_uid = (*x).second;
+ }
+ }
+ }
+ }
+
+ if (progress) {
+ progress->stop(total);
+ }
+}
+
+
+void POP3Folder::fetchMessage(const shared_ptr <message>& msg, const fetchAttributes& options) {
+
+ shared_ptr <POP3Store> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ } else if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ }
+
+ dynamicCast <POP3Message>(msg)->fetch(
+ dynamicCast <POP3Folder>(shared_from_this()),
+ options
+ );
+
+ if (options.has(fetchAttributes::SIZE)) {
+
+ // Send the "LIST" command
+ POP3Command::LIST(msg->getNumber())->send(store->getConnection());
+
+ // Get the response
+ shared_ptr <POP3Response> response =
+ POP3Response::readResponse(store->getConnection());
+
+ if (response->isSuccess()) {
+
+ string responseText = response->getText();
+
+ // C: LIST 2
+ // S: +OK 2 4242
+ string::iterator it = responseText.begin();
+
+ while (it != responseText.end() && (*it == ' ' || *it == '\t')) ++it;
+ while (it != responseText.end() && !(*it == ' ' || *it == '\t')) ++it;
+ while (it != responseText.end() && (*it == ' ' || *it == '\t')) ++it;
+
+ if (it != responseText.end()) {
+
+ size_t size = 0;
+
+ std::istringstream iss(string(it, responseText.end()));
+ iss.imbue(std::locale::classic());
+ iss >> size;
+
+ dynamicCast <POP3Message>(msg)->m_size = size;
+ }
+ }
+ }
+
+ if (options.has(fetchAttributes::UID)) {
+
+ // Send the "UIDL" command
+ POP3Command::UIDL(msg->getNumber())->send(store->getConnection());
+
+ // Get the response
+ shared_ptr <POP3Response> response =
+ POP3Response::readResponse(store->getConnection());
+
+ if (response->isSuccess()) {
+
+ string responseText = response->getText();
+
+ // C: UIDL 2
+ // S: +OK 2 QhdPYR:00WBw1Ph7x7
+ string::iterator it = responseText.begin();
+
+ while (it != responseText.end() && (*it == ' ' || *it == '\t')) ++it;
+ while (it != responseText.end() && !(*it == ' ' || *it == '\t')) ++it;
+ while (it != responseText.end() && (*it == ' ' || *it == '\t')) ++it;
+
+ if (it != responseText.end()) {
+ dynamicCast <POP3Message>(msg)->m_uid = string(it, responseText.end());
+ }
+ }
+ }
+}
+
+
+std::vector <shared_ptr <message> > POP3Folder::getAndFetchMessages(
+ const messageSet& msgs,
+ const fetchAttributes& attribs
+) {
+
+ if (msgs.isEmpty()) {
+ return std::vector <shared_ptr <message> >();
+ }
+
+ std::vector <shared_ptr <message> > messages = getMessages(msgs);
+ fetchMessages(messages, attribs);
+
+ return messages;
+}
+
+
+int POP3Folder::getFetchCapabilities() const {
+
+ return fetchAttributes::ENVELOPE |
+ fetchAttributes::CONTENT_INFO |
+ fetchAttributes::SIZE |
+ fetchAttributes::FULL_HEADER |
+ fetchAttributes::UID |
+ fetchAttributes::IMPORTANCE;
+}
+
+
+shared_ptr <folder> POP3Folder::getParent() {
+
+ if (m_path.isEmpty()) {
+ return null;
+ } else {
+ return shared_ptr <POP3Folder>(new POP3Folder(m_path.getParent(), m_store.lock()));
+ }
+}
+
+
+shared_ptr <const store> POP3Folder::getStore() const {
+
+ return m_store.lock();
+}
+
+
+shared_ptr <store> POP3Folder::getStore() {
+
+ return m_store.lock();
+}
+
+
+void POP3Folder::registerMessage(POP3Message* msg) {
+
+ m_messages.insert(MessageMap::value_type(msg, msg->getNumber()));
+}
+
+
+void POP3Folder::unregisterMessage(POP3Message* msg) {
+
+ m_messages.erase(msg);
+}
+
+
+void POP3Folder::onStoreDisconnected() {
+
+ m_store.reset();
+}
+
+
+void POP3Folder::deleteMessages(const messageSet& msgs) {
+
+ shared_ptr <POP3Store> store = m_store.lock();
+
+ const std::vector <size_t> nums = POP3Utils::messageSetToNumberList(msgs, m_messageCount);
+
+ if (nums.empty()) {
+ throw exceptions::invalid_argument();
+ }
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ } else if (!isOpen()) {
+ throw exceptions::illegal_state("Folder not open");
+ }
+
+ for (std::vector <size_t>::const_iterator
+ it = nums.begin() ; it != nums.end() ; ++it) {
+
+ POP3Command::DELE(*it)->send(store->getConnection());
+
+ shared_ptr <POP3Response> response =
+ POP3Response::readResponse(store->getConnection());
+
+ if (!response->isSuccess()) {
+ throw exceptions::command_error("DELE", response->getFirstLine());
+ }
+ }
+
+ // Sort message list
+ std::vector <size_t> list;
+
+ list.resize(nums.size());
+ std::copy(nums.begin(), nums.end(), list.begin());
+
+ std::sort(list.begin(), list.end());
+
+ // Update local flags
+ for (std::map <POP3Message*, size_t>::iterator it =
+ m_messages.begin() ; it != m_messages.end() ; ++it) {
+
+ POP3Message* msg = (*it).first;
+
+ if (std::binary_search(list.begin(), list.end(), msg->getNumber())) {
+ msg->m_deleted = true;
+ }
+ }
+
+ // Notify message flags changed
+ shared_ptr <events::messageChangedEvent> event =
+ make_shared <events::messageChangedEvent>(
+ dynamicCast <folder>(shared_from_this()),
+ events::messageChangedEvent::TYPE_FLAGS,
+ list
+ );
+
+ notifyMessageChanged(event);
+}
+
+
+void POP3Folder::setMessageFlags(
+ const messageSet& /* msgs */,
+ const int /* flags */,
+ const int /* mode */
+) {
+
+ throw exceptions::operation_not_supported();
+}
+
+
+void POP3Folder::rename(const folder::path& /* newPath */) {
+
+ throw exceptions::operation_not_supported();
+}
+
+
+messageSet POP3Folder::addMessage(
+ const shared_ptr <vmime::message>& /* msg */,
+ const int /* flags */,
+ vmime::datetime* /* date */,
+ utility::progressListener* /* progress */
+) {
+
+ throw exceptions::operation_not_supported();
+}
+
+
+messageSet POP3Folder::addMessage(
+ utility::inputStream& /* is */,
+ const size_t /* size */,
+ const int /* flags */,
+ vmime::datetime* /* date */,
+ utility::progressListener* /* progress */
+) {
+
+ throw exceptions::operation_not_supported();
+}
+
+
+messageSet POP3Folder::copyMessages(
+ const folder::path& /* dest */,
+ const messageSet& /* msgs */
+) {
+
+ throw exceptions::operation_not_supported();
+}
+
+
+void POP3Folder::status(size_t& count, size_t& unseen) {
+
+ count = 0;
+ unseen = 0;
+
+ shared_ptr <folderStatus> status = getStatus();
+
+ count = status->getMessageCount();
+ unseen = status->getUnseenCount();
+
+ m_messageCount = count;
+}
+
+
+shared_ptr <folderStatus> POP3Folder::getStatus() {
+
+ shared_ptr <POP3Store> store = m_store.lock();
+
+ if (!store) {
+ throw exceptions::illegal_state("Store disconnected");
+ }
+
+ POP3Command::STAT()->send(store->getConnection());
+
+ shared_ptr <POP3Response> response =
+ POP3Response::readResponse(store->getConnection());
+
+ if (!response->isSuccess()) {
+ throw exceptions::command_error("STAT", response->getFirstLine());
+ }
+
+
+ size_t count = 0;
+
+ std::istringstream iss(response->getText());
+ iss.imbue(std::locale::classic());
+ iss >> count;
+
+ shared_ptr <POP3FolderStatus> status = make_shared <POP3FolderStatus>();
+
+ status->setMessageCount(count);
+ status->setUnseenCount(count);
+
+ // Update local message count
+ if (m_messageCount != count) {
+
+ const size_t oldCount = m_messageCount;
+
+ m_messageCount = count;
+
+ if (count > oldCount) {
+
+ std::vector <size_t> nums;
+ nums.resize(count - oldCount);
+
+ for (size_t i = oldCount + 1, j = 0 ; i <= count ; ++i, ++j) {
+ nums[j] = i;
+ }
+
+ // Notify message count changed
+ shared_ptr <events::messageCountEvent> event =
+ make_shared <events::messageCountEvent>(
+ dynamicCast <folder>(shared_from_this()),
+ events::messageCountEvent::TYPE_ADDED,
+ nums
+ );
+
+ notifyMessageCount(event);
+
+ // Notify folders with the same path
+ for (std::list <POP3Folder*>::iterator it = store->m_folders.begin() ;
+ it != store->m_folders.end() ; ++it) {
+
+ if ((*it) != this && (*it)->getFullPath() == m_path) {
+
+ (*it)->m_messageCount = count;
+
+ shared_ptr <events::messageCountEvent> event =
+ make_shared <events::messageCountEvent>(
+ dynamicCast <folder>((*it)->shared_from_this()),
+ events::messageCountEvent::TYPE_ADDED,
+ nums
+ );
+
+ (*it)->notifyMessageCount(event);
+ }
+ }
+ }
+ }
+
+ return status;
+}
+
+
+void POP3Folder::expunge() {
+
+ // Not supported by POP3 protocol (deleted messages are automatically
+ // expunged at the end of the session...).
+}
+
+
+std::vector <size_t> POP3Folder::getMessageNumbersStartingOnUID(const message::uid& /* uid */) {
+
+ throw exceptions::operation_not_supported();
+}
+
+
+} // pop3
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
diff --git a/vmime-master/src/vmime/net/pop3/POP3Folder.hpp b/vmime-master/src/vmime/net/pop3/POP3Folder.hpp
new file mode 100644
index 0000000..73e29f9
--- /dev/null
+++ b/vmime-master/src/vmime/net/pop3/POP3Folder.hpp
@@ -0,0 +1,179 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_POP3_POP3FOLDER_HPP_INCLUDED
+#define VMIME_NET_POP3_POP3FOLDER_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+
+#include <vector>
+#include <map>
+
+#include "vmime/types.hpp"
+
+#include "vmime/net/folder.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace pop3 {
+
+
+class POP3Store;
+class POP3Message;
+
+
+/** POP3 folder implementation.
+ */
+class VMIME_EXPORT POP3Folder : public folder {
+
+private:
+
+ friend class POP3Store;
+ friend class POP3Message;
+
+ POP3Folder(const POP3Folder&);
+ POP3Folder(const folder::path& path, const shared_ptr <POP3Store>& store);
+
+public:
+
+ ~POP3Folder();
+
+ int getMode() const;
+
+ const folderAttributes getAttributes();
+
+ const folder::path::component getName() const;
+ const folder::path getFullPath() const;
+
+ void open(const int mode, bool failIfModeIsNotAvailable = false);
+ void close(const bool expunge);
+ void create(const folderAttributes& attribs);
+
+ bool exists();
+
+ void destroy();
+
+ bool isOpen() const;
+
+ shared_ptr <message> getMessage(const size_t num);
+ std::vector <shared_ptr <message> > getMessages(const messageSet& msgs);
+
+ size_t getMessageCount();
+
+ shared_ptr <folder> getFolder(const folder::path::component& name);
+ std::vector <shared_ptr <folder> > getFolders(const bool recursive = false);
+
+ void rename(const folder::path& newPath);
+
+ void deleteMessages(const messageSet& msgs);
+
+ void setMessageFlags(
+ const messageSet& msgs,
+ const int flags,
+ const int mode = message::FLAG_MODE_SET
+ );
+
+ messageSet addMessage(
+ const shared_ptr <vmime::message>& msg,
+ const int flags = -1,
+ vmime::datetime* date = NULL,
+ utility::progressListener* progress = NULL
+ );
+
+ messageSet addMessage(
+ utility::inputStream& is,
+ const size_t size,
+ const int flags = -1,
+ vmime::datetime* date = NULL,
+ utility::progressListener* progress = NULL
+ );
+
+ messageSet copyMessages(const folder::path& dest, const messageSet& msgs);
+
+ void status(size_t& count, size_t& unseen);
+ shared_ptr <folderStatus> getStatus();
+
+ void expunge();
+
+ shared_ptr <folder> getParent();
+
+ shared_ptr <const store> getStore() const;
+ shared_ptr <store> getStore();
+
+
+ void fetchMessages(
+ std::vector <shared_ptr <message> >& msg,
+ const fetchAttributes& options,
+ utility::progressListener* progress = NULL
+ );
+
+ void fetchMessage(const shared_ptr <message>& msg, const fetchAttributes& options);
+
+ std::vector <shared_ptr <message> > getAndFetchMessages(
+ const messageSet& msgs,
+ const fetchAttributes& attribs
+ );
+
+ int getFetchCapabilities() const;
+
+ std::vector <size_t> getMessageNumbersStartingOnUID(const message::uid& uid);
+
+private:
+
+ void registerMessage(POP3Message* msg);
+ void unregisterMessage(POP3Message* msg);
+
+ void onStoreDisconnected();
+
+ void onClose();
+
+
+ weak_ptr <POP3Store> m_store;
+
+ folder::path m_path;
+ folder::path::component m_name;
+
+ int m_mode;
+ bool m_open;
+
+ size_t m_messageCount;
+
+ typedef std::map <POP3Message*, size_t> MessageMap;
+ MessageMap m_messages;
+};
+
+
+} // pop3
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+#endif // VMIME_NET_POP3_POP3FOLDER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/pop3/POP3FolderStatus.cpp b/vmime-master/src/vmime/net/pop3/POP3FolderStatus.cpp
new file mode 100644
index 0000000..9f2c49f
--- /dev/null
+++ b/vmime-master/src/vmime/net/pop3/POP3FolderStatus.cpp
@@ -0,0 +1,88 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+
+#include "vmime/net/pop3/POP3FolderStatus.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace pop3 {
+
+
+POP3FolderStatus::POP3FolderStatus()
+ : m_count(0),
+ m_unseen(0) {
+
+}
+
+
+POP3FolderStatus::POP3FolderStatus(const POP3FolderStatus& other)
+ : folderStatus(),
+ m_count(other.m_count),
+ m_unseen(other.m_unseen) {
+
+}
+
+
+size_t POP3FolderStatus::getMessageCount() const {
+
+ return m_count;
+}
+
+
+size_t POP3FolderStatus::getUnseenCount() const {
+
+ return m_unseen;
+}
+
+
+void POP3FolderStatus::setMessageCount(const size_t count) {
+
+ m_count = count;
+}
+
+
+void POP3FolderStatus::setUnseenCount(const size_t unseen) {
+
+ m_unseen = unseen;
+}
+
+
+shared_ptr <folderStatus> POP3FolderStatus::clone() const {
+
+ return make_shared <POP3FolderStatus>(*this);
+}
+
+
+} // pop3
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
diff --git a/vmime-master/src/vmime/net/pop3/POP3FolderStatus.hpp b/vmime-master/src/vmime/net/pop3/POP3FolderStatus.hpp
new file mode 100644
index 0000000..0ce413e
--- /dev/null
+++ b/vmime-master/src/vmime/net/pop3/POP3FolderStatus.hpp
@@ -0,0 +1,75 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_POP3_POP3FOLDERSTATUS_HPP_INCLUDED
+#define VMIME_NET_POP3_POP3FOLDERSTATUS_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+
+#include "vmime/net/folderStatus.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace pop3 {
+
+
+/** Holds the status of a POP3 folder.
+ */
+class VMIME_EXPORT POP3FolderStatus : public folderStatus {
+
+public:
+
+ POP3FolderStatus();
+ POP3FolderStatus(const POP3FolderStatus& other);
+
+ // Inherited from folderStatus
+ size_t getMessageCount() const;
+ size_t getUnseenCount() const;
+
+ shared_ptr <folderStatus> clone() const;
+
+
+ void setMessageCount(const size_t count);
+ void setUnseenCount(const size_t unseen);
+
+private:
+
+ size_t m_count;
+ size_t m_unseen;
+};
+
+
+} // pop3
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+#endif // VMIME_NET_POP3_POP3FOLDERSTATUS_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/pop3/POP3Message.cpp b/vmime-master/src/vmime/net/pop3/POP3Message.cpp
new file mode 100644
index 0000000..8d6b7f5
--- /dev/null
+++ b/vmime-master/src/vmime/net/pop3/POP3Message.cpp
@@ -0,0 +1,283 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+
+#include "vmime/net/pop3/POP3Message.hpp"
+#include "vmime/net/pop3/POP3Command.hpp"
+#include "vmime/net/pop3/POP3Response.hpp"
+#include "vmime/net/pop3/POP3Folder.hpp"
+#include "vmime/net/pop3/POP3Store.hpp"
+
+#include "vmime/utility/outputStreamAdapter.hpp"
+#include "vmime/utility/outputStreamStringAdapter.hpp"
+
+#include <sstream>
+
+
+namespace vmime {
+namespace net {
+namespace pop3 {
+
+
+POP3Message::POP3Message(
+ const shared_ptr <POP3Folder>& folder,
+ const size_t num
+)
+ : m_folder(folder),
+ m_num(num),
+ m_size(-1),
+ m_deleted(false) {
+
+ folder->registerMessage(this);
+}
+
+
+POP3Message::~POP3Message() {
+
+ try {
+
+ shared_ptr <POP3Folder> folder = m_folder.lock();
+
+ if (folder) {
+ folder->unregisterMessage(this);
+ }
+
+ } catch (...) {
+
+ // Don't throw in destructor
+ }
+}
+
+
+void POP3Message::onFolderClosed() {
+
+ m_folder.reset();
+}
+
+
+size_t POP3Message::getNumber() const {
+
+ return m_num;
+}
+
+
+const message::uid POP3Message::getUID() const {
+
+ return m_uid;
+}
+
+
+size_t POP3Message::getSize() const {
+
+ if (m_size == static_cast <size_t>(-1)) {
+ throw exceptions::unfetched_object();
+ }
+
+ return m_size;
+}
+
+
+bool POP3Message::isExpunged() const {
+
+ return false;
+}
+
+
+int POP3Message::getFlags() const {
+
+ int flags = 0;
+
+ if (m_deleted) {
+ flags |= FLAG_DELETED;
+ }
+
+ return flags;
+}
+
+
+shared_ptr <const messageStructure> POP3Message::getStructure() const {
+
+ throw exceptions::operation_not_supported();
+}
+
+
+shared_ptr <messageStructure> POP3Message::getStructure() {
+
+ throw exceptions::operation_not_supported();
+}
+
+
+shared_ptr <const header> POP3Message::getHeader() const {
+
+ if (!m_header) {
+ throw exceptions::unfetched_object();
+ }
+
+ return m_header;
+}
+
+
+void POP3Message::extract(
+ utility::outputStream& os,
+ utility::progressListener* progress,
+ const size_t start,
+ const size_t length,
+ const bool /* peek */
+) const {
+
+ shared_ptr <const POP3Folder> folder = m_folder.lock();
+
+ if (!folder) {
+ throw exceptions::illegal_state("Folder closed");
+ } else if (!folder->getStore()) {
+ throw exceptions::illegal_state("Store disconnected");
+ }
+
+ if (start != 0 && length != static_cast <size_t>(-1)) {
+ throw exceptions::partial_fetch_not_supported();
+ }
+
+ // Emit the "RETR" command
+ shared_ptr <POP3Store> store = folder->m_store.lock();
+
+ POP3Command::RETR(m_num)->send(store->getConnection());
+
+ try {
+
+ POP3Response::readLargeResponse(
+ store->getConnection(), os, progress,
+ m_size == static_cast <size_t>(-1) ? 0 : m_size
+ );
+
+ } catch (exceptions::command_error& e) {
+
+ throw exceptions::command_error("RETR", e.response());
+ }
+}
+
+
+void POP3Message::extractPart(
+ const shared_ptr <const messagePart>& /* p */,
+ utility::outputStream& /* os */,
+ utility::progressListener* /* progress */,
+ const size_t /* start */,
+ const size_t /* length */,
+ const bool /* peek */
+) const {
+
+ throw exceptions::operation_not_supported();
+}
+
+
+void POP3Message::fetchPartHeader(const shared_ptr <messagePart>& /* p */) {
+
+ throw exceptions::operation_not_supported();
+}
+
+
+void POP3Message::fetch(
+ const shared_ptr <POP3Folder>& msgFolder,
+ const fetchAttributes& options
+) {
+
+ shared_ptr <POP3Folder> folder = m_folder.lock();
+
+ if (folder != msgFolder) {
+ throw exceptions::folder_not_found();
+ }
+
+ // STRUCTURE and FLAGS attributes are not supported by POP3
+ if (options.has(fetchAttributes::STRUCTURE | fetchAttributes::FLAGS)) {
+ throw exceptions::operation_not_supported();
+ }
+
+ // Check for the real need to fetch the full header
+ static const int optionsRequiringHeader =
+ fetchAttributes::ENVELOPE | fetchAttributes::CONTENT_INFO |
+ fetchAttributes::FULL_HEADER | fetchAttributes::IMPORTANCE;
+
+ if (!options.has(optionsRequiringHeader)) {
+ return;
+ }
+
+ // No need to differenciate between ENVELOPE, CONTENT_INFO, ...
+ // since POP3 only permits to retrieve the whole header and not
+ // fields in particular.
+
+ // Emit the "TOP" command
+ shared_ptr <POP3Store> store = folder->m_store.lock();
+
+ POP3Command::TOP(m_num, 0)->send(store->getConnection());
+
+ try {
+
+ string buffer;
+ utility::outputStreamStringAdapter bufferStream(buffer);
+
+ POP3Response::readLargeResponse(
+ store->getConnection(),
+ bufferStream, /* progress */ NULL, /* predictedSize */ 0
+ );
+
+ m_header = make_shared <header>();
+ m_header->parse(buffer);
+
+ } catch (exceptions::command_error& e) {
+
+ throw exceptions::command_error("TOP", e.response());
+ }
+}
+
+
+void POP3Message::setFlags(const int /* flags */, const int /* mode */) {
+
+ throw exceptions::operation_not_supported();
+}
+
+
+shared_ptr <vmime::message> POP3Message::getParsedMessage() {
+
+ std::ostringstream oss;
+ utility::outputStreamAdapter os(oss);
+
+ extract(os);
+
+ shared_ptr <vmime::message> msg = make_shared <vmime::message>();
+ msg->parse(oss.str());
+
+ return msg;
+}
+
+
+} // pop3
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
diff --git a/vmime-master/src/vmime/net/pop3/POP3Message.hpp b/vmime-master/src/vmime/net/pop3/POP3Message.hpp
new file mode 100644
index 0000000..3d6dc92
--- /dev/null
+++ b/vmime-master/src/vmime/net/pop3/POP3Message.hpp
@@ -0,0 +1,124 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_POP3_POP3MESSAGE_HPP_INCLUDED
+#define VMIME_NET_POP3_POP3MESSAGE_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+
+#include "vmime/net/message.hpp"
+#include "vmime/net/folder.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace pop3 {
+
+
+class POP3Folder;
+
+
+/** POP3 message implementation.
+ */
+class VMIME_EXPORT POP3Message : public message {
+
+private:
+
+ friend class POP3Folder;
+
+ POP3Message(const POP3Message&);
+
+public:
+
+ POP3Message(const shared_ptr <POP3Folder>& folder, const size_t num);
+
+ ~POP3Message();
+
+
+ size_t getNumber() const;
+
+ const uid getUID() const;
+
+ size_t getSize() const;
+
+ bool isExpunged() const;
+
+ shared_ptr <const messageStructure> getStructure() const;
+ shared_ptr <messageStructure> getStructure();
+
+ shared_ptr <const header> getHeader() const;
+
+ int getFlags() const;
+ void setFlags(const int flags, const int mode = FLAG_MODE_SET);
+
+ void extract(
+ utility::outputStream& os,
+ utility::progressListener* progress = NULL,
+ const size_t start = 0,
+ const size_t length = -1,
+ const bool peek = false
+ ) const;
+
+ void extractPart(
+ const shared_ptr <const messagePart>& p,
+ utility::outputStream& os,
+ utility::progressListener* progress = NULL,
+ const size_t start = 0,
+ const size_t length = -1,
+ const bool peek = false
+ ) const;
+
+ void fetchPartHeader(const shared_ptr <messagePart>& p);
+
+ shared_ptr <vmime::message> getParsedMessage();
+
+private:
+
+ void fetch(const shared_ptr <POP3Folder>& folder, const fetchAttributes& options);
+
+ void onFolderClosed();
+
+ weak_ptr <POP3Folder> m_folder;
+ size_t m_num;
+ uid m_uid;
+ size_t m_size;
+
+ bool m_deleted;
+
+ shared_ptr <header> m_header;
+};
+
+
+} // pop3
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+#endif // VMIME_NET_POP3_POP3MESSAGE_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/pop3/POP3Response.cpp b/vmime-master/src/vmime/net/pop3/POP3Response.cpp
new file mode 100644
index 0000000..725841e
--- /dev/null
+++ b/vmime-master/src/vmime/net/pop3/POP3Response.cpp
@@ -0,0 +1,504 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+
+#include "vmime/net/pop3/POP3Response.hpp"
+#include "vmime/net/pop3/POP3Connection.hpp"
+
+#include "vmime/platform.hpp"
+
+#include "vmime/utility/stringUtils.hpp"
+#include "vmime/utility/filteredStream.hpp"
+#include "vmime/utility/stringUtils.hpp"
+#include "vmime/utility/inputStreamSocketAdapter.hpp"
+
+#include "vmime/net/socket.hpp"
+#include "vmime/net/timeoutHandler.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace pop3 {
+
+
+POP3Response::POP3Response(
+ const shared_ptr <socket>& sok,
+ const shared_ptr <timeoutHandler>& toh,
+ const shared_ptr <tracer>& tracer
+)
+ : m_socket(sok),
+ m_timeoutHandler(toh),
+ m_tracer(tracer) {
+
+}
+
+
+// static
+shared_ptr <POP3Response> POP3Response::readResponse(
+ const shared_ptr <POP3Connection>& conn
+) {
+
+ shared_ptr <POP3Response> resp = shared_ptr <POP3Response>(
+ new POP3Response(conn->getSocket(), conn->getTimeoutHandler(), conn->getTracer())
+ );
+
+ string buffer;
+ resp->readResponseImpl(buffer, /* multiLine */ false);
+
+ resp->m_firstLine = buffer;
+ resp->m_code = getResponseCode(buffer);
+ stripResponseCode(buffer, resp->m_text);
+
+ if (resp->m_tracer) {
+ resp->m_tracer->traceReceive(buffer);
+ }
+
+ return resp;
+}
+
+
+// static
+shared_ptr <POP3Response> POP3Response::readMultilineResponse(
+ const shared_ptr <POP3Connection>& conn
+) {
+
+ shared_ptr <POP3Response> resp = shared_ptr <POP3Response>(
+ new POP3Response(conn->getSocket(), conn->getTimeoutHandler(), conn->getTracer())
+ );
+
+ string buffer;
+ resp->readResponseImpl(buffer, /* multiLine */ true);
+
+ string firstLine, nextLines;
+ stripFirstLine(buffer, nextLines, &firstLine);
+
+ resp->m_firstLine = firstLine;
+ resp->m_code = getResponseCode(firstLine);
+ stripResponseCode(firstLine, resp->m_text);
+
+ std::istringstream iss(nextLines);
+ string line;
+
+ if (resp->m_tracer) {
+ resp->m_tracer->traceReceive(firstLine);
+ }
+
+ while (std::getline(iss, line, '\n')) {
+
+ line = utility::stringUtils::trim(line);
+ resp->m_lines.push_back(line);
+
+ if (resp->m_tracer) {
+ resp->m_tracer->traceReceive(line);
+ }
+ }
+
+ if (resp->m_tracer) {
+ resp->m_tracer->traceReceive(".");
+ }
+
+ return resp;
+}
+
+
+// static
+shared_ptr <POP3Response> POP3Response::readLargeResponse(
+ const shared_ptr <POP3Connection>& conn,
+ utility::outputStream& os,
+ utility::progressListener* progress,
+ const size_t predictedSize
+) {
+
+ shared_ptr <POP3Response> resp = shared_ptr <POP3Response>(
+ new POP3Response(conn->getSocket(), conn->getTimeoutHandler(), conn->getTracer())
+ );
+
+ string firstLine;
+ const size_t length = resp->readResponseImpl(firstLine, os, progress, predictedSize);
+
+ resp->m_firstLine = firstLine;
+ resp->m_code = getResponseCode(firstLine);
+ stripResponseCode(firstLine, resp->m_text);
+
+ if (resp->m_tracer) {
+ resp->m_tracer->traceReceive(firstLine);
+ resp->m_tracer->traceReceiveBytes(length - firstLine.length());
+ resp->m_tracer->traceReceive(".");
+ }
+
+ return resp;
+}
+
+
+bool POP3Response::isSuccess() const {
+
+ return m_code == CODE_OK;
+}
+
+
+const string POP3Response::getFirstLine() const {
+
+ return m_firstLine;
+}
+
+
+POP3Response::ResponseCode POP3Response::getCode() const {
+
+ return m_code;
+}
+
+
+const string POP3Response::getText() const {
+
+ return m_text;
+}
+
+
+const string POP3Response::getLineAt(const size_t pos) const {
+
+ return m_lines[pos];
+}
+
+
+size_t POP3Response::getLineCount() const {
+
+ return m_lines.size();
+}
+
+
+void POP3Response::readResponseImpl(string& buffer, const bool multiLine) {
+
+ bool foundTerminator = false;
+
+ if (m_timeoutHandler) {
+ m_timeoutHandler->resetTimeOut();
+ }
+
+ buffer.clear();
+
+ char last1 = '\0', last2 = '\0';
+
+ for ( ; !foundTerminator ; ) {
+
+ // Check whether the time-out delay is elapsed
+ if (m_timeoutHandler && m_timeoutHandler->isTimeOut()) {
+
+ if (!m_timeoutHandler->handleTimeOut()) {
+ throw exceptions::operation_timed_out();
+ }
+
+ m_timeoutHandler->resetTimeOut();
+ }
+
+ // Receive data from the socket
+ string receiveBuffer;
+ m_socket->receive(receiveBuffer);
+
+ if (receiveBuffer.empty()) { // buffer is empty
+
+ if (m_socket->getStatus() & socket::STATUS_WANT_WRITE) {
+ m_socket->waitForWrite();
+ } else {
+ m_socket->waitForRead();
+ }
+
+ continue;
+ }
+
+ // We have received data: reset the time-out counter
+ if (m_timeoutHandler) {
+ m_timeoutHandler->resetTimeOut();
+ }
+
+ // Check for transparent characters: '\n..' becomes '\n.'
+ const char first = receiveBuffer[0];
+
+ if (first == '.' && last2 == '\n' && last1 == '.') {
+
+ receiveBuffer.erase(receiveBuffer.begin());
+
+ } else if (receiveBuffer.length() >= 2 && first == '.' &&
+ receiveBuffer[1] == '.' && last1 == '\n') {
+
+ receiveBuffer.erase(receiveBuffer.begin());
+ }
+
+ for (size_t trans ;
+ string::npos != (trans = receiveBuffer.find("\n..")) ; ) {
+
+ receiveBuffer.replace(trans, 3, "\n.");
+ }
+
+ last1 = receiveBuffer[receiveBuffer.length() - 1];
+ last2 = static_cast <char>((receiveBuffer.length() >= 2) ? receiveBuffer[receiveBuffer.length() - 2] : 0);
+
+ // Append the data to the response buffer
+ buffer += receiveBuffer;
+
+ // Check for terminator string (and strip it if present)
+ foundTerminator = checkTerminator(buffer, multiLine);
+
+ // If there is an error (-ERR) when executing a command that
+ // requires a multi-line response, the error response will
+ // include only one line, so we stop waiting for a multi-line
+ // terminator and check for a "normal" one.
+ if (multiLine &&
+ !foundTerminator &&
+ buffer.length() >= 4 && buffer[0] == '-') {
+
+ foundTerminator = checkTerminator(buffer, false);
+ }
+ }
+}
+
+
+size_t POP3Response::readResponseImpl(
+ string& firstLine,
+ utility::outputStream& os,
+ utility::progressListener* progress,
+ const size_t predictedSize
+) {
+
+ size_t current = 0, total = predictedSize;
+
+ string temp;
+ bool codeDone = false;
+
+ if (progress) {
+ progress->start(total);
+ }
+
+ if (m_timeoutHandler) {
+ m_timeoutHandler->resetTimeOut();
+ }
+
+ utility::inputStreamSocketAdapter sis(*m_socket);
+ utility::stopSequenceFilteredInputStream <5> sfis1(sis, "\r\n.\r\n");
+ utility::stopSequenceFilteredInputStream <3> sfis2(sfis1, "\n.\n");
+ utility::dotFilteredInputStream dfis(sfis2); // "\n.." --> "\n."
+
+ utility::inputStream& is = dfis;
+
+ while (!is.eof()) {
+
+ // Check whether the time-out delay is elapsed
+ if (m_timeoutHandler && m_timeoutHandler->isTimeOut()) {
+
+ if (!m_timeoutHandler->handleTimeOut()) {
+ throw exceptions::operation_timed_out();
+ }
+ }
+
+ // Receive data from the socket
+ byte_t buffer[65536];
+ const size_t read = is.read(buffer, sizeof(buffer));
+
+ if (read == 0) { // buffer is empty
+
+ if (m_socket->getStatus() & socket::STATUS_WANT_WRITE) {
+ m_socket->waitForWrite();
+ } else if (m_socket->getStatus() & socket::STATUS_WANT_READ) {
+ m_socket->waitForRead();
+ } else {
+ // Input stream needs more bytes to continue, but there
+ // is enough data into socket buffer. Do not waitForRead(),
+ // just retry read()ing on the stream.
+ }
+
+ continue;
+ }
+
+ // We have received data: reset the time-out counter
+ if (m_timeoutHandler) {
+ m_timeoutHandler->resetTimeOut();
+ }
+
+ // Notify progress
+ current += read;
+
+ if (progress) {
+ total = std::max(total, current);
+ progress->progress(current, total);
+ }
+
+ // If we don't have extracted the response code yet
+ if (!codeDone) {
+
+ vmime::utility::stringUtils::appendBytesToString(temp, buffer, read);
+
+ string responseData;
+
+ if (stripFirstLine(temp, responseData, &firstLine) == true) {
+
+ if (getResponseCode(firstLine) != CODE_OK) {
+ throw exceptions::command_error("?", firstLine);
+ }
+
+ codeDone = true;
+
+ os.write(responseData.data(), responseData.length());
+ temp.clear();
+
+ continue;
+ }
+
+ } else {
+
+ // Inject the data into the output stream
+ os.write(buffer, read);
+ }
+ }
+
+ if (progress) {
+ progress->stop(total);
+ }
+
+ return current;
+}
+
+
+// static
+bool POP3Response::stripFirstLine(
+ const string& buffer,
+ string& result,
+ string* firstLine
+) {
+
+ const size_t end = buffer.find('\n');
+
+ if (end != string::npos) {
+
+ if (firstLine) {
+ *firstLine = utility::stringUtils::trim(buffer.substr(0, end));
+ }
+
+ result = buffer.substr(end + 1);
+
+ return true;
+
+ } else {
+
+ if (firstLine) {
+ *firstLine = utility::stringUtils::trim(buffer);
+ }
+
+ result = "";
+
+ return false;
+ }
+}
+
+
+// static
+POP3Response::ResponseCode POP3Response::getResponseCode(const string& buffer) {
+
+ if (buffer.length() >= 2) {
+
+ // +[space]
+ if (buffer[0] == '+' &&
+ (buffer[1] == ' ' || buffer[1] == '\t')) {
+
+ return CODE_READY;
+ }
+
+ // +OK
+ if (buffer.length() >= 3) {
+
+ if (buffer[0] == '+' &&
+ (buffer[1] == 'O' || buffer[1] == 'o') &&
+ (buffer[2] == 'K' || buffer[1] == 'k')) {
+
+ return CODE_OK;
+ }
+ }
+ }
+
+ // -ERR or whatever
+ return CODE_ERR;
+}
+
+
+// static
+void POP3Response::stripResponseCode(const string& buffer, string& result) {
+
+ const size_t pos = buffer.find_first_of(" \t");
+
+ if (pos != string::npos) {
+ result = buffer.substr(pos + 1);
+ } else {
+ result = buffer;
+ }
+}
+
+
+// static
+bool POP3Response::checkTerminator(string& buffer, const bool multiLine) {
+
+ // Multi-line response
+ if (multiLine) {
+
+ static const string term1("\r\n.\r\n");
+ static const string term2("\n.\n");
+
+ return checkOneTerminator(buffer, term1) ||
+ checkOneTerminator(buffer, term2);
+
+ // Normal response
+ } else {
+
+ static const string term1("\r\n");
+ static const string term2("\n");
+
+ return checkOneTerminator(buffer, term1) ||
+ checkOneTerminator(buffer, term2);
+ }
+
+ return false;
+}
+
+
+// static
+bool POP3Response::checkOneTerminator(string& buffer, const string& term) {
+
+ if (buffer.length() >= term.length() &&
+ std::equal(buffer.end() - term.length(), buffer.end(), term.begin())) {
+
+ buffer.erase(buffer.end() - term.length(), buffer.end());
+ return true;
+ }
+
+ return false;
+}
+
+
+} // pop3
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
diff --git a/vmime-master/src/vmime/net/pop3/POP3Response.hpp b/vmime-master/src/vmime/net/pop3/POP3Response.hpp
new file mode 100644
index 0000000..69f8d5d
--- /dev/null
+++ b/vmime-master/src/vmime/net/pop3/POP3Response.hpp
@@ -0,0 +1,194 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_SMTP_POP3RESPONSE_HPP_INCLUDED
+#define VMIME_NET_SMTP_POP3RESPONSE_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+
+#include "vmime/object.hpp"
+#include "vmime/base.hpp"
+
+#include "vmime/utility/outputStream.hpp"
+#include "vmime/utility/progressListener.hpp"
+
+#include "vmime/net/socket.hpp"
+#include "vmime/net/tracer.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+class timeoutHandler;
+
+
+namespace pop3 {
+
+
+class POP3Connection;
+
+
+/** A POP3 response, as sent by the server.
+ */
+class VMIME_EXPORT POP3Response : public object {
+
+public:
+
+ /** Possible response codes. */
+ enum ResponseCode {
+ CODE_OK = 0,
+ CODE_READY,
+ CODE_ERR
+ };
+
+
+ /** Receive and parse a POP3 response from the
+ * specified connection.
+ *
+ * @param conn connection from which to read
+ * @return POP3 response
+ * @throws exceptions::operation_timed_out if no data
+ * has been received within the granted time
+ */
+ static shared_ptr <POP3Response> readResponse(const shared_ptr <POP3Connection>& conn);
+
+ /** Receive and parse a multiline POP3 response from
+ * the specified connection.
+ *
+ * @param conn connection from which to read
+ * @return POP3 response
+ * @throws exceptions::operation_timed_out if no data
+ * has been received within the granted time
+ */
+ static shared_ptr <POP3Response> readMultilineResponse(const shared_ptr <POP3Connection>& conn);
+
+ /** Receive and parse a large POP3 response (eg. message data)
+ * from the specified connection.
+ *
+ * @param conn connection from which to read
+ * @param os output stream to which response data will be written
+ * @param progress progress listener (can be NULL)
+ * @param predictedSize estimated size of response data (in bytes)
+ * @return POP3 response
+ * @throws exceptions::operation_timed_out if no data
+ * has been received within the granted time
+ */
+ static shared_ptr <POP3Response> readLargeResponse(
+ const shared_ptr <POP3Connection>& conn,
+ utility::outputStream& os,
+ utility::progressListener* progress,
+ const size_t predictedSize
+ );
+
+
+ /** Returns whether the response is successful ("OK").
+ *
+ * @return true if the response if successful, false otherwise
+ */
+ bool isSuccess() const;
+
+ /** Return the POP3 response code.
+ *
+ * @return response code
+ */
+ ResponseCode getCode() const;
+
+ /** Return the POP3 response text (first line).
+ *
+ * @return response text
+ */
+ const string getText() const;
+
+ /** Return the first POP3 response line.
+ *
+ * @return first response line
+ */
+ const string getFirstLine() const;
+
+ /** Return the response line at the specified position.
+ *
+ * @param pos line index
+ * @return line at the specified index
+ */
+ const string getLineAt(const size_t pos) const;
+
+ /** Return the number of lines in the response.
+ *
+ * @return number of lines in the response
+ */
+ size_t getLineCount() const;
+
+private:
+
+ POP3Response(
+ const shared_ptr <socket>& sok,
+ const shared_ptr <timeoutHandler>& toh,
+ const shared_ptr <tracer>& tracer
+ );
+
+ void readResponseImpl(string& buffer, const bool multiLine);
+
+ size_t readResponseImpl(
+ string& firstLine,
+ utility::outputStream& os,
+ utility::progressListener* progress,
+ const size_t predictedSize
+ );
+
+
+ static bool stripFirstLine(const string& buffer, string& result, string* firstLine);
+
+ static ResponseCode getResponseCode(const string& buffer);
+
+ static void stripResponseCode(const string& buffer, string& result);
+
+ static bool checkTerminator(string& buffer, const bool multiLine);
+ static bool checkOneTerminator(string& buffer, const string& term);
+
+
+ shared_ptr <socket> m_socket;
+ shared_ptr <timeoutHandler> m_timeoutHandler;
+ shared_ptr <tracer> m_tracer;
+
+ string m_firstLine;
+ ResponseCode m_code;
+ string m_text;
+
+ std::vector <string> m_lines;
+};
+
+
+} // pop3
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+#endif // VMIME_NET_SMTP_POP3RESPONSE_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/pop3/POP3SStore.cpp b/vmime-master/src/vmime/net/pop3/POP3SStore.cpp
new file mode 100644
index 0000000..81a50bc
--- /dev/null
+++ b/vmime-master/src/vmime/net/pop3/POP3SStore.cpp
@@ -0,0 +1,82 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+
+#include "vmime/net/pop3/POP3SStore.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace pop3 {
+
+
+POP3SStore::POP3SStore(
+ const shared_ptr <session>& sess,
+ const shared_ptr <security::authenticator>& auth
+)
+ : POP3Store(sess, auth, true) {
+
+}
+
+
+POP3SStore::~POP3SStore() {
+
+}
+
+
+const string POP3SStore::getProtocolName() const {
+
+ return "pop3s";
+}
+
+
+
+// Service infos
+
+POP3ServiceInfos POP3SStore::sm_infos(true);
+
+
+const serviceInfos& POP3SStore::getInfosInstance() {
+
+ return sm_infos;
+}
+
+
+const serviceInfos& POP3SStore::getInfos() const {
+
+ return sm_infos;
+}
+
+
+} // pop3
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
diff --git a/vmime-master/src/vmime/net/pop3/POP3SStore.hpp b/vmime-master/src/vmime/net/pop3/POP3SStore.hpp
new file mode 100644
index 0000000..76a6ee1
--- /dev/null
+++ b/vmime-master/src/vmime/net/pop3/POP3SStore.hpp
@@ -0,0 +1,74 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_POP3_POP3SSTORE_HPP_INCLUDED
+#define VMIME_NET_POP3_POP3SSTORE_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+
+#include "vmime/net/pop3/POP3Store.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace pop3 {
+
+
+/** POP3S store service.
+ */
+class VMIME_EXPORT POP3SStore : public POP3Store {
+
+public:
+
+ POP3SStore(
+ const shared_ptr <session>& sess,
+ const shared_ptr <security::authenticator>& auth
+ );
+
+ ~POP3SStore();
+
+ const string getProtocolName() const;
+
+ static const serviceInfos& getInfosInstance();
+ const serviceInfos& getInfos() const;
+
+private:
+
+ static POP3ServiceInfos sm_infos;
+};
+
+
+} // pop3
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+#endif // VMIME_NET_POP3_POP3SSTORE_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/pop3/POP3ServiceInfos.cpp b/vmime-master/src/vmime/net/pop3/POP3ServiceInfos.cpp
new file mode 100644
index 0000000..4deee74
--- /dev/null
+++ b/vmime-master/src/vmime/net/pop3/POP3ServiceInfos.cpp
@@ -0,0 +1,142 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+
+#include "vmime/net/pop3/POP3ServiceInfos.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace pop3 {
+
+
+POP3ServiceInfos::POP3ServiceInfos(const bool pop3s)
+ : m_pop3s(pop3s) {
+
+}
+
+
+const string POP3ServiceInfos::getPropertyPrefix() const {
+
+ if (m_pop3s) {
+ return "store.pop3s.";
+ } else {
+ return "store.pop3.";
+ }
+}
+
+
+const POP3ServiceInfos::props& POP3ServiceInfos::getProperties() const {
+
+ static props pop3Props = {
+ // POP3-specific options
+ property("options.apop", serviceInfos::property::TYPE_BOOLEAN, "true"),
+ property("options.apop.fallback", serviceInfos::property::TYPE_BOOLEAN, "true"),
+#if VMIME_HAVE_SASL_SUPPORT
+ property("options.sasl", serviceInfos::property::TYPE_BOOLEAN, "true"),
+ property("options.sasl.fallback", serviceInfos::property::TYPE_BOOLEAN, "true"),
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+ // Common properties
+ property(serviceInfos::property::AUTH_USERNAME, serviceInfos::property::FLAG_REQUIRED),
+ property(serviceInfos::property::AUTH_PASSWORD, serviceInfos::property::FLAG_REQUIRED),
+
+#if VMIME_HAVE_TLS_SUPPORT
+ property(serviceInfos::property::CONNECTION_TLS),
+ property(serviceInfos::property::CONNECTION_TLS_REQUIRED),
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+ property(serviceInfos::property::SERVER_ADDRESS, serviceInfos::property::FLAG_REQUIRED),
+ property(serviceInfos::property::SERVER_PORT, "110"),
+ };
+
+ static props pop3sProps = {
+
+ // POP3-specific options
+ property("options.apop", serviceInfos::property::TYPE_BOOLEAN, "true"),
+ property("options.apop.fallback", serviceInfos::property::TYPE_BOOLEAN, "true"),
+#if VMIME_HAVE_SASL_SUPPORT
+ property("options.sasl", serviceInfos::property::TYPE_BOOLEAN, "true"),
+ property("options.sasl.fallback", serviceInfos::property::TYPE_BOOLEAN, "true"),
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+ // Common properties
+ property(serviceInfos::property::AUTH_USERNAME, serviceInfos::property::FLAG_REQUIRED),
+ property(serviceInfos::property::AUTH_PASSWORD, serviceInfos::property::FLAG_REQUIRED),
+
+#if VMIME_HAVE_TLS_SUPPORT
+ property(serviceInfos::property::CONNECTION_TLS),
+ property(serviceInfos::property::CONNECTION_TLS_REQUIRED),
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+ property(serviceInfos::property::SERVER_ADDRESS, serviceInfos::property::FLAG_REQUIRED),
+ property(serviceInfos::property::SERVER_PORT, "995"),
+ };
+
+ return m_pop3s ? pop3sProps : pop3Props;
+}
+
+
+const std::vector <serviceInfos::property> POP3ServiceInfos::getAvailableProperties() const {
+
+ std::vector <property> list;
+ const props& p = getProperties();
+
+ // POP3-specific options
+ list.push_back(p.PROPERTY_OPTIONS_APOP);
+ list.push_back(p.PROPERTY_OPTIONS_APOP_FALLBACK);
+#if VMIME_HAVE_SASL_SUPPORT
+ list.push_back(p.PROPERTY_OPTIONS_SASL);
+ list.push_back(p.PROPERTY_OPTIONS_SASL_FALLBACK);
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+ // Common properties
+ list.push_back(p.PROPERTY_AUTH_USERNAME);
+ list.push_back(p.PROPERTY_AUTH_PASSWORD);
+
+#if VMIME_HAVE_TLS_SUPPORT
+ if (!m_pop3s) {
+ list.push_back(p.PROPERTY_CONNECTION_TLS);
+ list.push_back(p.PROPERTY_CONNECTION_TLS_REQUIRED);
+ }
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+ list.push_back(p.PROPERTY_SERVER_ADDRESS);
+ list.push_back(p.PROPERTY_SERVER_PORT);
+
+ return list;
+}
+
+
+} // pop3
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
diff --git a/vmime-master/src/vmime/net/pop3/POP3ServiceInfos.hpp b/vmime-master/src/vmime/net/pop3/POP3ServiceInfos.hpp
new file mode 100644
index 0000000..590a6be
--- /dev/null
+++ b/vmime-master/src/vmime/net/pop3/POP3ServiceInfos.hpp
@@ -0,0 +1,91 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_POP3_POP3SERVICEINFOS_HPP_INCLUDED
+#define VMIME_NET_POP3_POP3SERVICEINFOS_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+
+#include "vmime/net/serviceInfos.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace pop3 {
+
+
+/** Information about POP3 service.
+ */
+class VMIME_EXPORT POP3ServiceInfos : public serviceInfos {
+
+public:
+
+ POP3ServiceInfos(const bool pop3s);
+
+ struct props {
+ // POP3-specific options
+ serviceInfos::property PROPERTY_OPTIONS_APOP;
+ serviceInfos::property PROPERTY_OPTIONS_APOP_FALLBACK;
+#if VMIME_HAVE_SASL_SUPPORT
+ serviceInfos::property PROPERTY_OPTIONS_SASL;
+ serviceInfos::property PROPERTY_OPTIONS_SASL_FALLBACK;
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+ // Common properties
+ serviceInfos::property PROPERTY_AUTH_USERNAME;
+ serviceInfos::property PROPERTY_AUTH_PASSWORD;
+
+#if VMIME_HAVE_TLS_SUPPORT
+ serviceInfos::property PROPERTY_CONNECTION_TLS;
+ serviceInfos::property PROPERTY_CONNECTION_TLS_REQUIRED;
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+ serviceInfos::property PROPERTY_SERVER_ADDRESS;
+ serviceInfos::property PROPERTY_SERVER_PORT;
+ };
+
+ const props& getProperties() const;
+
+ const string getPropertyPrefix() const;
+ const std::vector <serviceInfos::property> getAvailableProperties() const;
+
+private:
+
+ const bool m_pop3s;
+};
+
+
+} // pop3
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+#endif // VMIME_NET_POP3_POP3SERVICEINFOS_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/pop3/POP3Store.cpp b/vmime-master/src/vmime/net/pop3/POP3Store.cpp
new file mode 100644
index 0000000..b06640f
--- /dev/null
+++ b/vmime-master/src/vmime/net/pop3/POP3Store.cpp
@@ -0,0 +1,262 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+
+#include "vmime/net/pop3/POP3Store.hpp"
+#include "vmime/net/pop3/POP3Folder.hpp"
+#include "vmime/net/pop3/POP3Command.hpp"
+#include "vmime/net/pop3/POP3Response.hpp"
+
+#include "vmime/exception.hpp"
+
+#include <algorithm>
+
+
+namespace vmime {
+namespace net {
+namespace pop3 {
+
+
+POP3Store::POP3Store(
+ const shared_ptr <session>& sess,
+ const shared_ptr <security::authenticator>& auth,
+ const bool secured
+)
+ : store(sess, getInfosInstance(), auth),
+ m_isPOP3S(secured) {
+
+}
+
+
+POP3Store::~POP3Store() {
+
+ try {
+
+ if (isConnected()) {
+ disconnect();
+ }
+
+ } catch (...) {
+
+ // Don't throw in destructor
+ }
+}
+
+
+const string POP3Store::getProtocolName() const {
+
+ return "pop3";
+}
+
+
+shared_ptr <folder> POP3Store::getDefaultFolder() {
+
+ if (!isConnected()) {
+ throw exceptions::illegal_state("Not connected");
+ }
+
+ return shared_ptr <POP3Folder>(
+ new POP3Folder(
+ folder::path(folder::path::component("INBOX")),
+ dynamicCast <POP3Store>(shared_from_this())
+ )
+ );
+}
+
+
+shared_ptr <folder> POP3Store::getRootFolder() {
+
+ if (!isConnected()) {
+ throw exceptions::illegal_state("Not connected");
+ }
+
+ return shared_ptr <POP3Folder>(
+ new POP3Folder(
+ folder::path(),
+ dynamicCast <POP3Store>(shared_from_this())
+ )
+ );
+}
+
+
+shared_ptr <folder> POP3Store::getFolder(const folder::path& path) {
+
+ if (!isConnected()) {
+ throw exceptions::illegal_state("Not connected");
+ }
+
+ return shared_ptr <POP3Folder>(
+ new POP3Folder(
+ path,
+ dynamicCast <POP3Store>(shared_from_this())
+ )
+ );
+}
+
+
+bool POP3Store::isValidFolderName(const folder::path::component& /* name */) const {
+
+ return true;
+}
+
+
+void POP3Store::connect() {
+
+ if (isConnected()) {
+ throw exceptions::already_connected();
+ }
+
+ m_connection = make_shared <POP3Connection>(
+ dynamicCast <POP3Store>(shared_from_this()), getAuthenticator()
+ );
+
+ m_connection->connect();
+}
+
+
+bool POP3Store::isPOP3S() const {
+
+ return m_isPOP3S;
+}
+
+
+bool POP3Store::isConnected() const {
+
+ return m_connection && m_connection->isConnected();
+}
+
+
+bool POP3Store::isSecuredConnection() const {
+
+ if (!m_connection) {
+ return false;
+ }
+
+ return m_connection->isSecuredConnection();
+}
+
+
+shared_ptr <connectionInfos> POP3Store::getConnectionInfos() const {
+
+ if (!m_connection) {
+ return null;
+ }
+
+ return m_connection->getConnectionInfos();
+}
+
+
+shared_ptr <POP3Connection> POP3Store::getConnection() {
+
+ return m_connection;
+}
+
+
+void POP3Store::disconnect() {
+
+ if (!isConnected()) {
+ throw exceptions::not_connected();
+ }
+
+ for (std::list <POP3Folder*>::iterator it = m_folders.begin() ;
+ it != m_folders.end() ; ++it) {
+
+ (*it)->onStoreDisconnected();
+ }
+
+ m_folders.clear();
+
+
+ m_connection->disconnect();
+ m_connection = null;
+}
+
+
+void POP3Store::noop() {
+
+ if (!m_connection) {
+ throw exceptions::not_connected();
+ }
+
+ POP3Command::NOOP()->send(m_connection);
+
+ shared_ptr <POP3Response> response = POP3Response::readResponse(m_connection);
+
+ if (!response->isSuccess()) {
+ throw exceptions::command_error("NOOP", response->getFirstLine());
+ }
+}
+
+
+void POP3Store::registerFolder(POP3Folder* folder) {
+
+ m_folders.push_back(folder);
+}
+
+
+void POP3Store::unregisterFolder(POP3Folder* folder) {
+
+ std::list <POP3Folder*>::iterator it = std::find(m_folders.begin(), m_folders.end(), folder);
+
+ if (it != m_folders.end()) {
+ m_folders.erase(it);
+ }
+}
+
+
+int POP3Store::getCapabilities() const {
+
+ return CAPABILITY_DELETE_MESSAGE;
+}
+
+
+
+// Service infos
+
+POP3ServiceInfos POP3Store::sm_infos(false);
+
+
+const serviceInfos& POP3Store::getInfosInstance() {
+
+ return sm_infos;
+}
+
+
+const serviceInfos& POP3Store::getInfos() const {
+
+ return sm_infos;
+}
+
+
+} // pop3
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
diff --git a/vmime-master/src/vmime/net/pop3/POP3Store.hpp b/vmime-master/src/vmime/net/pop3/POP3Store.hpp
new file mode 100644
index 0000000..140a1ab
--- /dev/null
+++ b/vmime-master/src/vmime/net/pop3/POP3Store.hpp
@@ -0,0 +1,120 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_POP3_POP3STORE_HPP_INCLUDED
+#define VMIME_NET_POP3_POP3STORE_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+
+#include "vmime/net/store.hpp"
+
+#include "vmime/net/pop3/POP3ServiceInfos.hpp"
+#include "vmime/net/pop3/POP3Connection.hpp"
+
+#include "vmime/utility/stream.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace pop3 {
+
+
+class POP3Folder;
+class POP3Command;
+class POP3Response;
+
+
+/** POP3 store service.
+ */
+class VMIME_EXPORT POP3Store : public store {
+
+ friend class POP3Folder;
+ friend class POP3Message;
+
+public:
+
+ POP3Store(
+ const shared_ptr <session>& sess,
+ const shared_ptr <security::authenticator>& auth,
+ const bool secured = false
+ );
+
+ ~POP3Store();
+
+ const string getProtocolName() const;
+
+ shared_ptr <folder> getDefaultFolder();
+ shared_ptr <folder> getRootFolder();
+ shared_ptr <folder> getFolder(const folder::path& path);
+
+ bool isValidFolderName(const folder::path::component& name) const;
+
+ static const serviceInfos& getInfosInstance();
+ const serviceInfos& getInfos() const;
+
+ void connect();
+ bool isConnected() const;
+ void disconnect();
+
+ void noop();
+
+ int getCapabilities() const;
+
+ bool isSecuredConnection() const;
+ shared_ptr <connectionInfos> getConnectionInfos() const;
+ shared_ptr <POP3Connection> getConnection();
+
+ bool isPOP3S() const;
+
+private:
+
+ shared_ptr <POP3Connection> m_connection;
+
+
+ void registerFolder(POP3Folder* folder);
+ void unregisterFolder(POP3Folder* folder);
+
+ std::list <POP3Folder*> m_folders;
+
+
+ const bool m_isPOP3S;
+
+
+ // Service infos
+ static POP3ServiceInfos sm_infos;
+};
+
+
+} // pop3
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+#endif // VMIME_NET_POP3_POP3STORE_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/pop3/POP3Utils.cpp b/vmime-master/src/vmime/net/pop3/POP3Utils.cpp
new file mode 100644
index 0000000..b38161e
--- /dev/null
+++ b/vmime-master/src/vmime/net/pop3/POP3Utils.cpp
@@ -0,0 +1,135 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+
+#include "vmime/net/pop3/POP3Utils.hpp"
+#include "vmime/net/pop3/POP3Response.hpp"
+
+#include <sstream>
+
+
+namespace vmime {
+namespace net {
+namespace pop3 {
+
+
+// static
+void POP3Utils::parseMultiListOrUidlResponse(
+ const shared_ptr <POP3Response>& response,
+ std::map <size_t, string>& result
+) {
+
+ std::map <size_t, string> ids;
+
+ for (size_t i = 0, n = response->getLineCount() ; i < n ; ++i) {
+
+ string line = response->getLineAt(i);
+ string::iterator it = line.begin();
+
+ while (it != line.end() && (*it == ' ' || *it == '\t')) {
+ ++it;
+ }
+
+ if (it != line.end()) {
+
+ size_t number = 0;
+
+ while (it != line.end() && (*it >= '0' && *it <= '9')) {
+ number = (number * 10) + (*it - '0');
+ ++it;
+ }
+
+ while (it != line.end() && !(*it == ' ' || *it == '\t')) ++it;
+ while (it != line.end() && (*it == ' ' || *it == '\t')) ++it;
+
+ if (it != line.end()) {
+ result.insert(std::map <size_t, string>::value_type(number, string(it, line.end())));
+ }
+ }
+ }
+}
+
+
+
+class POP3MessageSetEnumerator : public messageSetEnumerator {
+
+public:
+
+ POP3MessageSetEnumerator(const size_t msgCount)
+ : m_msgCount(msgCount) {
+
+ }
+
+ void enumerateNumberMessageRange(const vmime::net::numberMessageRange& range) {
+
+ size_t last = range.getLast();
+
+ if (last == size_t(-1)) {
+ last = m_msgCount;
+ }
+
+ for (size_t i = range.getFirst() ; i <= last ; ++i) {
+ list.push_back(i);
+ }
+ }
+
+ void enumerateUIDMessageRange(const vmime::net::UIDMessageRange& /* range */) {
+
+ // Not supported
+ }
+
+public:
+
+ std::vector <size_t> list;
+
+private:
+
+ size_t m_msgCount;
+};
+
+
+// static
+const std::vector <size_t> POP3Utils::messageSetToNumberList(
+ const messageSet& msgs,
+ const size_t msgCount
+) {
+
+ POP3MessageSetEnumerator en(msgCount);
+ msgs.enumerate(en);
+
+ return en.list;
+}
+
+
+} // pop3
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
diff --git a/vmime-master/src/vmime/net/pop3/POP3Utils.hpp b/vmime-master/src/vmime/net/pop3/POP3Utils.hpp
new file mode 100644
index 0000000..09d15d5
--- /dev/null
+++ b/vmime-master/src/vmime/net/pop3/POP3Utils.hpp
@@ -0,0 +1,92 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_POP3_POP3UTILS_HPP_INCLUDED
+#define VMIME_NET_POP3_POP3UTILS_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+
+#include <map>
+
+#include "vmime/types.hpp"
+
+#include "vmime/net/messageSet.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace pop3 {
+
+
+class POP3Response;
+
+
+class VMIME_EXPORT POP3Utils {
+
+public:
+
+ /** Parse a response of type ([integer] [string] \n)*.
+ * This is used in LIST or UIDL commands:
+ *
+ * C: UIDL
+ * S: +OK
+ * S: 1 whqtswO00WBw418f9t5JxYwZ
+ * S: 2 QhdPYR:00WBw1Ph7x7
+ * S: .
+ *
+ * @param response raw response string as returned by the server
+ * @param result points to an associative array which maps a message
+ * number to its corresponding data (either UID or size)
+ */
+ static void parseMultiListOrUidlResponse(
+ const shared_ptr <POP3Response>& response,
+ std::map <size_t, string>& result
+ );
+
+ /** Returns a list of message numbers given a message set.
+ *
+ * @param msgs message set
+ * @param msgCount number of messages in folder
+ * @return list of message numbers
+ */
+ static const std::vector <size_t> messageSetToNumberList(
+ const messageSet& msgs,
+ const size_t msgCount
+ );
+};
+
+
+} // pop3
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_POP3
+
+#endif // VMIME_NET_POP3_POP3UTILS_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/pop3/pop3.hpp b/vmime-master/src/vmime/net/pop3/pop3.hpp
new file mode 100644
index 0000000..ced3a97
--- /dev/null
+++ b/vmime-master/src/vmime/net/pop3/pop3.hpp
@@ -0,0 +1,35 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_POP3_POP3_HPP_INCLUDED
+#define VMIME_NET_POP3_POP3_HPP_INCLUDED
+
+
+#include "vmime/net/pop3/POP3Folder.hpp"
+#include "vmime/net/pop3/POP3FolderStatus.hpp"
+#include "vmime/net/pop3/POP3Message.hpp"
+#include "vmime/net/pop3/POP3Store.hpp"
+#include "vmime/net/pop3/POP3SStore.hpp"
+
+
+#endif // VMIME_NET_POP3_POP3_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/securedConnectionInfos.hpp b/vmime-master/src/vmime/net/securedConnectionInfos.hpp
new file mode 100644
index 0000000..6025801
--- /dev/null
+++ b/vmime-master/src/vmime/net/securedConnectionInfos.hpp
@@ -0,0 +1,55 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_SECUREDCONNECTIONINFOS_HPP_INCLUDED
+#define VMIME_NET_SECUREDCONNECTIONINFOS_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/net/connectionInfos.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+/** Information about the secured connection used by a service.
+ */
+class VMIME_EXPORT securedConnectionInfos : public connectionInfos {
+
+};
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+#endif // VMIME_NET_SECUREDCONNECTIONINFOS_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/sendmail/sendmail.hpp b/vmime-master/src/vmime/net/sendmail/sendmail.hpp
new file mode 100644
index 0000000..a8d1412
--- /dev/null
+++ b/vmime-master/src/vmime/net/sendmail/sendmail.hpp
@@ -0,0 +1,31 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_SENDMAIL_SENDMAIL_HPP_INCLUDED
+#define VMIME_NET_SENDMAIL_SENDMAIL_HPP_INCLUDED
+
+
+#include "vmime/net/sendmail/sendmailTransport.hpp"
+
+
+#endif // VMIME_NET_SENDMAIL_SENDMAIL_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/sendmail/sendmailServiceInfos.cpp b/vmime-master/src/vmime/net/sendmail/sendmailServiceInfos.cpp
new file mode 100644
index 0000000..b865446
--- /dev/null
+++ b/vmime-master/src/vmime/net/sendmail/sendmailServiceInfos.cpp
@@ -0,0 +1,77 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SENDMAIL
+
+
+#include "vmime/net/sendmail/sendmailServiceInfos.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace sendmail {
+
+
+sendmailServiceInfos::sendmailServiceInfos() {
+
+}
+
+
+const string sendmailServiceInfos::getPropertyPrefix() const {
+
+ return "transport.sendmail.";
+}
+
+
+const sendmailServiceInfos::props& sendmailServiceInfos::getProperties() const {
+
+ static props sendmailProps = {
+ // Path to sendmail (override default)
+ property("binpath", serviceInfos::property::TYPE_STRING, string(VMIME_SENDMAIL_PATH))
+ };
+
+ return sendmailProps;
+}
+
+
+const std::vector <serviceInfos::property> sendmailServiceInfos::getAvailableProperties() const {
+
+ std::vector <property> list;
+ const props& p = getProperties();
+
+ list.push_back(p.PROPERTY_BINPATH);
+
+ return list;
+}
+
+
+} // sendmail
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SENDMAIL
+
diff --git a/vmime-master/src/vmime/net/sendmail/sendmailServiceInfos.hpp b/vmime-master/src/vmime/net/sendmail/sendmailServiceInfos.hpp
new file mode 100644
index 0000000..bfec2e0
--- /dev/null
+++ b/vmime-master/src/vmime/net/sendmail/sendmailServiceInfos.hpp
@@ -0,0 +1,69 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_SENDMAIL_SENDMAILSERVICEINFOS_HPP_INCLUDED
+#define VMIME_NET_SENDMAIL_SENDMAILSERVICEINFOS_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SENDMAIL
+
+
+#include "vmime/net/serviceInfos.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace sendmail {
+
+
+/** Information about sendmail service.
+ */
+class VMIME_EXPORT sendmailServiceInfos : public serviceInfos {
+
+public:
+
+ sendmailServiceInfos();
+
+ struct props {
+ serviceInfos::property PROPERTY_BINPATH;
+ };
+
+ const props& getProperties() const;
+
+ const string getPropertyPrefix() const;
+ const std::vector <serviceInfos::property> getAvailableProperties() const;
+};
+
+
+} // sendmail
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SENDMAIL
+
+#endif // VMIME_NET_SENDMAIL_SENDMAILSERVICEINFOS_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/sendmail/sendmailTransport.cpp b/vmime-master/src/vmime/net/sendmail/sendmailTransport.cpp
new file mode 100644
index 0000000..7010fd8
--- /dev/null
+++ b/vmime-master/src/vmime/net/sendmail/sendmailTransport.cpp
@@ -0,0 +1,244 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SENDMAIL
+
+
+#include "vmime/net/sendmail/sendmailTransport.hpp"
+
+#include "vmime/exception.hpp"
+#include "vmime/platform.hpp"
+#include "vmime/message.hpp"
+#include "vmime/mailboxList.hpp"
+
+#include "vmime/utility/filteredStream.hpp"
+#include "vmime/utility/childProcess.hpp"
+
+#include "vmime/utility/streamUtils.hpp"
+
+#include "vmime/net/defaultConnectionInfos.hpp"
+
+#include "vmime/config.hpp"
+
+
+// Helpers for service properties
+#define GET_PROPERTY(type, prop) \
+ (getInfos().getPropertyValue <type>(getSession(), \
+ dynamic_cast <const sendmailServiceInfos&>(getInfos()).getProperties().prop))
+#define HAS_PROPERTY(prop) \
+ (getInfos().hasProperty(getSession(), \
+ dynamic_cast <const sendmailServiceInfos&>(getInfos()).getProperties().prop))
+
+
+namespace vmime {
+namespace net {
+namespace sendmail {
+
+
+sendmailTransport::sendmailTransport(
+ const shared_ptr <session>& sess,
+ const shared_ptr <security::authenticator>& auth
+)
+ : transport(sess, getInfosInstance(), auth),
+ m_connected(false) {
+
+}
+
+
+sendmailTransport::~sendmailTransport() {
+
+ try {
+
+ if (isConnected()) {
+ disconnect();
+ }
+
+ } catch (...) {
+
+ // Don't throw in destructor
+ }
+}
+
+
+const string sendmailTransport::getProtocolName() const {
+
+ return "sendmail";
+}
+
+
+void sendmailTransport::connect() {
+
+ if (isConnected()) {
+ throw exceptions::already_connected();
+ }
+
+ // Use the specified path for 'sendmail' or a default one if no path is specified
+ m_sendmailPath = GET_PROPERTY(string, PROPERTY_BINPATH);
+
+ m_connected = true;
+}
+
+
+bool sendmailTransport::isConnected() const {
+
+ return m_connected;
+}
+
+
+bool sendmailTransport::isSecuredConnection() const {
+
+ return false;
+}
+
+
+shared_ptr <connectionInfos> sendmailTransport::getConnectionInfos() const {
+
+ return make_shared <defaultConnectionInfos>("localhost", static_cast <port_t>(0));
+}
+
+
+void sendmailTransport::disconnect() {
+
+ if (!isConnected()) {
+ throw exceptions::not_connected();
+ }
+
+ internalDisconnect();
+}
+
+
+void sendmailTransport::internalDisconnect() {
+
+ m_connected = false;
+}
+
+
+void sendmailTransport::noop() {
+
+ // Do nothing
+}
+
+
+void sendmailTransport::send(
+ const mailbox& expeditor,
+ const mailboxList& recipients,
+ utility::inputStream& is,
+ const size_t size,
+ utility::progressListener* progress,
+ const mailbox& sender,
+ const dsnAttributes& /*dsnAttrs*/
+) {
+
+ // If no recipient/expeditor was found, throw an exception
+ if (recipients.isEmpty()) {
+ throw exceptions::no_recipient();
+ } else if (expeditor.isEmpty()) {
+ throw exceptions::no_expeditor();
+ }
+
+ // Construct the argument list
+ std::vector <string> args;
+
+ args.push_back("-i");
+ args.push_back("-f");
+
+ if (!sender.isEmpty()) {
+ args.push_back(expeditor.getEmail().generate());
+ } else {
+ args.push_back(sender.getEmail().generate());
+ }
+
+ args.push_back("--");
+
+ for (size_t i = 0 ; i < recipients.getMailboxCount() ; ++i) {
+ args.push_back(recipients.getMailboxAt(i)->getEmail().generate());
+ }
+
+ // Call sendmail
+ try {
+ internalSend(args, is, size, progress);
+ } catch (vmime::exception& e) {
+ throw exceptions::command_error("SEND", "", "sendmail failed", e);
+ }
+}
+
+
+void sendmailTransport::internalSend(
+ const std::vector <string>& args,
+ utility::inputStream& is,
+ const size_t size,
+ utility::progressListener* progress
+) {
+
+ const utility::file::path path = vmime::platform::getHandler()->
+ getFileSystemFactory()->stringToPath(m_sendmailPath);
+
+ shared_ptr <utility::childProcess> proc =
+ vmime::platform::getHandler()->getChildProcessFactory()->create(path);
+
+ proc->start(args, utility::childProcess::FLAG_REDIRECT_STDIN);
+
+ // Copy message data from input stream to output pipe
+ utility::outputStream& os = *(proc->getStdIn());
+
+ // Workaround for lame sendmail implementations that
+ // can't handle CRLF eoln sequences: we transform CRLF
+ // sequences into LF characters.
+ utility::CRLFToLFFilteredOutputStream fos(os);
+
+ // TODO: remove 'Bcc:' field from message header
+
+ utility::bufferedStreamCopy(is, fos, size, progress);
+
+ // Wait for sendmail to exit
+ proc->waitForFinish();
+}
+
+
+// Service infos
+
+sendmailServiceInfos sendmailTransport::sm_infos;
+
+
+const serviceInfos& sendmailTransport::getInfosInstance() {
+
+ return sm_infos;
+}
+
+
+const serviceInfos& sendmailTransport::getInfos() const {
+
+ return sm_infos;
+}
+
+
+} // sendmail
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SENDMAIL
+
diff --git a/vmime-master/src/vmime/net/sendmail/sendmailTransport.hpp b/vmime-master/src/vmime/net/sendmail/sendmailTransport.hpp
new file mode 100644
index 0000000..ce2cfe9
--- /dev/null
+++ b/vmime-master/src/vmime/net/sendmail/sendmailTransport.hpp
@@ -0,0 +1,112 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_SENDMAIL_SENDMAILTRANSPORT_HPP_INCLUDED
+#define VMIME_NET_SENDMAIL_SENDMAILTRANSPORT_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SENDMAIL
+
+
+#include "vmime/net/transport.hpp"
+#include "vmime/net/socket.hpp"
+#include "vmime/net/timeoutHandler.hpp"
+
+#include "vmime/net/sendmail/sendmailServiceInfos.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace sendmail {
+
+
+/** Sendmail local transport service.
+ */
+class VMIME_EXPORT sendmailTransport : public transport {
+
+public:
+
+ sendmailTransport(
+ const shared_ptr <session>& sess,
+ const shared_ptr <security::authenticator>& auth
+ );
+
+ ~sendmailTransport();
+
+ const string getProtocolName() const;
+
+ static const serviceInfos& getInfosInstance();
+ const serviceInfos& getInfos() const;
+
+ void connect();
+ bool isConnected() const;
+ void disconnect();
+
+ void noop();
+
+ void send(
+ const mailbox& expeditor,
+ const mailboxList& recipients,
+ utility::inputStream& is,
+ const size_t size,
+ utility::progressListener* progress = NULL,
+ const mailbox& sender = mailbox(),
+ const dsnAttributes& dsnAttrs = dsnAttributes()
+ );
+
+ bool isSecuredConnection() const;
+ shared_ptr <connectionInfos> getConnectionInfos() const;
+
+private:
+
+ void internalDisconnect();
+
+ void internalSend(
+ const std::vector <string>& args,
+ utility::inputStream& is,
+ const size_t size,
+ utility::progressListener* progress
+ );
+
+
+ string m_sendmailPath;
+
+ bool m_connected;
+
+
+ // Service infos
+ static sendmailServiceInfos sm_infos;
+};
+
+
+} // sendmail
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SENDMAIL
+
+#endif // VMIME_NET_SENDMAIL_SENDMAILTRANSPORT_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/service.cpp b/vmime-master/src/vmime/net/service.cpp
new file mode 100644
index 0000000..b43c3e2
--- /dev/null
+++ b/vmime-master/src/vmime/net/service.cpp
@@ -0,0 +1,170 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/net/service.hpp"
+
+#include "vmime/platform.hpp"
+
+#include "vmime/net/defaultTimeoutHandler.hpp"
+
+#if VMIME_HAVE_SASL_SUPPORT
+ #include "vmime/security/sasl/defaultSASLAuthenticator.hpp"
+#else
+ #include "vmime/security/defaultAuthenticator.hpp"
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+#if VMIME_HAVE_TLS_SUPPORT
+ #include "vmime/security/cert/defaultCertificateVerifier.hpp"
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+
+namespace vmime {
+namespace net {
+
+
+service::service(
+ const shared_ptr <session>& sess,
+ const serviceInfos& /* infos */,
+ const shared_ptr <security::authenticator>& auth
+)
+ : m_session(sess),
+ m_auth(auth) {
+
+ if (!auth) {
+
+#if VMIME_HAVE_SASL_SUPPORT
+ m_auth = make_shared <security::sasl::defaultSASLAuthenticator>();
+#else
+ m_auth = make_shared <security::defaultAuthenticator>();
+#endif // VMIME_HAVE_SASL_SUPPORT
+ }
+
+#if VMIME_HAVE_TLS_SUPPORT
+ m_certVerifier = make_shared <security::cert::defaultCertificateVerifier>();
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+ m_socketFactory = platform::getHandler()->getSocketFactory();
+
+ m_toHandlerFactory = make_shared <defaultTimeoutHandlerFactory>();
+}
+
+
+service::~service() {
+
+}
+
+
+shared_ptr <const session> service::getSession() const {
+
+ return m_session;
+}
+
+
+shared_ptr <session> service::getSession() {
+
+ return m_session;
+}
+
+
+shared_ptr <const security::authenticator> service::getAuthenticator() const {
+
+ return m_auth;
+}
+
+
+shared_ptr <security::authenticator> service::getAuthenticator() {
+
+ return m_auth;
+}
+
+
+void service::setAuthenticator(const shared_ptr <security::authenticator>& auth) {
+
+ m_auth = auth;
+}
+
+
+#if VMIME_HAVE_TLS_SUPPORT
+
+void service::setCertificateVerifier(const shared_ptr <security::cert::certificateVerifier>& cv) {
+
+ m_certVerifier = cv;
+}
+
+
+shared_ptr <security::cert::certificateVerifier> service::getCertificateVerifier() {
+
+ return m_certVerifier;
+}
+
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+
+void service::setSocketFactory(const shared_ptr <socketFactory>& sf) {
+
+ m_socketFactory = sf;
+}
+
+
+shared_ptr <socketFactory> service::getSocketFactory() {
+
+ return m_socketFactory;
+}
+
+
+void service::setTracerFactory(const shared_ptr <tracerFactory>& tf) {
+
+ m_tracerFactory = tf;
+}
+
+
+shared_ptr <tracerFactory> service::getTracerFactory() {
+
+ return m_tracerFactory;
+}
+
+
+void service::setTimeoutHandlerFactory(const shared_ptr <timeoutHandlerFactory>& thf) {
+
+ m_toHandlerFactory = thf;
+}
+
+
+shared_ptr <timeoutHandlerFactory> service::getTimeoutHandlerFactory() {
+
+ return m_toHandlerFactory;
+}
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
diff --git a/vmime-master/src/vmime/net/service.hpp b/vmime-master/src/vmime/net/service.hpp
new file mode 100644
index 0000000..a1869de
--- /dev/null
+++ b/vmime-master/src/vmime/net/service.hpp
@@ -0,0 +1,239 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_SERVICE_HPP_INCLUDED
+#define VMIME_NET_SERVICE_HPP_INCLUDED
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/types.hpp"
+
+#include "vmime/net/session.hpp"
+
+#include "vmime/net/serviceInfos.hpp"
+#include "vmime/net/connectionInfos.hpp"
+
+#include "vmime/net/socket.hpp"
+#include "vmime/net/timeoutHandler.hpp"
+#include "vmime/net/tracer.hpp"
+
+#if VMIME_HAVE_TLS_SUPPORT
+ #include "vmime/security/cert/certificateVerifier.hpp"
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+#include "vmime/utility/progressListener.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+/** Base class for messaging services.
+ */
+class VMIME_EXPORT service : public object, public enable_shared_from_this <service> {
+
+protected:
+
+ service(
+ const shared_ptr <session>& sess,
+ const serviceInfos& infos,
+ const shared_ptr <security::authenticator>& auth
+ );
+
+public:
+
+ virtual ~service();
+
+ /** Possible service types. */
+ enum Type {
+ TYPE_STORE = 0, /**< The service is a message store. */
+ TYPE_TRANSPORT /**< The service sends messages. */
+ };
+
+ /** Return the type of service.
+ *
+ * @return type of service
+ */
+ virtual Type getType() const = 0;
+
+ /** Return the protocol name of this service.
+ *
+ * @return protocol name
+ */
+ virtual const string getProtocolName() const = 0;
+
+ /** Return the session object associated with this service instance.
+ *
+ * @return session object
+ */
+ shared_ptr <const session> getSession() const;
+
+ /** Return the session object associated with this service instance.
+ *
+ * @return session object
+ */
+ shared_ptr <session> getSession();
+
+ /** Return information about this service.
+ *
+ * @return information about the service
+ */
+ virtual const serviceInfos& getInfos() const = 0;
+
+ /** Connect to service.
+ */
+ virtual void connect() = 0;
+
+ /** Disconnect from service.
+ */
+ virtual void disconnect() = 0;
+
+ /** Test whether this service is connected.
+ *
+ * @return true if the service is connected, false otherwise
+ */
+ virtual bool isConnected() const = 0;
+
+ /** Do nothing but ensure the server do not disconnect (for
+ * example, this can reset the auto-logout timer on the
+ * server, if one exists).
+ */
+ virtual void noop() = 0;
+
+ /** Return the authenticator object used with this service instance.
+ *
+ * @return authenticator object
+ */
+ shared_ptr <const security::authenticator> getAuthenticator() const;
+
+ /** Return the authenticator object used with this service instance.
+ *
+ * @return authenticator object
+ */
+ shared_ptr <security::authenticator> getAuthenticator();
+
+ /** Set the authenticator object used with this service instance.
+ *
+ * @param auth authenticator object
+ */
+ void setAuthenticator(const shared_ptr <security::authenticator>& auth);
+
+#if VMIME_HAVE_TLS_SUPPORT
+
+ /** Set the object responsible for verifying certificates when
+ * using secured connections (TLS/SSL).
+ */
+ void setCertificateVerifier(const shared_ptr <security::cert::certificateVerifier>& cv);
+
+ /** Get the object responsible for verifying certificates when
+ * using secured connections (TLS/SSL).
+ */
+ shared_ptr <security::cert::certificateVerifier> getCertificateVerifier();
+
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+ /** Set the factory used to create socket objects for this
+ * service.
+ *
+ * @param sf socket factory
+ */
+ void setSocketFactory(const shared_ptr <socketFactory>& sf);
+
+ /** Return the factory used to create socket objects for this
+ * service.
+ *
+ * @return socket factory
+ */
+ shared_ptr <socketFactory> getSocketFactory();
+
+ /** Set the factory used to create timeoutHandler objects for
+ * this service. By default, the defaultTimeoutHandler class
+ * is used. Not all services support timeout handling.
+ *
+ * @param thf timeoutHandler factory
+ */
+ void setTimeoutHandlerFactory(const shared_ptr <timeoutHandlerFactory>& thf);
+
+ /** Return the factory used to create timeoutHandler objects for
+ * this service.
+ *
+ * @return timeoutHandler factory
+ */
+ shared_ptr <timeoutHandlerFactory> getTimeoutHandlerFactory();
+
+
+ void setTracerFactory(const shared_ptr <tracerFactory>& tf);
+
+ shared_ptr <tracerFactory> getTracerFactory();
+
+ /** Set a property for this service (service prefix is added automatically).
+ *
+ * WARNING: this sets the property on the session object, so all service
+ * instances created with the session object will inherit the property.
+ *
+ * @param name property name
+ * @param value property value
+ */
+ template <typename TYPE>
+ void setProperty(const string& name, const TYPE& value) {
+ m_session->getProperties()[getInfos().getPropertyPrefix() + name] = value;
+ }
+
+ /** Check whether the connection is secured.
+ *
+ * @return true if the connection is secured, false otherwise
+ */
+ virtual bool isSecuredConnection() const = 0;
+
+ /** Get information about the connection.
+ *
+ * @return information about the connection
+ */
+ virtual shared_ptr <connectionInfos> getConnectionInfos() const = 0;
+
+private:
+
+ shared_ptr <session> m_session;
+ shared_ptr <security::authenticator> m_auth;
+
+#if VMIME_HAVE_TLS_SUPPORT
+ shared_ptr <security::cert::certificateVerifier> m_certVerifier;
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+ shared_ptr <socketFactory> m_socketFactory;
+ shared_ptr <timeoutHandlerFactory> m_toHandlerFactory;
+ shared_ptr <tracerFactory> m_tracerFactory;
+};
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+#endif // VMIME_NET_SERVICE_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/serviceFactory.cpp b/vmime-master/src/vmime/net/serviceFactory.cpp
new file mode 100644
index 0000000..72b96fe
--- /dev/null
+++ b/vmime-master/src/vmime/net/serviceFactory.cpp
@@ -0,0 +1,157 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/net/serviceFactory.hpp"
+#include "vmime/net/service.hpp"
+
+#include "vmime/exception.hpp"
+
+#include "vmime/net/builtinServices.inl"
+
+
+namespace vmime {
+namespace net {
+
+
+serviceFactory::serviceFactory() {
+
+}
+
+
+serviceFactory::~serviceFactory() {
+
+}
+
+
+shared_ptr <serviceFactory> serviceFactory::getInstance() {
+
+ static serviceFactory instance;
+ return shared_ptr <serviceFactory>(&instance, noop_shared_ptr_deleter <serviceFactory>());
+}
+
+
+shared_ptr <service> serviceFactory::create(
+ const shared_ptr <session>& sess,
+ const string& protocol,
+ const shared_ptr <security::authenticator>& auth
+) {
+
+ shared_ptr <const registeredService> rserv = getServiceByProtocol(protocol);
+
+ if (!rserv) {
+ throw exceptions::no_factory_available("No service is registered for protocol '" + protocol + "'.");
+ }
+
+ return rserv->create(sess, auth);
+}
+
+
+shared_ptr <service> serviceFactory::create(
+ const shared_ptr <session>& sess,
+ const utility::url& u,
+ const shared_ptr <security::authenticator>& auth
+) {
+
+ shared_ptr <service> serv = create(sess, u.getProtocol(), auth);
+
+ sess->getProperties()[serv->getInfos().getPropertyPrefix() + "server.address"] = u.getHost();
+
+ if (u.getPort() != utility::url::UNSPECIFIED_PORT) {
+ sess->getProperties()[serv->getInfos().getPropertyPrefix() + "server.port"] = u.getPort();
+ }
+
+ // Path portion of the URL is used to point a specific folder (empty = root).
+ // In maildir, this is used to point to the root of the message repository.
+ if (!u.getPath().empty()) {
+ sess->getProperties()[serv->getInfos().getPropertyPrefix() + "server.rootpath"] = u.getPath();
+ }
+
+ if (!u.getUsername().empty()) {
+ sess->getProperties()[serv->getInfos().getPropertyPrefix() + "auth.username"] = u.getUsername();
+ sess->getProperties()[serv->getInfos().getPropertyPrefix() + "auth.password"] = u.getPassword();
+ }
+
+ return serv;
+}
+
+
+shared_ptr <const serviceFactory::registeredService> serviceFactory::getServiceByProtocol(const string& protocol) const {
+
+ const string name(utility::stringUtils::toLower(protocol));
+
+ for (std::vector <shared_ptr <registeredService> >::const_iterator it = m_services.begin() ;
+ it != m_services.end() ; ++it) {
+
+ if ((*it)->getName() == name) {
+ return (*it);
+ }
+ }
+
+ return null;
+}
+
+
+size_t serviceFactory::getServiceCount() const {
+
+ return m_services.size();
+}
+
+
+shared_ptr <const serviceFactory::registeredService> serviceFactory::getServiceAt(const size_t pos) const {
+
+ return m_services[pos];
+}
+
+
+const std::vector <shared_ptr <const serviceFactory::registeredService> > serviceFactory::getServiceList() const {
+
+ std::vector <shared_ptr <const registeredService> > res;
+
+ for (std::vector <shared_ptr <registeredService> >::const_iterator it = m_services.begin() ;
+ it != m_services.end() ; ++it) {
+
+ res.push_back(*it);
+ }
+
+ return (res);
+}
+
+
+void serviceFactory::registerService(const shared_ptr <registeredService>& reg) {
+
+ m_services.push_back(reg);
+}
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
diff --git a/vmime-master/src/vmime/net/serviceFactory.hpp b/vmime-master/src/vmime/net/serviceFactory.hpp
new file mode 100644
index 0000000..8911e08
--- /dev/null
+++ b/vmime-master/src/vmime/net/serviceFactory.hpp
@@ -0,0 +1,168 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_SERVICEFACTORY_HPP_INCLUDED
+#define VMIME_NET_SERVICEFACTORY_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include <map>
+
+#include "vmime/types.hpp"
+#include "vmime/base.hpp"
+
+#include "vmime/utility/stringUtils.hpp"
+#include "vmime/utility/url.hpp"
+
+#include "vmime/net/service.hpp"
+#include "vmime/net/serviceInfos.hpp"
+#include "vmime/net/timeoutHandler.hpp"
+
+#include "vmime/security/authenticator.hpp"
+
+#include "vmime/utility/progressListener.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+class session;
+
+
+/** A factory to create 'service' objects for a specified protocol.
+ */
+
+class VMIME_EXPORT serviceFactory {
+
+private:
+
+ serviceFactory();
+ ~serviceFactory();
+
+public:
+
+ static shared_ptr <serviceFactory> getInstance();
+
+ /** Information about a registered service. */
+ class registeredService : public object {
+
+ friend class serviceFactory;
+
+ protected:
+
+ virtual ~registeredService() { }
+
+ public:
+
+ virtual shared_ptr <service> create(
+ const shared_ptr <session>& sess,
+ const shared_ptr <security::authenticator>& auth
+ ) const = 0;
+
+ virtual int getType() const = 0;
+ virtual const string& getName() const = 0;
+ virtual const serviceInfos& getInfos() const = 0;
+ };
+
+
+ /** Register a new service by its protocol name.
+ *
+ * @param reg service registration infos
+ */
+ void registerService(const shared_ptr <registeredService>& reg);
+
+ /** Create a new service instance from a protocol name.
+ *
+ * @param sess session
+ * @param protocol protocol name (eg. "pop3")
+ * @param auth authenticator used to provide credentials (can be NULL if not used)
+ * @return a new service instance for the specified protocol, or NULL if no service
+ * is registered for this protocol
+ */
+ shared_ptr <service> create(
+ const shared_ptr <session>& sess,
+ const string& protocol,
+ const shared_ptr <security::authenticator>& auth = null
+ );
+
+ /** Create a new service instance from a URL.
+ *
+ * @param sess session
+ * @param u full URL with at least protocol and server (you can also specify
+ * port, username and password)
+ * @param auth authenticator used to provide credentials (can be NULL if not used)
+ * @return a new service instance for the specified protocol or NULL if no service
+ * is registered for this protocol
+ */
+ shared_ptr <service> create(
+ const shared_ptr <session>& sess,
+ const utility::url& u,
+ const shared_ptr <security::authenticator>& auth = null
+ );
+
+ /** Return information about a registered protocol.
+ *
+ * @param protocol protocol name
+ * @return information about this protocol, or NULL if no service is registered
+ * for this protocol
+ */
+ shared_ptr <const registeredService> getServiceByProtocol(const string& protocol) const;
+
+ /** Return the number of registered services.
+ *
+ * @return number of registered services
+ */
+ size_t getServiceCount() const;
+
+ /** Return the registered service at the specified position.
+ *
+ * @param pos position of the registered service to return
+ * @return registered service at the specified position
+ */
+ shared_ptr <const registeredService> getServiceAt(const size_t pos) const;
+
+ /** Return a list of all registered services.
+ *
+ * @return list of registered services
+ */
+ const std::vector <shared_ptr <const registeredService> > getServiceList() const;
+
+private:
+
+ std::vector <shared_ptr <registeredService> > m_services;
+};
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+#endif // VMIME_NET_SERVICEFACTORY_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/serviceInfos.cpp b/vmime-master/src/vmime/net/serviceInfos.cpp
new file mode 100644
index 0000000..2c7b044
--- /dev/null
+++ b/vmime-master/src/vmime/net/serviceInfos.cpp
@@ -0,0 +1,198 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/net/serviceInfos.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+// Common properties
+const serviceInfos::property serviceInfos::property::SERVER_ADDRESS(
+ "server.address",
+ serviceInfos::property::TYPE_STRING
+);
+
+const serviceInfos::property serviceInfos::property::SERVER_PORT(
+ "server.port",
+ serviceInfos::property::TYPE_INTEGER
+);
+
+const serviceInfos::property serviceInfos::property::SERVER_ROOTPATH(
+ "server.rootpath",
+ serviceInfos::property::TYPE_STRING
+);
+
+const serviceInfos::property serviceInfos::property::AUTH_USERNAME(
+ "auth.username",
+ serviceInfos::property::TYPE_STRING
+);
+
+const serviceInfos::property serviceInfos::property::AUTH_PASSWORD(
+ "auth.password",
+ serviceInfos::property::TYPE_STRING
+);
+
+const serviceInfos::property serviceInfos::property::AUTH_ACCESS_TOKEN(
+ "auth.accesstoken",
+ serviceInfos::property::TYPE_STRING
+);
+
+#if VMIME_HAVE_TLS_SUPPORT
+
+const serviceInfos::property serviceInfos::property::CONNECTION_TLS(
+ "connection.tls",
+ serviceInfos::property::TYPE_BOOLEAN,
+ "false"
+);
+
+const serviceInfos::property serviceInfos::property::CONNECTION_TLS_REQUIRED(
+ "connection.tls.required",
+ serviceInfos::property::TYPE_BOOLEAN,
+ "false"
+);
+
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+
+
+// serviceInfos
+
+serviceInfos::serviceInfos() {
+
+}
+
+
+serviceInfos::serviceInfos(const serviceInfos&) {
+
+}
+
+
+serviceInfos& serviceInfos::operator=(const serviceInfos&) {
+
+ return *this;
+}
+
+
+serviceInfos::~serviceInfos() {
+
+}
+
+
+bool serviceInfos::hasProperty(const shared_ptr <session>& s, const property& p) const {
+ return s->getProperties().hasProperty(getPropertyPrefix() + p.getName());
+}
+
+
+
+// serviceInfos::property
+
+serviceInfos::property::property(
+ const string& name,
+ const Types type,
+ const string& defaultValue,
+ const int flags
+)
+ : m_name(name),
+ m_defaultValue(defaultValue),
+ m_type(type),
+ m_flags(flags) {
+
+}
+
+
+serviceInfos::property::property(
+ const property& p,
+ const int addFlags,
+ const int removeFlags
+) {
+
+ m_name = p.m_name;
+ m_type = p.m_type;
+ m_defaultValue = p.m_defaultValue;
+ m_flags = (p.m_flags | addFlags) & ~removeFlags;
+}
+
+
+serviceInfos::property::property(
+ const property& p,
+ const string& newDefaultValue,
+ const int addFlags,
+ const int removeFlags
+) {
+
+ m_name = p.m_name;
+ m_type = p.m_type;
+ m_defaultValue = newDefaultValue;
+ m_flags = (p.m_flags | addFlags) & ~removeFlags;
+}
+
+
+serviceInfos::property& serviceInfos::property::operator=(const property& p) {
+
+ m_name = p.m_name;
+ m_type = p.m_type;
+ m_defaultValue = p.m_defaultValue;
+ m_flags = p.m_flags;
+
+ return *this;
+}
+
+
+const string& serviceInfos::property::getName() const {
+
+ return m_name;
+}
+
+
+const string& serviceInfos::property::getDefaultValue() const {
+
+ return m_defaultValue;
+}
+
+
+serviceInfos::property::Types serviceInfos::property::getType() const {
+
+ return m_type;
+}
+
+
+int serviceInfos::property::getFlags() const {
+
+ return m_flags;
+}
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
diff --git a/vmime-master/src/vmime/net/serviceInfos.hpp b/vmime-master/src/vmime/net/serviceInfos.hpp
new file mode 100644
index 0000000..1c4ac99
--- /dev/null
+++ b/vmime-master/src/vmime/net/serviceInfos.hpp
@@ -0,0 +1,263 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_SERVICEINFOS_HPP_INCLUDED
+#define VMIME_NET_SERVICEINFOS_HPP_INCLUDED
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include <vector>
+
+#include "vmime/types.hpp"
+
+#include "vmime/net/session.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+/** Stores information about a messaging service.
+ */
+class VMIME_EXPORT serviceInfos {
+
+ friend class serviceFactory;
+
+protected:
+
+ serviceInfos();
+ serviceInfos(const serviceInfos&);
+
+private:
+
+ serviceInfos& operator=(const serviceInfos&);
+
+public:
+
+ virtual ~serviceInfos();
+
+
+ /** A service property.
+ */
+ class VMIME_EXPORT property {
+
+ public:
+
+ /** The common property 'server.address' which is
+ * the host name or the IP address of the server. */
+ static const property SERVER_ADDRESS;
+
+ /** The common property 'server.port' which is
+ * the port used to connect to the server. */
+ static const property SERVER_PORT;
+
+ /** The common property 'server.rootpath' which is
+ * the full path of the folder on the server (for
+ * maildir, this is the local filesystem directory). */
+ static const property SERVER_ROOTPATH;
+
+ /** The common property 'auth.username' which is the
+ * username used to authenticate with the server. */
+ static const property AUTH_USERNAME;
+
+ /** The common property 'auth.password' which is the
+ * password used to authenticate with the server. */
+ static const property AUTH_PASSWORD;
+
+ /** The common property 'auth.accesstoken' which is the
+ * access token used to authenticate with the server. */
+ static const property AUTH_ACCESS_TOKEN;
+
+#if VMIME_HAVE_TLS_SUPPORT
+
+ /** The common property 'connection.tls': this is used to
+ * start a secured connection if it is supported by the
+ * server (STARTTLS extension).
+ */
+ static const property CONNECTION_TLS;
+
+ /** The common property 'connection.tls.required' should be
+ * set to 'true' to make the connection process fail if the
+ * server can't start a secured connection (no effect if
+ * 'connection.tls' is not set to 'true').
+ */
+ static const property CONNECTION_TLS_REQUIRED;
+
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+
+ /** Value types.
+ */
+ enum Types {
+ TYPE_INTEGER, /*< Integer number. */
+ TYPE_STRING, /*< Character string. */
+ TYPE_BOOLEAN, /*< Boolean (true or false). */
+
+ TYPE_DEFAULT = TYPE_STRING
+ };
+
+ /** Property flags.
+ */
+ enum Flags {
+ FLAG_NONE = 0, /*< No flags. */
+ FLAG_REQUIRED = (1 << 0), /*< The property must be valued. */
+ FLAG_HIDDEN = (1 << 1), /*< The property should not be shown
+ to the user but can be modified. */
+
+ FLAG_DEFAULT = FLAG_NONE /*< Default flags. */
+ };
+
+
+ /** Construct a new property.
+ *
+ * @param name property name
+ * @param type value type
+ * @param defaultValue default value
+ * @param flags property attributes
+ */
+ property(
+ const string& name,
+ const Types type,
+ const string& defaultValue = "",
+ const int flags = FLAG_DEFAULT
+ );
+
+ /** Construct a new property from an existing property.
+ *
+ * @param p source property
+ * @param addFlags flags to add
+ * @param removeFlags flags to remove
+ */
+ property(
+ const property& p,
+ const int addFlags = FLAG_NONE,
+ const int removeFlags = FLAG_NONE
+ );
+
+ /** Construct a new property from an existing property.
+ *
+ * @param p source property
+ * @param newDefaultValue new default value
+ * @param addFlags flags to add
+ * @param removeFlags flags to remove
+ */
+ property(
+ const property& p,
+ const string& newDefaultValue,
+ const int addFlags = FLAG_NONE,
+ const int removeFlags = FLAG_NONE
+ );
+
+ property& operator=(const property& p);
+
+ /** Return the name of the property.
+ *
+ * @return property name
+ */
+ const string& getName() const;
+
+ /** Return the default value of the property or
+ * an empty string if there is no default value.
+ *
+ * @return default value for the property
+ */
+ const string& getDefaultValue() const;
+
+ /** Return the value type of the property.
+ *
+ * @return property value type
+ */
+ Types getType() const;
+
+ /** Return the attributes of the property (see
+ * serviceInfos::property::Types constants).
+ *
+ * @return property attributes
+ */
+ int getFlags() const;
+
+ private:
+
+ string m_name;
+ string m_defaultValue;
+ Types m_type;
+ int m_flags;
+ };
+
+
+ /** Return the property prefix used by this service.
+ * Use this to set/get properties in the session object.
+ *
+ * @return property prefix
+ */
+ virtual const string getPropertyPrefix() const = 0;
+
+ /** Return a list of available properties for this service.
+ *
+ * @return list of properties
+ */
+ virtual const std::vector <property> getAvailableProperties() const = 0;
+
+ /** Helper function to retrieve the value of a property.
+ *
+ * @param s session object
+ * @param p property to retrieve
+ * @throw exceptions::no_such_property if the property does not exist
+ * and has the flag property::FLAG_REQUIRED
+ * @return value of the property
+ */
+ template <typename TYPE>
+ const TYPE getPropertyValue(const shared_ptr <session>& s, const property& p) const {
+
+ if (p.getFlags() & property::FLAG_REQUIRED) {
+ return s->getProperties()[getPropertyPrefix() + p.getName()].template getValue <TYPE>();
+ }
+
+ return s->getProperties().template getProperty <TYPE>(
+ getPropertyPrefix() + p.getName(),
+ propertySet::valueFromString <TYPE>(p.getDefaultValue())
+ );
+ }
+
+ /** Helper function to test if the specified property is set in
+ * the session object.
+ *
+ * @param s session object
+ * @param p property to test
+ * @return true if the property is set, false otherwise
+ */
+ bool hasProperty(const shared_ptr <session>& s, const property& p) const;
+};
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+#endif // VMIME_NET_SERVICEINFOS_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/serviceRegistration.inl b/vmime-master/src/vmime/net/serviceRegistration.inl
new file mode 100644
index 0000000..9365199
--- /dev/null
+++ b/vmime-master/src/vmime/net/serviceRegistration.inl
@@ -0,0 +1,105 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/net/serviceFactory.hpp"
+
+
+#ifndef VMIME_BUILDING_DOC
+
+
+namespace vmime {
+namespace net {
+
+
+template <class S>
+class registeredServiceImpl : public serviceFactory::registeredService {
+
+public:
+
+ registeredServiceImpl(
+ const string& name,
+ const int type
+ )
+ : m_type(type),
+ m_name(name),
+ m_servInfos(S::getInfosInstance()) {
+
+ }
+
+ shared_ptr <service> create(
+ const shared_ptr <session>& sess,
+ const shared_ptr <security::authenticator>& auth
+ ) const {
+
+ return make_shared <S>(sess, auth);
+ }
+
+ const serviceInfos& getInfos() const {
+
+ return m_servInfos;
+ }
+
+ const string& getName() const {
+
+ return m_name;
+ }
+
+ int getType() const {
+
+ return m_type;
+ }
+
+private:
+
+ const int m_type;
+ const string m_name;
+ const serviceInfos& m_servInfos;
+};
+
+
+// Basic service registerer
+template <class S>
+class serviceRegisterer {
+
+public:
+
+ serviceRegisterer(const string& protocol, const service::Type type) {
+
+ serviceFactory::getInstance()->registerService(
+ make_shared <registeredServiceImpl <S> >(protocol, type)
+ );
+ }
+};
+
+
+} // net
+} // vmime
+
+
+#define REGISTER_SERVICE(p_class, p_name, p_type) \
+ vmime::net::serviceRegisterer <vmime::net::p_class> \
+ p_name(#p_name, vmime::net::service::p_type)
+
+
+#endif // VMIME_BUILDING_DOC
+
diff --git a/vmime-master/src/vmime/net/session.cpp b/vmime-master/src/vmime/net/session.cpp
new file mode 100644
index 0000000..d4b13b4
--- /dev/null
+++ b/vmime-master/src/vmime/net/session.cpp
@@ -0,0 +1,188 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/net/session.hpp"
+#include "vmime/net/serviceFactory.hpp"
+
+#include "vmime/net/store.hpp"
+#include "vmime/net/transport.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+session::session() {
+
+#if VMIME_HAVE_TLS_SUPPORT
+ m_tlsProps = make_shared <tls::TLSProperties>();
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+}
+
+
+session::session(const propertySet& props)
+ : m_props(props) {
+
+#if VMIME_HAVE_TLS_SUPPORT
+ m_tlsProps = make_shared <tls::TLSProperties>();
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+}
+
+
+session::~session() {
+
+}
+
+
+// static
+shared_ptr <session> session::create() {
+
+ return shared_ptr <session>(new session());
+}
+
+
+// static
+shared_ptr <session> session::create(const propertySet& props) {
+
+ return shared_ptr <session>(new session(props));
+}
+
+
+shared_ptr <transport> session::getTransport(const shared_ptr <security::authenticator>& auth) {
+
+ return getTransport(m_props["transport.protocol"], auth);
+}
+
+
+shared_ptr <transport> session::getTransport(
+ const string& protocol,
+ const shared_ptr <security::authenticator>& auth
+) {
+
+ shared_ptr <session> sess(dynamicCast <session>(shared_from_this()));
+ shared_ptr <service> sv = serviceFactory::getInstance()->create(sess, protocol, auth);
+
+ if (!sv || sv->getType() != service::TYPE_TRANSPORT) {
+ return null;
+ }
+
+ return dynamicCast <transport>(sv);
+}
+
+
+shared_ptr <transport> session::getTransport(
+ const utility::url& url,
+ const shared_ptr <security::authenticator>& auth
+) {
+
+ shared_ptr <session> sess(dynamicCast <session>(shared_from_this()));
+ shared_ptr <service> sv = serviceFactory::getInstance()->create(sess, url, auth);
+
+ if (!sv || sv->getType() != service::TYPE_TRANSPORT) {
+ return null;
+ }
+
+ return dynamicCast <transport>(sv);
+}
+
+
+shared_ptr <store> session::getStore(const shared_ptr <security::authenticator>& auth) {
+
+ return getStore(m_props["store.protocol"], auth);
+}
+
+
+shared_ptr <store> session::getStore(
+ const string& protocol,
+ const shared_ptr <security::authenticator>& auth
+) {
+
+ shared_ptr <session> sess(dynamicCast <session>(shared_from_this()));
+ shared_ptr <service> sv = serviceFactory::getInstance()->create(sess, protocol, auth);
+
+ if (!sv || sv->getType() != service::TYPE_STORE) {
+ return null;
+ }
+
+ return dynamicCast <store>(sv);
+}
+
+
+shared_ptr <store> session::getStore(
+ const utility::url& url,
+ const shared_ptr <security::authenticator>& auth
+) {
+
+ shared_ptr <session> sess(dynamicCast <session>(shared_from_this()));
+ shared_ptr <service> sv = serviceFactory::getInstance()->create(sess, url, auth);
+
+ if (!sv || sv->getType() != service::TYPE_STORE) {
+ return null;
+ }
+
+ return dynamicCast <store>(sv);
+}
+
+
+const propertySet& session::getProperties() const {
+
+ return m_props;
+}
+
+
+propertySet& session::getProperties() {
+
+ return m_props;
+}
+
+
+#if VMIME_HAVE_TLS_SUPPORT
+
+void session::setTLSProperties(const shared_ptr <tls::TLSProperties>& tlsProps) {
+
+ m_tlsProps = make_shared <tls::TLSProperties>(*tlsProps);
+}
+
+
+shared_ptr <tls::TLSProperties> session::getTLSProperties() const {
+
+ return m_tlsProps;
+}
+
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
diff --git a/vmime-master/src/vmime/net/session.hpp b/vmime-master/src/vmime/net/session.hpp
new file mode 100644
index 0000000..7ccd0be
--- /dev/null
+++ b/vmime-master/src/vmime/net/session.hpp
@@ -0,0 +1,206 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_SESSION_HPP_INCLUDED
+#define VMIME_NET_SESSION_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/security/authenticator.hpp"
+
+#if VMIME_HAVE_TLS_SUPPORT
+# include "vmime/net/tls/TLSProperties.hpp"
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+#include "vmime/utility/url.hpp"
+
+#include "vmime/propertySet.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+class store;
+class transport;
+
+
+/** An object that contains all the information needed
+ * for connection to a service.
+ */
+class VMIME_EXPORT session : public object, public enable_shared_from_this <session> {
+
+public:
+
+ /** Construct a new session.
+ *
+ * @return pointer to a new session
+ */
+ static shared_ptr <session> create();
+
+ /** Construct a new session given properties.
+ *
+ * @param props session properties
+ * @return pointer to a new session
+ */
+ static shared_ptr <session> create(const propertySet& props);
+
+ ~session();
+
+ /** Return a transport service instance for the protocol specified
+ * in the session properties.
+ *
+ * The property "transport.protocol" specify the protocol to use.
+ *
+ * @param auth authenticator object to use for the new transport service. If
+ * NULL, a default one is used. The default authenticator simply return user
+ * credentials by reading the session properties "auth.username" and "auth.password".
+ * @return a new transport service, or NULL if no service is registered for this
+ * protocol or is not a transport protocol
+ */
+ shared_ptr <transport> getTransport(
+ const shared_ptr <security::authenticator>& auth = null
+ );
+
+ /** Return a transport service instance for the specified protocol.
+ *
+ * @param protocol transport protocol to use (eg. "smtp")
+ * @param auth authenticator object to use for the new transport service. If
+ * NULL, a default one is used. The default authenticator simply return user
+ * credentials by reading the session properties "auth.username" and "auth.password".
+ * @return a new transport service, or NULL if no service is registered for this
+ * protocol or is not a transport protocol
+ */
+ shared_ptr <transport> getTransport(
+ const string& protocol,
+ const shared_ptr <security::authenticator>& auth = null
+ );
+
+ /** Return a transport service instance for the specified URL.
+ *
+ * @param url full URL with at least the protocol to use (eg: "smtp://myserver.com/")
+ * @param auth authenticator object to use for the new transport service. If
+ * NULL, a default one is used. The default authenticator simply return user
+ * credentials by reading the session properties "auth.username" and "auth.password".
+ * @return a new transport service, or NULL if no service is registered for this
+ * protocol or is not a transport protocol
+ */
+ shared_ptr <transport> getTransport(
+ const utility::url& url,
+ const shared_ptr <security::authenticator>& auth = null
+ );
+
+ /** Return a transport service instance for the protocol specified
+ * in the session properties.
+ *
+ * The property "store.protocol" specify the protocol to use.
+ *
+ * @param auth authenticator object to use for the new store service. If
+ * NULL, a default one is used. The default authenticator simply return user
+ * credentials by reading the session properties "auth.username" and "auth.password".
+ * @return a new store service, or NULL if no service is registered for this
+ * protocol or is not a store protocol
+ */
+ shared_ptr <store> getStore(
+ const shared_ptr <security::authenticator>& auth = null
+ );
+
+ /** Return a store service instance for the specified protocol.
+ *
+ * @param protocol store protocol to use (eg. "imap")
+ * @param auth authenticator object to use for the new store service. If
+ * NULL, a default one is used. The default authenticator simply return user
+ * credentials by reading the session properties "auth.username" and "auth.password".
+ * @return a new store service, or NULL if no service is registered for this
+ * protocol or is not a store protocol
+ */
+ shared_ptr <store> getStore(
+ const string& protocol,
+ const shared_ptr <security::authenticator>& auth = null
+ );
+
+ /** Return a store service instance for the specified URL.
+ *
+ * @param url full URL with at least the protocol to use (eg: "imap://username:password@myserver.com/")
+ * @param auth authenticator object to use for the new store service. If
+ * NULL, a default one is used. The default authenticator simply return user
+ * credentials by reading the session properties "auth.username" and "auth.password".
+ * @return a new store service, or NULL if no service is registered for this
+ * protocol or is not a store protocol
+ */
+ shared_ptr <store> getStore(
+ const utility::url& url,
+ const shared_ptr <security::authenticator>& auth = null
+ );
+
+ /** Properties for the session and for the services.
+ */
+ const propertySet& getProperties() const;
+
+ /** Properties for the session and for the services.
+ */
+ propertySet& getProperties();
+
+#if VMIME_HAVE_TLS_SUPPORT
+
+ /** Set properties for SSL/TLS secured connections in this session.
+ *
+ * @param tlsProps SSL/TLS properties
+ */
+ void setTLSProperties(const shared_ptr <tls::TLSProperties>& tlsProps);
+
+ /** Get properties for SSL/TLS secured connections in this session.
+ *
+ * @return SSL/TLS properties
+ */
+ shared_ptr <tls::TLSProperties> getTLSProperties() const;
+
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+private:
+
+ session();
+ session(const propertySet& props);
+
+
+ propertySet m_props;
+
+#if VMIME_HAVE_TLS_SUPPORT
+ shared_ptr <tls::TLSProperties> m_tlsProps;
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+};
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+#endif // VMIME_NET_SESSION_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/smtp/SMTPChunkingOutputStreamAdapter.cpp b/vmime-master/src/vmime/net/smtp/SMTPChunkingOutputStreamAdapter.cpp
new file mode 100644
index 0000000..3b242d1
--- /dev/null
+++ b/vmime-master/src/vmime/net/smtp/SMTPChunkingOutputStreamAdapter.cpp
@@ -0,0 +1,180 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+
+#include "vmime/net/smtp/SMTPChunkingOutputStreamAdapter.hpp"
+
+#include "vmime/net/smtp/SMTPConnection.hpp"
+#include "vmime/net/smtp/SMTPTransport.hpp"
+
+#include <algorithm>
+
+
+namespace vmime {
+namespace net {
+namespace smtp {
+
+
+SMTPChunkingOutputStreamAdapter::SMTPChunkingOutputStreamAdapter(
+ const shared_ptr <SMTPConnection>& conn,
+ const size_t size,
+ utility::progressListener* progress
+)
+ : m_connection(conn),
+ m_bufferSize(0),
+ m_chunkCount(0),
+ m_totalSize(size),
+ m_totalSent(0),
+ m_progress(progress) {
+
+ if (progress) {
+ progress->start(size);
+ }
+}
+
+
+void SMTPChunkingOutputStreamAdapter::sendChunk(
+ const byte_t* const data,
+ const size_t count,
+ const bool last
+) {
+
+ if (count == 0 && !last) {
+ // Nothing to send
+ return;
+ }
+
+ // Send this chunk
+ m_connection->sendRequest(SMTPCommand::BDAT(count, last));
+ m_connection->getSocket()->sendRaw(data, count);
+
+ ++m_chunkCount;
+
+ if (m_progress) {
+
+ m_totalSent += count;
+ m_totalSize = std::max(m_totalSize, m_totalSent);
+
+ m_progress->progress(m_totalSent, m_totalSize);
+ }
+
+ if (m_connection->getTracer()) {
+ m_connection->getTracer()->traceSendBytes(count);
+ }
+
+ // If PIPELINING is not supported, read one response for this BDAT command
+ if (!m_connection->hasExtension("PIPELINING")) {
+
+ shared_ptr <SMTPResponse> resp = m_connection->readResponse();
+
+ if (resp->getCode() != 250) {
+ m_connection->getTransport()->disconnect();
+ throw exceptions::command_error("BDAT", resp->getText());
+ }
+
+ // If PIPELINING is supported, read one response for each chunk (ie. number
+ // of BDAT commands issued) after the last chunk has been sent
+ } else if (last) {
+
+ bool invalidReply = false;
+ shared_ptr <SMTPResponse> resp;
+
+ for (unsigned int i = 0 ; i < m_chunkCount ; ++i) {
+
+ resp = m_connection->readResponse();
+
+ if (resp->getCode() != 250) {
+ invalidReply = true;
+ }
+ }
+
+ if (invalidReply) {
+ m_connection->getTransport()->disconnect();
+ throw exceptions::command_error("BDAT", resp->getText());
+ }
+ }
+}
+
+
+void SMTPChunkingOutputStreamAdapter::writeImpl(
+ const byte_t* const data,
+ const size_t count
+) {
+
+ const byte_t* curData = data;
+ size_t curCount = count;
+
+ while (curCount != 0) {
+
+ // Fill the buffer
+ const size_t remaining = sizeof(m_buffer) - m_bufferSize;
+ const size_t bytesToCopy = std::min(remaining, curCount);
+
+ std::copy(curData, curData + bytesToCopy, m_buffer + m_bufferSize);
+
+ m_bufferSize += bytesToCopy;
+ curData += bytesToCopy;
+ curCount -= bytesToCopy;
+
+ // If the buffer is full, send this chunk
+ if (m_bufferSize >= sizeof(m_buffer)) {
+
+ sendChunk(m_buffer, m_bufferSize, /* last */ false);
+ m_bufferSize = 0;
+ }
+ }
+}
+
+
+void SMTPChunkingOutputStreamAdapter::flush() {
+
+ sendChunk(m_buffer, m_bufferSize, /* last */ true);
+ m_bufferSize = 0;
+
+ if (m_progress) {
+ m_progress->stop(m_totalSize);
+ }
+
+ if (m_connection->getTracer()) {
+ m_connection->getTracer()->traceSendBytes(m_bufferSize);
+ }
+}
+
+
+size_t SMTPChunkingOutputStreamAdapter::getBlockSize() {
+
+ return sizeof(m_buffer);
+}
+
+
+} // smtp
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
diff --git a/vmime-master/src/vmime/net/smtp/SMTPChunkingOutputStreamAdapter.hpp b/vmime-master/src/vmime/net/smtp/SMTPChunkingOutputStreamAdapter.hpp
new file mode 100644
index 0000000..4ef466a
--- /dev/null
+++ b/vmime-master/src/vmime/net/smtp/SMTPChunkingOutputStreamAdapter.hpp
@@ -0,0 +1,94 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_SMTP_SMTPCHUNKINGOUTPUTSTREAMADAPTER_HPP_INCLUDED
+#define VMIME_NET_SMTP_SMTPCHUNKINGOUTPUTSTREAMADAPTER_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+
+#include "vmime/utility/outputStream.hpp"
+#include "vmime/utility/progressListener.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace smtp {
+
+
+class SMTPConnection;
+
+
+/** An output stream adapter used with ESMTP CHUNKING extension.
+ */
+class VMIME_EXPORT SMTPChunkingOutputStreamAdapter : public utility::outputStream {
+
+public:
+
+ SMTPChunkingOutputStreamAdapter(
+ const shared_ptr <SMTPConnection>& conn,
+ const size_t size,
+ utility::progressListener* progress
+ );
+
+ void flush();
+
+ size_t getBlockSize();
+
+protected:
+
+ void writeImpl(const byte_t* const data, const size_t count);
+
+private:
+
+ SMTPChunkingOutputStreamAdapter(const SMTPChunkingOutputStreamAdapter&);
+
+
+ void sendChunk(const byte_t* const data, const size_t count, const bool last);
+
+
+ shared_ptr <SMTPConnection> m_connection;
+
+ byte_t m_buffer[262144]; // 256 KB
+ size_t m_bufferSize;
+
+ unsigned int m_chunkCount;
+
+ size_t m_totalSize;
+ size_t m_totalSent;
+ utility::progressListener* m_progress;
+};
+
+
+} // smtp
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+#endif // VMIME_NET_SMTP_SMTPCHUNKINGOUTPUTSTREAMADAPTER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/smtp/SMTPCommand.cpp b/vmime-master/src/vmime/net/smtp/SMTPCommand.cpp
new file mode 100644
index 0000000..5e533d1
--- /dev/null
+++ b/vmime-master/src/vmime/net/smtp/SMTPCommand.cpp
@@ -0,0 +1,258 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+
+#include "vmime/net/smtp/SMTPCommand.hpp"
+
+#include "vmime/net/socket.hpp"
+#include "vmime/net/tracer.hpp"
+
+#include "vmime/mailbox.hpp"
+#include "vmime/utility/outputStreamAdapter.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace smtp {
+
+
+SMTPCommand::SMTPCommand(const string& text, const string& traceText)
+ : m_text(text),
+ m_traceText(traceText)
+{
+}
+
+
+// static
+shared_ptr <SMTPCommand> SMTPCommand::EHLO(const string& hostname) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "EHLO " << hostname;
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <SMTPCommand> SMTPCommand::HELO(const string& hostname) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "HELO " << hostname;
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <SMTPCommand> SMTPCommand::AUTH(const string& mechName) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "AUTH " << mechName;
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <SMTPCommand> SMTPCommand::AUTH(const string& mechName, const std::string& initialResponse) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "AUTH " << mechName << " " << initialResponse;
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <SMTPCommand> SMTPCommand::STARTTLS() {
+
+ return createCommand("STARTTLS");
+}
+
+
+// static
+shared_ptr <SMTPCommand> SMTPCommand::MAIL(const mailbox& mbox, const bool utf8,
+ const std::string& dsnRet, const std::string& dsnEnvelopId) {
+
+ return MAIL(mbox, utf8, 0, dsnRet, dsnEnvelopId);
+}
+
+
+// static
+shared_ptr <SMTPCommand> SMTPCommand::MAIL(const mailbox& mbox, const bool utf8, const size_t size,
+ const std::string& dsnRet, const std::string& dsnEnvelopId) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "MAIL FROM:<";
+
+ if (utf8) {
+
+ cmd << mbox.getEmail().toText().getConvertedText(vmime::charsets::UTF_8);
+
+ } else {
+
+ vmime::utility::outputStreamAdapter cmd2(cmd);
+ mbox.getEmail().generate(cmd2);
+ }
+
+ cmd << ">";
+
+ if (!dsnRet.empty()) {
+ cmd << " " << dsn::RET << "=" << dsnRet;
+ }
+ if (!dsnEnvelopId.empty()) {
+ cmd << " " << dsn::ENVID << "=<" << dsnEnvelopId << ">";
+ }
+
+ if (utf8) {
+ cmd << " SMTPUTF8";
+ }
+
+ if (size != 0) {
+ cmd << " SIZE=" << size;
+ }
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <SMTPCommand> SMTPCommand::RCPT(const mailbox& mbox, const bool utf8,
+ const string& dsnNotify) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "RCPT TO:<";
+
+ if (utf8) {
+
+ cmd << mbox.getEmail().toText().getConvertedText(vmime::charsets::UTF_8);
+
+ } else {
+
+ vmime::utility::outputStreamAdapter cmd2(cmd);
+ mbox.getEmail().generate(cmd2);
+ }
+
+ cmd << ">";
+
+ if (!dsnNotify.empty()) {
+ cmd << " " << dsn::NOTIFY << "=" << dsnNotify;
+ }
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <SMTPCommand> SMTPCommand::RSET() {
+
+ return createCommand("RSET");
+}
+
+
+// static
+shared_ptr <SMTPCommand> SMTPCommand::DATA() {
+
+ return createCommand("DATA");
+}
+
+
+// static
+shared_ptr <SMTPCommand> SMTPCommand::BDAT(const size_t chunkSize, const bool last) {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+ cmd << "BDAT " << chunkSize;
+
+ if (last) {
+ cmd << " LAST";
+ }
+
+ return createCommand(cmd.str());
+}
+
+
+// static
+shared_ptr <SMTPCommand> SMTPCommand::NOOP() {
+
+ return createCommand("NOOP");
+}
+
+
+// static
+shared_ptr <SMTPCommand> SMTPCommand::QUIT() {
+
+ return createCommand("QUIT");
+}
+
+
+// static
+shared_ptr <SMTPCommand> SMTPCommand::createCommand(const string& text, const string& traceText) {
+
+ if (traceText.empty()) {
+ return shared_ptr <SMTPCommand>(new SMTPCommand(text, text));
+ } else {
+ return shared_ptr <SMTPCommand>(new SMTPCommand(text, traceText));
+ }
+}
+
+
+const string SMTPCommand::getText() const {
+
+ return m_text;
+}
+
+
+const string SMTPCommand::getTraceText() const {
+
+ return m_traceText;
+}
+
+
+void SMTPCommand::writeToSocket(const shared_ptr <socket>& sok, shared_ptr <tracer> tr) {
+
+ sok->send(m_text + "\r\n");
+
+ if (tr) {
+ tr->traceSend(m_traceText);
+ }
+}
+
+
+} // smtp
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
diff --git a/vmime-master/src/vmime/net/smtp/SMTPCommand.hpp b/vmime-master/src/vmime/net/smtp/SMTPCommand.hpp
new file mode 100644
index 0000000..9a32d1e
--- /dev/null
+++ b/vmime-master/src/vmime/net/smtp/SMTPCommand.hpp
@@ -0,0 +1,125 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_SMTP_SMTPCOMMAND_HPP_INCLUDED
+#define VMIME_NET_SMTP_SMTPCOMMAND_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+
+#include "vmime/object.hpp"
+#include "vmime/base.hpp"
+
+
+namespace vmime {
+
+
+class mailbox;
+
+
+namespace net {
+
+
+class socket;
+class timeoutHandler;
+class tracer;
+
+
+namespace smtp {
+
+
+/** A SMTP command, as sent to server.
+ */
+class VMIME_EXPORT SMTPCommand : public object {
+
+public:
+
+ static shared_ptr <SMTPCommand> HELO(const string& hostname);
+ static shared_ptr <SMTPCommand> EHLO(const string& hostname);
+ static shared_ptr <SMTPCommand> AUTH(const string& mechName);
+ static shared_ptr <SMTPCommand> AUTH(const string& mechName, const std::string& initialResponse);
+ static shared_ptr <SMTPCommand> STARTTLS();
+ static shared_ptr <SMTPCommand> MAIL(const mailbox& mbox, const bool utf8,
+ const std::string& dsnRet, const std::string& dsnEnvelopId);
+ static shared_ptr <SMTPCommand> MAIL(const mailbox& mbox, const bool utf8, const size_t size,
+ const std::string& dsnRet, const std::string& dsnEnvelopId);
+ static shared_ptr <SMTPCommand> RCPT(const mailbox& mbox, const bool utf8,
+ const std::string& dsnNotify);
+ static shared_ptr <SMTPCommand> RSET();
+ static shared_ptr <SMTPCommand> DATA();
+ static shared_ptr <SMTPCommand> BDAT(const size_t chunkSize, const bool last);
+ static shared_ptr <SMTPCommand> NOOP();
+ static shared_ptr <SMTPCommand> QUIT();
+
+ /** Creates a new SMTP command with the specified text.
+ *
+ * @param text command text
+ * @return a new SMTPCommand object
+ */
+ static shared_ptr <SMTPCommand> createCommand(const string& text, const string& traceText = "");
+
+ /** Sends this command to the specified socket.
+ *
+ * @param sok socket to which the command will be written
+ * @param tr tracer
+ */
+ virtual void writeToSocket(const shared_ptr <socket>& sok, shared_ptr <tracer> tr);
+
+ /** Returns the full text of the command, including command name
+ * and parameters (if any).
+ *
+ * @return command text (eg. "RCPT TO:<vincent@kisli.com>")
+ */
+ virtual const string getText() const;
+
+ /** Returns the full text of the command, suitable for outputing
+ * to the tracer.
+ *
+ * @return trace text (eg. "LOGIN myusername ***")
+ */
+ virtual const string getTraceText() const;
+
+protected:
+
+ SMTPCommand(const string& text, const string& traceText);
+ SMTPCommand(const SMTPCommand&);
+
+private:
+
+ string m_text;
+ string m_traceText;
+};
+
+
+} // smtp
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+#endif // VMIME_NET_SMTP_SMTPCOMMAND_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/smtp/SMTPCommandSet.cpp b/vmime-master/src/vmime/net/smtp/SMTPCommandSet.cpp
new file mode 100644
index 0000000..eab7086
--- /dev/null
+++ b/vmime-master/src/vmime/net/smtp/SMTPCommandSet.cpp
@@ -0,0 +1,160 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+
+#include "vmime/net/smtp/SMTPCommandSet.hpp"
+
+#include "vmime/net/socket.hpp"
+
+#include "vmime/mailbox.hpp"
+
+#include <stdexcept>
+
+
+namespace vmime {
+namespace net {
+namespace smtp {
+
+
+SMTPCommandSet::SMTPCommandSet(const bool pipeline)
+ : SMTPCommand("", ""),
+ m_pipeline(pipeline),
+ m_started(false),
+ m_lastCommandSent() {
+
+}
+
+
+// static
+shared_ptr <SMTPCommandSet> SMTPCommandSet::create(const bool pipeline) {
+
+ return shared_ptr <SMTPCommandSet>(new SMTPCommandSet(pipeline));
+}
+
+
+void SMTPCommandSet::addCommand(const shared_ptr <SMTPCommand>& cmd) {
+
+ if (m_started) {
+ throw std::runtime_error("Could not add command to pipeline: "
+ "one or more commands have already been sent to the server.");
+ }
+
+ m_commands.push_back(cmd);
+}
+
+
+void SMTPCommandSet::writeToSocket(const shared_ptr <socket>& sok, const shared_ptr <tracer>& tr) {
+
+ if (m_pipeline) {
+
+ if (!m_started) {
+
+ // Send all commands at once
+ for (std::list <shared_ptr <SMTPCommand> >::const_iterator it = m_commands.begin() ;
+ it != m_commands.end() ; ++it) {
+
+ shared_ptr <SMTPCommand> cmd = *it;
+ cmd->writeToSocket(sok, tr);
+ }
+ }
+
+ if (!m_commands.empty()) {
+
+ // Advance the pointer to last command sent
+ shared_ptr <SMTPCommand> cmd = m_commands.front();
+ m_commands.pop_front();
+
+ m_lastCommandSent = cmd;
+ }
+
+ } else {
+
+ if (!m_commands.empty()) {
+
+ // Send only one command
+ shared_ptr <SMTPCommand> cmd = m_commands.front();
+ m_commands.pop_front();
+
+ cmd->writeToSocket(sok, tr);
+
+ m_lastCommandSent = cmd;
+ }
+ }
+
+ m_started = true;
+}
+
+
+const string SMTPCommandSet::getText() const {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+
+ for (std::list <shared_ptr <SMTPCommand> >::const_iterator it = m_commands.begin() ;
+ it != m_commands.end() ; ++it) {
+
+ cmd << (*it)->getText() << "\r\n";
+ }
+
+ return cmd.str();
+}
+
+
+const string SMTPCommandSet::getTraceText() const {
+
+ std::ostringstream cmd;
+ cmd.imbue(std::locale::classic());
+
+ for (std::list <shared_ptr <SMTPCommand> >::const_iterator it = m_commands.begin() ;
+ it != m_commands.end() ; ++it) {
+
+ cmd << (*it)->getTraceText() << "\r\n";
+ }
+
+ return cmd.str();
+}
+
+
+bool SMTPCommandSet::isFinished() const {
+
+ return (m_pipeline && m_started) || (m_commands.size() == 0 && m_started);
+}
+
+
+shared_ptr <SMTPCommand> SMTPCommandSet::getLastCommandSent() const {
+
+ return m_lastCommandSent;
+}
+
+
+} // smtp
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
diff --git a/vmime-master/src/vmime/net/smtp/SMTPCommandSet.hpp b/vmime-master/src/vmime/net/smtp/SMTPCommandSet.hpp
new file mode 100644
index 0000000..2fd977c
--- /dev/null
+++ b/vmime-master/src/vmime/net/smtp/SMTPCommandSet.hpp
@@ -0,0 +1,106 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_SMTP_SMTPCOMMANDSET_HPP_INCLUDED
+#define VMIME_NET_SMTP_SMTPCOMMANDSET_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+
+#include <list>
+
+#include "vmime/net/smtp/SMTPCommand.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace smtp {
+
+
+/** A set of SMTP commands, which may be sent all at once
+ * to the server if pipelining is supported.
+ */
+class VMIME_EXPORT SMTPCommandSet : public SMTPCommand {
+
+public:
+
+ /** Creates a new set of SMTP commands.
+ *
+ * @param pipeline set to true if the server supports pipelining
+ * @return a new SMTPCommandSet object
+ */
+ static shared_ptr <SMTPCommandSet> create(const bool pipeline);
+
+ /** Adds a new command to this set.
+ * If one or more comments have already been sent to the server,
+ * an exception will be thrown.
+ *
+ * @param cmd command to add
+ */
+ void addCommand(const shared_ptr <SMTPCommand>& cmd);
+
+ /** Tests whether all commands have been sent.
+ *
+ * @return true if all commands have been sent,
+ * or false otherwise
+ */
+ bool isFinished() const;
+
+ /** Returns the last command which has been sent.
+ *
+ * @return a pointer to a SMTPCommand, of NULL if no command
+ * has been sent yet
+ */
+ shared_ptr <SMTPCommand> getLastCommandSent() const;
+
+
+ void writeToSocket(const shared_ptr <socket>& sok, const shared_ptr <tracer>& tr);
+
+ const string getText() const;
+ const string getTraceText() const;
+
+private:
+
+ SMTPCommandSet(const bool pipeline);
+ SMTPCommandSet(const SMTPCommandSet&);
+
+
+ bool m_pipeline;
+ bool m_started;
+ std::list <shared_ptr <SMTPCommand> > m_commands;
+ shared_ptr <SMTPCommand> m_lastCommandSent;
+};
+
+
+} // smtp
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+#endif // VMIME_NET_SMTP_SMTPCOMMANDSET_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/smtp/SMTPConnection.cpp b/vmime-master/src/vmime/net/smtp/SMTPConnection.cpp
new file mode 100644
index 0000000..07d0376
--- /dev/null
+++ b/vmime-master/src/vmime/net/smtp/SMTPConnection.cpp
@@ -0,0 +1,714 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+
+#include "vmime/net/smtp/SMTPConnection.hpp"
+#include "vmime/net/smtp/SMTPTransport.hpp"
+#include "vmime/net/smtp/SMTPExceptions.hpp"
+
+#include "vmime/exception.hpp"
+#include "vmime/platform.hpp"
+
+#include "vmime/security/digest/messageDigestFactory.hpp"
+
+#include "vmime/net/defaultConnectionInfos.hpp"
+
+#if VMIME_HAVE_SASL_SUPPORT
+ #include "vmime/security/sasl/SASLContext.hpp"
+#else
+ #include "vmime/utility/encoder/b64Encoder.hpp"
+ #include "vmime/utility/inputStreamStringAdapter.hpp"
+ #include "vmime/utility/outputStreamStringAdapter.hpp"
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+#if VMIME_HAVE_TLS_SUPPORT
+ #include "vmime/net/tls/TLSSession.hpp"
+ #include "vmime/net/tls/TLSSecuredConnectionInfos.hpp"
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+
+// Helpers for service properties
+#define GET_PROPERTY(type, prop) \
+ (m_transport.lock()->getInfos().getPropertyValue <type>(getSession(), \
+ dynamic_cast <const SMTPServiceInfos&>(m_transport.lock()->getInfos()).getProperties().prop))
+#define HAS_PROPERTY(prop) \
+ (m_transport.lock()->getInfos().hasProperty(getSession(), \
+ dynamic_cast <const SMTPServiceInfos&>(m_transport.lock()->getInfos()).getProperties().prop))
+
+
+namespace vmime {
+namespace net {
+namespace smtp {
+
+
+
+SMTPConnection::SMTPConnection(
+ const shared_ptr <SMTPTransport>& transport,
+ const shared_ptr <security::authenticator>& auth
+)
+ : m_transport(transport),
+ m_auth(auth),
+ m_socket(null),
+ m_timeoutHandler(null),
+ m_authenticated(false),
+ m_secured(false),
+ m_extendedSMTP(false) {
+
+ static int connectionId = 0;
+
+ if (transport->getTracerFactory()) {
+ m_tracer = transport->getTracerFactory()->create(transport, ++connectionId);
+ }
+}
+
+
+SMTPConnection::~SMTPConnection() {
+
+ try {
+
+ if (isConnected()) {
+ disconnect();
+ } else if (m_socket) {
+ internalDisconnect();
+ }
+
+ } catch (...) {
+
+ // Don't throw in destructor
+ }
+}
+
+
+void SMTPConnection::connect() {
+
+ if (isConnected()) {
+ throw exceptions::already_connected();
+ }
+
+ const string address = GET_PROPERTY(string, PROPERTY_SERVER_ADDRESS);
+ const port_t port = GET_PROPERTY(port_t, PROPERTY_SERVER_PORT);
+
+ shared_ptr <SMTPTransport> transport = m_transport.lock();
+
+ // Create the time-out handler
+ if (transport->getTimeoutHandlerFactory()) {
+ m_timeoutHandler = transport->getTimeoutHandlerFactory()->create();
+ }
+
+ // Create and connect the socket
+ m_socket = transport->getSocketFactory()->create(m_timeoutHandler);
+ m_socket->setTracer(m_tracer);
+
+#if VMIME_HAVE_TLS_SUPPORT
+ if (transport->isSMTPS()) { // dedicated port/SMTPS
+
+ shared_ptr <tls::TLSSession> tlsSession = tls::TLSSession::create(
+ transport->getCertificateVerifier(),
+ transport->getSession()->getTLSProperties()
+ );
+
+ shared_ptr <tls::TLSSocket> tlsSocket = tlsSession->getSocket(m_socket);
+
+ m_socket = tlsSocket;
+
+ m_secured = true;
+ m_cntInfos = make_shared <tls::TLSSecuredConnectionInfos>(address, port, tlsSession, tlsSocket);
+
+ } else
+#endif // VMIME_HAVE_TLS_SUPPORT
+ {
+ m_cntInfos = make_shared <defaultConnectionInfos>(address, port);
+ }
+
+ m_socket->connect(address, port);
+
+ // Connection
+ //
+ // eg: C: <connection to server>
+ // --- S: 220 smtp.domain.com Service ready
+
+ shared_ptr <SMTPResponse> resp;
+
+ if ((resp = readResponse())->getCode() != 220) {
+ internalDisconnect();
+ throw exceptions::connection_greeting_error(resp->getText());
+ }
+
+ // Identification
+ helo();
+
+#if VMIME_HAVE_TLS_SUPPORT
+ // Setup secured connection, if requested
+ const bool tls = HAS_PROPERTY(PROPERTY_CONNECTION_TLS)
+ && GET_PROPERTY(bool, PROPERTY_CONNECTION_TLS);
+ const bool tlsRequired = HAS_PROPERTY(PROPERTY_CONNECTION_TLS_REQUIRED)
+ && GET_PROPERTY(bool, PROPERTY_CONNECTION_TLS_REQUIRED);
+
+ if (!transport->isSMTPS() && tls) { // only if not SMTPS
+
+ try {
+
+ startTLS();
+
+ // Non-fatal error
+ } catch (exceptions::command_error&) {
+
+ if (tlsRequired) {
+ throw;
+ } else {
+ // TLS is not required, so don't bother
+ }
+
+ // Fatal error
+ } catch (...) {
+
+ throw;
+ }
+
+ // Must reissue a EHLO command [RFC-2487, 5.2]
+ helo();
+ }
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+ // Authentication
+ if (GET_PROPERTY(bool, PROPERTY_OPTIONS_NEEDAUTH)) {
+ authenticate();
+ } else {
+ m_authenticated = true;
+ }
+}
+
+
+void SMTPConnection::helo() {
+
+ // First, try Extended SMTP (ESMTP)
+ //
+ // eg: C: EHLO thismachine.ourdomain.com
+ // S: 250-smtp.theserver.com
+ // S: 250-AUTH CRAM-MD5 DIGEST-MD5
+ // S: 250-PIPELINING
+ // S: 250 SIZE 2555555555
+
+ sendRequest(SMTPCommand::EHLO(platform::getHandler()->getHostName()));
+
+ shared_ptr <SMTPResponse> resp;
+
+ if ((resp = readResponse())->getCode() != 250) {
+
+ // Next, try "Basic" SMTP
+ //
+ // eg: C: HELO thismachine.ourdomain.com
+ // S: 250 OK
+
+ sendRequest(SMTPCommand::HELO(platform::getHandler()->getHostName()));
+
+ if ((resp = readResponse())->getCode() != 250) {
+ internalDisconnect();
+ throw exceptions::connection_greeting_error(resp->getLastLine().getText());
+ }
+
+ m_extendedSMTP = false;
+ m_extensions.clear();
+
+ } else {
+
+ m_extendedSMTP = true;
+ m_extensions.clear();
+
+ // Get supported extensions from SMTP response
+ // One extension per line, format is: EXT PARAM1 PARAM2...
+ for (size_t i = 1, n = resp->getLineCount() ; i < n ; ++i) {
+
+ const string line = resp->getLineAt(i).getText();
+
+ std::istringstream iss(line);
+ iss.imbue(std::locale::classic());
+
+ string ext;
+ iss >> ext;
+
+ std::vector <string> params;
+ string param;
+
+ // Special case: some servers send "AUTH=MECH [MECH MECH...]"
+ if (ext.length() >= 5 && utility::stringUtils::toUpper(ext.substr(0, 5)) == "AUTH=") {
+
+ params.push_back(utility::stringUtils::toUpper(ext.substr(5)));
+ ext = "AUTH";
+ }
+
+ while (iss >> param) {
+ params.push_back(utility::stringUtils::toUpper(param));
+ }
+
+ m_extensions[ext] = params;
+ }
+ }
+}
+
+
+bool SMTPConnection::hasExtension(
+ const std::string& extName,
+ std::vector <string>* params
+) const {
+
+ std::map <string, std::vector <string> >::const_iterator
+ it = m_extensions.find(extName);
+
+ if (it != m_extensions.end()) {
+
+ if (params) {
+ *params = (*it).second;
+ }
+
+ return true;
+
+ } else {
+
+ return false;
+ }
+}
+
+
+void SMTPConnection::authenticate() {
+
+ if (!m_extendedSMTP) {
+ internalDisconnect();
+ throw exceptions::command_error("AUTH", "ESMTP not supported.");
+ }
+
+ getAuthenticator()->setService(m_transport.lock());
+
+#if VMIME_HAVE_SASL_SUPPORT
+ // Try SASL authentication
+ if (GET_PROPERTY(bool, PROPERTY_OPTIONS_SASL)) {
+
+ try {
+
+ authenticateSASL();
+
+ m_authenticated = true;
+ return;
+
+ } catch (exception&) {
+
+ internalDisconnect();
+ throw;
+ }
+ }
+#else // no SASL
+
+ // allow AUTH PLAIN over TLS - it is a popular and simple mechanism
+ if (m_secured) {
+
+ std::vector <string> authMechs;
+ hasExtension("AUTH", &authMechs);
+
+ if (authMechs.empty()) {
+ throw exceptions::authentication_error("No AUTH mechanism available.");
+ }
+
+ const string plain("PLAIN");
+
+ if (std::find(authMechs.begin(), authMechs.end(), plain) != authMechs.end()) {
+
+ const string username = getAuthenticator()->getUsername();
+ const string password = getAuthenticator()->getPassword();
+ const string authToken = username + '\0' + username + '\0' + password;
+
+ utility::inputStreamStringAdapter in(authToken);
+ string authTokenBase64;
+ utility::outputStreamStringAdapter out(authTokenBase64);
+
+ vmime::utility::encoder::b64Encoder encoder;
+ encoder.encode(in, out);
+
+ sendRequest(SMTPCommand::AUTH(plain, authTokenBase64));
+
+ shared_ptr <SMTPResponse> response = readResponse();
+
+ const int code = response ? response->getCode() : -1;
+
+ if (code == 235) {
+ m_authenticated = true;
+ return;
+ }
+ }
+ }
+
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+ // No other authentication method is possible
+ throw exceptions::authentication_error("All authentication methods failed");
+}
+
+
+
+#if VMIME_HAVE_SASL_SUPPORT
+
+void SMTPConnection::authenticateSASL() {
+
+ if (!dynamicCast <security::sasl::SASLAuthenticator>(getAuthenticator())) {
+ throw exceptions::authentication_error("No SASL authenticator available.");
+ }
+
+ // Obtain SASL mechanisms supported by server from ESMTP extensions
+ std::vector <string> saslMechs;
+ hasExtension("AUTH", &saslMechs);
+
+ if (saslMechs.empty()) {
+ throw exceptions::authentication_error("No SASL mechanism available.");
+ }
+
+ std::vector <shared_ptr <security::sasl::SASLMechanism> > mechList;
+
+ shared_ptr <security::sasl::SASLContext> saslContext =
+ security::sasl::SASLContext::create();
+
+ for (unsigned int i = 0 ; i < saslMechs.size() ; ++i) {
+
+ try {
+
+ mechList.push_back
+ (saslContext->createMechanism(saslMechs[i]));
+
+ } catch (exceptions::no_such_mechanism&) {
+
+ // Ignore mechanism
+ }
+ }
+
+ if (mechList.empty()) {
+ throw exceptions::authentication_error("No SASL mechanism available.");
+ }
+
+ // Try to suggest a mechanism among all those supported
+ shared_ptr <security::sasl::SASLMechanism> suggestedMech =
+ saslContext->suggestMechanism(mechList);
+
+ if (!suggestedMech) {
+ throw exceptions::authentication_error("Unable to suggest SASL mechanism.");
+ }
+
+ // Allow application to choose which mechanisms to use
+ mechList = dynamicCast <security::sasl::SASLAuthenticator>(getAuthenticator())->
+ getAcceptableMechanisms(mechList, suggestedMech);
+
+ if (mechList.empty()) {
+ throw exceptions::authentication_error("No SASL mechanism available.");
+ }
+
+ // Try each mechanism in the list in turn
+ for (unsigned int i = 0 ; i < mechList.size() ; ++i) {
+
+ shared_ptr <security::sasl::SASLMechanism> mech = mechList[i];
+
+ shared_ptr <security::sasl::SASLSession> saslSession =
+ saslContext->createSession("smtp", getAuthenticator(), mech);
+
+ saslSession->init();
+
+ if (saslSession->getMechanism()->hasInitialResponse()) {
+
+ byte_t* initialResp = 0;
+ size_t initialRespLen = 0;
+
+ saslSession->evaluateChallenge(NULL, 0, &initialResp, &initialRespLen);
+
+ string encodedInitialResp(saslContext->encodeB64(initialResp, initialRespLen));
+ delete [] initialResp;
+
+ if (encodedInitialResp.empty()) {
+ sendRequest(SMTPCommand::AUTH(mech->getName(), "="));
+ } else {
+ sendRequest(SMTPCommand::AUTH(mech->getName(), encodedInitialResp));
+ }
+
+ } else {
+
+ sendRequest(SMTPCommand::AUTH(mech->getName()));
+ }
+
+ for (bool cont = true ; cont ; ) {
+
+ shared_ptr <SMTPResponse> response = readResponse();
+
+ switch (response->getCode()) {
+
+ case 235: {
+
+ m_socket = saslSession->getSecuredSocket(m_socket);
+ return;
+ }
+ case 334: {
+
+ byte_t* challenge = 0;
+ size_t challengeLen = 0;
+
+ byte_t* resp = 0;
+ size_t respLen = 0;
+
+ try {
+
+ // Extract challenge
+ saslContext->decodeB64(response->getText(), &challenge, &challengeLen);
+
+ // Prepare response
+ saslSession->evaluateChallenge(challenge, challengeLen, &resp, &respLen);
+
+ // Send response
+ const string respB64 = saslContext->encodeB64(resp, respLen) + "\r\n";
+ m_socket->sendRaw(utility::stringUtils::bytesFromString(respB64), respB64.length());
+
+ if (m_tracer) {
+ m_tracer->traceSendBytes(respB64.length() - 2, "SASL exchange");
+ }
+
+ } catch (exceptions::sasl_exception& e) {
+
+ if (challenge) {
+ delete [] challenge;
+ challenge = NULL;
+ }
+
+ if (resp) {
+ delete [] resp;
+ resp = NULL;
+ }
+
+ // Cancel SASL exchange
+ m_socket->send("*\r\n");
+
+ if (m_tracer) {
+ m_tracer->traceSend("*");
+ }
+
+ } catch (...) {
+
+ if (challenge) {
+ delete [] challenge;
+ }
+
+ if (resp) {
+ delete [] resp;
+ }
+
+ throw;
+ }
+
+ if (challenge) {
+ delete [] challenge;
+ }
+
+ if (resp) {
+ delete [] resp;
+ }
+
+ break;
+ }
+ default:
+
+ cont = false;
+ break;
+ }
+ }
+ }
+
+ throw exceptions::authentication_error("Could not authenticate using SASL: all mechanisms failed.");
+}
+
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+
+#if VMIME_HAVE_TLS_SUPPORT
+
+void SMTPConnection::startTLS() {
+
+ try {
+
+ sendRequest(SMTPCommand::STARTTLS());
+
+ shared_ptr <SMTPResponse> resp = readResponse();
+
+ if (resp->getCode() != 220) {
+
+ throw SMTPCommandError(
+ "STARTTLS", resp->getText(), resp->getCode(), resp->getEnhancedCode()
+ );
+ }
+
+ shared_ptr <tls::TLSSession> tlsSession = tls::TLSSession::create(
+ getTransport()->getCertificateVerifier(),
+ getTransport()->getSession()->getTLSProperties()
+ );
+
+ shared_ptr <tls::TLSSocket> tlsSocket = tlsSession->getSocket(m_socket);
+
+ tlsSocket->handshake();
+
+ m_socket = tlsSocket;
+
+ m_secured = true;
+ m_cntInfos = make_shared <tls::TLSSecuredConnectionInfos>(
+ m_cntInfos->getHost(), m_cntInfos->getPort(), tlsSession, tlsSocket
+ );
+
+ } catch (exceptions::command_error&) {
+
+ // Non-fatal error
+ throw;
+
+ } catch (exception&) {
+
+ // Fatal error
+ internalDisconnect();
+ throw;
+ }
+}
+
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+
+void SMTPConnection::disconnect() {
+
+ if (!isConnected()) {
+ throw exceptions::not_connected();
+ }
+
+ internalDisconnect();
+}
+
+
+void SMTPConnection::internalDisconnect() {
+
+ if (isConnected()) {
+
+ try {
+
+ sendRequest(SMTPCommand::QUIT());
+
+ // Do not wait for server response. This is contrary to the RFC, but
+ // some servers never send a response to a QUIT command.
+
+ } catch (exception&) {
+
+ // Not important
+ }
+ }
+
+ m_socket->disconnect();
+ m_socket = null;
+
+ m_timeoutHandler = null;
+
+ m_authenticated = false;
+ m_extendedSMTP = false;
+
+ m_secured = false;
+ m_cntInfos = null;
+}
+
+
+void SMTPConnection::sendRequest(const shared_ptr <SMTPCommand>& cmd) {
+
+ cmd->writeToSocket(m_socket, m_tracer);
+}
+
+
+shared_ptr <SMTPResponse> SMTPConnection::readResponse() {
+
+ shared_ptr <SMTPResponse> resp = SMTPResponse::readResponse(
+ m_tracer, m_socket, m_timeoutHandler, m_responseState
+ );
+
+ m_responseState = resp->getCurrentState();
+
+ return resp;
+}
+
+
+bool SMTPConnection::isConnected() const {
+
+ return m_socket && m_socket->isConnected() && m_authenticated;
+}
+
+
+bool SMTPConnection::isSecuredConnection() const {
+
+ return m_secured;
+}
+
+
+shared_ptr <connectionInfos> SMTPConnection::getConnectionInfos() const {
+
+ return m_cntInfos;
+}
+
+
+shared_ptr <SMTPTransport> SMTPConnection::getTransport() {
+
+ return m_transport.lock();
+}
+
+
+shared_ptr <session> SMTPConnection::getSession() {
+
+ return m_transport.lock()->getSession();
+}
+
+
+shared_ptr <socket> SMTPConnection::getSocket() {
+
+ return m_socket;
+}
+
+
+shared_ptr <tracer> SMTPConnection::getTracer() {
+
+ return m_tracer;
+}
+
+
+shared_ptr <timeoutHandler> SMTPConnection::getTimeoutHandler() {
+
+ return m_timeoutHandler;
+}
+
+
+shared_ptr <security::authenticator> SMTPConnection::getAuthenticator() {
+
+ return m_auth;
+}
+
+
+} // smtp
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
diff --git a/vmime-master/src/vmime/net/smtp/SMTPConnection.hpp b/vmime-master/src/vmime/net/smtp/SMTPConnection.hpp
new file mode 100644
index 0000000..d8a2375
--- /dev/null
+++ b/vmime-master/src/vmime/net/smtp/SMTPConnection.hpp
@@ -0,0 +1,136 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_SMTP_SMTPCONNECTION_HPP_INCLUDED
+#define VMIME_NET_SMTP_SMTPCONNECTION_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+
+#include "vmime/messageId.hpp"
+
+#include "vmime/net/socket.hpp"
+#include "vmime/net/timeoutHandler.hpp"
+#include "vmime/net/session.hpp"
+#include "vmime/net/connectionInfos.hpp"
+#include "vmime/net/tracer.hpp"
+
+#include "vmime/net/smtp/SMTPCommand.hpp"
+#include "vmime/net/smtp/SMTPResponse.hpp"
+
+#include "vmime/security/authenticator.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+class socket;
+class timeoutHandler;
+
+
+namespace smtp {
+
+
+class SMTPTransport;
+
+
+/** Manage connection to a SMTP server.
+ */
+class VMIME_EXPORT SMTPConnection : public object {
+
+public:
+
+ SMTPConnection(
+ const shared_ptr <SMTPTransport>& transport,
+ const shared_ptr <security::authenticator>& auth
+ );
+
+ ~SMTPConnection();
+
+
+ virtual void connect();
+ virtual bool isConnected() const;
+ virtual void disconnect();
+
+ bool isSecuredConnection() const;
+ shared_ptr <connectionInfos> getConnectionInfos() const;
+
+ virtual shared_ptr <SMTPTransport> getTransport();
+ virtual shared_ptr <socket> getSocket();
+ virtual shared_ptr <timeoutHandler> getTimeoutHandler();
+ virtual shared_ptr <security::authenticator> getAuthenticator();
+ virtual shared_ptr <session> getSession();
+ virtual shared_ptr <tracer> getTracer();
+
+ void sendRequest(const shared_ptr <SMTPCommand>& cmd);
+ shared_ptr <SMTPResponse> readResponse();
+
+ bool hasExtension(const std::string& extName, std::vector <string>* params = NULL) const;
+
+private:
+
+ void internalDisconnect();
+
+ void helo();
+ void authenticate();
+#if VMIME_HAVE_SASL_SUPPORT
+ void authenticateSASL();
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+#if VMIME_HAVE_TLS_SUPPORT
+ void startTLS();
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+
+ weak_ptr <SMTPTransport> m_transport;
+
+ shared_ptr <security::authenticator> m_auth;
+ shared_ptr <socket> m_socket;
+ shared_ptr <timeoutHandler> m_timeoutHandler;
+ shared_ptr <tracer> m_tracer;
+
+ SMTPResponse::state m_responseState;
+
+ bool m_authenticated;
+ bool m_secured;
+
+ shared_ptr <connectionInfos> m_cntInfos;
+
+ bool m_extendedSMTP;
+ std::map <string, std::vector <string> > m_extensions;
+};
+
+
+} // smtp
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+#endif // VMIME_NET_SMTP_SMTPCONNECTION_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/smtp/SMTPExceptions.cpp b/vmime-master/src/vmime/net/smtp/SMTPExceptions.cpp
new file mode 100644
index 0000000..e3b4652
--- /dev/null
+++ b/vmime-master/src/vmime/net/smtp/SMTPExceptions.cpp
@@ -0,0 +1,212 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+
+#include "vmime/net/smtp/SMTPExceptions.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace smtp {
+
+
+//
+// SMTPCommandError
+//
+
+SMTPCommandError::SMTPCommandError(
+ const string& command,
+ const string& response,
+ const string& desc,
+ const int statusCode,
+ const SMTPResponse::enhancedStatusCode& extendedStatusCode,
+ const exception& other
+)
+ : command_error(command, response, desc, other),
+ m_status(statusCode),
+ m_exStatus(extendedStatusCode) {
+
+}
+
+
+SMTPCommandError::SMTPCommandError(
+ const string& command,
+ const string& response,
+ const int statusCode,
+ const SMTPResponse::enhancedStatusCode& extendedStatusCode,
+ const exception& other
+)
+ : command_error(command, response, "", other),
+ m_status(statusCode),
+ m_exStatus(extendedStatusCode) {
+
+}
+
+
+SMTPCommandError::~SMTPCommandError() throw() {
+
+}
+
+
+int SMTPCommandError::statusCode() const {
+
+ return m_status;
+}
+
+
+const SMTPResponse::enhancedStatusCode SMTPCommandError::extendedStatusCode() const {
+
+ return m_exStatus;
+}
+
+
+exception* SMTPCommandError::clone() const {
+
+ return new SMTPCommandError(*this);
+}
+
+
+const char* SMTPCommandError::name() const throw() {
+
+ return "SMTPCommandError";
+}
+
+
+//
+// SMTPMessageSizeExceedsMaxLimitsException
+//
+
+SMTPMessageSizeExceedsMaxLimitsException::SMTPMessageSizeExceedsMaxLimitsException(const exception& other)
+ : net_exception("Message size exceeds maximum server limits (permanent error).", other) {
+
+}
+
+
+SMTPMessageSizeExceedsMaxLimitsException::~SMTPMessageSizeExceedsMaxLimitsException() throw() {
+
+}
+
+
+exception* SMTPMessageSizeExceedsMaxLimitsException::clone() const {
+
+ return new SMTPMessageSizeExceedsMaxLimitsException(*this);
+}
+
+
+const char* SMTPMessageSizeExceedsMaxLimitsException::name() const throw() {
+
+ return "SMTPMessageSizeExceedsMaxLimitsException";
+}
+
+
+//
+// SMTPMessageSizeExceedsCurLimitsException
+//
+
+SMTPMessageSizeExceedsCurLimitsException::SMTPMessageSizeExceedsCurLimitsException(const exception& other)
+ : net_exception("Message size exceeds current server limits (temporary storage error).", other) {
+
+}
+
+
+SMTPMessageSizeExceedsCurLimitsException::~SMTPMessageSizeExceedsCurLimitsException() throw() {
+
+}
+
+
+exception* SMTPMessageSizeExceedsCurLimitsException::clone() const {
+
+ return new SMTPMessageSizeExceedsCurLimitsException(*this);
+}
+
+
+const char* SMTPMessageSizeExceedsCurLimitsException::name() const throw() {
+
+ return "SMTPMessageSizeExceedsCurLimitsException";
+}
+
+
+//
+// SMTPExtensionNotSupportedException
+//
+
+SMTPExtensionNotSupportedException::SMTPExtensionNotSupportedException(const string &what, const exception& other)
+ : net_exception(what.empty() ? "A required extension is not supported by the SMTP server." : what, other) {
+
+}
+
+
+SMTPExtensionNotSupportedException::~SMTPExtensionNotSupportedException() throw() {
+
+}
+
+
+exception* SMTPExtensionNotSupportedException::clone() const {
+
+ return new SMTPExtensionNotSupportedException(*this);
+}
+
+
+const char* SMTPExtensionNotSupportedException::name() const throw() {
+
+ return "SMTPExtensionNotSupportedException";
+}
+
+
+//
+// SMTPDSNExtensionNotSupportedException
+//
+
+SMTPDSNExtensionNotSupportedException::SMTPDSNExtensionNotSupportedException(const exception& other)
+ : SMTPExtensionNotSupportedException("RFC-1891 DSN extension is not supported by the SMTP server.", other) {
+
+}
+
+
+SMTPDSNExtensionNotSupportedException::~SMTPDSNExtensionNotSupportedException() throw() {
+
+}
+
+
+exception* SMTPDSNExtensionNotSupportedException::clone() const {
+ return new SMTPDSNExtensionNotSupportedException(*this);
+}
+
+
+const char* SMTPDSNExtensionNotSupportedException::name() const throw() {
+
+ return "SMTPDSNExtensionNotSupportedException";
+}
+
+
+} // smtp
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
diff --git a/vmime-master/src/vmime/net/smtp/SMTPExceptions.hpp b/vmime-master/src/vmime/net/smtp/SMTPExceptions.hpp
new file mode 100644
index 0000000..488ee2e
--- /dev/null
+++ b/vmime-master/src/vmime/net/smtp/SMTPExceptions.hpp
@@ -0,0 +1,159 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_SMTP_SMTPEXCEPTIONS_HPP_INCLUDED
+#define VMIME_NET_SMTP_SMTPEXCEPTIONS_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+
+#include "vmime/exception.hpp"
+#include "vmime/base.hpp"
+
+#include "vmime/net/smtp/SMTPResponse.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace smtp {
+
+
+/** SMTP Command error: a SMTP command failed.
+ */
+class VMIME_EXPORT SMTPCommandError : public exceptions::command_error {
+
+public:
+
+ SMTPCommandError(
+ const string& command,
+ const string& response,
+ const string& desc,
+ const int statusCode,
+ const SMTPResponse::enhancedStatusCode& extendedStatusCode,
+ const exception& other = NO_EXCEPTION
+ );
+
+ SMTPCommandError(
+ const string& command,
+ const string& response,
+ const int statusCode, const SMTPResponse::enhancedStatusCode& extendedStatusCode,
+ const exception& other = NO_EXCEPTION
+ );
+
+ ~SMTPCommandError() throw();
+
+ /** Returns the SMTP status code for this error.
+ *
+ * @return status code (protocol-dependent)
+ */
+ int statusCode() const;
+
+ /** Returns the extended status code (following RFC-3463) for this
+ * error, if available.
+ *
+ * @return status code
+ */
+ const SMTPResponse::enhancedStatusCode extendedStatusCode() const;
+
+
+ exception* clone() const;
+ const char* name() const throw();
+
+private:
+
+ int m_status;
+ SMTPResponse::enhancedStatusCode m_exStatus;
+};
+
+
+/** SMTP error: message size exceeds maximum server limits.
+ * This is a permanent error.
+ */
+class VMIME_EXPORT SMTPMessageSizeExceedsMaxLimitsException : public exceptions::net_exception {
+
+public:
+
+ SMTPMessageSizeExceedsMaxLimitsException(const exception& other = NO_EXCEPTION);
+ ~SMTPMessageSizeExceedsMaxLimitsException() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+};
+
+
+/** SMTP error: message size exceeds current server limits.
+ * This is a temporary error (you may retry later).
+ */
+class VMIME_EXPORT SMTPMessageSizeExceedsCurLimitsException : public exceptions::net_exception {
+
+public:
+
+ SMTPMessageSizeExceedsCurLimitsException(const exception& other = NO_EXCEPTION);
+ ~SMTPMessageSizeExceedsCurLimitsException() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+};
+
+
+/** SMTP error: a required extension is not supported by the server.
+ */
+class VMIME_EXPORT SMTPExtensionNotSupportedException : public exceptions::net_exception {
+
+public:
+
+ SMTPExtensionNotSupportedException(const string& what, const exception& other = NO_EXCEPTION);
+ ~SMTPExtensionNotSupportedException() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+};
+
+
+/** SMTP error: RFC-1891 DSN extension is not supported by the server.
+ */
+class VMIME_EXPORT SMTPDSNExtensionNotSupportedException : public SMTPExtensionNotSupportedException {
+
+public:
+
+ SMTPDSNExtensionNotSupportedException(const exception& other = NO_EXCEPTION);
+ ~SMTPDSNExtensionNotSupportedException() throw();
+
+ exception* clone() const;
+ const char* name() const throw();
+};
+
+
+} // smtp
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+#endif // VMIME_NET_SMTP_SMTPEXCEPTIONS_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/smtp/SMTPResponse.cpp b/vmime-master/src/vmime/net/smtp/SMTPResponse.cpp
new file mode 100644
index 0000000..2234705
--- /dev/null
+++ b/vmime-master/src/vmime/net/smtp/SMTPResponse.cpp
@@ -0,0 +1,366 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+
+#include "vmime/net/smtp/SMTPResponse.hpp"
+
+#include "vmime/platform.hpp"
+#include "vmime/utility/stringUtils.hpp"
+
+#include "vmime/net/socket.hpp"
+#include "vmime/net/timeoutHandler.hpp"
+#include "vmime/net/tracer.hpp"
+
+#include <cctype>
+
+
+namespace vmime {
+namespace net {
+namespace smtp {
+
+
+SMTPResponse::SMTPResponse(
+ const shared_ptr <tracer>& tr,
+ const shared_ptr <socket>& sok,
+ const shared_ptr <timeoutHandler>& toh,
+ const state& st
+)
+ : m_socket(sok),
+ m_timeoutHandler(toh),
+ m_tracer(tr),
+ m_responseBuffer(st.responseBuffer),
+ m_responseContinues(false) {
+
+}
+
+
+SMTPResponse::SMTPResponse(const SMTPResponse&)
+ : vmime::object() {
+
+ // Not used
+}
+
+
+int SMTPResponse::getCode() const {
+
+ const int firstCode = m_lines[0].getCode();
+
+ for (unsigned int i = 1 ; i < m_lines.size() ; ++i) {
+
+ // All response codes returned must be equal
+ // or else this in an error...
+ if (m_lines[i].getCode() != firstCode) {
+ return 0;
+ }
+ }
+
+ return firstCode;
+}
+
+
+const SMTPResponse::enhancedStatusCode SMTPResponse::getEnhancedCode() const {
+
+ return m_lines[m_lines.size() - 1].getEnhancedCode();
+}
+
+
+const string SMTPResponse::getText() const {
+
+ string text = m_lines[0].getText();
+
+ for (unsigned int i = 1 ; i < m_lines.size() ; ++i) {
+
+ text += '\n';
+ text += m_lines[i].getText();
+ }
+
+ return text;
+}
+
+
+// static
+shared_ptr <SMTPResponse> SMTPResponse::readResponse(
+ const shared_ptr <tracer>& tr,
+ const shared_ptr <socket>& sok,
+ const shared_ptr <timeoutHandler>& toh,
+ const state& st
+) {
+
+ shared_ptr <SMTPResponse> resp =
+ shared_ptr <SMTPResponse>(new SMTPResponse(tr, sok, toh, st));
+
+ resp->readResponse();
+
+ return resp;
+}
+
+
+void SMTPResponse::readResponse() {
+
+ responseLine line = getNextResponse();
+ m_lines.push_back(line);
+
+ while (m_responseContinues) {
+ line = getNextResponse();
+ m_lines.push_back(line);
+ }
+}
+
+
+const string SMTPResponse::readResponseLine() {
+
+ string currentBuffer = m_responseBuffer;
+
+ if (m_timeoutHandler) {
+ m_timeoutHandler->resetTimeOut();
+ }
+
+ while (true) {
+
+ // Get a line from the response buffer
+ const size_t lineEnd = currentBuffer.find_first_of('\n');
+
+ if (lineEnd != string::npos) {
+
+ size_t actualLineEnd = lineEnd;
+
+ if (actualLineEnd != 0 && currentBuffer[actualLineEnd - 1] == '\r') { // CRLF case
+ actualLineEnd--;
+ }
+
+ const string line(currentBuffer.begin(), currentBuffer.begin() + actualLineEnd);
+
+ currentBuffer.erase(currentBuffer.begin(), currentBuffer.begin() + lineEnd + 1);
+ m_responseBuffer = currentBuffer;
+
+ if (m_tracer) {
+ m_tracer->traceReceive(line);
+ }
+
+ return line;
+ }
+
+ // Check whether the time-out delay is elapsed
+ if (m_timeoutHandler && m_timeoutHandler->isTimeOut()) {
+
+ if (!m_timeoutHandler->handleTimeOut()) {
+ throw exceptions::operation_timed_out();
+ }
+
+ m_timeoutHandler->resetTimeOut();
+ }
+
+ // Receive data from the socket
+ string receiveBuffer;
+ m_socket->receive(receiveBuffer);
+
+ if (receiveBuffer.empty()) { // buffer is empty
+ m_socket->waitForRead();
+ continue;
+ }
+
+ currentBuffer += receiveBuffer;
+ }
+}
+
+
+const SMTPResponse::responseLine SMTPResponse::getNextResponse() {
+
+ string line = readResponseLine();
+
+ const int code = extractResponseCode(line);
+ string text;
+
+ m_responseContinues = (line.length() >= 4 && line[3] == '-');
+
+ if (line.length() > 4) {
+ text = utility::stringUtils::trim(line.substr(4));
+ } else {
+ text = "";
+ }
+
+ return responseLine(code, text, extractEnhancedCode(text));
+}
+
+
+// static
+int SMTPResponse::extractResponseCode(const string& response) {
+
+ int code = 0;
+
+ if (response.length() >= 3) {
+
+ code = (response[0] - '0') * 100
+ + (response[1] - '0') * 10
+ + (response[2] - '0');
+ }
+
+ return code;
+}
+
+
+// static
+const SMTPResponse::enhancedStatusCode SMTPResponse::extractEnhancedCode(const string& responseText) {
+
+ enhancedStatusCode enhCode;
+
+ std::istringstream iss(responseText);
+ iss.imbue(std::locale::classic());
+
+ if (std::isdigit(iss.peek())) {
+
+ iss >> enhCode.klass;
+
+ if (iss.get() == '.' && std::isdigit(iss.peek())) {
+
+ iss >> enhCode.subject;
+
+ if (iss.get() == '.' && std::isdigit(iss.peek())) {
+
+ iss >> enhCode.detail;
+ return enhCode;
+ }
+ }
+ }
+
+ return enhancedStatusCode(); // no enhanced code found
+}
+
+
+const SMTPResponse::responseLine SMTPResponse::getLineAt(const size_t pos) const {
+
+ return m_lines[pos];
+}
+
+
+size_t SMTPResponse::getLineCount() const {
+
+ return m_lines.size();
+}
+
+
+const SMTPResponse::responseLine SMTPResponse::getLastLine() const {
+
+ return m_lines[m_lines.size() - 1];
+}
+
+
+const SMTPResponse::state SMTPResponse::getCurrentState() const {
+
+ state st;
+ st.responseBuffer = m_responseBuffer;
+
+ return st;
+}
+
+
+
+// SMTPResponse::responseLine
+
+SMTPResponse::responseLine::responseLine(
+ const int code,
+ const string& text,
+ const enhancedStatusCode& enhCode
+)
+ : m_code(code),
+ m_text(text),
+ m_enhCode(enhCode) {
+
+}
+
+
+void SMTPResponse::responseLine::setCode(const int code) {
+
+ m_code = code;
+}
+
+
+int SMTPResponse::responseLine::getCode() const {
+
+ return m_code;
+}
+
+
+void SMTPResponse::responseLine::setEnhancedCode(const enhancedStatusCode& enhCode) {
+
+ m_enhCode = enhCode;
+}
+
+
+const SMTPResponse::enhancedStatusCode SMTPResponse::responseLine::getEnhancedCode() const {
+
+ return m_enhCode;
+}
+
+
+void SMTPResponse::responseLine::setText(const string& text) {
+
+ m_text = text;
+}
+
+
+const string SMTPResponse::responseLine::getText() const {
+
+ return m_text;
+}
+
+
+
+// SMTPResponse::enhancedStatusCode
+
+
+SMTPResponse::enhancedStatusCode::enhancedStatusCode()
+ : klass(0),
+ subject(0),
+ detail(0) {
+
+}
+
+
+SMTPResponse::enhancedStatusCode::enhancedStatusCode(const enhancedStatusCode& enhCode)
+ : klass(enhCode.klass),
+ subject(enhCode.subject),
+ detail(enhCode.detail) {
+
+}
+
+
+std::ostream& operator<<(std::ostream& os, const SMTPResponse::enhancedStatusCode& code) {
+
+ os << code.klass << '.' << code.subject << '.' << code.detail;
+ return os;
+}
+
+
+} // smtp
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
diff --git a/vmime-master/src/vmime/net/smtp/SMTPResponse.hpp b/vmime-master/src/vmime/net/smtp/SMTPResponse.hpp
new file mode 100644
index 0000000..2eec7f4
--- /dev/null
+++ b/vmime-master/src/vmime/net/smtp/SMTPResponse.hpp
@@ -0,0 +1,200 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_SMTP_SMTPRESPONSE_HPP_INCLUDED
+#define VMIME_NET_SMTP_SMTPRESPONSE_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+
+#include "vmime/object.hpp"
+#include "vmime/base.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+class socket;
+class timeoutHandler;
+class tracer;
+
+
+namespace smtp {
+
+
+/** A SMTP response, as sent by the server.
+ */
+class VMIME_EXPORT SMTPResponse : public object {
+
+public:
+
+ /** Current state of response parser. */
+ struct state {
+
+ string responseBuffer;
+ };
+
+ /** Enhanced status code (as per RFC-3463). */
+ struct enhancedStatusCode {
+
+ enhancedStatusCode();
+ enhancedStatusCode(const enhancedStatusCode& enhCode);
+
+ unsigned short klass; /**< Success/failure. */
+ unsigned short subject; /**< Source of anomaly. */
+ unsigned short detail; /**< Precise error condition. */
+ };
+
+ /** An element of a SMTP response. */
+ class responseLine {
+
+ public:
+
+ responseLine(const int code, const string& text, const enhancedStatusCode& enhCode);
+
+ void setCode(const int code);
+ int getCode() const;
+
+ void setEnhancedCode(const enhancedStatusCode& enhCode);
+ const enhancedStatusCode getEnhancedCode() const;
+
+ void setText(const string& text);
+ const string getText() const;
+
+ private:
+
+ int m_code;
+ string m_text;
+ enhancedStatusCode m_enhCode;
+ };
+
+ /** Receive and parse a new SMTP response from the
+ * specified socket.
+ *
+ * @param tr tracer
+ * @param sok socket from which to read
+ * @param toh time-out handler
+ * @param st previous state of response parser for the specified socket
+ * @return SMTP response
+ * @throws exceptions::operation_timed_out if no data
+ * has been received within the granted time
+ */
+ static shared_ptr <SMTPResponse> readResponse(
+ const shared_ptr <tracer>& tr,
+ const shared_ptr <socket>& sok,
+ const shared_ptr <timeoutHandler>& toh,
+ const state& st
+ );
+
+ /** Return the SMTP response code.
+ *
+ * @return response code
+ */
+ int getCode() const;
+
+ /** Return the SMTP enhanced status code, if available.
+ *
+ * @return enhanced status code
+ */
+ const enhancedStatusCode getEnhancedCode() const;
+
+ /** Return the SMTP response text.
+ * The text of each line is concatenated.
+ *
+ * @return response text
+ */
+ const string getText() const;
+
+ /** Return the response line at the specified position.
+ *
+ * @param pos line index
+ * @return line at the specified index
+ */
+ const responseLine getLineAt(const size_t pos) const;
+
+ /** Return the number of lines in the response.
+ *
+ * @return number of lines in the response
+ */
+ size_t getLineCount() const;
+
+ /** Return the last line in the response.
+ *
+ * @return last response line
+ */
+ const responseLine getLastLine() const;
+
+ /** Returns the current state of the response parser.
+ *
+ * @return current parser state
+ */
+ const state getCurrentState() const;
+
+private:
+
+ SMTPResponse(
+ const shared_ptr <tracer>& tr,
+ const shared_ptr <socket>& sok,
+ const shared_ptr <timeoutHandler>& toh,
+ const state& st
+ );
+
+ SMTPResponse(const SMTPResponse&);
+
+ void readResponse();
+
+ const string readResponseLine();
+ const responseLine getNextResponse();
+
+ static int extractResponseCode(const string& response);
+ static const enhancedStatusCode extractEnhancedCode(const string& responseText);
+
+
+ std::vector <responseLine> m_lines;
+
+ shared_ptr <socket> m_socket;
+ shared_ptr <timeoutHandler> m_timeoutHandler;
+ shared_ptr <tracer> m_tracer;
+
+ string m_responseBuffer;
+ bool m_responseContinues;
+};
+
+
+VMIME_EXPORT std::ostream& operator<<(std::ostream& os, const SMTPResponse::enhancedStatusCode& code);
+
+
+} // smtp
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+#endif // VMIME_NET_SMTP_SMTPRESPONSE_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/smtp/SMTPSTransport.cpp b/vmime-master/src/vmime/net/smtp/SMTPSTransport.cpp
new file mode 100644
index 0000000..5158aa9
--- /dev/null
+++ b/vmime-master/src/vmime/net/smtp/SMTPSTransport.cpp
@@ -0,0 +1,82 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+
+#include "vmime/net/smtp/SMTPSTransport.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace smtp {
+
+
+SMTPSTransport::SMTPSTransport(
+ const shared_ptr <session>& sess,
+ const shared_ptr <security::authenticator>& auth
+)
+ : SMTPTransport(sess, auth, true) {
+
+}
+
+
+SMTPSTransport::~SMTPSTransport() {
+
+}
+
+
+const string SMTPSTransport::getProtocolName() const {
+
+ return "smtps";
+}
+
+
+
+// Service infos
+
+SMTPServiceInfos SMTPSTransport::sm_infos(true);
+
+
+const serviceInfos& SMTPSTransport::getInfosInstance() {
+
+ return sm_infos;
+}
+
+
+const serviceInfos& SMTPSTransport::getInfos() const {
+
+ return sm_infos;
+}
+
+
+} // smtp
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
diff --git a/vmime-master/src/vmime/net/smtp/SMTPSTransport.hpp b/vmime-master/src/vmime/net/smtp/SMTPSTransport.hpp
new file mode 100644
index 0000000..f19b3c5
--- /dev/null
+++ b/vmime-master/src/vmime/net/smtp/SMTPSTransport.hpp
@@ -0,0 +1,74 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_SMTP_SMTPSSTORE_HPP_INCLUDED
+#define VMIME_NET_SMTP_SMTPSSTORE_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+
+#include "vmime/net/smtp/SMTPTransport.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace smtp {
+
+
+/** SMTPS transport service.
+ */
+class VMIME_EXPORT SMTPSTransport : public SMTPTransport {
+
+public:
+
+ SMTPSTransport(
+ const shared_ptr <session>& sess,
+ const shared_ptr <security::authenticator>& auth
+ );
+
+ ~SMTPSTransport();
+
+ const string getProtocolName() const;
+
+ static const serviceInfos& getInfosInstance();
+ const serviceInfos& getInfos() const;
+
+private:
+
+ static SMTPServiceInfos sm_infos;
+};
+
+
+} // smtp
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+#endif // VMIME_NET_SMTP_SMTPSSTORE_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/smtp/SMTPServiceInfos.cpp b/vmime-master/src/vmime/net/smtp/SMTPServiceInfos.cpp
new file mode 100644
index 0000000..a2ee3d5
--- /dev/null
+++ b/vmime-master/src/vmime/net/smtp/SMTPServiceInfos.cpp
@@ -0,0 +1,144 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+
+#include "vmime/net/smtp/SMTPServiceInfos.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace smtp {
+
+
+SMTPServiceInfos::SMTPServiceInfos(const bool smtps)
+ : m_smtps(smtps) {
+
+}
+
+
+const string SMTPServiceInfos::getPropertyPrefix() const {
+
+ if (m_smtps) {
+ return "transport.smtps.";
+ } else {
+ return "transport.smtp.";
+ }
+}
+
+
+const SMTPServiceInfos::props& SMTPServiceInfos::getProperties() const {
+
+ static props smtpProps = {
+ // SMTP-specific options
+ property("options.need-authentication", serviceInfos::property::TYPE_BOOLEAN, "false"),
+#if VMIME_HAVE_SASL_SUPPORT
+ property("options.sasl", serviceInfos::property::TYPE_BOOLEAN, "true"),
+ property("options.sasl.fallback", serviceInfos::property::TYPE_BOOLEAN, "false"),
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+ property("options.pipelining", serviceInfos::property::TYPE_BOOLEAN, "true"),
+ property("options.chunking", serviceInfos::property::TYPE_BOOLEAN, "true"),
+
+ // Common properties
+ property(serviceInfos::property::AUTH_USERNAME, serviceInfos::property::FLAG_REQUIRED),
+ property(serviceInfos::property::AUTH_PASSWORD, serviceInfos::property::FLAG_REQUIRED),
+
+#if VMIME_HAVE_TLS_SUPPORT
+ property(serviceInfos::property::CONNECTION_TLS),
+ property(serviceInfos::property::CONNECTION_TLS_REQUIRED),
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+ property(serviceInfos::property::SERVER_ADDRESS, serviceInfos::property::FLAG_REQUIRED),
+ property(serviceInfos::property::SERVER_PORT, "25"),
+ };
+
+ static props smtpsProps = {
+ // SMTP-specific options
+ property("options.need-authentication", serviceInfos::property::TYPE_BOOLEAN, "false"),
+#if VMIME_HAVE_SASL_SUPPORT
+ property("options.sasl", serviceInfos::property::TYPE_BOOLEAN, "true"),
+ property("options.sasl.fallback", serviceInfos::property::TYPE_BOOLEAN, "false"),
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+ property("options.pipelining", serviceInfos::property::TYPE_BOOLEAN, "true"),
+ property("options.chunking", serviceInfos::property::TYPE_BOOLEAN, "true"),
+
+ // Common properties
+ property(serviceInfos::property::AUTH_USERNAME, serviceInfos::property::FLAG_REQUIRED),
+ property(serviceInfos::property::AUTH_PASSWORD, serviceInfos::property::FLAG_REQUIRED),
+
+#if VMIME_HAVE_TLS_SUPPORT
+ property(serviceInfos::property::CONNECTION_TLS),
+ property(serviceInfos::property::CONNECTION_TLS_REQUIRED),
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+ property(serviceInfos::property::SERVER_ADDRESS, serviceInfos::property::FLAG_REQUIRED),
+ property(serviceInfos::property::SERVER_PORT, "465"),
+ };
+
+ return m_smtps ? smtpsProps : smtpProps;
+}
+
+
+const std::vector <serviceInfos::property> SMTPServiceInfos::getAvailableProperties() const {
+
+ std::vector <property> list;
+ const props& p = getProperties();
+
+ // SMTP-specific options
+ list.push_back(p.PROPERTY_OPTIONS_NEEDAUTH);
+#if VMIME_HAVE_SASL_SUPPORT
+ list.push_back(p.PROPERTY_OPTIONS_SASL);
+ list.push_back(p.PROPERTY_OPTIONS_SASL_FALLBACK);
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+ // Common properties
+ list.push_back(p.PROPERTY_AUTH_USERNAME);
+ list.push_back(p.PROPERTY_AUTH_PASSWORD);
+
+#if VMIME_HAVE_TLS_SUPPORT
+ if (!m_smtps) {
+ list.push_back(p.PROPERTY_CONNECTION_TLS);
+ list.push_back(p.PROPERTY_CONNECTION_TLS_REQUIRED);
+ }
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+ list.push_back(p.PROPERTY_SERVER_ADDRESS);
+ list.push_back(p.PROPERTY_SERVER_PORT);
+
+ return list;
+}
+
+
+} // smtp
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
diff --git a/vmime-master/src/vmime/net/smtp/SMTPServiceInfos.hpp b/vmime-master/src/vmime/net/smtp/SMTPServiceInfos.hpp
new file mode 100644
index 0000000..005a0a2
--- /dev/null
+++ b/vmime-master/src/vmime/net/smtp/SMTPServiceInfos.hpp
@@ -0,0 +1,93 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_SMTP_SMTPSERVICEINFOS_HPP_INCLUDED
+#define VMIME_NET_SMTP_SMTPSERVICEINFOS_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+
+#include "vmime/net/serviceInfos.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace smtp {
+
+
+/** Information about SMTP service.
+ */
+class VMIME_EXPORT SMTPServiceInfos : public serviceInfos {
+
+public:
+
+ SMTPServiceInfos(const bool smtps);
+
+ struct props {
+ // SMTP-specific options
+ serviceInfos::property PROPERTY_OPTIONS_NEEDAUTH;
+#if VMIME_HAVE_SASL_SUPPORT
+ serviceInfos::property PROPERTY_OPTIONS_SASL;
+ serviceInfos::property PROPERTY_OPTIONS_SASL_FALLBACK;
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+ serviceInfos::property PROPERTY_OPTIONS_PIPELINING;
+ serviceInfos::property PROPERTY_OPTIONS_CHUNKING;
+
+ // Common properties
+ serviceInfos::property PROPERTY_AUTH_USERNAME;
+ serviceInfos::property PROPERTY_AUTH_PASSWORD;
+
+#if VMIME_HAVE_TLS_SUPPORT
+ serviceInfos::property PROPERTY_CONNECTION_TLS;
+ serviceInfos::property PROPERTY_CONNECTION_TLS_REQUIRED;
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+ serviceInfos::property PROPERTY_SERVER_ADDRESS;
+ serviceInfos::property PROPERTY_SERVER_PORT;
+ };
+
+ const props& getProperties() const;
+
+ const string getPropertyPrefix() const;
+ const std::vector <serviceInfos::property> getAvailableProperties() const;
+
+private:
+
+ const bool m_smtps;
+};
+
+
+} // smtp
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+#endif // VMIME_NET_SMTP_SMTPSERVICEINFOS_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/smtp/SMTPTransport.cpp b/vmime-master/src/vmime/net/smtp/SMTPTransport.cpp
new file mode 100644
index 0000000..561bd59
--- /dev/null
+++ b/vmime-master/src/vmime/net/smtp/SMTPTransport.cpp
@@ -0,0 +1,502 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+
+#include "vmime/net/smtp/SMTPTransport.hpp"
+#include "vmime/net/smtp/SMTPResponse.hpp"
+#include "vmime/net/smtp/SMTPCommand.hpp"
+#include "vmime/net/smtp/SMTPCommandSet.hpp"
+#include "vmime/net/smtp/SMTPChunkingOutputStreamAdapter.hpp"
+#include "vmime/net/smtp/SMTPExceptions.hpp"
+
+#include "vmime/exception.hpp"
+#include "vmime/mailboxList.hpp"
+#include "vmime/message.hpp"
+
+#include "vmime/utility/filteredStream.hpp"
+#include "vmime/utility/stringUtils.hpp"
+#include "vmime/utility/outputStreamSocketAdapter.hpp"
+#include "vmime/utility/streamUtils.hpp"
+#include "vmime/utility/outputStreamAdapter.hpp"
+#include "vmime/utility/inputStreamStringAdapter.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace smtp {
+
+
+SMTPTransport::SMTPTransport(
+ const shared_ptr <session>& sess,
+ const shared_ptr <security::authenticator>& auth,
+ const bool secured
+)
+ : transport(sess, getInfosInstance(), auth),
+ m_isSMTPS(secured),
+ m_needReset(false) {
+
+}
+
+
+SMTPTransport::~SMTPTransport() {
+
+ try {
+
+ if (isConnected()) {
+ disconnect();
+ }
+
+ } catch (...) {
+
+ // Don't throw in destructor
+ }
+}
+
+
+const string SMTPTransport::getProtocolName() const {
+
+ return "smtp";
+}
+
+
+bool SMTPTransport::isSMTPS() const {
+
+ return m_isSMTPS;
+}
+
+
+void SMTPTransport::connect() {
+
+ if (isConnected()) {
+ throw exceptions::already_connected();
+ }
+
+ m_connection = make_shared <SMTPConnection>(
+ dynamicCast <SMTPTransport>(shared_from_this()), getAuthenticator()
+ );
+
+ m_connection->connect();
+}
+
+
+bool SMTPTransport::isConnected() const {
+
+ return m_connection && m_connection->isConnected();
+}
+
+
+bool SMTPTransport::isSecuredConnection() const {
+
+ if (!m_connection) {
+ return false;
+ }
+
+ return m_connection->isSecuredConnection();
+}
+
+
+shared_ptr <connectionInfos> SMTPTransport::getConnectionInfos() const {
+
+ if (!m_connection) {
+ return null;
+ }
+
+ return m_connection->getConnectionInfos();
+}
+
+
+shared_ptr <SMTPConnection> SMTPTransport::getConnection() {
+
+ return m_connection;
+}
+
+
+void SMTPTransport::disconnect() {
+
+ if (!isConnected()) {
+ throw exceptions::not_connected();
+ }
+
+ m_connection->disconnect();
+ m_connection = null;
+}
+
+
+void SMTPTransport::noop() {
+
+ if (!isConnected()) {
+ throw exceptions::not_connected();
+ }
+
+ m_connection->sendRequest(SMTPCommand::NOOP());
+
+ shared_ptr <SMTPResponse> resp = m_connection->readResponse();
+
+ if (resp->getCode() != 250) {
+ throw SMTPCommandError("NOOP", resp->getText(), resp->getCode(), resp->getEnhancedCode());
+ }
+}
+
+
+// static
+bool SMTPTransport::mailboxNeedsUTF8(const mailbox& mb) {
+
+ bool all7bit =
+ utility::stringUtils::is7bit(mb.getEmail().getLocalName().getBuffer())
+ && utility::stringUtils::is7bit(mb.getEmail().getDomainName().getBuffer());
+
+ for (size_t i = 0, n = mb.getName().getWordCount() ; all7bit && i != n ; ++i) {
+ all7bit = utility::stringUtils::is7bit(mb.getName().getWordAt(i)->getBuffer());
+ }
+
+ return !all7bit;
+}
+
+
+void SMTPTransport::sendEnvelope(
+ const mailbox& expeditor,
+ const mailboxList& recipients,
+ const mailbox& sender,
+ bool sendDATACommand,
+ const size_t size,
+ const dsnAttributes& dsnAttrs
+) {
+
+ // If no recipient/expeditor was found, throw an exception
+ if (recipients.isEmpty()) {
+ throw exceptions::no_recipient();
+ } else if (expeditor.isEmpty()) {
+ throw exceptions::no_expeditor();
+ }
+
+ // If DSN extension is used, ensure it is supported by the server
+ if (!dsnAttrs.isEmpty() && !m_connection->hasExtension("DSN")) {
+ throw SMTPDSNExtensionNotSupportedException();
+ }
+
+
+ const bool needReset = m_needReset;
+ const bool hasPipelining = m_connection->hasExtension("PIPELINING") &&
+ getInfos().getPropertyValue <bool>(getSession(),
+ dynamic_cast <const SMTPServiceInfos&>(getInfos()).getProperties().PROPERTY_OPTIONS_PIPELINING);
+
+ shared_ptr <SMTPResponse> resp;
+ shared_ptr <SMTPCommandSet> commands = SMTPCommandSet::create(hasPipelining);
+
+ // Emit a "RSET" command if we previously sent a message on this connection
+ if (needReset) {
+ commands->addCommand(SMTPCommand::RSET());
+ }
+
+ // Check whether we need SMTPUTF8
+ const bool hasSMTPUTF8 = m_connection->hasExtension("SMTPUTF8");
+ bool needSMTPUTF8 = false;
+
+ if (!sender.isEmpty()) {
+ needSMTPUTF8 = needSMTPUTF8 || mailboxNeedsUTF8(sender);
+ } else {
+ needSMTPUTF8 = needSMTPUTF8 || mailboxNeedsUTF8(expeditor);
+ }
+
+ for (size_t i = 0 ; i < recipients.getMailboxCount() ; ++i) {
+
+ const mailbox& mbox = *recipients.getMailboxAt(i);
+ needSMTPUTF8 = needSMTPUTF8 || mailboxNeedsUTF8(mbox);
+ }
+
+ // Emit the "MAIL" command
+ const bool hasSize = m_connection->hasExtension("SIZE");
+
+ if (!sender.isEmpty()) {
+
+ commands->addCommand(
+ SMTPCommand::MAIL(
+ sender, hasSMTPUTF8 && needSMTPUTF8, hasSize ? size : 0,
+ dsnAttrs.getNotificationConditions(),
+ dsnAttrs.getEnvelopId()
+ )
+ );
+
+ } else {
+
+ commands->addCommand(
+ SMTPCommand::MAIL(
+ expeditor, hasSMTPUTF8 && needSMTPUTF8, hasSize ? size : 0,
+ dsnAttrs.getNotificationConditions(),
+ dsnAttrs.getEnvelopId()
+ )
+ );
+ }
+
+ // Now, we will need to reset next time
+ m_needReset = true;
+
+ // Emit a "RCPT TO" command for each recipient
+ for (size_t i = 0 ; i < recipients.getMailboxCount() ; ++i) {
+
+ const mailbox& mbox = *recipients.getMailboxAt(i);
+ commands->addCommand(SMTPCommand::RCPT(mbox, hasSMTPUTF8 && needSMTPUTF8,
+ dsnAttrs.getNotificationConditions()));
+ }
+
+ // Prepare sending of message data
+ if (sendDATACommand) {
+ commands->addCommand(SMTPCommand::DATA());
+ }
+
+ // Read response for "RSET" command
+ if (needReset) {
+
+ commands->writeToSocket(m_connection->getSocket(), m_connection->getTracer());
+
+ resp = m_connection->readResponse();
+
+ if (resp->getCode() != 250 &&
+ resp->getCode() != 200) { // RFC-876: << In reply to a RSET and/or a NOOP command,
+ // some servers reply "200" >>
+
+ disconnect();
+
+ throw SMTPCommandError(
+ commands->getLastCommandSent()->getText(), resp->getText(),
+ resp->getCode(), resp->getEnhancedCode()
+ );
+ }
+ }
+
+ // Read response for "MAIL" command
+ commands->writeToSocket(m_connection->getSocket(), m_connection->getTracer());
+
+ if ((resp = m_connection->readResponse())->getCode() != 250) {
+
+ // SIZE extension: insufficient system storage
+ if (resp->getCode() == 452) {
+
+ throw SMTPMessageSizeExceedsCurLimitsException(
+ SMTPCommandError(
+ commands->getLastCommandSent()->getText(), resp->getText(),
+ resp->getCode(), resp->getEnhancedCode()
+ )
+ );
+
+ // SIZE extension: message size exceeds fixed maximum message size
+ } else if (resp->getCode() == 552) {
+
+ throw SMTPMessageSizeExceedsMaxLimitsException(
+ SMTPCommandError(
+ commands->getLastCommandSent()->getText(), resp->getText(),
+ resp->getCode(), resp->getEnhancedCode()
+ )
+ );
+
+ // Other error
+ } else {
+
+ throw SMTPCommandError(
+ commands->getLastCommandSent()->getText(), resp->getText(),
+ resp->getCode(), resp->getEnhancedCode()
+ );
+ }
+ }
+
+ // Read responses for "RCPT TO" commands
+ for (size_t i = 0 ; i < recipients.getMailboxCount() ; ++i) {
+
+ commands->writeToSocket(m_connection->getSocket(), m_connection->getTracer());
+
+ resp = m_connection->readResponse();
+
+ if (resp->getCode() != 250 &&
+ resp->getCode() != 251) {
+
+ // SIZE extension: insufficient system storage
+ if (resp->getCode() == 452) {
+
+ throw SMTPMessageSizeExceedsCurLimitsException(
+ SMTPCommandError(
+ commands->getLastCommandSent()->getText(), resp->getText(),
+ resp->getCode(), resp->getEnhancedCode()
+ )
+ );
+
+ // SIZE extension: message size exceeds fixed maximum message size
+ } else if (resp->getCode() == 552) {
+
+ throw SMTPMessageSizeExceedsMaxLimitsException(
+ SMTPCommandError(
+ commands->getLastCommandSent()->getText(), resp->getText(),
+ resp->getCode(), resp->getEnhancedCode()
+ )
+ );
+
+ // Other error
+ } else {
+
+ throw SMTPCommandError(
+ commands->getLastCommandSent()->getText(), resp->getText(),
+ resp->getCode(), resp->getEnhancedCode()
+ );
+ }
+ }
+ }
+
+ // Read response for "DATA" command
+ if (sendDATACommand) {
+
+ commands->writeToSocket(m_connection->getSocket(), m_connection->getTracer());
+
+ if ((resp = m_connection->readResponse())->getCode() != 354) {
+
+ throw SMTPCommandError(
+ commands->getLastCommandSent()->getText(), resp->getText(),
+ resp->getCode(), resp->getEnhancedCode()
+ );
+ }
+ }
+}
+
+
+void SMTPTransport::send(
+ const mailbox& expeditor,
+ const mailboxList& recipients,
+ utility::inputStream& is,
+ const size_t size,
+ utility::progressListener* progress,
+ const mailbox& sender,
+ const dsnAttributes& dsnAttrs
+) {
+
+ if (!isConnected()) {
+ throw exceptions::not_connected();
+ }
+
+ // Send message envelope
+ sendEnvelope(expeditor, recipients, sender, /* sendDATACommand */ true, size,
+ dsnAttrs);
+
+ // Send the message data
+ // Stream copy with "\n." to "\n.." transformation
+ utility::outputStreamSocketAdapter sos(*m_connection->getSocket());
+ utility::dotFilteredOutputStream fos(sos);
+
+ utility::bufferedStreamCopy(is, fos, size, progress);
+
+ fos.flush();
+
+ // Send end-of-data delimiter
+ m_connection->getSocket()->send("\r\n.\r\n");
+
+ if (m_connection->getTracer()) {
+ m_connection->getTracer()->traceSendBytes(size);
+ m_connection->getTracer()->traceSend(".");
+ }
+
+ shared_ptr <SMTPResponse> resp;
+
+ if ((resp = m_connection->readResponse())->getCode() != 250) {
+ throw SMTPCommandError("DATA", resp->getText(), resp->getCode(), resp->getEnhancedCode());
+ }
+}
+
+
+void SMTPTransport::send(
+ const shared_ptr <vmime::message>& msg,
+ const mailbox& expeditor,
+ const mailboxList& recipients,
+ utility::progressListener* progress,
+ const mailbox& sender,
+ const dsnAttributes& dsnAttrs
+) {
+
+ if (!isConnected()) {
+ throw exceptions::not_connected();
+ }
+
+ // Generate the message with Internationalized Email support,
+ // if this is supported by the SMTP server
+ generationContext ctx(generationContext::getDefaultContext());
+ ctx.setInternationalizedEmailSupport(m_connection->hasExtension("SMTPUTF8"));
+
+ // If CHUNKING is not supported, generate the message to a temporary
+ // buffer then use the send() method which takes an inputStream
+ if (!m_connection->hasExtension("CHUNKING") ||
+ !getInfos().getPropertyValue <bool>(getSession(),
+ dynamic_cast <const SMTPServiceInfos&>(getInfos()).getProperties().PROPERTY_OPTIONS_CHUNKING)) {
+
+ std::ostringstream oss;
+ utility::outputStreamAdapter ossAdapter(oss);
+
+ msg->generate(ctx, ossAdapter);
+
+ const string& str(oss.str());
+
+ utility::inputStreamStringAdapter isAdapter(str);
+
+ send(expeditor, recipients, isAdapter, str.length(), progress, sender, dsnAttrs);
+ return;
+ }
+
+ // Send message envelope
+ const size_t msgSize = msg->getGeneratedSize(ctx);
+
+ sendEnvelope(expeditor, recipients, sender, /* sendDATACommand */ false, msgSize, dsnAttrs);
+
+ // Send the message by chunks
+ SMTPChunkingOutputStreamAdapter chunkStream(m_connection, msgSize, progress);
+
+ msg->generate(ctx, chunkStream);
+
+ chunkStream.flush();
+}
+
+
+
+// Service infos
+
+SMTPServiceInfos SMTPTransport::sm_infos(false);
+
+
+const serviceInfos& SMTPTransport::getInfosInstance() {
+
+ return sm_infos;
+}
+
+
+const serviceInfos& SMTPTransport::getInfos() const {
+
+ return sm_infos;
+}
+
+
+} // smtp
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
diff --git a/vmime-master/src/vmime/net/smtp/SMTPTransport.hpp b/vmime-master/src/vmime/net/smtp/SMTPTransport.hpp
new file mode 100644
index 0000000..cd7c712
--- /dev/null
+++ b/vmime-master/src/vmime/net/smtp/SMTPTransport.hpp
@@ -0,0 +1,144 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_SMTP_SMTPTRANSPORT_HPP_INCLUDED
+#define VMIME_NET_SMTP_SMTPTRANSPORT_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+
+#include "vmime/net/transport.hpp"
+#include "vmime/net/socket.hpp"
+#include "vmime/net/timeoutHandler.hpp"
+
+#include "vmime/net/smtp/SMTPServiceInfos.hpp"
+#include "vmime/net/smtp/SMTPConnection.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace smtp {
+
+
+class SMTPCommand;
+
+
+/** SMTP transport service.
+ */
+class VMIME_EXPORT SMTPTransport : public transport {
+
+public:
+
+ SMTPTransport(
+ const shared_ptr <session>& sess,
+ const shared_ptr <security::authenticator>& auth,
+ const bool secured = false
+ );
+
+ ~SMTPTransport();
+
+ const string getProtocolName() const;
+
+ static const serviceInfos& getInfosInstance();
+ const serviceInfos& getInfos() const;
+
+ void connect();
+ bool isConnected() const;
+ void disconnect();
+
+ void noop();
+
+ void send(
+ const mailbox& expeditor,
+ const mailboxList& recipients,
+ utility::inputStream& is,
+ const size_t size,
+ utility::progressListener* progress = NULL,
+ const mailbox& sender = mailbox(),
+ const dsnAttributes& dsnAttrs = dsnAttributes()
+ );
+
+ void send(
+ const shared_ptr <vmime::message>& msg,
+ const mailbox& expeditor,
+ const mailboxList& recipients,
+ utility::progressListener* progress = NULL,
+ const mailbox& sender = mailbox(),
+ const dsnAttributes& dsnAttrs = dsnAttributes()
+ );
+
+ bool isSecuredConnection() const;
+ shared_ptr <connectionInfos> getConnectionInfos() const;
+ shared_ptr <SMTPConnection> getConnection();
+
+ bool isSMTPS() const;
+
+private:
+
+ static bool mailboxNeedsUTF8(const mailbox& mb);
+
+ /** Send the MAIL and RCPT commands to the server, checking the
+ * response, and using pipelining if supported by the server.
+ * Optionally, the DATA command can also be sent.
+ *
+ * @param expeditor expeditor mailbox
+ * @param recipients list of recipient mailboxes
+ * @param sender envelope sender (if empty, expeditor will be used)
+ * @param sendDATACommand if true, the DATA command will be sent
+ * @param size message size, in bytes (or 0, if not known)
+ * @param dsnAttributes attributes for Delivery Status Notification (if needed)
+ */
+ void sendEnvelope(
+ const mailbox& expeditor,
+ const mailboxList& recipients,
+ const mailbox& sender,
+ bool sendDATACommand,
+ const size_t size,
+ const dsnAttributes& dsnAttrs = dsnAttributes()
+ );
+
+
+ shared_ptr <SMTPConnection> m_connection;
+
+
+ const bool m_isSMTPS;
+
+ bool m_needReset;
+
+ // Service infos
+ static SMTPServiceInfos sm_infos;
+};
+
+
+} // smtp
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_MESSAGING_PROTO_SMTP
+
+#endif // VMIME_NET_SMTP_SMTPTRANSPORT_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/smtp/smtp.hpp b/vmime-master/src/vmime/net/smtp/smtp.hpp
new file mode 100644
index 0000000..4c0b17d
--- /dev/null
+++ b/vmime-master/src/vmime/net/smtp/smtp.hpp
@@ -0,0 +1,33 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_SMTP_SMTP_HPP_INCLUDED
+#define VMIME_NET_SMTP_SMTP_HPP_INCLUDED
+
+
+#include "vmime/net/smtp/SMTPTransport.hpp"
+#include "vmime/net/smtp/SMTPSTransport.hpp"
+#include "vmime/net/smtp/SMTPExceptions.hpp"
+
+
+#endif // VMIME_NET_SMTP_SMTP_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/socket.hpp b/vmime-master/src/vmime/net/socket.hpp
new file mode 100644
index 0000000..a236a9f
--- /dev/null
+++ b/vmime-master/src/vmime/net/socket.hpp
@@ -0,0 +1,223 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_SOCKET_HPP_INCLUDED
+#define VMIME_NET_SOCKET_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/base.hpp"
+
+#include "vmime/net/timeoutHandler.hpp"
+#include "vmime/net/tracer.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+/** Interface for connecting to servers.
+ */
+class VMIME_EXPORT socket : public object {
+
+public:
+
+ enum Status {
+ STATUS_WOULDBLOCK = 0xf, /**< The operation would block. Retry later. */
+ STATUS_WANT_READ = 0x1, /**< The socket wants to read data, retry when data is available. */
+ STATUS_WANT_WRITE = 0x2 /**< The socket wants to write data, retry when data can be written. */
+ };
+
+
+ virtual ~socket() { }
+
+
+ /** Connect to the specified address and port.
+ *
+ * @param address server address (this can be a full qualified domain name
+ * or an IP address, doesn't matter)
+ * @param port server port
+ */
+ virtual void connect(const string& address, const port_t port) = 0;
+
+ /** Disconnect from the server.
+ */
+ virtual void disconnect() = 0;
+
+ /** Test whether this socket is connected.
+ *
+ * @return true if the socket is connected, false otherwise
+ */
+ virtual bool isConnected() const = 0;
+
+ /** Block until new data is available for reading. The function will
+ * timeout after msecs milliseconds.
+ *
+ * @param timeout maximum wait time, in milliseconds (default is 30000);
+ * resolution is 10ms
+ * @return true if data is available, or false if the operation timed out
+ */
+ virtual bool waitForRead(const int msecs = 30000) = 0;
+
+ /** Block until pending data has been written and new data can be written.
+ * The function will timeout after msecs milliseconds.
+ *
+ * @param timeout maximum wait time, in milliseconds (default is 30000);
+ * resolution is 10ms
+ * @return true if new data can be written immediately, or false if the
+ * operation timed out
+ */
+ virtual bool waitForWrite(const int msecs = 30000) = 0;
+
+ /** Receive text data from the socket.
+ *
+ * @param buffer buffer in which to write received data
+ */
+ virtual void receive(string& buffer) = 0;
+
+ /** Receive raw data from the socket.
+ *
+ * @param buffer buffer in which to write received data
+ * @param count maximum number of bytes to receive (size of buffer)
+ * @return number of bytes received/written into output buffer
+ */
+ virtual size_t receiveRaw(byte_t* buffer, const size_t count) = 0;
+
+ /** Send text data to the socket.
+ *
+ * @param buffer data to send
+ */
+ virtual void send(const string& buffer) = 0;
+
+ /** Send text data to the socket.
+ *
+ * @param str null-terminated string
+ */
+ virtual void send(const char* str) = 0;
+
+ /** Send raw data to the socket.
+ *
+ * @param buffer data to send
+ * @param count number of bytes to send (size of buffer)
+ */
+ virtual void sendRaw(const byte_t* buffer, const size_t count) = 0;
+
+ /** Send raw data to the socket.
+ * Function may returns before all data is sent.
+ *
+ * @param buffer data to send
+ * @param count number of bytes to send (size of buffer)
+ * @return number of bytes sent
+ */
+ virtual size_t sendRawNonBlocking(const byte_t* buffer, const size_t count) = 0;
+
+ /** Return the preferred maximum block size when reading
+ * from or writing to this stream.
+ *
+ * @return block size, in bytes
+ */
+ virtual size_t getBlockSize() const = 0;
+
+ /** Return the current status of this socket.
+ *
+ * @return status flags for this socket
+ */
+ virtual unsigned int getStatus() const = 0;
+
+ /** Return the hostname of peer this socket is connected to.
+ *
+ * @return name of the peer, or numeric address if it cannot be found
+ */
+ virtual const string getPeerName() const = 0;
+
+ /** Return the address of peer this socket is connected to.
+ *
+ * @return numeric address of the peer
+ */
+ virtual const string getPeerAddress() const = 0;
+
+ /** Return the timeout handler associated with this socket.
+ *
+ * @return timeout handler, or NULL if none is set
+ */
+ virtual shared_ptr <timeoutHandler> getTimeoutHandler() = 0;
+
+ /** Set the tracer used by this socket. Tracer will only be used
+ * to report socket-specific events such as connection (not when
+ * sending/receiving data).
+ *
+ * @param tracer tracer to use
+ */
+ virtual void setTracer(const shared_ptr <tracer>& tracer) = 0;
+
+ /** Return the tracer used by this socket.
+ *
+ * @return tracer, or NULL if none is set
+ */
+ virtual shared_ptr <tracer> getTracer() = 0;
+
+protected:
+
+ socket() { }
+
+private:
+
+ socket(const socket&) : object() { }
+};
+
+
+/** A class to create 'socket' objects.
+ */
+class socketFactory : public object {
+
+public:
+
+ virtual ~socketFactory() { }
+
+ /** Creates a socket without timeout handler.
+ *
+ * @return a new socket
+ */
+ virtual shared_ptr <socket> create() = 0;
+
+ /** Creates a socket with the specified timeout handler.
+ *
+ * @param th timeout handler
+ * @return a new socket
+ */
+ virtual shared_ptr <socket> create(const shared_ptr <timeoutHandler>& th) = 0;
+};
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+#endif // VMIME_NET_SOCKET_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/store.cpp b/vmime-master/src/vmime/net/store.cpp
new file mode 100644
index 0000000..3c9a66d
--- /dev/null
+++ b/vmime-master/src/vmime/net/store.cpp
@@ -0,0 +1,57 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/net/store.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+store::store(
+ const shared_ptr <session>& sess,
+ const serviceInfos& infos,
+ const shared_ptr <security::authenticator>& auth
+)
+ : service(sess, infos, auth) {
+
+}
+
+
+store::Type store::getType() const {
+
+ return TYPE_STORE;
+}
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
diff --git a/vmime-master/src/vmime/net/store.hpp b/vmime-master/src/vmime/net/store.hpp
new file mode 100644
index 0000000..a96f267
--- /dev/null
+++ b/vmime-master/src/vmime/net/store.hpp
@@ -0,0 +1,115 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_STORE_HPP_INCLUDED
+#define VMIME_NET_STORE_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/net/service.hpp"
+#include "vmime/net/folder.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+/** A store service.
+ * Encapsulate protocols that provide access to user's mail drop.
+ */
+class VMIME_EXPORT store : public service {
+
+protected:
+
+ store(
+ const shared_ptr <session>& sess,
+ const serviceInfos& infos,
+ const shared_ptr <security::authenticator>& auth
+ );
+
+public:
+
+ /** Return the default folder. This is protocol dependent
+ * and usually is the INBOX folder.
+ *
+ * @return default folder
+ */
+ virtual shared_ptr <folder> getDefaultFolder() = 0;
+
+ /** Return the root folder. This is protocol dependent
+ * and usually is the user's mail drop root folder.
+ *
+ * @return root folder
+ */
+ virtual shared_ptr <folder> getRootFolder() = 0;
+
+ /** Return the folder specified by the path.
+ *
+ * @param path absolute folder path
+ * @return folder at the specified path
+ */
+ virtual shared_ptr <folder> getFolder(const folder::path& path) = 0;
+
+ /** Test whether the specified folder name is a syntactically
+ * a valid name.
+ *
+ * @return true if the specified folder name is valid, false otherwise
+ */
+ virtual bool isValidFolderName(const folder::path::component& name) const = 0;
+
+ /** Store capabilities. */
+ enum Capabilities {
+ CAPABILITY_CREATE_FOLDER = (1 << 0), /**< Can create folders. */
+ CAPABILITY_RENAME_FOLDER = (1 << 1), /**< Can rename folders. */
+ CAPABILITY_ADD_MESSAGE = (1 << 2), /**< Can append message to folders. */
+ CAPABILITY_COPY_MESSAGE = (1 << 3), /**< Can copy messages from a folder to another one. */
+ CAPABILITY_DELETE_MESSAGE = (1 << 4), /**< Can delete messages. */
+ CAPABILITY_PARTIAL_FETCH = (1 << 5), /**< Is partial fetch supported? */
+ CAPABILITY_MESSAGE_FLAGS = (1 << 6), /**< Can set flags on messages. */
+ CAPABILITY_EXTRACT_PART = (1 << 7) /**< Can extract a specific part of the message. */
+ };
+
+ /** Return the features supported by this service. This is
+ * a combination of store::CAPABILITY_xxx flags.
+ *
+ * @return features supported by this service
+ */
+ virtual int getCapabilities() const = 0;
+
+
+ Type getType() const;
+};
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+#endif // VMIME_NET_STORE_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/timeoutHandler.hpp b/vmime-master/src/vmime/net/timeoutHandler.hpp
new file mode 100644
index 0000000..fed1bc4
--- /dev/null
+++ b/vmime-master/src/vmime/net/timeoutHandler.hpp
@@ -0,0 +1,89 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_TIMEOUTHANDLER_HPP_INCLUDED
+#define VMIME_NET_TIMEOUTHANDLER_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/types.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+/** A class to manage timeouts in messaging services. This can be used
+ * to stop operations that takes too much time to complete (ie. no data
+ * received from the server for a long time if the network link is down).
+ */
+class VMIME_EXPORT timeoutHandler : public object {
+
+public:
+
+ virtual ~timeoutHandler() { }
+
+ /** Called to test if the time limit has been reached.
+ *
+ * @return true if the timeout delay is elapsed
+ */
+ virtual bool isTimeOut() = 0;
+
+ /** Called to reset the timeout counter.
+ */
+ virtual void resetTimeOut() = 0;
+
+ /** Called when the time limit has been reached (when
+ * isTimeOut() returned true).
+ *
+ * @return true to continue (and reset the timeout)
+ * or false to cancel the current operation
+ */
+ virtual bool handleTimeOut() = 0;
+};
+
+
+/** A class to create 'timeoutHandler' objects.
+ */
+class timeoutHandlerFactory : public object {
+
+public:
+
+ virtual ~timeoutHandlerFactory() { }
+
+ virtual shared_ptr <timeoutHandler> create() = 0;
+};
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+#endif // VMIME_NET_TIMEOUTHANDLER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/tls/TLSProperties.cpp b/vmime-master/src/vmime/net/tls/TLSProperties.cpp
new file mode 100644
index 0000000..f7721d4
--- /dev/null
+++ b/vmime-master/src/vmime/net/tls/TLSProperties.cpp
@@ -0,0 +1,44 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+
+#include "vmime/net/tls/TLSProperties.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
diff --git a/vmime-master/src/vmime/net/tls/TLSProperties.hpp b/vmime-master/src/vmime/net/tls/TLSProperties.hpp
new file mode 100644
index 0000000..94341ca
--- /dev/null
+++ b/vmime-master/src/vmime/net/tls/TLSProperties.hpp
@@ -0,0 +1,105 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_TLS_TLSPROPERTIES_HPP_INCLUDED
+#define VMIME_NET_TLS_TLSPROPERTIES_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+
+#include "vmime/types.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+/** Holds options for a TLS session.
+ */
+class VMIME_EXPORT TLSProperties : public object {
+
+public:
+
+ TLSProperties();
+ TLSProperties(const TLSProperties&);
+
+
+ /** Predefined generic cipher suites (work with all TLS libraries). */
+ enum GenericCipherSuite {
+
+ CIPHERSUITE_HIGH, /**< High encryption cipher suites (> 128 bits). */
+ CIPHERSUITE_MEDIUM, /**< Medium encryption cipher suites (>= 128 bits). */
+ CIPHERSUITE_LOW, /**< Low encryption cipher suites (>= 64 bits). */
+
+ CIPHERSUITE_DEFAULT /**< Default cipher suite. */
+ };
+
+ /** Sets the cipher suite preferences for a SSL/TLS session, using
+ * predefined, generic suites. This works with all underlying TLS
+ * libraries (OpenSSL and GNU TLS).
+ *
+ * @param cipherSuite predefined cipher suite
+ */
+ void setCipherSuite(const GenericCipherSuite cipherSuite);
+
+ /** Sets the cipher suite preferences for a SSL/TLS session, using
+ * a character string. The format and meaning of the string depend
+ * on the underlying TLS library.
+ *
+ * For GNU TLS, read this:
+ * http://gnutls.org/manual/html_node/Priority-Strings.html
+ *
+ * For OpenSSL, read this:
+ * http://www.openssl.org/docs/apps/ciphers.html#CIPHER_STRINGS
+ *
+ * @param cipherSuite cipher suite as a string
+ */
+ void setCipherSuite(const string& cipherSuite);
+
+ /** Returns the cipher suite preferences for a SSL/TLS session, as
+ * a character string. The format and meaning of the string depend
+ * on the underlying TLS library (see setCipherSuite() method).
+ *
+ * @return cipher suite string
+ */
+ const string getCipherSuite() const;
+
+private:
+
+ shared_ptr <object> m_data;
+};
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+#endif // VMIME_NET_TLS_TLSPROPERTIES_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/tls/TLSSecuredConnectionInfos.cpp b/vmime-master/src/vmime/net/tls/TLSSecuredConnectionInfos.cpp
new file mode 100644
index 0000000..055dfea
--- /dev/null
+++ b/vmime-master/src/vmime/net/tls/TLSSecuredConnectionInfos.cpp
@@ -0,0 +1,77 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+
+#include "vmime/net/tls/TLSSecuredConnectionInfos.hpp"
+#include "vmime/net/tls/TLSSession.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+TLSSecuredConnectionInfos::TLSSecuredConnectionInfos(
+ const string& host,
+ const port_t port,
+ const shared_ptr <TLSSession>& tlsSession,
+ const shared_ptr <TLSSocket>& tlsSocket
+)
+ : m_host(host),
+ m_port(port),
+ m_tlsSession(tlsSession),
+ m_tlsSocket(tlsSocket) {
+
+}
+
+
+const string TLSSecuredConnectionInfos::getHost() const {
+
+ return m_host;
+}
+
+
+port_t TLSSecuredConnectionInfos::getPort() const {
+
+ return m_port;
+}
+
+
+shared_ptr <const security::cert::certificateChain> TLSSecuredConnectionInfos::getPeerCertificates() const {
+
+ return m_tlsSocket->getPeerCertificates();
+}
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
diff --git a/vmime-master/src/vmime/net/tls/TLSSecuredConnectionInfos.hpp b/vmime-master/src/vmime/net/tls/TLSSecuredConnectionInfos.hpp
new file mode 100644
index 0000000..c65e9d2
--- /dev/null
+++ b/vmime-master/src/vmime/net/tls/TLSSecuredConnectionInfos.hpp
@@ -0,0 +1,88 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_TLSSECUREDCONNECTIONINFOS_HPP_INCLUDED
+#define VMIME_NET_TLSSECUREDCONNECTIONINFOS_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+
+#include "vmime/net/securedConnectionInfos.hpp"
+
+#include "vmime/security/cert/certificateChain.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+class TLSSession;
+class TLSSocket;
+
+
+/** Information about a TLS-secured connection used by a service.
+ */
+class VMIME_EXPORT TLSSecuredConnectionInfos : public securedConnectionInfos {
+
+public:
+
+ TLSSecuredConnectionInfos(
+ const string& host,
+ const port_t port,
+ const shared_ptr <TLSSession>& tlsSession,
+ const shared_ptr <TLSSocket>& tlsSocket
+ );
+
+ const string getHost() const;
+ port_t getPort() const;
+
+ /** Return the peer's certificate (chain) as sent by the peer.
+ *
+ * @return server certificate chain
+ */
+ shared_ptr <const security::cert::certificateChain> getPeerCertificates() const;
+
+private:
+
+ string m_host;
+ port_t m_port;
+
+ shared_ptr <TLSSession> m_tlsSession;
+ shared_ptr <TLSSocket> m_tlsSocket;
+};
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+#endif // VMIME_NET_TLSSECUREDCONNECTIONINFOS_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/tls/TLSSession.cpp b/vmime-master/src/vmime/net/tls/TLSSession.cpp
new file mode 100644
index 0000000..ab8b7c3
--- /dev/null
+++ b/vmime-master/src/vmime/net/tls/TLSSession.cpp
@@ -0,0 +1,48 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+
+#include "vmime/net/tls/TLSSession.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+TLSSession::TLSSession() {
+
+}
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
diff --git a/vmime-master/src/vmime/net/tls/TLSSession.hpp b/vmime-master/src/vmime/net/tls/TLSSession.hpp
new file mode 100644
index 0000000..9e84fe7
--- /dev/null
+++ b/vmime-master/src/vmime/net/tls/TLSSession.hpp
@@ -0,0 +1,96 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_TLS_TLSSESSION_HPP_INCLUDED
+#define VMIME_NET_TLS_TLSSESSION_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+
+#include "vmime/types.hpp"
+
+#include "vmime/net/tls/TLSSocket.hpp"
+#include "vmime/net/tls/TLSProperties.hpp"
+
+#include "vmime/security/cert/certificateVerifier.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+/** Describe a TLS connection between a client and a server.
+ */
+class VMIME_EXPORT TLSSession : public object, public enable_shared_from_this <TLSSession> {
+
+public:
+
+ /** Create and initialize a new TLS session.
+ *
+ * @param cv object responsible for verifying certificates
+ * sent by the server
+ * @param props TLS properties for this session
+ * @return a new TLS session
+ */
+ static shared_ptr <TLSSession> create(
+ const shared_ptr <security::cert::certificateVerifier>& cv,
+ const shared_ptr <TLSProperties>& props
+ );
+
+ /** Create a new socket that adds a TLS security layer around
+ * an existing socket. You should create only one socket
+ * per session.
+ *
+ * @param sok socket to wrap
+ * @return TLS socket wrapper
+ */
+ virtual shared_ptr <TLSSocket> getSocket(const shared_ptr <socket>& sok) = 0;
+
+ /** Get the object responsible for verifying certificates when
+ * using secured connections (TLS/SSL).
+ */
+ virtual shared_ptr <security::cert::certificateVerifier> getCertificateVerifier() = 0;
+
+protected:
+
+ TLSSession();
+
+private:
+
+ TLSSession(const TLSSession&);
+};
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+#endif // VMIME_NET_TLS_TLSSESSION_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/tls/TLSSocket.cpp b/vmime-master/src/vmime/net/tls/TLSSocket.cpp
new file mode 100644
index 0000000..fbca082
--- /dev/null
+++ b/vmime-master/src/vmime/net/tls/TLSSocket.cpp
@@ -0,0 +1,44 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+
+#include "vmime/net/tls/TLSSocket.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
diff --git a/vmime-master/src/vmime/net/tls/TLSSocket.hpp b/vmime-master/src/vmime/net/tls/TLSSocket.hpp
new file mode 100644
index 0000000..ca50aa8
--- /dev/null
+++ b/vmime-master/src/vmime/net/tls/TLSSocket.hpp
@@ -0,0 +1,88 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_TLS_TLSSOCKET_HPP_INCLUDED
+#define VMIME_NET_TLS_TLSSOCKET_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+
+#include "vmime/exception.hpp"
+
+#include "vmime/net/socket.hpp"
+#include "vmime/net/timeoutHandler.hpp"
+
+#include "vmime/security/cert/certificateChain.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+class TLSSession;
+
+
+/** Add a TLS security layer to an existing socket.
+ */
+class VMIME_EXPORT TLSSocket : public socket {
+
+public:
+
+ /** Create a new socket object that adds a security layer
+ * around an existing socket.
+ *
+ * @param session TLS session
+ * @param sok socket to wrap
+ */
+ static shared_ptr <TLSSocket> wrap(const shared_ptr <TLSSession>& session, const shared_ptr <socket>& sok);
+
+ /** Starts a TLS handshake on this connection.
+ *
+ * @throw exceptions::tls_exception if a fatal error occurs
+ * during the negociation process, exceptions::operation_timed_out
+ * if a time-out occurs
+ */
+ virtual void handshake() = 0;
+
+ /** Return the peer's certificate (chain) as sent by the peer.
+ *
+ * @return server certificate chain, or NULL if the handshake
+ * has not been performed yet
+ */
+ virtual shared_ptr <security::cert::certificateChain> getPeerCertificates() = 0;
+};
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+#endif // VMIME_NET_TLS_TLSSOCKET_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/tls/gnutls/TLSProperties_GnuTLS.cpp b/vmime-master/src/vmime/net/tls/gnutls/TLSProperties_GnuTLS.cpp
new file mode 100644
index 0000000..b2996fb
--- /dev/null
+++ b/vmime-master/src/vmime/net/tls/gnutls/TLSProperties_GnuTLS.cpp
@@ -0,0 +1,113 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
+
+
+#include "vmime/base.hpp"
+#include "vmime/net/tls/gnutls/TLSProperties_GnuTLS.hpp"
+
+#include <gnutls/gnutls.h>
+#if GNUTLS_VERSION_NUMBER < 0x030000
+#include <gnutls/extra.h>
+#endif
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+TLSProperties::TLSProperties()
+ : m_data(make_shared <TLSProperties_GnuTLS>()) {
+
+ setCipherSuite(CIPHERSUITE_DEFAULT);
+}
+
+
+TLSProperties::TLSProperties(const TLSProperties& props)
+ : object(),
+ m_data(make_shared <TLSProperties_GnuTLS>()) {
+
+ *dynamicCast <TLSProperties_GnuTLS>(m_data) = *dynamicCast <TLSProperties_GnuTLS>(props.m_data);
+}
+
+
+void TLSProperties::setCipherSuite(const GenericCipherSuite cipherSuite) {
+
+ switch (cipherSuite) {
+
+ case CIPHERSUITE_HIGH:
+
+ setCipherSuite("SECURE256:%SSL3_RECORD_VERSION");
+ break;
+
+ case CIPHERSUITE_MEDIUM:
+
+ setCipherSuite("SECURE128:%SSL3_RECORD_VERSION");
+ break;
+
+ case CIPHERSUITE_LOW:
+
+ setCipherSuite("NORMAL:%SSL3_RECORD_VERSION");
+ break;
+
+ default:
+ case CIPHERSUITE_DEFAULT:
+
+ setCipherSuite("NORMAL:%SSL3_RECORD_VERSION");
+ break;
+ }
+}
+
+
+void TLSProperties::setCipherSuite(const string& cipherSuite) {
+
+ dynamicCast <TLSProperties_GnuTLS>(m_data)->cipherSuite = cipherSuite;
+}
+
+
+const string TLSProperties::getCipherSuite() const {
+
+ return dynamicCast <TLSProperties_GnuTLS>(m_data)->cipherSuite;
+}
+
+
+
+TLSProperties_GnuTLS& TLSProperties_GnuTLS::operator=(const TLSProperties_GnuTLS& other) {
+
+ cipherSuite = other.cipherSuite;
+
+ return *this;
+}
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
diff --git a/vmime-master/src/vmime/net/tls/gnutls/TLSProperties_GnuTLS.hpp b/vmime-master/src/vmime/net/tls/gnutls/TLSProperties_GnuTLS.hpp
new file mode 100644
index 0000000..96bbaea
--- /dev/null
+++ b/vmime-master/src/vmime/net/tls/gnutls/TLSProperties_GnuTLS.hpp
@@ -0,0 +1,68 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_TLS_TLSPROPERTIES_GNUTLS_HPP_INCLUDED
+#define VMIME_NET_TLS_TLSPROPERTIES_GNUTLS_HPP_INCLUDED
+
+
+#ifndef VMIME_BUILDING_DOC
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
+
+
+#include "vmime/types.hpp"
+
+#include "vmime/net/tls/TLSProperties.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+class TLSProperties_GnuTLS : public object {
+
+public:
+
+ TLSProperties_GnuTLS& operator=(const TLSProperties_GnuTLS& other);
+
+
+ string cipherSuite;
+};
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
+
+#endif // VMIME_BUILDING_DOC
+
+#endif // VMIME_NET_TLS_TLSPROPERTIES_GNUTLS_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/tls/gnutls/TLSSession_GnuTLS.cpp b/vmime-master/src/vmime/net/tls/gnutls/TLSSession_GnuTLS.cpp
new file mode 100644
index 0000000..8586537
--- /dev/null
+++ b/vmime-master/src/vmime/net/tls/gnutls/TLSSession_GnuTLS.cpp
@@ -0,0 +1,313 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
+
+
+#include <gnutls/gnutls.h>
+#if GNUTLS_VERSION_NUMBER < 0x030000
+#include <gnutls/extra.h>
+#endif
+
+
+// Dependency on gcrypt is not needed since GNU TLS version 2.12.
+// See here: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=638651
+#if GNUTLS_VERSION_NUMBER <= 0x020b00
+# define VMIME_GNUTLS_NEEDS_GCRYPT 1
+#endif
+
+#if VMIME_HAVE_PTHREAD
+# include <pthread.h>
+# if VMIME_GNUTLS_NEEDS_GCRYPT
+# include <gcrypt.h>
+# endif
+# include <errno.h>
+#endif // VMIME_HAVE_PTHREAD
+
+#include "vmime/net/tls/gnutls/TLSSession_GnuTLS.hpp"
+#include "vmime/net/tls/gnutls/TLSSocket_GnuTLS.hpp"
+#include "vmime/net/tls/gnutls/TLSProperties_GnuTLS.hpp"
+
+#include "vmime/exception.hpp"
+
+
+// Enable GnuTLS debugging by defining GNUTLS_DEBUG
+//#define GNUTLS_DEBUG 1
+
+
+#include <sstream>
+#include <iomanip>
+
+#if VMIME_DEBUG && GNUTLS_DEBUG
+ #include <iostream>
+#endif // VMIME_DEBUG && GNUTLS_DEBUG
+
+
+#if VMIME_HAVE_PTHREAD && VMIME_GNUTLS_NEEDS_GCRYPT && defined(GCRY_THREAD_OPTION_PTHREAD_IMPL)
+extern "C"
+{
+ GCRY_THREAD_OPTION_PTHREAD_IMPL;
+}
+#endif // VMIME_HAVE_PTHREAD && defined(GCRY_THREAD_OPTION_PTHREAD_IMPL
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+#ifndef VMIME_BUILDING_DOC
+
+// Initialize GNU TLS library
+struct TLSGlobal {
+
+ TLSGlobal() {
+
+#if VMIME_HAVE_PTHREAD && defined(GCRY_THREAD_OPTION_PTHREAD_IMPL)
+ #if VMIME_GNUTLS_NEEDS_GCRYPT
+ gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
+ #endif // VMIME_GNUTLS_NEEDS_GCRYPT
+#endif // VMIME_HAVE_PTHREAD && defined(GCRY_THREAD_OPTION_PTHREAD_IMPL
+
+ gnutls_global_init();
+ //gnutls_global_init_extra();
+
+#if VMIME_DEBUG && GNUTLS_DEBUG
+ gnutls_global_set_log_function(TLSLogFunc);
+ gnutls_global_set_log_level(10);
+#endif // VMIME_DEBUG && GNUTLS_DEBUG
+
+ gnutls_anon_allocate_client_credentials(&anonCred);
+ gnutls_certificate_allocate_credentials(&certCred);
+ }
+
+ ~TLSGlobal() {
+
+ gnutls_anon_free_client_credentials(anonCred);
+ gnutls_certificate_free_credentials(certCred);
+
+ gnutls_global_deinit();
+ }
+
+#if VMIME_DEBUG && GNUTLS_DEBUG
+
+ static void TLSLogFunc(int level, const char *str) {
+
+ std::cerr << "GNUTLS: [" << level << "] " << str << std::endl;
+ }
+
+#endif // VMIME_DEBUG && GNUTLS_DEBUG
+
+
+ gnutls_anon_client_credentials_t anonCred;
+ gnutls_certificate_credentials_t certCred;
+};
+
+static TLSGlobal g_gnutlsGlobal;
+
+
+#endif // VMIME_BUILDING_DOC
+
+
+
+// static
+shared_ptr <TLSSession> TLSSession::create(
+ const shared_ptr <security::cert::certificateVerifier>& cv,
+ const shared_ptr <TLSProperties>& props
+) {
+
+ return make_shared <TLSSession_GnuTLS>(cv, props);
+}
+
+
+TLSSession_GnuTLS::TLSSession_GnuTLS(
+ const shared_ptr <security::cert::certificateVerifier>& cv,
+ const shared_ptr <TLSProperties>& props
+)
+ : m_certVerifier(cv),
+ m_props(props) {
+
+ int res;
+
+ m_gnutlsSession = new gnutls_session_t;
+
+ if (gnutls_init(m_gnutlsSession, GNUTLS_CLIENT) != 0) {
+ throw std::bad_alloc();
+ }
+
+ // Sets some default priority on the ciphers, key exchange methods,
+ // macs and compression methods.
+#ifdef VMIME_HAVE_GNUTLS_PRIORITY_FUNCS
+ gnutls_dh_set_prime_bits(*m_gnutlsSession, 128);
+
+ if ((res = gnutls_priority_set_direct
+ (*m_gnutlsSession, m_props->getCipherSuite().c_str(), NULL)) != 0) {
+
+ throwTLSException("gnutls_priority_set_direct", res);
+ }
+
+#else // !VMIME_HAVE_GNUTLS_PRIORITY_FUNCS
+
+ gnutls_set_default_priority(*m_gnutlsSession);
+
+ // Sets the priority on the certificate types supported by gnutls.
+ // Priority is higher for types specified before others. After
+ // specifying the types you want, you must append a 0.
+ const int certTypePriority[] = { GNUTLS_CRT_X509, 0 };
+
+ res = gnutls_certificate_type_set_priority(*m_gnutlsSession, certTypePriority);
+
+ if (res < 0) {
+ throwTLSException("gnutls_certificate_type_set_priority", res);
+ }
+
+ // Sets the priority on the protocol types
+ const int protoPriority[] = { GNUTLS_TLS1, GNUTLS_SSL3, 0 };
+
+ res = gnutls_protocol_set_priority(*m_gnutlsSession, protoPriority);
+
+ if (res < 0) {
+ throwTLSException("gnutls_certificate_type_set_priority", res);
+ }
+
+ // Priority on the ciphers
+ const int cipherPriority[] = {
+ GNUTLS_CIPHER_ARCFOUR_128,
+ GNUTLS_CIPHER_3DES_CBC,
+ GNUTLS_CIPHER_AES_128_CBC,
+ GNUTLS_CIPHER_AES_256_CBC,
+ GNUTLS_CIPHER_ARCFOUR_40,
+ GNUTLS_CIPHER_RC2_40_CBC,
+ GNUTLS_CIPHER_DES_CBC,
+ 0
+ };
+
+ gnutls_cipher_set_priority(*m_gnutlsSession, cipherPriority);
+
+ // Priority on MACs
+ const int macPriority[] = {
+ GNUTLS_MAC_SHA,
+ GNUTLS_MAC_MD5,
+ 0
+ };
+
+ gnutls_mac_set_priority(*m_gnutlsSession, macPriority);
+
+ // Priority on key exchange methods
+ const int kxPriority[] = {
+ GNUTLS_KX_RSA,
+ GNUTLS_KX_DHE_DSS,
+ GNUTLS_KX_DHE_RSA,
+ GNUTLS_KX_ANON_DH,
+ GNUTLS_KX_SRP,
+ GNUTLS_KX_RSA_EXPORT,
+ GNUTLS_KX_SRP_RSA,
+ GNUTLS_KX_SRP_DSS,
+ 0
+ };
+
+ gnutls_kx_set_priority(*m_gnutlsSession, kxPriority);
+
+ // Priority on compression methods
+ const int compressionPriority[] = {
+ GNUTLS_COMP_ZLIB,
+ //GNUTLS_COMP_LZO,
+ GNUTLS_COMP_NULL,
+ 0
+ };
+
+ gnutls_compression_set_priority(*m_gnutlsSession, compressionPriority);
+
+#endif // !VMIME_HAVE_GNUTLS_PRIORITY_FUNCS
+
+ // Initialize credentials
+ gnutls_credentials_set(
+ *m_gnutlsSession, GNUTLS_CRD_ANON, g_gnutlsGlobal.anonCred
+ );
+
+ gnutls_credentials_set(
+ *m_gnutlsSession, GNUTLS_CRD_CERTIFICATE, g_gnutlsGlobal.certCred
+ );
+}
+
+
+TLSSession_GnuTLS::TLSSession_GnuTLS(const TLSSession_GnuTLS&)
+ : TLSSession() {
+
+ // Not used
+}
+
+
+TLSSession_GnuTLS::~TLSSession_GnuTLS() {
+
+ try {
+
+ if (m_gnutlsSession) {
+
+ gnutls_deinit(*m_gnutlsSession);
+
+ delete m_gnutlsSession;
+ m_gnutlsSession = NULL;
+ }
+
+ } catch (...) {
+
+ // Don't throw in destructor
+ }
+}
+
+
+shared_ptr <TLSSocket> TLSSession_GnuTLS::getSocket(const shared_ptr <socket>& sok) {
+
+ return TLSSocket::wrap(dynamicCast <TLSSession>(shared_from_this()), sok);
+}
+
+
+shared_ptr <security::cert::certificateVerifier> TLSSession_GnuTLS::getCertificateVerifier() {
+
+ return m_certVerifier;
+}
+
+
+void TLSSession_GnuTLS::throwTLSException(const string& fname, const int code) {
+
+ std::ostringstream msg;
+
+ msg << fname + "() returned code ";
+ msg << std::hex << code;
+ msg << ": ";
+ msg << gnutls_strerror(code);
+
+ throw exceptions::tls_exception(msg.str());
+}
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
diff --git a/vmime-master/src/vmime/net/tls/gnutls/TLSSession_GnuTLS.hpp b/vmime-master/src/vmime/net/tls/gnutls/TLSSession_GnuTLS.hpp
new file mode 100644
index 0000000..2a7f9d7
--- /dev/null
+++ b/vmime-master/src/vmime/net/tls/gnutls/TLSSession_GnuTLS.hpp
@@ -0,0 +1,95 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_TLS_TLSSESSION_GNUTLS_HPP_INCLUDED
+#define VMIME_NET_TLS_TLSSESSION_GNUTLS_HPP_INCLUDED
+
+
+#ifndef VMIME_BUILDING_DOC
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
+
+
+#include "vmime/types.hpp"
+
+#include "vmime/net/tls/TLSSession.hpp"
+#include "vmime/net/tls/TLSSocket.hpp"
+#include "vmime/net/tls/TLSProperties.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+class TLSSession_GnuTLS : public TLSSession {
+
+ friend class TLSSocket_GnuTLS;
+
+public:
+
+ TLSSession_GnuTLS(
+ const shared_ptr <security::cert::certificateVerifier>& cv,
+ const shared_ptr <TLSProperties>& props
+ );
+
+ ~TLSSession_GnuTLS();
+
+
+ shared_ptr <TLSSocket> getSocket(const shared_ptr <socket>& sok);
+
+ shared_ptr <security::cert::certificateVerifier> getCertificateVerifier();
+
+private:
+
+ TLSSession_GnuTLS(const TLSSession_GnuTLS&);
+
+ static void throwTLSException(const string& fname, const int code);
+
+
+#ifdef LIBGNUTLS_VERSION
+ gnutls_session_t* m_gnutlsSession;
+#else
+ void* m_gnutlsSession;
+#endif // LIBGNUTLS_VERSION
+
+ shared_ptr <security::cert::certificateVerifier> m_certVerifier;
+ shared_ptr <TLSProperties> m_props;
+};
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
+
+#endif // VMIME_BUILDING_DOC
+
+#endif // VMIME_NET_TLS_TLSSESSION_GNUTLS_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/tls/gnutls/TLSSocket_GnuTLS.cpp b/vmime-master/src/vmime/net/tls/gnutls/TLSSocket_GnuTLS.cpp
new file mode 100644
index 0000000..53e4eae
--- /dev/null
+++ b/vmime-master/src/vmime/net/tls/gnutls/TLSSocket_GnuTLS.cpp
@@ -0,0 +1,548 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
+
+
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+
+#include <errno.h>
+
+#include "vmime/net/tls/gnutls/TLSSocket_GnuTLS.hpp"
+#include "vmime/net/tls/gnutls/TLSSession_GnuTLS.hpp"
+
+#include "vmime/platform.hpp"
+
+#include "vmime/security/cert/X509Certificate.hpp"
+
+#include "vmime/utility/stringUtils.hpp"
+
+#include <cstring>
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+// static
+shared_ptr <TLSSocket> TLSSocket::wrap(
+ const shared_ptr <TLSSession>& session,
+ const shared_ptr <socket>& sok
+)
+{
+ return make_shared <TLSSocket_GnuTLS>(dynamicCast <TLSSession_GnuTLS>(session), sok);
+}
+
+
+TLSSocket_GnuTLS::TLSSocket_GnuTLS(
+ const shared_ptr <TLSSession_GnuTLS>& session,
+ const shared_ptr <socket>& sok
+)
+ : m_session(session),
+ m_wrapped(sok),
+ m_connected(false),
+ m_ex(NULL),
+ m_status(0),
+ m_errno(0) {
+
+ gnutls_transport_set_ptr(*m_session->m_gnutlsSession, this);
+
+ gnutls_transport_set_push_function(*m_session->m_gnutlsSession, gnutlsPushFunc);
+ gnutls_transport_set_pull_function(*m_session->m_gnutlsSession, gnutlsPullFunc);
+ gnutls_transport_set_errno_function(*m_session->m_gnutlsSession, gnutlsErrnoFunc);
+}
+
+
+TLSSocket_GnuTLS::~TLSSocket_GnuTLS() {
+
+ resetException();
+
+ try {
+ disconnect();
+ } catch (...) {
+ // Don't throw exception in destructor
+ }
+}
+
+
+void TLSSocket_GnuTLS::connect(const string& address, const port_t port) {
+
+ try {
+
+ m_wrapped->connect(address, port);
+
+ handshake();
+
+ } catch (...) {
+
+ disconnect();
+ throw;
+ }
+}
+
+
+void TLSSocket_GnuTLS::disconnect() {
+
+ if (m_connected) {
+
+ gnutls_bye(*m_session->m_gnutlsSession, GNUTLS_SHUT_RDWR);
+
+ m_wrapped->disconnect();
+
+ m_connected = false;
+ }
+}
+
+
+bool TLSSocket_GnuTLS::isConnected() const {
+
+ return m_wrapped->isConnected() && m_connected;
+}
+
+
+size_t TLSSocket_GnuTLS::getBlockSize() const {
+
+ return 16384; // 16 KB
+}
+
+
+const string TLSSocket_GnuTLS::getPeerName() const {
+
+ return m_wrapped->getPeerName();
+}
+
+
+const string TLSSocket_GnuTLS::getPeerAddress() const {
+
+ return m_wrapped->getPeerAddress();
+}
+
+
+shared_ptr <timeoutHandler> TLSSocket_GnuTLS::getTimeoutHandler() {
+
+ return m_wrapped->getTimeoutHandler();
+}
+
+
+void TLSSocket_GnuTLS::setTracer(const shared_ptr <net::tracer>& tracer) {
+
+ m_wrapped->setTracer(tracer);
+}
+
+
+shared_ptr <net::tracer> TLSSocket_GnuTLS::getTracer() {
+
+ return m_wrapped->getTracer();
+}
+
+
+bool TLSSocket_GnuTLS::waitForRead(const int msecs) {
+
+ return m_wrapped->waitForRead(msecs);
+}
+
+
+bool TLSSocket_GnuTLS::waitForWrite(const int msecs) {
+
+ return m_wrapped->waitForWrite(msecs);
+}
+
+
+void TLSSocket_GnuTLS::receive(string& buffer) {
+
+ const size_t size = receiveRaw(m_buffer, sizeof(m_buffer));
+ buffer = utility::stringUtils::makeStringFromBytes(m_buffer, size);
+}
+
+
+void TLSSocket_GnuTLS::send(const string& buffer) {
+
+ sendRaw(reinterpret_cast <const byte_t*>(buffer.data()), buffer.length());
+}
+
+
+void TLSSocket_GnuTLS::send(const char* str) {
+
+ sendRaw(reinterpret_cast <const byte_t*>(str), ::strlen(str));
+}
+
+
+size_t TLSSocket_GnuTLS::receiveRaw(byte_t* buffer, const size_t count) {
+
+ m_status &= ~(STATUS_WANT_WRITE | STATUS_WANT_READ);
+
+ resetException();
+
+ const ssize_t ret = gnutls_record_recv(
+ *m_session->m_gnutlsSession,
+ buffer, static_cast <size_t>(count)
+ );
+
+ throwException();
+
+ if (ret < 0) {
+
+ if (ret == GNUTLS_E_AGAIN) {
+
+ if (gnutls_record_get_direction(*m_session->m_gnutlsSession) == 0) {
+ m_status |= STATUS_WANT_READ;
+ } else {
+ m_status |= STATUS_WANT_WRITE;
+ }
+
+ return 0;
+ }
+
+ TLSSession_GnuTLS::throwTLSException("gnutls_record_recv", static_cast <int>(ret));
+ }
+
+ return static_cast <size_t>(ret);
+}
+
+
+void TLSSocket_GnuTLS::sendRaw(const byte_t* buffer, const size_t count) {
+
+ m_status &= ~(STATUS_WANT_WRITE | STATUS_WANT_READ);
+
+ for (size_t size = count ; size > 0 ; ) {
+
+ resetException();
+
+ ssize_t ret = gnutls_record_send(
+ *m_session->m_gnutlsSession,
+ buffer, static_cast <size_t>(size)
+ );
+
+ throwException();
+
+ if (ret < 0) {
+
+ if (ret == GNUTLS_E_AGAIN) {
+
+ if (gnutls_record_get_direction(*m_session->m_gnutlsSession) == 0) {
+ m_wrapped->waitForRead();
+ } else {
+ m_wrapped->waitForWrite();
+ }
+
+ continue;
+ }
+
+ TLSSession_GnuTLS::throwTLSException("gnutls_record_send", static_cast <int>(ret));
+
+ } else {
+
+ buffer += ret;
+ size -= ret;
+ }
+ }
+}
+
+
+size_t TLSSocket_GnuTLS::sendRawNonBlocking(const byte_t* buffer, const size_t count) {
+
+ m_status &= ~(STATUS_WANT_WRITE | STATUS_WANT_READ);
+
+ resetException();
+
+ ssize_t ret = gnutls_record_send(
+ *m_session->m_gnutlsSession,
+ buffer, static_cast <size_t>(count)
+ );
+
+ throwException();
+
+ if (ret < 0) {
+
+ if (ret == GNUTLS_E_AGAIN) {
+
+ if (gnutls_record_get_direction(*m_session->m_gnutlsSession) == 0) {
+ m_status |= STATUS_WANT_READ;
+ } else {
+ m_status |= STATUS_WANT_WRITE;
+ }
+
+ return 0;
+ }
+
+ TLSSession_GnuTLS::throwTLSException("gnutls_record_send", static_cast <int>(ret));
+ }
+
+ return static_cast <size_t>(ret);
+}
+
+
+unsigned int TLSSocket_GnuTLS::getStatus() const {
+
+ return m_status | m_wrapped->getStatus();
+}
+
+
+void TLSSocket_GnuTLS::handshake() {
+
+ shared_ptr <timeoutHandler> toHandler = m_wrapped->getTimeoutHandler();
+
+ if (toHandler) {
+ toHandler->resetTimeOut();
+ }
+
+ if (getTracer()) {
+ getTracer()->traceSend("Beginning SSL/TLS handshake");
+ }
+
+ // Start handshaking process
+ try {
+ string peerName = getPeerName();
+
+ gnutls_server_name_set(*m_session->m_gnutlsSession, GNUTLS_NAME_DNS, peerName.c_str(), peerName.size());
+
+ while (true) {
+
+ resetException();
+
+ const int ret = gnutls_handshake(*m_session->m_gnutlsSession);
+
+ throwException();
+
+ if (ret < 0) {
+
+ if (ret == GNUTLS_E_AGAIN) {
+
+ if (gnutls_record_get_direction(*m_session->m_gnutlsSession) == 0) {
+ m_wrapped->waitForRead();
+ } else {
+ m_wrapped->waitForWrite();
+ }
+
+ } else if (ret == GNUTLS_E_INTERRUPTED) {
+
+ // Non-fatal error
+
+ } else {
+
+ TLSSession_GnuTLS::throwTLSException("gnutls_handshake", ret);
+ }
+
+ } else {
+
+ // Successful handshake
+ break;
+ }
+ }
+
+ } catch (...) {
+
+ throw;
+ }
+
+ // Verify server's certificate(s)
+ shared_ptr <security::cert::certificateChain> certs = getPeerCertificates();
+
+ if (certs == NULL) {
+ throw exceptions::tls_exception("No peer certificate.");
+ }
+
+ m_session->getCertificateVerifier()->verify(certs, getPeerName());
+
+ m_connected = true;
+}
+
+
+int TLSSocket_GnuTLS::gnutlsErrnoFunc(gnutls_transport_ptr_t trspt) {
+
+ TLSSocket_GnuTLS* sok = reinterpret_cast <TLSSocket_GnuTLS*>(trspt);
+ return sok->m_errno;
+}
+
+
+ssize_t TLSSocket_GnuTLS::gnutlsPushFunc(
+ gnutls_transport_ptr_t trspt,
+ const void* data,
+ size_t len
+) {
+
+ TLSSocket_GnuTLS* sok = reinterpret_cast <TLSSocket_GnuTLS*>(trspt);
+
+ try {
+
+ const ssize_t ret = static_cast <ssize_t>(
+ sok->m_wrapped->sendRawNonBlocking(reinterpret_cast <const byte_t*>(data), len)
+ );
+
+ if (ret == 0) {
+
+ gnutls_transport_set_errno(*sok->m_session->m_gnutlsSession, EAGAIN);
+ sok->m_errno = EAGAIN;
+ return -1;
+ }
+
+ return ret;
+
+ } catch (exception& e) {
+
+ // Workaround for non-portable behaviour when throwing C++ exceptions
+ // from C functions (GNU TLS)
+ sok->m_ex = e.clone();
+ return -1;
+ }
+}
+
+
+ssize_t TLSSocket_GnuTLS::gnutlsPullFunc(
+ gnutls_transport_ptr_t trspt,
+ void* data,
+ size_t len
+) {
+
+ TLSSocket_GnuTLS* sok = reinterpret_cast <TLSSocket_GnuTLS*>(trspt);
+
+ try {
+
+ const ssize_t n = static_cast <ssize_t>(
+ sok->m_wrapped->receiveRaw(reinterpret_cast <byte_t*>(data), len)
+ );
+
+ if (n == 0) {
+
+ gnutls_transport_set_errno(*sok->m_session->m_gnutlsSession, EAGAIN);
+ sok->m_errno = EAGAIN;
+ return -1;
+ }
+
+ return n;
+
+ } catch (exception& e) {
+
+ // Workaround for non-portable behaviour when throwing C++ exceptions
+ // from C functions (GNU TLS)
+ sok->m_ex = e.clone();
+ return -1;
+ }
+}
+
+
+shared_ptr <security::cert::certificateChain> TLSSocket_GnuTLS::getPeerCertificates() {
+
+ if (getTracer()) {
+ getTracer()->traceSend("Getting peer certificates");
+ }
+
+ unsigned int certCount = 0;
+ const gnutls_datum_t* rawData = gnutls_certificate_get_peers(
+ *m_session->m_gnutlsSession, &certCount
+ );
+
+ if (rawData == NULL) {
+ return null;
+ }
+
+ // Try X.509
+ gnutls_x509_crt_t* x509Certs = new gnutls_x509_crt_t[certCount];
+
+ for (unsigned int i = 0; i < certCount; ++i) {
+
+ gnutls_x509_crt_init(x509Certs + i);
+
+ int res = gnutls_x509_crt_import(x509Certs[i], rawData + i, GNUTLS_X509_FMT_DER);
+
+ if (res < 0) {
+
+ for (unsigned int j = 0 ; j <= i ; ++j) {
+ gnutls_x509_crt_deinit(x509Certs[j]);
+ }
+
+ // XXX more fine-grained error reporting?
+ delete [] x509Certs;
+ return null;
+ }
+ }
+
+ std::vector <shared_ptr <security::cert::certificate> > certs;
+ bool error = false;
+
+ for (unsigned int i = 0 ; i < certCount ; ++i) {
+
+ size_t dataSize = 0;
+
+ gnutls_x509_crt_export(x509Certs[i], GNUTLS_X509_FMT_DER, NULL, &dataSize);
+
+ std::vector <byte_t> data(dataSize);
+
+ gnutls_x509_crt_export(x509Certs[i], GNUTLS_X509_FMT_DER, &data[0], &dataSize);
+
+ shared_ptr <security::cert::X509Certificate> cert =
+ security::cert::X509Certificate::import(&data[0], dataSize);
+
+ if (cert != NULL) {
+ certs.push_back(cert);
+ } else {
+ error = true;
+ }
+
+ gnutls_x509_crt_deinit(x509Certs[i]);
+ }
+
+ delete [] x509Certs;
+
+ if (error) {
+ return null;
+ }
+
+ return make_shared <security::cert::certificateChain>(certs);
+}
+
+
+// Following is a workaround for C++ exceptions to pass correctly between
+// C and C++ calls.
+//
+// gnutls_record_recv() calls TLSSocket::gnutlsPullFunc, and exceptions
+// thrown by the socket can not be caught.
+
+void TLSSocket_GnuTLS::throwException() {
+
+ if (m_ex) {
+ throw *m_ex;
+ }
+}
+
+
+void TLSSocket_GnuTLS::resetException() {
+
+ if (m_ex) {
+ delete m_ex;
+ m_ex = NULL;
+ }
+}
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
diff --git a/vmime-master/src/vmime/net/tls/gnutls/TLSSocket_GnuTLS.hpp b/vmime-master/src/vmime/net/tls/gnutls/TLSSocket_GnuTLS.hpp
new file mode 100644
index 0000000..0ac3e70
--- /dev/null
+++ b/vmime-master/src/vmime/net/tls/gnutls/TLSSocket_GnuTLS.hpp
@@ -0,0 +1,129 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_TLS_TLSSOCKET_GNUTLS_HPP_INCLUDED
+#define VMIME_NET_TLS_TLSSOCKET_GNUTLS_HPP_INCLUDED
+
+
+#ifndef VMIME_BUILDING_DOC
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
+
+
+#include "vmime/net/tls/TLSSocket.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+class TLSSession;
+class TLSSession_GnuTLS;
+
+
+class TLSSocket_GnuTLS : public TLSSocket {
+
+public:
+
+ TLSSocket_GnuTLS(const shared_ptr <TLSSession_GnuTLS>& session, const shared_ptr <socket>& sok);
+ ~TLSSocket_GnuTLS();
+
+
+ void handshake();
+
+ shared_ptr <security::cert::certificateChain> getPeerCertificates();
+
+ // Implementation of 'socket'
+ void connect(const string& address, const port_t port);
+ void disconnect();
+ bool isConnected() const;
+
+ bool waitForRead(const int msecs = 30000);
+ bool waitForWrite(const int msecs = 30000);
+
+ void receive(string& buffer);
+ size_t receiveRaw(byte_t* buffer, const size_t count);
+
+ void send(const string& buffer);
+ void send(const char* str);
+ void sendRaw(const byte_t* buffer, const size_t count);
+ size_t sendRawNonBlocking(const byte_t* buffer, const size_t count);
+
+ size_t getBlockSize() const;
+
+ unsigned int getStatus() const;
+
+ const string getPeerName() const;
+ const string getPeerAddress() const;
+
+ shared_ptr <timeoutHandler> getTimeoutHandler();
+
+ void setTracer(const shared_ptr <net::tracer>& tracer);
+ shared_ptr <net::tracer> getTracer();
+
+private:
+
+ void resetException();
+ void throwException();
+
+#ifdef LIBGNUTLS_VERSION
+ static ssize_t gnutlsPushFunc(gnutls_transport_ptr_t trspt, const void* data, size_t len);
+ static ssize_t gnutlsPullFunc(gnutls_transport_ptr_t trspt, void* data, size_t len);
+ static int gnutlsErrnoFunc(gnutls_transport_ptr_t trspt);
+#else
+ static int gnutlsPushFunc(void* trspt, const void* data, size_t len);
+ static int gnutlsPullFunc(void* trspt, void* data, size_t len);
+ static int gnutlsErrnoFunc(void* trspt);
+#endif // LIBGNUTLS_VERSION
+
+
+ shared_ptr <TLSSession_GnuTLS> m_session;
+ shared_ptr <socket> m_wrapped;
+
+ bool m_connected;
+
+ byte_t m_buffer[65536];
+
+ exception* m_ex;
+
+ unsigned int m_status;
+ int m_errno;
+};
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
+
+#endif // VMIME_BUILDING_DOC
+
+#endif // VMIME_NET_TLS_TLSSOCKET_GNUTLS_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/tls/openssl/OpenSSLInitializer.cpp b/vmime-master/src/vmime/net/tls/openssl/OpenSSLInitializer.cpp
new file mode 100644
index 0000000..c7b1013
--- /dev/null
+++ b/vmime-master/src/vmime/net/tls/openssl/OpenSSLInitializer.cpp
@@ -0,0 +1,169 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+
+
+#include "vmime/net/tls/openssl/OpenSSLInitializer.hpp"
+
+#include "vmime/platform.hpp"
+
+#include <openssl/opensslv.h>
+
+#if OPENSSL_VERSION_NUMBER >= 0x10100000L
+# define OPENSSL_API_COMPAT 0x10100000L
+#endif
+
+#include <openssl/ssl.h>
+#include <openssl/rand.h>
+#include <openssl/crypto.h>
+#include <openssl/err.h>
+
+#if OPENSSL_VERSION_NUMBER >= 0x0907000L
+# include <openssl/conf.h>
+#endif
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+# include "vmime/utility/sync/autoLock.hpp"
+# include "vmime/utility/sync/criticalSection.hpp"
+#endif
+
+
+// OpenSSL locking callbacks for multithreading support (< v1.1 only)
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+
+namespace {
+
+vmime::shared_ptr <vmime::utility::sync::criticalSection >* g_openSSLMutexes = NULL;
+
+extern "C" void VMime_OpenSSLCallback_lock(int mode, int n, const char* /* file */, int /* line */) {
+
+ if (mode & CRYPTO_LOCK) {
+ g_openSSLMutexes[n]->lock();
+ } else {
+ g_openSSLMutexes[n]->unlock();
+ }
+}
+
+extern "C" unsigned long VMime_OpenSSLCallback_id() {
+
+ return vmime::platform::getHandler()->getThreadId();
+}
+
+}
+
+#endif
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+OpenSSLInitializer::autoInitializer::autoInitializer() {
+
+ // The construction of this unique 'oneTimeInitializer' object will be triggered
+ // by the 'autoInitializer' objects from the other translation units
+ static OpenSSLInitializer::oneTimeInitializer oneTimeInitializer;
+}
+
+
+OpenSSLInitializer::autoInitializer::~autoInitializer() {
+
+}
+
+
+OpenSSLInitializer::oneTimeInitializer::oneTimeInitializer() {
+
+ initialize();
+}
+
+
+OpenSSLInitializer::oneTimeInitializer::~oneTimeInitializer() {
+
+ uninitialize();
+}
+
+
+// static
+void OpenSSLInitializer::initialize() {
+
+#if OPENSSL_VERSION_NUMBER >= 0x0907000L && OPENSSL_VERSION_NUMBER < 0x10100000L
+ OPENSSL_config(NULL);
+#endif
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+ SSL_load_error_strings();
+ SSL_library_init();
+ OpenSSL_add_all_algorithms();
+
+ int numMutexes = CRYPTO_num_locks();
+ g_openSSLMutexes = new shared_ptr <vmime::utility::sync::criticalSection>[numMutexes];
+
+ for (int i = 0 ; i < numMutexes ; ++i) {
+ g_openSSLMutexes[i] = vmime::platform::getHandler()->createCriticalSection();
+ }
+
+ CRYPTO_set_locking_callback(VMime_OpenSSLCallback_lock);
+ CRYPTO_set_id_callback(VMime_OpenSSLCallback_id);
+#endif
+
+ // Seed the RNG, in case /dev/urandom is not available. Explicitely calling
+ // RAND_seed() even though /dev/urandom is available is harmless.
+ enum {
+ SEEDSIZE = 256
+ };
+
+ unsigned char seed[SEEDSIZE];
+ vmime::platform::getHandler()->generateRandomBytes(seed, SEEDSIZE);
+ RAND_seed(seed, SEEDSIZE);
+}
+
+
+// static
+void OpenSSLInitializer::uninitialize() {
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+ EVP_cleanup();
+ ERR_free_strings();
+
+ CRYPTO_set_locking_callback(NULL);
+ CRYPTO_set_id_callback(NULL);
+
+ delete [] g_openSSLMutexes;
+ g_openSSLMutexes = NULL;
+#endif
+
+}
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+
diff --git a/vmime-master/src/vmime/net/tls/openssl/OpenSSLInitializer.hpp b/vmime-master/src/vmime/net/tls/openssl/OpenSSLInitializer.hpp
new file mode 100644
index 0000000..3b8496d
--- /dev/null
+++ b/vmime-master/src/vmime/net/tls/openssl/OpenSSLInitializer.hpp
@@ -0,0 +1,90 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_TLS_OPENSSL_OPENSSLINITIALIZER_HPP_INCLUDED
+#define VMIME_NET_TLS_OPENSSL_OPENSSLINITIALIZER_HPP_INCLUDED
+
+
+#ifndef VMIME_BUILDING_DOC
+
+
+#include "vmime/config.hpp"
+
+#include <vector>
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+
+
+#include "vmime/utility/sync/criticalSection.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+/** Class responsible for setting up OpenSSL
+ */
+class OpenSSLInitializer {
+
+public:
+
+ /** Automatically initialize OpenSSL
+ */
+ struct autoInitializer {
+
+ autoInitializer();
+ ~autoInitializer();
+ };
+
+protected:
+
+ struct oneTimeInitializer {
+
+ oneTimeInitializer();
+ ~oneTimeInitializer();
+ };
+
+
+ /** Initializes the OpenSSL lib
+ */
+ static void initialize();
+
+ /** Shutdown the OpenSSL lib
+ */
+ static void uninitialize();
+};
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+
+#endif // VMIME_BUILDING_DOC
+
+#endif // VMIME_NET_TLS_OPENSSL_OPENSSLINITIALIZER_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/tls/openssl/TLSProperties_OpenSSL.cpp b/vmime-master/src/vmime/net/tls/openssl/TLSProperties_OpenSSL.cpp
new file mode 100644
index 0000000..ea22f1c
--- /dev/null
+++ b/vmime-master/src/vmime/net/tls/openssl/TLSProperties_OpenSSL.cpp
@@ -0,0 +1,112 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+
+
+#include "vmime/base.hpp"
+#include "vmime/net/tls/openssl/TLSProperties_OpenSSL.hpp"
+
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+TLSProperties::TLSProperties()
+ : m_data(make_shared <TLSProperties_OpenSSL>()) {
+
+ setCipherSuite(CIPHERSUITE_DEFAULT);
+}
+
+
+TLSProperties::TLSProperties(const TLSProperties& props)
+ : object(),
+ m_data(make_shared <TLSProperties_OpenSSL>()) {
+
+ *dynamicCast <TLSProperties_OpenSSL>(m_data) = *dynamicCast <TLSProperties_OpenSSL>(props.m_data);
+}
+
+
+void TLSProperties::setCipherSuite(const GenericCipherSuite cipherSuite) {
+
+ switch (cipherSuite) {
+
+ case CIPHERSUITE_HIGH:
+
+ setCipherSuite("HIGH:!ADH:@STRENGTH");
+ break;
+
+ case CIPHERSUITE_MEDIUM:
+
+ setCipherSuite("MEDIUM:!ADH:@STRENGTH");
+ break;
+
+ case CIPHERSUITE_LOW:
+
+ setCipherSuite("LOW:!ADH:@STRENGTH");
+ break;
+
+ default:
+ case CIPHERSUITE_DEFAULT:
+
+ setCipherSuite("DEFAULT:!ADH:@STRENGTH");
+ break;
+ }
+}
+
+
+void TLSProperties::setCipherSuite(const string& cipherSuite) {
+
+ dynamicCast <TLSProperties_OpenSSL>(m_data)->cipherSuite = cipherSuite;
+}
+
+
+const string TLSProperties::getCipherSuite() const {
+
+ return dynamicCast <TLSProperties_OpenSSL>(m_data)->cipherSuite;
+}
+
+
+
+TLSProperties_OpenSSL& TLSProperties_OpenSSL::operator=(const TLSProperties_OpenSSL& other) {
+
+ cipherSuite = other.cipherSuite;
+
+ return *this;
+}
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+
diff --git a/vmime-master/src/vmime/net/tls/openssl/TLSProperties_OpenSSL.hpp b/vmime-master/src/vmime/net/tls/openssl/TLSProperties_OpenSSL.hpp
new file mode 100644
index 0000000..8304df2
--- /dev/null
+++ b/vmime-master/src/vmime/net/tls/openssl/TLSProperties_OpenSSL.hpp
@@ -0,0 +1,68 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_TLS_TLSPROPERTIES_OPENSSL_HPP_INCLUDED
+#define VMIME_NET_TLS_TLSPROPERTIES_OPENSSL_HPP_INCLUDED
+
+
+#ifndef VMIME_BUILDING_DOC
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+
+
+#include "vmime/types.hpp"
+
+#include "vmime/net/tls/TLSProperties.hpp"
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+class TLSProperties_OpenSSL : public object {
+
+public:
+
+ TLSProperties_OpenSSL& operator=(const TLSProperties_OpenSSL& other);
+
+
+ string cipherSuite;
+};
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+
+#endif // VMIME_BUILDING_DOC
+
+#endif // VMIME_NET_TLS_TLSPROPERTIES_OPENSSL_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/tls/openssl/TLSSession_OpenSSL.cpp b/vmime-master/src/vmime/net/tls/openssl/TLSSession_OpenSSL.cpp
new file mode 100644
index 0000000..019341c
--- /dev/null
+++ b/vmime-master/src/vmime/net/tls/openssl/TLSSession_OpenSSL.cpp
@@ -0,0 +1,147 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+
+
+#include "vmime/net/tls/openssl/TLSSession_OpenSSL.hpp"
+#include "vmime/net/tls/openssl/TLSProperties_OpenSSL.hpp"
+#include "vmime/net/tls/openssl/OpenSSLInitializer.hpp"
+
+#include "vmime/security/cert/certificateException.hpp"
+
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+static OpenSSLInitializer::autoInitializer openSSLInitializer;
+
+
+// static
+shared_ptr <TLSSession> TLSSession::create(
+ const shared_ptr <security::cert::certificateVerifier>& cv,
+ const shared_ptr <TLSProperties>& props
+) {
+
+ return make_shared <TLSSession_OpenSSL>(cv, props);
+}
+
+
+TLSSession_OpenSSL::TLSSession_OpenSSL(
+ const shared_ptr <vmime::security::cert::certificateVerifier>& cv,
+ const shared_ptr <TLSProperties>& props
+)
+ : m_sslctx(0),
+ m_certVerifier(cv),
+ m_props(props) {
+
+ m_sslctx = SSL_CTX_new(SSLv23_client_method());
+ SSL_CTX_set_options(m_sslctx, SSL_OP_ALL | SSL_OP_NO_SSLv2);
+ SSL_CTX_set_mode(m_sslctx, SSL_MODE_AUTO_RETRY);
+ SSL_CTX_set_cipher_list(m_sslctx, m_props->getCipherSuite().c_str());
+ SSL_CTX_set_session_cache_mode(m_sslctx, SSL_SESS_CACHE_OFF);
+}
+
+
+TLSSession_OpenSSL::TLSSession_OpenSSL(const TLSSession_OpenSSL&)
+ : TLSSession() {
+
+ // Not used
+}
+
+
+TLSSession_OpenSSL::~TLSSession_OpenSSL() {
+
+ SSL_CTX_free(m_sslctx);
+}
+
+
+shared_ptr <TLSSocket> TLSSession_OpenSSL::getSocket(const shared_ptr <socket>& sok) {
+
+ return TLSSocket::wrap(dynamicCast <TLSSession>(shared_from_this()), sok);
+}
+
+
+shared_ptr <security::cert::certificateVerifier> TLSSession_OpenSSL::getCertificateVerifier() {
+
+ return m_certVerifier;
+}
+
+
+void TLSSession_OpenSSL::usePrivateKeyFile(const vmime::string& keyfile) {
+
+ ERR_clear_error();
+
+ if (SSL_CTX_use_PrivateKey_file(m_sslctx, keyfile.c_str(), SSL_FILETYPE_PEM) != 1) {
+
+ unsigned long errCode = ERR_get_error();
+ char buffer[256];
+ ERR_error_string_n(errCode, buffer, sizeof(buffer));
+ vmime::string sslErr(buffer);
+ std::ostringstream oss;
+ oss << "Error loading private key from file " << keyfile;
+ oss << " - msg: " << sslErr;
+ throw security::cert::certificateException(oss.str());
+ }
+}
+
+
+void TLSSession_OpenSSL::useCertificateChainFile(const vmime::string& chainFile) {
+
+ ERR_clear_error();
+
+ if (SSL_CTX_use_certificate_chain_file(m_sslctx, chainFile.c_str()) != 1) {
+
+ unsigned long errCode = ERR_get_error();
+ char buffer[256];
+ ERR_error_string_n(errCode, buffer, sizeof(buffer));
+ vmime::string sslErr(buffer);
+ std::ostringstream oss;
+ oss << "Error loading certificate from file " << chainFile;
+ oss << " - msg: " << sslErr;
+ throw security::cert::certificateException(oss.str());
+ }
+}
+
+
+SSL_CTX* TLSSession_OpenSSL::getContext() const {
+
+ return m_sslctx;
+}
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+
diff --git a/vmime-master/src/vmime/net/tls/openssl/TLSSession_OpenSSL.hpp b/vmime-master/src/vmime/net/tls/openssl/TLSSession_OpenSSL.hpp
new file mode 100644
index 0000000..518216b
--- /dev/null
+++ b/vmime-master/src/vmime/net/tls/openssl/TLSSession_OpenSSL.hpp
@@ -0,0 +1,109 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_TLS_TLSSESSION_OPENSSL_HPP_INCLUDED
+#define VMIME_NET_TLS_TLSSESSION_OPENSSL_HPP_INCLUDED
+
+
+#ifndef VMIME_BUILDING_DOC
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+
+
+#include "vmime/types.hpp"
+
+#include "vmime/net/tls/TLSSession.hpp"
+#include "vmime/net/tls/TLSSocket.hpp"
+#include "vmime/net/tls/TLSProperties.hpp"
+
+
+#include <openssl/ssl.h>
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+class TLSSession_OpenSSL : public TLSSession {
+
+ friend class TLSSocket_OpenSSL;
+
+public:
+
+ TLSSession_OpenSSL(
+ const shared_ptr <security::cert::certificateVerifier>& cv,
+ const shared_ptr <TLSProperties>& props
+ );
+
+ ~TLSSession_OpenSSL();
+
+
+ shared_ptr <TLSSocket> getSocket(const shared_ptr <socket>& sok);
+
+ shared_ptr <security::cert::certificateVerifier> getCertificateVerifier();
+
+
+ /** Set the private key to use if server requires a client certificate.
+ *
+ * @param keyfile path to the private key in PEM format
+ */
+ void usePrivateKeyFile(const vmime::string& keyfile);
+
+ /** Supply the certificate chain to present if requested by server.
+ *
+ * @param chainFile File in PEM format holding certificate chain
+ */
+ void useCertificateChainFile(const vmime::string& chainFile);
+
+ /** Get a pointer to the SSL_CTX used for this session.
+ *
+ * @return the SSL_CTX used for all connections created with this session
+ */
+ SSL_CTX* getContext() const;
+
+private:
+
+ TLSSession_OpenSSL(const TLSSession_OpenSSL&);
+
+ SSL_CTX* m_sslctx;
+
+ shared_ptr <security::cert::certificateVerifier> m_certVerifier;
+ shared_ptr <TLSProperties> m_props;
+};
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+
+#endif // VMIME_BUILDING_DOC
+
+#endif // VMIME_NET_TLS_TLSSESSION_OPENSSL_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/tls/openssl/TLSSocket_OpenSSL.cpp b/vmime-master/src/vmime/net/tls/openssl/TLSSocket_OpenSSL.cpp
new file mode 100644
index 0000000..978f0ca
--- /dev/null
+++ b/vmime-master/src/vmime/net/tls/openssl/TLSSocket_OpenSSL.cpp
@@ -0,0 +1,761 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+
+
+#include <openssl/ssl.h>
+#include <openssl/err.h>
+
+#include "vmime/net/tls/openssl/TLSSocket_OpenSSL.hpp"
+#include "vmime/net/tls/openssl/TLSSession_OpenSSL.hpp"
+#include "vmime/net/tls/openssl/OpenSSLInitializer.hpp"
+
+#include "vmime/platform.hpp"
+
+#include "vmime/security/cert/openssl/X509Certificate_OpenSSL.hpp"
+
+#include "vmime/utility/stringUtils.hpp"
+
+#include <vector>
+#include <cstring>
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+static OpenSSLInitializer::autoInitializer openSSLInitializer;
+
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+
+// static
+BIO_METHOD TLSSocket_OpenSSL::sm_customBIOMethod = {
+ 100 | BIO_TYPE_SOURCE_SINK,
+ "vmime::socket glue",
+ TLSSocket_OpenSSL::bio_write,
+ TLSSocket_OpenSSL::bio_read,
+ TLSSocket_OpenSSL::bio_puts,
+ NULL, // gets
+ TLSSocket_OpenSSL::bio_ctrl,
+ TLSSocket_OpenSSL::bio_create,
+ TLSSocket_OpenSSL::bio_destroy,
+ 0
+};
+
+#define BIO_set_init(b, val) b->init = val
+#define BIO_set_data(b, val) b->ptr = val
+#define BIO_set_num(b, val) b->num = val
+#define BIO_set_flags(b, val) b->flags = val
+#define BIO_set_shutdown(b, val) b->shutdown = val
+#define BIO_get_init(b) b->init
+#define BIO_get_data(b) b->ptr
+#define BIO_get_shutdown(b) b->shutdown
+
+#else
+
+#define BIO_set_num(b, val)
+
+#endif
+
+
+
+// static
+shared_ptr <TLSSocket> TLSSocket::wrap(
+ const shared_ptr <TLSSession>& session,
+ const shared_ptr <socket>& sok
+) {
+
+ return make_shared <TLSSocket_OpenSSL>(dynamicCast <TLSSession_OpenSSL>(session), sok);
+}
+
+
+TLSSocket_OpenSSL::TLSSocket_OpenSSL(
+ const shared_ptr <TLSSession_OpenSSL>& session,
+ const shared_ptr <socket>& sok
+)
+ : m_session(session),
+ m_wrapped(sok),
+ m_connected(false),
+ m_ssl(0),
+ m_status(0),
+ m_ex() {
+
+}
+
+
+TLSSocket_OpenSSL::~TLSSocket_OpenSSL() {
+
+ try {
+ disconnect();
+ } catch (...) {
+ // Don't throw in destructor
+ }
+}
+
+
+void TLSSocket_OpenSSL::createSSLHandle() {
+
+ if (m_wrapped->isConnected()) {
+ string peerName = getPeerName();
+
+ if (peerName.empty()) {
+ throw exceptions::tls_exception("Unknown host name, will not be able to set SNI");
+ }
+
+#if OPENSSL_VERSION_NUMBER < 0x10100000L
+
+ BIO* sockBio = BIO_new(&sm_customBIOMethod);
+ sockBio->ptr = this;
+ sockBio->init = 1;
+
+#else
+
+ BIO_METHOD* bioMeth = BIO_meth_new(BIO_TYPE_SOURCE_SINK | BIO_get_new_index(), "vmime::socket glue");
+
+ if (!bioMeth) {
+ BIO_meth_free(bioMeth);
+ throw exceptions::tls_exception("BIO_meth_new() failed");
+ }
+
+ BIO_meth_set_write(bioMeth, TLSSocket_OpenSSL::bio_write);
+ BIO_meth_set_read(bioMeth, TLSSocket_OpenSSL::bio_read);
+ BIO_meth_set_puts(bioMeth, TLSSocket_OpenSSL::bio_puts);
+ BIO_meth_set_ctrl(bioMeth, TLSSocket_OpenSSL::bio_ctrl);
+ BIO_meth_set_create(bioMeth, TLSSocket_OpenSSL::bio_create);
+ BIO_meth_set_destroy(bioMeth, TLSSocket_OpenSSL::bio_destroy);
+
+ BIO* sockBio = BIO_new(bioMeth);
+ BIO_set_data(sockBio, this);
+ BIO_set_init(sockBio, 1);
+
+#endif
+
+ if (!sockBio) {
+ throw exceptions::tls_exception("BIO_new() failed");
+ }
+
+ m_ssl = SSL_new(m_session->getContext());
+
+ if (!m_ssl) {
+ BIO_free(sockBio);
+ throw exceptions::tls_exception("Cannot create SSL object");
+ }
+
+ SSL_set_bio(m_ssl, sockBio, sockBio);
+ SSL_set_tlsext_host_name(m_ssl, peerName.c_str());
+ SSL_set_connect_state(m_ssl);
+ SSL_set_mode(m_ssl, SSL_MODE_AUTO_RETRY | SSL_MODE_ENABLE_PARTIAL_WRITE | SSL_MODE_ACCEPT_MOVING_WRITE_BUFFER);
+
+ } else {
+
+ throw exceptions::tls_exception("Unconnected socket error");
+ }
+}
+
+
+void TLSSocket_OpenSSL::connect(const string& address, const port_t port) {
+
+ try {
+
+ m_wrapped->connect(address, port);
+
+ createSSLHandle();
+
+ handshake();
+
+ } catch (...) {
+
+ disconnect();
+ throw;
+ }
+}
+
+
+void TLSSocket_OpenSSL::disconnect() {
+
+ if (m_ssl) {
+
+ // Don't shut down the socket more than once.
+ int shutdownState = SSL_get_shutdown(m_ssl);
+ bool shutdownSent = (shutdownState & SSL_SENT_SHUTDOWN) == SSL_SENT_SHUTDOWN;
+
+ if (!shutdownSent) {
+ SSL_shutdown(m_ssl);
+ }
+
+ SSL_free(m_ssl);
+ m_ssl = 0;
+ }
+
+ if (m_connected) {
+ m_connected = false;
+ m_wrapped->disconnect();
+ }
+}
+
+
+bool TLSSocket_OpenSSL::isConnected() const {
+
+ return m_wrapped->isConnected() && m_connected;
+}
+
+
+size_t TLSSocket_OpenSSL::getBlockSize() const {
+
+ return 16384; // 16 KB
+}
+
+
+const string TLSSocket_OpenSSL::getPeerName() const {
+
+ return m_wrapped->getPeerName();
+}
+
+
+const string TLSSocket_OpenSSL::getPeerAddress() const {
+
+ return m_wrapped->getPeerAddress();
+}
+
+
+shared_ptr <timeoutHandler> TLSSocket_OpenSSL::getTimeoutHandler() {
+
+ return m_wrapped->getTimeoutHandler();
+}
+
+
+void TLSSocket_OpenSSL::setTracer(const shared_ptr <net::tracer>& tracer) {
+
+ m_wrapped->setTracer(tracer);
+}
+
+
+shared_ptr <net::tracer> TLSSocket_OpenSSL::getTracer() {
+
+ return m_wrapped->getTracer();
+}
+
+
+bool TLSSocket_OpenSSL::waitForRead(const int msecs) {
+
+ return m_wrapped->waitForRead(msecs);
+}
+
+
+bool TLSSocket_OpenSSL::waitForWrite(const int msecs) {
+
+ return m_wrapped->waitForWrite(msecs);
+}
+
+
+void TLSSocket_OpenSSL::receive(string& buffer) {
+
+ const size_t size = receiveRaw(m_buffer, sizeof(m_buffer));
+
+ if (size != 0) {
+ buffer = utility::stringUtils::makeStringFromBytes(m_buffer, size);
+ } else {
+ buffer.clear();
+ }
+}
+
+
+void TLSSocket_OpenSSL::send(const string& buffer) {
+
+ sendRaw(reinterpret_cast <const byte_t*>(buffer.data()), buffer.length());
+}
+
+
+void TLSSocket_OpenSSL::send(const char* str) {
+
+ sendRaw(reinterpret_cast <const byte_t*>(str), ::strlen(str));
+}
+
+
+size_t TLSSocket_OpenSSL::receiveRaw(byte_t* buffer, const size_t count) {
+
+ if (!m_ssl) {
+ throw exceptions::socket_not_connected_exception();
+ }
+
+ m_status &= ~(STATUS_WANT_WRITE | STATUS_WANT_READ);
+
+ ERR_clear_error();
+ int rc = SSL_read(m_ssl, buffer, static_cast <int>(count));
+
+ if (m_ex.get()) {
+ internalThrow();
+ }
+
+ if (rc <= 0) {
+
+ int error = SSL_get_error(m_ssl, rc);
+
+ if (error == SSL_ERROR_WANT_WRITE) {
+ m_status |= STATUS_WANT_WRITE;
+ return 0;
+ } else if (error == SSL_ERROR_WANT_READ) {
+ m_status |= STATUS_WANT_READ;
+ return 0;
+ }
+
+ handleError(rc);
+ }
+
+ return rc;
+}
+
+
+void TLSSocket_OpenSSL::sendRaw(const byte_t* buffer, const size_t count) {
+
+ if (!m_ssl) {
+ throw exceptions::socket_not_connected_exception();
+ }
+
+ m_status &= ~(STATUS_WANT_WRITE | STATUS_WANT_READ);
+
+ for (size_t size = count ; size > 0 ; ) {
+
+ ERR_clear_error();
+ int rc = SSL_write(m_ssl, buffer, static_cast <int>(size));
+
+ if (rc <= 0) {
+
+ int error = SSL_get_error(m_ssl, rc);
+
+ if (error == SSL_ERROR_WANT_READ) {
+ m_wrapped->waitForRead();
+ continue;
+ } else if (error == SSL_ERROR_WANT_WRITE) {
+ m_wrapped->waitForWrite();
+ continue;
+ }
+
+ handleError(rc);
+
+ } else {
+
+ buffer += rc;
+ size -= rc;
+ }
+ }
+}
+
+
+size_t TLSSocket_OpenSSL::sendRawNonBlocking(const byte_t* buffer, const size_t count) {
+
+ if (!m_ssl) {
+ throw exceptions::socket_not_connected_exception();
+ }
+
+ m_status &= ~(STATUS_WANT_WRITE | STATUS_WANT_READ);
+
+ ERR_clear_error();
+ int rc = SSL_write(m_ssl, buffer, static_cast <int>(count));
+
+ if (m_ex.get()) {
+ internalThrow();
+ }
+
+ if (rc <= 0) {
+
+ int error = SSL_get_error(m_ssl, rc);
+
+ if (error == SSL_ERROR_WANT_WRITE) {
+ m_status |= STATUS_WANT_WRITE;
+ return 0;
+ } else if (error == SSL_ERROR_WANT_READ) {
+ m_status |= STATUS_WANT_READ;
+ return 0;
+ }
+
+ handleError(rc);
+ }
+
+ return rc;
+}
+
+
+void TLSSocket_OpenSSL::handshake() {
+
+ shared_ptr <timeoutHandler> toHandler = m_wrapped->getTimeoutHandler();
+
+ if (toHandler) {
+ toHandler->resetTimeOut();
+ }
+
+ if (getTracer()) {
+ getTracer()->traceSend("Beginning SSL/TLS handshake");
+ }
+
+ // Start handshaking process
+ if (!m_ssl) {
+ createSSLHandle();
+ }
+
+ try {
+
+ int rc;
+
+ ERR_clear_error();
+
+ while ((rc = SSL_do_handshake(m_ssl)) <= 0) {
+
+ const int err = SSL_get_error(m_ssl, rc);
+
+ if (err == SSL_ERROR_WANT_READ) {
+ m_wrapped->waitForRead();
+ } else if (err == SSL_ERROR_WANT_WRITE) {
+ m_wrapped->waitForWrite();
+ } else {
+ handleError(rc);
+ }
+
+ // Check whether the time-out delay is elapsed
+ if (toHandler && toHandler->isTimeOut()) {
+
+ if (!toHandler->handleTimeOut()) {
+ throw exceptions::operation_timed_out();
+ }
+
+ toHandler->resetTimeOut();
+ }
+
+ ERR_clear_error();
+ }
+
+ } catch (...) {
+
+ throw;
+ }
+
+ // Verify server's certificate(s)
+ shared_ptr <security::cert::certificateChain> certs = getPeerCertificates();
+
+ if (!certs) {
+ throw exceptions::tls_exception("No peer certificate.");
+ }
+
+ m_session->getCertificateVerifier()->verify(certs, getPeerName());
+
+ m_connected = true;
+}
+
+
+shared_ptr <security::cert::certificateChain> TLSSocket_OpenSSL::getPeerCertificates() {
+
+ if (getTracer()) {
+ getTracer()->traceSend("Getting peer certificates");
+ }
+
+ STACK_OF(X509)* chain = SSL_get_peer_cert_chain(m_ssl);
+
+ if (chain == NULL) {
+ return null;
+ }
+
+ int certCount = sk_X509_num(chain);
+
+ if (certCount == 0) {
+ return null;
+ }
+
+ bool error = false;
+ std::vector <shared_ptr <security::cert::certificate> > certs;
+
+ for (int i = 0; i < certCount && !error; i++) {
+
+ shared_ptr <vmime::security::cert::X509Certificate> cert =
+ vmime::security::cert::X509Certificate_OpenSSL::importInternal(sk_X509_value(chain, i));
+
+ if (cert) {
+ certs.push_back(cert);
+ } else {
+ error = true;
+ }
+ }
+
+ if (error) {
+ return null;
+ }
+
+ return make_shared <security::cert::certificateChain>(certs);
+}
+
+
+void TLSSocket_OpenSSL::internalThrow() {
+
+ if (m_ex.get()) {
+ throw *m_ex;
+ }
+}
+
+
+void TLSSocket_OpenSSL::handleError(int rc) {
+
+ if (rc > 0) {
+ return;
+ }
+
+ internalThrow();
+
+ int sslError = SSL_get_error(m_ssl, rc);
+ long lastError = ERR_get_error();
+
+ switch (sslError) {
+
+ case SSL_ERROR_ZERO_RETURN:
+
+ disconnect();
+ return;
+
+ case SSL_ERROR_SYSCALL: {
+
+ if (lastError == 0) {
+
+ if (rc == 0) {
+
+ throw exceptions::tls_exception("SSL connection unexpectedly closed");
+
+ } else {
+
+ std::ostringstream oss;
+ oss << "The BIO reported an error: " << rc;
+ oss.flush();
+ throw exceptions::tls_exception(oss.str());
+ }
+ }
+
+ break;
+ }
+
+ case SSL_ERROR_WANT_READ:
+
+ BIO_set_retry_read(SSL_get_rbio(m_ssl));
+ break;
+
+ case SSL_ERROR_WANT_WRITE:
+
+ BIO_set_retry_write(SSL_get_wbio(m_ssl));
+ break;
+
+ // This happens only for BIOs of type BIO_s_connect() or BIO_s_accept()
+ case SSL_ERROR_WANT_CONNECT:
+ case SSL_ERROR_WANT_ACCEPT:
+ // SSL_CTX_set_client_cert_cb related, not used
+ case SSL_ERROR_WANT_X509_LOOKUP:
+ case SSL_ERROR_SSL:
+ default:
+
+ if (lastError == 0) {
+
+ throw exceptions::tls_exception("Unexpected SSL IO error");
+
+ } else {
+
+ char buffer[256];
+ ERR_error_string_n(lastError, buffer, sizeof(buffer));
+ vmime::string msg(buffer);
+ throw exceptions::tls_exception(msg);
+ }
+
+ break;
+ }
+}
+
+
+unsigned int TLSSocket_OpenSSL::getStatus() const {
+
+ return m_status;
+}
+
+
+// Implementation of custom BIO methods
+
+
+// static
+int TLSSocket_OpenSSL::bio_write(BIO* bio, const char* buf, int len) {
+
+ BIO_clear_retry_flags(bio);
+
+ if (buf == NULL || len <= 0) {
+ return -1;
+ }
+
+ TLSSocket_OpenSSL *sok = reinterpret_cast <TLSSocket_OpenSSL*>(BIO_get_data(bio));
+
+ if (!BIO_get_init(bio) || !sok) {
+ return -1;
+ }
+
+ try {
+
+ const size_t n = sok->m_wrapped->sendRawNonBlocking(
+ reinterpret_cast <const byte_t*>(buf), len
+ );
+
+ if (n == 0 && sok->m_wrapped->getStatus() & socket::STATUS_WOULDBLOCK) {
+ BIO_set_retry_write(bio);
+ return -1;
+ }
+
+ return static_cast <int>(n);
+
+ } catch (exception& e) {
+
+ // Workaround for passing C++ exceptions from C BIO functions
+ sok->m_ex.reset(e.clone());
+ return -1;
+ }
+}
+
+
+// static
+int TLSSocket_OpenSSL::bio_read(BIO* bio, char* buf, int len) {
+
+ BIO_clear_retry_flags(bio);
+
+ if (buf == NULL || len <= 0) {
+ return -1;
+ }
+
+ TLSSocket_OpenSSL *sok = reinterpret_cast <TLSSocket_OpenSSL*>(BIO_get_data(bio));
+
+ if (!BIO_get_init(bio) || !sok) {
+ return -1;
+ }
+
+ try {
+
+ const size_t n = sok->m_wrapped->receiveRaw(
+ reinterpret_cast <byte_t*>(buf), len
+ );
+
+ if (n == 0 || sok->m_wrapped->getStatus() & socket::STATUS_WOULDBLOCK) {
+ BIO_set_retry_read(bio);
+ return -1;
+ }
+
+ return static_cast <int>(n);
+
+ } catch (exception& e) {
+
+ // Workaround for passing C++ exceptions from C BIO functions
+ sok->m_ex.reset(e.clone());
+ return -1;
+ }
+}
+
+
+// static
+int TLSSocket_OpenSSL::bio_puts(BIO* bio, const char* str) {
+
+ return bio_write(bio, str, static_cast <int>(strlen(str)));
+}
+
+
+// static
+long TLSSocket_OpenSSL::bio_ctrl(BIO* bio, int cmd, long num, void* /* ptr */) {
+
+ long ret = 1;
+
+ switch (cmd) {
+
+ case BIO_CTRL_INFO:
+
+ ret = 0;
+ break;
+
+ case BIO_CTRL_GET_CLOSE:
+
+ ret = BIO_get_shutdown(bio);
+ break;
+
+ case BIO_CTRL_SET_CLOSE:
+
+ BIO_set_shutdown(bio, static_cast <int>(num));
+ break;
+
+ case BIO_CTRL_PENDING:
+ case BIO_CTRL_WPENDING:
+
+ ret = 0;
+ break;
+
+ case BIO_CTRL_DUP:
+ case BIO_CTRL_FLUSH:
+
+ ret = 1;
+ break;
+
+ default:
+
+ ret = 0;
+ break;
+ }
+
+ return ret;
+}
+
+
+// static
+int TLSSocket_OpenSSL::bio_create(BIO* bio) {
+
+ BIO_set_init(bio, 0);
+ BIO_set_num(bio, 0);
+ BIO_set_data(bio, NULL);
+ BIO_set_flags(bio, 0);
+
+ return 1;
+}
+
+
+// static
+int TLSSocket_OpenSSL::bio_destroy(BIO* bio) {
+
+ if (!bio) {
+ return 0;
+ }
+
+ if (BIO_get_shutdown(bio)) {
+ BIO_set_data(bio, NULL);
+ BIO_set_init(bio, 0);
+ BIO_set_flags(bio, 0);
+ }
+
+ return 1;
+}
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
diff --git a/vmime-master/src/vmime/net/tls/openssl/TLSSocket_OpenSSL.hpp b/vmime-master/src/vmime/net/tls/openssl/TLSSocket_OpenSSL.hpp
new file mode 100644
index 0000000..e30df68
--- /dev/null
+++ b/vmime-master/src/vmime/net/tls/openssl/TLSSocket_OpenSSL.hpp
@@ -0,0 +1,142 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_TLS_TLSSOCKET_OPENSSL_HPP_INCLUDED
+#define VMIME_NET_TLS_TLSSOCKET_OPENSSL_HPP_INCLUDED
+
+
+#ifndef VMIME_BUILDING_DOC
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+
+
+#include "vmime/net/tls/TLSSocket.hpp"
+
+#include <memory>
+
+#include <openssl/ssl.h>
+
+
+namespace vmime {
+namespace net {
+namespace tls {
+
+
+class TLSSession;
+class TLSSession_OpenSSL;
+
+
+class TLSSocket_OpenSSL : public TLSSocket {
+
+public:
+
+ TLSSocket_OpenSSL(
+ const shared_ptr <TLSSession_OpenSSL>& session,
+ const shared_ptr <socket>& sok
+ );
+
+ ~TLSSocket_OpenSSL();
+
+
+ void handshake();
+
+ shared_ptr <security::cert::certificateChain> getPeerCertificates();
+
+ // Implementation of 'socket'
+ void connect(const string& address, const port_t port);
+ void disconnect();
+ bool isConnected() const;
+
+ bool waitForRead(const int msecs = 30000);
+ bool waitForWrite(const int msecs = 30000);
+
+ void receive(string& buffer);
+ size_t receiveRaw(byte_t* buffer, const size_t count);
+
+ void send(const string& buffer);
+ void send(const char* str);
+ void sendRaw(const byte_t* buffer, const size_t count);
+ size_t sendRawNonBlocking(const byte_t* buffer, const size_t count);
+
+ size_t getBlockSize() const;
+
+ unsigned int getStatus() const;
+
+ const string getPeerName() const;
+ const string getPeerAddress() const;
+
+ shared_ptr <timeoutHandler> getTimeoutHandler();
+
+ void setTracer(const shared_ptr <net::tracer>& tracer);
+ shared_ptr <net::tracer> getTracer();
+
+private:
+
+ static BIO_METHOD sm_customBIOMethod;
+
+ static int bio_write(BIO* bio, const char* buf, int len);
+ static int bio_read(BIO* bio, char* buf, int len);
+ static int bio_puts(BIO* bio, const char* str);
+ static int bio_gets(BIO* bio, char* buf, int len);
+ static long bio_ctrl(BIO* bio, int cmd, long num, void* ptr);
+ static int bio_create(BIO* bio);
+ static int bio_destroy(BIO* bio);
+
+ void createSSLHandle();
+
+ void internalThrow();
+ void handleError(int rc);
+
+
+ shared_ptr <TLSSession_OpenSSL> m_session;
+
+ shared_ptr <socket> m_wrapped;
+
+ bool m_connected;
+
+ byte_t m_buffer[65536];
+
+ SSL* m_ssl;
+
+ unsigned int m_status;
+
+ // Last exception thrown from C BIO functions
+ scoped_ptr <exception> m_ex;
+};
+
+
+} // tls
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+
+#endif // VMIME_BUILDING_DOC
+
+#endif // VMIME_NET_TLS_TLSSOCKET_OPENSSL_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/net/tracer.cpp b/vmime-master/src/vmime/net/tracer.cpp
new file mode 100644
index 0000000..66afb36
--- /dev/null
+++ b/vmime-master/src/vmime/net/tracer.cpp
@@ -0,0 +1,74 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "tracer.hpp"
+
+
+#include <sstream>
+
+
+namespace vmime {
+namespace net {
+
+
+void tracer::traceReceiveBytes(const size_t count, const string& state) {
+
+ std::ostringstream oss;
+ oss << "{...";
+
+ if (!state.empty()) {
+ oss << state << ": ";
+ }
+
+ oss << count << " bytes of data...}";
+
+ traceReceive(oss.str());
+}
+
+
+void tracer::traceSendBytes(const size_t count, const string& state) {
+
+ std::ostringstream oss;
+ oss << "{...";
+
+ if (!state.empty()) {
+ oss << state << ": ";
+ }
+
+ oss << count << " bytes of data...}";
+
+ traceSend(oss.str());
+}
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
diff --git a/vmime-master/src/vmime/net/tracer.hpp b/vmime-master/src/vmime/net/tracer.hpp
new file mode 100644
index 0000000..7472463
--- /dev/null
+++ b/vmime-master/src/vmime/net/tracer.hpp
@@ -0,0 +1,110 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_TRACER_HPP_INCLUDED
+#define VMIME_NET_TRACER_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/base.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+class service;
+
+
+/** Base class for an object used to trace network communication
+ * between the client and the server.
+ */
+class VMIME_EXPORT tracer : public object {
+
+public:
+
+ virtual ~tracer() {
+
+ }
+
+ /** Trace raw bytes which have been received.
+ *
+ * @param count number of bytes
+ * @param state protocol state (eg. "SASL exchange"), or empty
+ */
+ virtual void traceReceiveBytes(const size_t count, const string& state = "");
+
+ /** Trace raw bytes which have been sent.
+ *
+ * @param count number of bytes
+ * @param state protocol state (eg. "SASL exchange"), or empty
+ */
+ virtual void traceSendBytes(const size_t count, const string& state = "");
+
+ /** Trace a command line which has been sent.
+ *
+ * @param line command line
+ */
+ virtual void traceSend(const string& line) = 0;
+
+ /** Trace a response line which has been received.
+ *
+ * @param line response line
+ */
+ virtual void traceReceive(const string& line) = 0;
+};
+
+
+/** A class to create 'tracer' objects.
+ */
+class VMIME_EXPORT tracerFactory : public object {
+
+public:
+
+ virtual ~tracerFactory() {
+
+ }
+
+ /** Creates a tracer for the specified service.
+ *
+ * @param serv messaging service
+ * @param connectionId an identifier for the connection to distinguate between
+ * different connections used by a service
+ * @return a new tracer
+ */
+ virtual shared_ptr <tracer> create(const shared_ptr <service>& serv, const int connectionId) = 0;
+};
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+#endif // VMIME_NET_TRACER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/net/transport.cpp b/vmime-master/src/vmime/net/transport.cpp
new file mode 100644
index 0000000..0991302
--- /dev/null
+++ b/vmime-master/src/vmime/net/transport.cpp
@@ -0,0 +1,265 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/net/transport.hpp"
+
+#include "vmime/utility/stream.hpp"
+#include "vmime/mailboxList.hpp"
+#include "vmime/message.hpp"
+#include "vmime/dateTime.hpp"
+#include "vmime/messageId.hpp"
+
+#include "vmime/utility/outputStreamAdapter.hpp"
+#include "vmime/utility/inputStreamStringAdapter.hpp"
+
+
+namespace vmime {
+namespace net {
+
+
+transport::transport(
+ const shared_ptr <session>& sess,
+ const serviceInfos& infos,
+ const shared_ptr <security::authenticator>& auth
+)
+ : service(sess, infos, auth) {
+
+}
+
+
+shared_ptr <headerField> transport::processHeaderField(const shared_ptr <headerField>& field) {
+
+ if (utility::stringUtils::isStringEqualNoCase(field->getName(), fields::BCC)) {
+
+ // Remove Bcc headers from the message, as required by the RFC.
+ // Some SMTP server automatically strip this header (Postfix, qmail),
+ // and others have an option for this (Exim).
+ return null;
+
+ } else if (utility::stringUtils::isStringEqualNoCase(field->getName(), fields::RETURN_PATH)) {
+
+ // RFC-2821: Return-Path header is added by the final transport system
+ // that delivers the message to its recipient. Then, it should not be
+ // transmitted to MSA.
+ return null;
+
+ } else if (utility::stringUtils::isStringEqualNoCase(field->getName(), fields::ORIGINAL_RECIPIENT)) {
+
+ // RFC-2298: Delivering MTA may add the Original-Recipient header and
+ // discard existing one; so, no need to send it.
+ return null;
+ }
+
+ // Leave the header field as is
+ return field;
+}
+
+
+void transport::processHeader(const shared_ptr <header>& header) {
+
+ if (header->getFieldCount() == 0) {
+ return;
+ }
+
+ // Remove/replace fields
+ for (size_t idx = header->getFieldCount() ; idx != 0 ; --idx) {
+
+ shared_ptr <headerField> field = header->getFieldAt(idx - 1);
+ shared_ptr <headerField> newField = processHeaderField(field);
+
+ if (newField == NULL) {
+ header->removeField(field);
+ } else if (newField != field) {
+ header->replaceField(field, newField);
+ }
+ }
+
+ // Add missing header fields
+ // -- Date
+ if (!header->hasField(fields::DATE)) {
+ header->Date()->setValue(datetime::now());
+ }
+
+ // -- Mime-Version
+ if (!header->hasField(fields::MIME_VERSION)) {
+ header->MimeVersion()->setValue(string(SUPPORTED_MIME_VERSION));
+ }
+
+ // -- Message-Id
+ if (!header->hasField(fields::MESSAGE_ID)) {
+ header->MessageId()->setValue(messageId::generateId());
+ }
+}
+
+
+static void extractMailboxes(
+ mailboxList& recipients,
+ const addressList& list
+) {
+
+ for (size_t i = 0 ; i < list.getAddressCount() ; ++i) {
+
+ shared_ptr <mailbox> mbox = dynamicCast <mailbox>(list.getAddressAt(i)->clone());
+
+ if (mbox) {
+ recipients.appendMailbox(mbox);
+ }
+ }
+}
+
+
+void transport::send(
+ const shared_ptr <vmime::message>& msg,
+ utility::progressListener* progress,
+ const dsnAttributes& dsnAttrs
+) {
+
+ // Extract expeditor
+ shared_ptr <mailbox> fromMbox =
+ msg->getHeader()->findFieldValue <mailbox>(fields::FROM);
+
+ if (!fromMbox) {
+ throw exceptions::no_expeditor();
+ }
+
+ mailbox expeditor = *fromMbox;
+
+ // Extract sender
+ shared_ptr <mailbox> senderMbox =
+ msg->getHeader()->findFieldValue <mailbox>(fields::SENDER);
+
+ mailbox sender;
+
+ if (!senderMbox) {
+ sender = expeditor;
+ } else {
+ sender = *senderMbox;
+ }
+
+ // Extract recipients
+ mailboxList recipients;
+
+ // -- "To" field
+ shared_ptr <addressList> addresses =
+ msg->getHeader()->findFieldValue <addressList>(fields::TO);
+
+ if (addresses) {
+ extractMailboxes(recipients, *addresses);
+ }
+
+ // -- "Cc" field
+ addresses = msg->getHeader()->findFieldValue <addressList>(fields::CC);
+
+ if (addresses) {
+ extractMailboxes(recipients, *addresses);
+ }
+
+ // -- "Bcc" field
+ addresses = msg->getHeader()->findFieldValue <addressList>(fields::BCC);
+
+ if (addresses) {
+ extractMailboxes(recipients, *addresses);
+ }
+
+ // Process message header by removing fields that should be removed
+ // before transmitting the message to MSA, and adding missing fields
+ // which are required/recommended by the RFCs.
+ shared_ptr <header> hdr = vmime::clone(msg->getHeader());
+ processHeader(hdr);
+
+ // To avoid cloning message body (too much overhead), use processed
+ // header during the time we are generating the message to a stream.
+ // Revert it back to original header after.
+ struct XChangeMsgHeader {
+
+ XChangeMsgHeader(
+ const shared_ptr <vmime::message>& _msg,
+ const shared_ptr <vmime::header>& _hdr
+ )
+ : msg(_msg),
+ hdr(msg->getHeader()) {
+
+ // Set new header
+ msg->setHeader(_hdr);
+ }
+
+ ~XChangeMsgHeader() {
+
+ // Revert original header
+ msg->setHeader(hdr);
+ }
+
+ private:
+
+ shared_ptr <vmime::message> msg;
+ shared_ptr <vmime::header> hdr;
+
+ } headerExchanger(msg, hdr);
+
+ send(msg, expeditor, recipients, progress, sender, dsnAttrs);
+}
+
+
+void transport::send(
+ const shared_ptr <vmime::message>& msg,
+ const mailbox& expeditor,
+ const mailboxList& recipients,
+ utility::progressListener* progress,
+ const mailbox& sender,
+ const dsnAttributes& dsnAttrs
+) {
+
+ // Generate the message, "stream" it and delegate the sending
+ // to the generic send() function.
+ std::ostringstream oss;
+ utility::outputStreamAdapter ossAdapter(oss);
+
+ msg->generate(ossAdapter);
+
+ const string& str(oss.str());
+
+ utility::inputStreamStringAdapter isAdapter(str);
+
+ send(expeditor, recipients, isAdapter, str.length(), progress, sender,
+ dsnAttrs);
+}
+
+
+transport::Type transport::getType() const {
+
+ return TYPE_TRANSPORT;
+}
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
diff --git a/vmime-master/src/vmime/net/transport.hpp b/vmime-master/src/vmime/net/transport.hpp
new file mode 100644
index 0000000..daa4717
--- /dev/null
+++ b/vmime-master/src/vmime/net/transport.hpp
@@ -0,0 +1,152 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_NET_TRANSPORT_HPP_INCLUDED
+#define VMIME_NET_TRANSPORT_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/net/dsnAttributes.hpp"
+#include "vmime/net/service.hpp"
+#include "vmime/utility/stream.hpp"
+
+#include "vmime/mailboxList.hpp"
+
+
+namespace vmime {
+
+class header;
+class headerField;
+class message;
+class mailbox;
+class mailboxList;
+
+namespace net {
+
+
+/** A transport service.
+ * Encapsulate protocols that can send messages.
+ */
+class VMIME_EXPORT transport : public service {
+
+protected:
+
+ transport(
+ const shared_ptr <session>& sess,
+ const serviceInfos& infos,
+ const shared_ptr <security::authenticator>& auth
+ );
+
+public:
+
+ /** Send a message over this transport service.
+ * The default implementation simply generates the whole message into
+ * a string buffer and "streams" it via a inputStreamStringAdapter.
+ *
+ * @param msg message to send
+ * @param progress progress listener, or NULL if not used
+ * @param dsnAttributes attributes for Delivery Status Notification (if needed)
+ */
+ virtual void send(
+ const shared_ptr <vmime::message>& msg,
+ utility::progressListener* progress = NULL,
+ const dsnAttributes& dsnAttrs = dsnAttributes()
+ );
+
+ /** Send a message over this transport service.
+ *
+ * @param expeditor expeditor mailbox
+ * @param recipients list of recipient mailboxes
+ * @param is input stream providing message data (header + body)
+ * @param size size of the message data
+ * @param progress progress listener, or NULL if not used
+ * @param sender envelope sender (if empty, expeditor will be used)
+ * @param dsnAttributes attributes for Delivery Status Notification (if needed)
+ */
+ virtual void send(
+ const mailbox& expeditor,
+ const mailboxList& recipients,
+ utility::inputStream& is,
+ const size_t size,
+ utility::progressListener* progress = NULL,
+ const mailbox& sender = mailbox(),
+ const dsnAttributes& dsnAttrs = dsnAttributes()
+ ) = 0;
+
+ /** Send a message over this transport service.
+ * The default implementation simply generates the whole message into
+ * a string buffer and "streams" it via a inputStreamStringAdapter.
+ *
+ * @param msg message to send
+ * @param expeditor expeditor mailbox
+ * @param recipients list of recipient mailboxes
+ * @param progress progress listener, or NULL if not used
+ * @param sender envelope sender (if empty, expeditor will be used)
+ * @param dsnAttributes attributes for Delivery Status Notification (if needed)
+ */
+ virtual void send(
+ const shared_ptr <vmime::message>& msg,
+ const mailbox& expeditor,
+ const mailboxList& recipients,
+ utility::progressListener* progress = NULL,
+ const mailbox& sender = mailbox(),
+ const dsnAttributes& dsnAttrs = dsnAttributes()
+ );
+
+
+ Type getType() const;
+
+protected:
+
+ /** Called by processHeader().
+ * Decides what to do with the specified header field.
+ *
+ * @return NULL if the header should be removed, a reference to a new headerField
+ * if the field is to be replaced, or a reference to the same headerField
+ * that was passed if the field should be left as is
+ */
+ shared_ptr <headerField> processHeaderField(const shared_ptr <headerField>& field);
+
+ /** Prepares the header before transmitting the message.
+ * Removes headers that should not be present (eg. "Bcc", "Return-Path"),
+ * or adds missing headers that are required/recommended by the RFCs.
+ * The header is modified inline.
+ *
+ * @param header headers to process
+ */
+ void processHeader(const shared_ptr <header>& header);
+};
+
+
+} // net
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+#endif // VMIME_NET_TRANSPORT_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/object.cpp b/vmime-master/src/vmime/object.cpp
new file mode 100644
index 0000000..f61b2ac
--- /dev/null
+++ b/vmime-master/src/vmime/object.cpp
@@ -0,0 +1,52 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/types.hpp"
+#include "vmime/object.hpp"
+
+
+namespace vmime {
+
+
+object::object() {
+
+}
+
+
+object::object(const object&) {
+
+}
+
+
+object& object::operator=(const object&) {
+
+ return *this;
+}
+
+
+object::~object() {
+
+}
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/object.hpp b/vmime-master/src/vmime/object.hpp
new file mode 100644
index 0000000..5869d38
--- /dev/null
+++ b/vmime-master/src/vmime/object.hpp
@@ -0,0 +1,52 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_OBJECT_HPP_INCLUDED
+#define VMIME_OBJECT_HPP_INCLUDED
+
+
+#include "vmime/types.hpp"
+
+
+namespace vmime {
+
+
+/** Base object for all objects in the library.
+ */
+class VMIME_EXPORT object {
+
+protected:
+
+ object();
+ object(const object&);
+
+ object& operator=(const object&);
+
+ virtual ~object();
+};
+
+
+} // vmime
+
+
+#endif // VMIME_OBJECT_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/parameter.cpp b/vmime-master/src/vmime/parameter.cpp
new file mode 100644
index 0000000..41b37a4
--- /dev/null
+++ b/vmime-master/src/vmime/parameter.cpp
@@ -0,0 +1,665 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/parameter.hpp"
+#include "vmime/parserHelpers.hpp"
+
+#include "vmime/text.hpp"
+#include "vmime/encoding.hpp"
+
+#include "vmime/utility/outputStreamAdapter.hpp"
+#include "vmime/utility/outputStreamStringAdapter.hpp"
+
+
+namespace vmime {
+
+
+parameter::parameter(const string& name)
+ : m_name(name),
+ m_value(make_shared <word>()) {
+
+}
+
+
+parameter::parameter(const string& name, const word& value)
+ : m_name(name),
+ m_value(make_shared <word>(value)) {
+
+}
+
+
+parameter::parameter(const string& name, const string& value)
+ : m_name(name),
+ m_value(make_shared <word>(value)) {
+
+}
+
+
+parameter::parameter(const parameter&)
+ : component() {
+
+}
+
+
+shared_ptr <component> parameter::clone() const {
+
+ shared_ptr <parameter> p = make_shared <parameter>(m_name);
+ p->copyFrom(*this);
+
+ return (p);
+}
+
+
+void parameter::copyFrom(const component& other) {
+
+ const parameter& param = dynamic_cast <const parameter&>(other);
+
+ m_name = param.m_name;
+ m_value->copyFrom(*param.m_value);
+}
+
+
+parameter& parameter::operator=(const parameter& other) {
+
+ copyFrom(other);
+ return (*this);
+}
+
+
+const string& parameter::getName() const {
+
+ return m_name;
+}
+
+
+const word& parameter::getValue() const {
+
+ return *m_value;
+}
+
+
+void parameter::setValue(const component& value) {
+
+ std::ostringstream oss;
+ utility::outputStreamAdapter vos(oss);
+
+ value.generate(vos);
+
+ setValue(word(oss.str(), vmime::charsets::US_ASCII));
+}
+
+
+void parameter::setValue(const word& value) {
+
+ *m_value = value;
+}
+
+
+void parameter::parseImpl(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition
+) {
+
+ m_value->setBuffer(string(buffer.begin() + position, buffer.begin() + end));
+
+ if (ctx.getInternationalizedEmailSupport()) {
+ m_value->setCharset(charset(charsets::UTF_8));
+ } else {
+ m_value->setCharset(charset(charsets::US_ASCII));
+ }
+
+ if (newPosition) {
+ *newPosition = end;
+ }
+}
+
+
+void parameter::parse(
+ const parsingContext& ctx,
+ const std::vector <valueChunk>& chunks
+) {
+
+ bool foundCharsetChunk = false;
+
+ charset ch(charsets::US_ASCII);
+ string lang;
+
+ std::ostringstream value;
+ value.imbue(std::locale::classic());
+
+ for (std::vector <valueChunk>::size_type i = 0 ; i < chunks.size() ; ++i) {
+
+ const valueChunk& chunk = chunks[i];
+
+ // Decode following data
+ if (chunk.encoded) {
+
+ const size_t len = chunk.data.length();
+ size_t pos = 0;
+
+ // If this is the first encoded chunk, extract charset
+ // and language information
+ if (!foundCharsetChunk) {
+
+ // Eg. "us-ascii'en'This%20is%20even%20more%20"
+ size_t q = chunk.data.find_first_of('\'');
+
+ if (q != string::npos) {
+
+ const string chs = chunk.data.substr(0, q);
+
+ if (!chs.empty()) {
+ ch = charset(chs);
+ }
+
+ ++q;
+ pos = q;
+ }
+
+ q = chunk.data.find_first_of('\'', pos);
+
+ if (q != string::npos) {
+
+ // Extract language
+ lang = chunk.data.substr(pos, q - pos);
+
+ ++q;
+ pos = q;
+ }
+
+ foundCharsetChunk = true;
+ }
+
+ for (size_t i = pos ; i < len ; ++i) {
+
+ const char c = chunk.data[i];
+
+ if (c == '%' && i + 2 < len) {
+
+ unsigned int v = 0;
+
+ // First char
+ switch (chunk.data[i + 1]) {
+
+ case 'a': case 'A': v += 10; break;
+ case 'b': case 'B': v += 11; break;
+ case 'c': case 'C': v += 12; break;
+ case 'd': case 'D': v += 13; break;
+ case 'e': case 'E': v += 14; break;
+ case 'f': case 'F': v += 15; break;
+ default: // assume 0-9
+
+ v += (chunk.data[i + 1] - '0');
+ break;
+ }
+
+ v *= 16;
+
+ // Second char
+ switch (chunk.data[i + 2]) {
+
+ case 'a': case 'A': v += 10; break;
+ case 'b': case 'B': v += 11; break;
+ case 'c': case 'C': v += 12; break;
+ case 'd': case 'D': v += 13; break;
+ case 'e': case 'E': v += 14; break;
+ case 'f': case 'F': v += 15; break;
+ default: // assume 0-9
+
+ v += (chunk.data[i + 2] - '0');
+ break;
+ }
+
+ value << static_cast <char>(v);
+
+ i += 2; // skip next 2 chars
+
+ } else {
+
+ value << c;
+ }
+ }
+
+ // Simply copy data, as it is not encoded
+ } else {
+
+ // This syntax is non-standard (expressly prohibited
+ // by RFC-2047), but is used by Mozilla:
+ //
+ // Content-Type: image/png;
+ // name="=?us-ascii?Q?Logo_VMime=2Epng?="
+
+ // Using 'vmime::text' to parse the data is safe even
+ // if the data is not encoded, because it can recover
+ // from parsing errors.
+ vmime::text t;
+ t.parse(ctx, chunk.data);
+
+ if (t.getWordCount() != 0) {
+
+ value << t.getWholeBuffer();
+
+ if (!foundCharsetChunk) {
+
+ // This is still wrong. Each word can have it's own charset, and can
+ // be mixed (eg. iso-8859-1 and iso-2022-jp), but very unlikely. Real
+ // fix is to have parameters store a vmime::text instead of a
+ // vmime::word in m_value. But that changes the interface.
+ for (size_t i = 0 ; i < t.getWordCount() ; ++i) {
+
+ if (t.getWordAt(i)->getCharset() != ch && ch == charsets::US_ASCII) {
+
+ ch = t.getWordAt(i)->getCharset();
+ break;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ m_value->setBuffer(value.str());
+ m_value->setCharset(ch);
+ m_value->setLanguage(lang);
+}
+
+
+void parameter::generateImpl(
+ const generationContext& ctx,
+ utility::outputStream& os,
+ const size_t curLinePos,
+ size_t* newLinePos
+) const {
+
+ const string& name = m_name;
+ const string& value = m_value->getBuffer();
+
+ // For compatibility with implementations that do not understand RFC-2231,
+ // we may also generate a normal "7bit/us-ascii" parameter
+ generationContext::EncodedParameterValueModes
+ genMode = ctx.getEncodedParameterValueMode();
+
+#if VMIME_ALWAYS_GENERATE_7BIT_PARAMETER
+ genMode = generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047;
+#endif
+
+ // [By Eugene A. Shatokhin]
+ // Note that if both the normal "7bit/us-ascii" value and the extended
+ // value are present, the latter can be ignored by mail processing systems.
+ // This may lead to annoying problems, for example, with strange names of
+ // attachments with all but 7-bit ascii characters removed, etc. To avoid
+ // this, I would suggest not to create "7bit/us-ascii" value if the extended
+ // value is to be generated.
+
+ // A stream for a temporary storage
+ string sevenBitBuffer;
+ utility::outputStreamStringAdapter sevenBitStream(sevenBitBuffer);
+
+ size_t pos = curLinePos;
+
+ if (pos + name.length() + 10 + value.length() > ctx.getMaxLineLength()) {
+
+ sevenBitStream << NEW_LINE_SEQUENCE;
+ pos = NEW_LINE_SEQUENCE_LENGTH;
+ }
+
+ bool needQuoting = false;
+ bool needQuotedPrintable = false;
+ size_t valueLength = 0;
+
+ // Use worst-case length name.length()+2 for 'name=' part of line
+ for (size_t i = 0 ; (i < value.length()) && (pos + name.length() + 2 + valueLength < ctx.getMaxLineLength() - 4) ; ++i, ++valueLength) {
+
+ switch (value[i]) {
+
+ // Characters that need to be quoted _and_ escaped
+ case '"':
+ case '\\':
+ // Other characters that need quoting
+ case ' ':
+ case '\t':
+ case '(':
+ case ')':
+ case '<':
+ case '>':
+ case '@':
+ case ',':
+ case ';':
+ case ':':
+ case '/':
+ case '[':
+ case ']':
+ case '?':
+ case '=':
+
+ needQuoting = true;
+ break;
+
+ default:
+
+ if (!parserHelpers::isAscii(value[i])) {
+ needQuotedPrintable = true;
+ needQuoting = true;
+ }
+
+ break;
+ }
+ }
+
+ const bool cutValue = (valueLength != value.length()); // has the value been cut?
+
+ if (needQuoting) {
+
+ sevenBitStream << name << "=\"";
+ pos += name.length() + 2;
+
+ } else {
+
+ sevenBitStream << name << "=";
+ pos += name.length() + 1;
+ }
+
+ // Check whether there is a recommended encoding for this charset.
+ // If so, the whole buffer will be encoded. Else, the number of
+ // 7-bit (ASCII) bytes in the input will be used to determine if
+ // we need to encode the whole buffer.
+ encoding recommendedEnc;
+ const bool alwaysEncode = m_value->getCharset().getRecommendedEncoding(recommendedEnc);
+ bool extended = alwaysEncode;
+
+ if ((needQuotedPrintable || cutValue || !m_value->getLanguage().empty()) &&
+ genMode != generationContext::PARAMETER_VALUE_NO_ENCODING) {
+
+ // Send the name in quoted-printable, so outlook express et.al.
+ // will understand the real filename
+ size_t oldLen = sevenBitBuffer.length();
+ m_value->generate(sevenBitStream);
+ pos += sevenBitBuffer.length() - oldLen;
+ extended = true; // also send with RFC-2231 encoding
+
+ } else {
+
+ // Do not chop off this value, but just add the complete name as one header line.
+ for (size_t i = 0, n = value.length(), curValueLength = 0 ;
+ i < n && curValueLength < valueLength ; ++i) {
+
+ const char_t c = value[i];
+
+ if (/* needQuoting && */ (c == '"' || c == '\\')) { // 'needQuoting' is implicit
+
+ sevenBitStream << '\\' << value[i]; // escape 'x' with '\x'
+ pos += 2;
+
+ } else if (parserHelpers::isAscii(c)) {
+
+ sevenBitStream << value[i];
+ ++pos;
+ ++curValueLength;
+
+ } else {
+
+ extended = true;
+ }
+ }
+
+ } // !needQuotedPrintable
+
+ if (needQuoting) {
+
+ sevenBitStream << '"';
+ ++pos;
+ }
+
+ if (genMode == generationContext::PARAMETER_VALUE_RFC2047_ONLY ||
+ genMode == generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047) {
+
+ os << sevenBitBuffer;
+ }
+
+ // Also generate an extended parameter if the value contains 8-bit characters
+ // or is too long for a single line
+ if ((extended || cutValue) &&
+ genMode != generationContext::PARAMETER_VALUE_NO_ENCODING &&
+ genMode != generationContext::PARAMETER_VALUE_RFC2047_ONLY) {
+
+
+ if (genMode == generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047) {
+
+ os << ';';
+ ++pos;
+
+ } else {
+
+ // The data output to 'sevenBitBuffer' will be discarded in this case
+ pos = curLinePos;
+ }
+
+ /* RFC-2231
+ * ========
+ *
+ * Content-Type: message/external-body; access-type=URL;
+ * URL*0="ftp://";
+ * URL*1="cs.utk.edu/pub/moore/bulk-mailer/bulk-mailer.tar"
+ *
+ * Content-Type: application/x-stuff;
+ * title*=us-ascii'en-us'This%20is%20%2A%2A%2Afun%2A%2A%2A
+ *
+ * Content-Type: application/x-stuff;
+ * title*0*=us-ascii'en'This%20is%20even%20more%20
+ * title*1*=%2A%2A%2Afun%2A%2A%2A%20
+ * title*2="isn't it!"
+ */
+
+ // Check whether there is enough space for the first section:
+ // parameter name, section identifier, charset and separators
+ // + at least 5 characters for the value
+ const size_t firstSectionLength =
+ name.length() + 4 /* *0*= */ + 2 /* '' */
+ + m_value->getCharset().getName().length();
+
+ if (pos + firstSectionLength + 5 >= ctx.getMaxLineLength()) {
+
+ os << NEW_LINE_SEQUENCE;
+ pos = NEW_LINE_SEQUENCE_LENGTH;
+ }
+
+ // Split text into multiple sections that fit on one line
+ int sectionCount = 0;
+ std::vector <string> sectionText;
+
+ string currentSection;
+ size_t currentSectionLength = firstSectionLength;
+
+ for (size_t i = 0 ; i < value.length() ; ++i) {
+
+ // Check whether we should start a new line (taking into
+ // account the next character will be encoded = worst case)
+ if (currentSectionLength + 3 >= ctx.getMaxLineLength()) {
+
+ sectionText.push_back(currentSection);
+ sectionCount++;
+
+ currentSection.clear();
+ currentSectionLength = NEW_LINE_SEQUENCE_LENGTH + name.length() + 6;
+ }
+
+ // Output next character
+ const char_t c = value[i];
+ bool encode = false;
+
+ switch (c) {
+
+ // special characters
+ case ' ':
+ case '\t':
+ case '\r':
+ case '\n':
+ case '%':
+ case '"':
+ case ';':
+ case ',':
+ case '(':
+ case ')':
+ case '<':
+ case '>':
+ case '@':
+ case ':':
+ case '/':
+ case '[':
+ case ']':
+ case '?':
+ case '=':
+
+ encode = true;
+ break;
+
+ default:
+
+ encode = (!parserHelpers::isPrint(c) ||
+ !parserHelpers::isAscii(c) ||
+ alwaysEncode);
+
+ break;
+ }
+
+ if (encode) { // need encoding
+
+ const int h1 = static_cast <unsigned char>(c) / 16;
+ const int h2 = static_cast <unsigned char>(c) % 16;
+
+ currentSection += '%';
+ currentSection += "0123456789ABCDEF"[h1];
+ currentSection += "0123456789ABCDEF"[h2];
+
+ pos += 3;
+ currentSectionLength += 3;
+
+ } else {
+
+ currentSection += value[i];
+
+ ++pos;
+ ++currentSectionLength;
+ }
+ }
+
+ if (!currentSection.empty()) {
+
+ sectionText.push_back(currentSection);
+ sectionCount++;
+ }
+
+ // Output sections
+ for (int sectionNumber = 0 ; sectionNumber < sectionCount ; ++sectionNumber) {
+
+ os << name;
+
+ if (sectionCount != 1) { // no section specifier when only a single one
+
+ os << '*';
+ os << sectionNumber;
+ }
+
+ os << "*=";
+
+ if (sectionNumber == 0) {
+
+ os << m_value->getCharset().getName();
+ os << '\'' << /* No language */ '\'';
+ }
+
+ os << sectionText[sectionNumber];
+
+ if (sectionNumber + 1 < sectionCount) {
+
+ os << ';';
+ os << NEW_LINE_SEQUENCE;
+ pos = NEW_LINE_SEQUENCE_LENGTH;
+ }
+ }
+
+ } else if (!(genMode == generationContext::PARAMETER_VALUE_RFC2047_ONLY ||
+ genMode == generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047)) {
+
+ // The value does not contain 8-bit characters and
+ // is short enough for a single line.
+ // "7bit/us-ascii" will suffice in this case.
+
+ // Output what has been stored in temporary buffer so far
+ os << sevenBitBuffer;
+ }
+
+ if (newLinePos) {
+ *newLinePos = pos;
+ }
+}
+
+
+size_t parameter::getGeneratedSize(const generationContext& ctx) {
+
+ const string& name = m_name;
+ const string& value = m_value->getBuffer();
+
+ const size_t bytesNeedingEncoding =
+ value.length() - utility::stringUtils::countASCIIchars(value.begin(), value.end());
+
+ const size_t valueLength = value.length();
+
+ // Compute generated length in the very worst case
+
+ // Non-encoded parameter + value (worst case: quoting + QP)
+ size_t len = name.length() + 1 /* = */ + 2 /* "" */ + 7 /* =?...?Q?...?= */
+ + m_value->getCharset().getName().length() + valueLength + bytesNeedingEncoding * 2 + 1 /* ; */;
+
+ // Encoded parameter + value
+ const size_t maxEncodedValueLengthOnLine =
+ ctx.getMaxLineLength() - 2 /* CRLF */ - NEW_LINE_SEQUENCE_LENGTH
+ - name.length() - 5 /* *00*= */ - 1 /* ; */;
+
+ const size_t encodedValueLength = (valueLength + bytesNeedingEncoding * 2)
+ + m_value->getCharset().getName().length() + m_value->getLanguage().length() + 2 /* 2 x ' */;
+
+ const size_t numberOfSections = 1 /* worst case: generation starts at the end of a line */
+ + std::max(size_t(1), encodedValueLength / maxEncodedValueLengthOnLine);
+
+ len += numberOfSections * (name.length() + 5 /* *00*= */ + 1 /* ; */ + 2 /* CRLF */ + NEW_LINE_SEQUENCE_LENGTH) + encodedValueLength;
+
+ return len;
+
+}
+
+
+const std::vector <shared_ptr <component> > parameter::getChildComponents() {
+
+ std::vector <shared_ptr <component> > list;
+
+ list.push_back(m_value);
+
+ return list;
+}
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/parameter.hpp b/vmime-master/src/vmime/parameter.hpp
new file mode 100644
index 0000000..f965bad
--- /dev/null
+++ b/vmime-master/src/vmime/parameter.hpp
@@ -0,0 +1,176 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_PARAMETER_HPP_INCLUDED
+#define VMIME_PARAMETER_HPP_INCLUDED
+
+
+#include "vmime/base.hpp"
+#include "vmime/component.hpp"
+#include "vmime/word.hpp"
+
+
+namespace vmime {
+
+
+class VMIME_EXPORT parameter : public component {
+
+ friend class parameterizedHeaderField;
+
+private:
+
+ parameter(const parameter&);
+
+public:
+
+ /** Construct a parameter with no value.
+ * Charset is set to the current locale charset.
+ *
+ * @param name parameter name
+ */
+ parameter(const string& name);
+
+ /** Construct a parameter given a name and a value.
+ *
+ * @param name parameter name
+ * @param value parameter value
+ */
+ parameter(const string& name, const word& value);
+
+ /** Construct a parameter given a name and a string value
+ * expressed in the current locale charset.
+ *
+ * @param name parameter name
+ * @param value parameter value
+ */
+ parameter(const string& name, const string& value);
+
+
+#ifndef VMIME_BUILDING_DOC
+
+ /** A single section of a multi-section parameter,
+ * as defined in RFC-2231/3. This is used when
+ * calling parse() on the parameter.
+ */
+ struct valueChunk {
+ bool encoded;
+ string data;
+ };
+
+#endif // VMIME_BUILDING_DOC
+
+ shared_ptr <component> clone() const;
+ void copyFrom(const component& other);
+ parameter& operator=(const parameter& other);
+
+ size_t getGeneratedSize(const generationContext& ctx);
+
+ const std::vector <shared_ptr <component> > getChildComponents();
+
+ /** Return the name of this parameter.
+ *
+ * @return name of this parameter
+ */
+ const string& getName() const;
+
+ /** Return the raw value of this parameter.
+ *
+ * @return read-only value
+ */
+ const word& getValue() const;
+
+ /** Return the value of this object in the specified type.
+ * For example, the following code:
+ *
+ * <pre>
+ * getParameter("creation-date")->getValueAs <vmime::dateTime>()
+ * </pre>
+ *
+ * is equivalent to:
+ *
+ * <pre>
+ * shared_ptr <vmime::word> rawValue = getParameter("creation-date");
+ *
+ * vmime::dateTime theDate;
+ * theDate.parse(rawValue->getBuffer());
+ * </pre>
+ *
+ * @param T type to which convert the value
+ * @return value
+ */
+ template <typename T>
+ const T getValueAs() const {
+
+ T ret;
+ ret.parse(m_value->getBuffer());
+
+ return ret;
+ }
+
+ /** Set the value of this parameter.
+ *
+ * @param value new value
+ */
+ void setValue(const component& value);
+
+ /** Set the raw value of this parameter.
+ *
+ * @param value new value
+ */
+ void setValue(const word& value);
+
+
+protected:
+
+ void parseImpl(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition = NULL
+ );
+
+ void generateImpl(
+ const generationContext& ctx,
+ utility::outputStream& os,
+ const size_t curLinePos = 0,
+ size_t* newLinePos = NULL
+ ) const;
+
+private:
+
+ void parse(
+ const parsingContext& ctx,
+ const std::vector <valueChunk>& chunks
+ );
+
+
+ string m_name;
+ shared_ptr <word> m_value;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_PARAMETER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/parameterizedHeaderField.cpp b/vmime-master/src/vmime/parameterizedHeaderField.cpp
new file mode 100644
index 0000000..6815fad
--- /dev/null
+++ b/vmime-master/src/vmime/parameterizedHeaderField.cpp
@@ -0,0 +1,634 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/parameterizedHeaderField.hpp"
+#include "vmime/text.hpp"
+#include "vmime/parserHelpers.hpp"
+
+
+namespace vmime {
+
+
+parameterizedHeaderField::parameterizedHeaderField() {
+
+}
+
+
+parameterizedHeaderField::~parameterizedHeaderField() {
+
+ removeAllParameters();
+}
+
+
+/*
+ This class handles field contents of the following form:
+ Field: VALUE; PARAM1="VALUE1"; PARAM2="VALUE2"...
+
+ eg. RFC-1521
+
+ content := "Content-Type" ":" type "/" subtype *(";" parameter)
+
+ parameter := attribute "=" value
+
+ attribute := token ; case-insensitive
+
+ value := token / quoted-string
+
+ token := 1*<any (ASCII) CHAR except SPACE, CTLs, or tspecials>
+
+ tspecials := "(" / ")" / "<" / ">" / "@"
+ / "," / ";" / ":" / "\" / <">
+ / "/" / "[" / "]" / "?" / "="
+ ; Must be in quoted-string,
+ ; to use within parameter values
+*/
+
+
+#ifndef VMIME_BUILDING_DOC
+
+struct paramInfo {
+
+ bool extended;
+ std::vector <parameter::valueChunk> value;
+ size_t start;
+ size_t end;
+};
+
+#endif // VMIME_BUILDING_DOC
+
+
+void parameterizedHeaderField::parseImpl(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition
+) {
+
+ const char* const pend = buffer.data() + end;
+ const char* const pstart = buffer.data() + position;
+ const char* p = pstart;
+
+ // Skip non-significant whitespaces
+ size_t valueStart = position;
+
+ while (p < pend && parserHelpers::isSpace(*p)) {
+ ++p;
+ ++valueStart;
+ }
+
+ // Advance up to ';', if any
+ size_t valueLength = 0;
+
+ while (p < pend && *p != ';' && (!parserHelpers::isSpace(*p))) { // FIXME: support ";" inside quoted or RFC-2047-encoded text
+
+ ++p;
+ ++valueLength;
+ }
+
+ // Trim whitespaces at the end of the value
+ while (valueLength > 0 && parserHelpers::isSpace(buffer[valueStart + valueLength - 1])) {
+ --valueLength;
+ }
+
+ // Parse value
+ getValue()->parse(ctx, buffer, valueStart, valueStart + valueLength);
+
+ // Reset parameters
+ removeAllParameters();
+
+ // If there is one or more parameters following...
+ if (p < pend) {
+
+ std::map <string, paramInfo> params;
+
+ if (*p != ';') {
+
+ while (p < pend && *p != ';') { // FIXME: support ";" inside quoted or RFC-2047-encoded text
+ ++p;
+ }
+ }
+
+ while (*p == ';') {
+
+ // Skip ';'
+ ++p;
+
+ while (p < pend && parserHelpers::isSpace(*p)) ++p;
+
+ const size_t attrStart = position + (p - pstart);
+
+ while (p < pend && !(*p == ';' || *p == '=')) {
+ ++p;
+ }
+
+ if (p >= pend || *p == ';') {
+
+ // Hmmmm... we didn't found an '=' sign.
+ // This parameter may not be valid so try to advance
+ // to the next one, if there is one.
+ while (p < pend && *p != ';')
+ ++p;
+
+ } else {
+
+ // Extract the attribute name
+ size_t attrEnd = position + (p - pstart);
+
+ while (attrEnd != attrStart && parserHelpers::isSpace(buffer[attrEnd - 1])) {
+ --attrEnd;
+ }
+
+ // Skip '='
+ ++p;
+
+ // Skip white-spaces between '=' and the value
+ while (p < pend && parserHelpers::isSpace(*p)) ++p;
+
+ // Extract the value
+ string value;
+
+ // -- this is a quoted-string
+ if (*p == '"') {
+
+ // Skip '"'
+ ++p;
+
+ // Extract quoted-string
+ bool escape = false;
+ bool stop = false;
+
+ std::ostringstream ss;
+ size_t start = position + (p - pstart);
+
+ for ( ; p < pend && !stop ; ++p) {
+
+ if (escape) {
+
+ escape = false;
+ start = position + (p - pstart);
+
+ } else {
+
+ switch (*p) {
+
+ case '"': {
+
+ ss << string(
+ buffer.begin() + start,
+ buffer.begin() + position + (p - pstart)
+ );
+
+ stop = true;
+ break;
+ }
+ case '\\': {
+
+ ss << string(
+ buffer.begin() + start,
+ buffer.begin() + position + (p - pstart)
+ );
+
+ escape = true;
+ break;
+ }
+
+ }
+ }
+ }
+
+ if (!stop) {
+
+ ss << string(
+ buffer.begin() + start,
+ buffer.begin() + position + (p - pstart)
+ );
+ }
+
+ value = ss.str();
+
+ // -- the value is a simple token
+ } else {
+
+ const size_t valStart = position + (p - pstart);
+
+ while (p < pend && *p != ';') {
+ ++p;
+ }
+
+ size_t valEnd = position + (p - pstart);
+
+ while (valEnd != valStart && parserHelpers::isSpace(buffer[valEnd - 1])) {
+ --valEnd;
+ }
+
+ value = string(
+ buffer.begin() + valStart,
+ buffer.begin() + valEnd
+ );
+ }
+
+ // Don't allow ill-formed parameters
+ if (attrStart != attrEnd && value.length()) {
+
+ string name(buffer.begin() + attrStart, buffer.begin() + attrEnd);
+
+ // Check for RFC-2231 extended parameters
+ bool extended = false;
+ bool encoded = false;
+
+ if (name[name.length() - 1] == '*') {
+
+ name.erase(name.end() - 1, name.end());
+
+ extended = true;
+ encoded = true;
+ }
+
+ // Check for RFC-2231 multi-section parameters
+ const size_t star = name.find_last_of('*');
+
+ if (star != string::npos) {
+
+ bool allDigits = true;
+
+ for (size_t i = star + 1 ; allDigits && (i < name.length()) ; ++i) {
+ allDigits = parserHelpers::isDigit(name[i]);
+ }
+
+ if (allDigits) {
+ name.erase(name.begin() + star, name.end());
+ extended = true;
+ }
+
+ // NOTE: we ignore section number, and we suppose that
+ // the sequence is correct (ie. the sections appear
+ // in order: param*0, param*1...)
+ }
+
+ // Add/replace/modify the parameter
+ const std::map <string, paramInfo>::iterator it = params.find(name);
+
+ if (it != params.end()) {
+
+ paramInfo& info = (*it).second;
+
+ // An extended parameter replaces a normal one
+ if (!info.extended) {
+
+ info.extended = extended;
+ info.value.clear();
+ info.start = attrStart;
+ }
+
+ // Append a new section for a multi-section parameter
+ parameter::valueChunk chunk;
+ chunk.encoded = encoded;
+ chunk.data = value;
+
+ info.value.push_back(chunk);
+ info.end = position + (p - pstart);
+
+ } else {
+
+ parameter::valueChunk chunk;
+ chunk.encoded = encoded;
+ chunk.data = value;
+
+ paramInfo info;
+ info.extended = extended;
+ info.value.push_back(chunk);
+ info.start = attrStart;
+ info.end = position + (p - pstart);
+
+ // Insert a new parameter
+ params.insert(std::map <string, paramInfo>::value_type(name, info));
+ }
+ }
+
+ // Skip white-spaces after this parameter
+ while (p < pend && parserHelpers::isSpace(*p)) ++p;
+ }
+ }
+
+ for (std::map <string, paramInfo>::const_iterator it = params.begin() ;
+ it != params.end() ; ++it) {
+
+ const paramInfo& info = (*it).second;
+
+ // Append this parameter to the list
+ shared_ptr <parameter> param = make_shared <parameter>((*it).first);
+
+ param->parse(ctx, info.value);
+ param->setParsedBounds(info.start, info.end);
+
+ appendParameter(param);
+ }
+ }
+
+ if (newPosition) {
+ *newPosition = end;
+ }
+}
+
+
+void parameterizedHeaderField::generateImpl(
+ const generationContext& ctx,
+ utility::outputStream& os,
+ const size_t curLinePos,
+ size_t* newLinePos
+) const {
+
+ size_t pos = curLinePos;
+
+ // Parent header field
+ headerField::generateImpl(ctx, os, pos, &pos);
+
+ // Parameters
+ for (std::vector <shared_ptr <parameter> >::const_iterator
+ it = m_params.begin() ; it != m_params.end() ; ++it) {
+
+ os << "; ";
+ pos += 2;
+
+ (*it)->generate(ctx, os, pos, &pos);
+ }
+
+ if (newLinePos) {
+ *newLinePos = pos;
+ }
+}
+
+
+size_t parameterizedHeaderField::getGeneratedSize(const generationContext& ctx)
+{
+ size_t size = headerField::getGeneratedSize(ctx);
+
+ for (std::vector <shared_ptr <parameter> >::const_iterator
+ it = m_params.begin() ; it != m_params.end() ; ++it) {
+
+ size += 2; // "; "
+ size += (*it)->getGeneratedSize(ctx);
+ }
+
+ return size;
+}
+
+
+void parameterizedHeaderField::copyFrom(const component& other) {
+
+ headerField::copyFrom(other);
+
+ const parameterizedHeaderField& source = dynamic_cast<const parameterizedHeaderField&>(other);
+
+ removeAllParameters();
+
+ for (std::vector <shared_ptr <parameter> >::const_iterator i = source.m_params.begin() ;
+ i != source.m_params.end() ; ++i) {
+
+ appendParameter(vmime::clone(*i));
+ }
+}
+
+
+parameterizedHeaderField& parameterizedHeaderField::operator=(const parameterizedHeaderField& other) {
+
+ copyFrom(other);
+ return *this;
+}
+
+
+bool parameterizedHeaderField::hasParameter(const string& paramName) const {
+
+ const string name = utility::stringUtils::toLower(paramName);
+
+ std::vector <shared_ptr <parameter> >::const_iterator pos = m_params.begin();
+ const std::vector <shared_ptr <parameter> >::const_iterator end = m_params.end();
+
+ for ( ; pos != end && utility::stringUtils::toLower((*pos)->getName()) != name ; ++pos) {}
+
+ return pos != end;
+}
+
+
+shared_ptr <parameter> parameterizedHeaderField::findParameter(const string& paramName) const {
+
+ const string name = utility::stringUtils::toLower(paramName);
+
+ // Find the first parameter that matches the specified name
+ std::vector <shared_ptr <parameter> >::const_iterator pos = m_params.begin();
+ const std::vector <shared_ptr <parameter> >::const_iterator end = m_params.end();
+
+ for ( ; pos != end && utility::stringUtils::toLower((*pos)->getName()) != name ; ++pos) {}
+
+ // No parameter with this name can be found
+ if (pos == end) {
+ return null;
+ }
+
+ // Else, return a reference to the existing parameter
+ return *pos;
+}
+
+
+shared_ptr <parameter> parameterizedHeaderField::getParameter(const string& paramName) {
+
+ const string name = utility::stringUtils::toLower(paramName);
+
+ // Find the first parameter that matches the specified name
+ std::vector <shared_ptr <parameter> >::const_iterator pos = m_params.begin();
+ const std::vector <shared_ptr <parameter> >::const_iterator end = m_params.end();
+
+ for ( ; pos != end && utility::stringUtils::toLower((*pos)->getName()) != name ; ++pos) {}
+
+ // If no parameter with this name can be found, create a new one
+ if (pos == end) {
+
+ shared_ptr <parameter> param = make_shared <parameter>(paramName);
+
+ appendParameter(param);
+
+ // Return a reference to the new parameter
+ return param;
+
+ // Else, return a reference to the existing parameter
+ } else {
+
+ return *pos;
+ }
+}
+
+
+void parameterizedHeaderField::appendParameter(const shared_ptr <parameter>& param) {
+
+ m_params.push_back(param);
+}
+
+
+void parameterizedHeaderField::insertParameterBefore(
+ const shared_ptr <parameter>& beforeParam,
+ const shared_ptr <parameter>& param
+) {
+
+ const std::vector <shared_ptr <parameter> >::iterator it =
+ std::find(m_params.begin(), m_params.end(), beforeParam);
+
+ if (it == m_params.end()) {
+ throw std::out_of_range("Invalid position");
+ }
+
+ m_params.insert(it, param);
+}
+
+
+void parameterizedHeaderField::insertParameterBefore(
+ const size_t pos,
+ const shared_ptr <parameter>& param
+) {
+
+ if (pos >= m_params.size()) {
+ throw std::out_of_range("Invalid position");
+ }
+
+ m_params.insert(m_params.begin() + pos, param);
+}
+
+
+void parameterizedHeaderField::insertParameterAfter(
+ const shared_ptr <parameter>& afterParam,
+ const shared_ptr <parameter>& param
+) {
+
+ const std::vector <shared_ptr <parameter> >::iterator it =
+ std::find(m_params.begin(), m_params.end(), afterParam);
+
+ if (it == m_params.end()) {
+ throw std::out_of_range("Invalid position");
+ }
+
+ m_params.insert(it + 1, param);
+}
+
+
+void parameterizedHeaderField::insertParameterAfter(
+ const size_t pos,
+ const shared_ptr <parameter>& param
+) {
+
+ if (pos >= m_params.size()) {
+ throw std::out_of_range("Invalid position");
+ }
+
+ m_params.insert(m_params.begin() + pos + 1, param);
+}
+
+
+void parameterizedHeaderField::removeParameter(const shared_ptr <parameter>& param) {
+
+ const std::vector <shared_ptr <parameter> >::iterator it =
+ std::find(m_params.begin(), m_params.end(), param);
+
+ if (it == m_params.end()) {
+ throw std::out_of_range("Invalid position");
+ }
+
+ m_params.erase(it);
+}
+
+
+void parameterizedHeaderField::removeParameter(const size_t pos) {
+
+ const std::vector <shared_ptr <parameter> >::iterator it = m_params.begin() + pos;
+
+ m_params.erase(it);
+}
+
+
+void parameterizedHeaderField::removeAllParameters() {
+
+ m_params.clear();
+}
+
+
+size_t parameterizedHeaderField::getParameterCount() const {
+
+ return m_params.size();
+}
+
+
+bool parameterizedHeaderField::isEmpty() const {
+
+ return m_params.empty();
+}
+
+
+const shared_ptr <parameter> parameterizedHeaderField::getParameterAt(const size_t pos) {
+
+ return m_params[pos];
+}
+
+
+const shared_ptr <const parameter> parameterizedHeaderField::getParameterAt(const size_t pos) const {
+
+ return m_params[pos];
+}
+
+
+const std::vector <shared_ptr <const parameter> > parameterizedHeaderField::getParameterList() const {
+
+ std::vector <shared_ptr <const parameter> > list;
+
+ list.reserve(m_params.size());
+
+ for (std::vector <shared_ptr <parameter> >::const_iterator it = m_params.begin() ;
+ it != m_params.end() ; ++it) {
+
+ list.push_back(*it);
+ }
+
+ return list;
+}
+
+
+const std::vector <shared_ptr <parameter> > parameterizedHeaderField::getParameterList() {
+
+ return m_params;
+}
+
+
+const std::vector <shared_ptr <component> > parameterizedHeaderField::getChildComponents() {
+
+ std::vector <shared_ptr <component> > list = headerField::getChildComponents();
+
+ for (std::vector <shared_ptr <parameter> >::iterator it = m_params.begin() ;
+ it != m_params.end() ; ++it) {
+
+ list.push_back(*it);
+ }
+
+ return list;
+}
+
+
+} // vmime
+
diff --git a/vmime-master/src/vmime/parameterizedHeaderField.hpp b/vmime-master/src/vmime/parameterizedHeaderField.hpp
new file mode 100644
index 0000000..d884f1f
--- /dev/null
+++ b/vmime-master/src/vmime/parameterizedHeaderField.hpp
@@ -0,0 +1,222 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_PARAMETERIZEDHEADERFIELD_HPP_INCLUDED
+#define VMIME_PARAMETERIZEDHEADERFIELD_HPP_INCLUDED
+
+
+#include "vmime/base.hpp"
+#include "vmime/headerFieldFactory.hpp"
+#include "vmime/parameter.hpp"
+#include "vmime/exception.hpp"
+
+
+namespace vmime {
+
+
+/** A header field that can also contain parameters (name=value pairs).
+ * Parameters can be created using vmime::parameterFactory.
+ */
+class VMIME_EXPORT parameterizedHeaderField : public headerField {
+
+ friend class headerFieldFactory;
+
+protected:
+
+ // Protected constructor to prevent the user from creating
+ // new objects without using 'headerFieldFactory'
+ parameterizedHeaderField();
+
+public:
+
+ ~parameterizedHeaderField();
+
+ void copyFrom(const component& other);
+ parameterizedHeaderField& operator=(const parameterizedHeaderField& other);
+
+ /** Checks whether (at least) one parameter with this name exists.
+ * Parameter name is case-insensitive.
+ *
+ * @param paramName parameter name
+ * @return true if at least one parameter with the specified name
+ * exists, or false otherwise
+ */
+ bool hasParameter(const string& paramName) const;
+
+ /** Find the first parameter that matches the specified name. Parameter name
+ * is case-insensitive. If no parameter is found, NULL is returned.
+ *
+ * @param paramName parameter name
+ * @return first parameter with the specified name, or NULL if
+ * no parameter with this name exists
+ */
+ shared_ptr <parameter> findParameter(const string& paramName) const;
+
+ /** Find the first parameter that matches the specified name.
+ * Parameter name is case-insensitive.
+ * If no parameter is found, one will be created and inserted into
+ * the parameter list.
+ *
+ * @param paramName parameter name
+ * @return first parameter with the specified name or a new field
+ * if no parameter is found
+ */
+ shared_ptr <parameter> getParameter(const string& paramName);
+
+ /** Add a parameter at the end of the list.
+ *
+ * @param param parameter to append
+ */
+ void appendParameter(const shared_ptr <parameter>& param);
+
+ /** Insert a new parameter before the specified parameter.
+ *
+ * @param beforeParam parameter before which the new parameter will be inserted
+ * @param param parameter to insert
+ * @throw std::out_of_range if the parameter is not in the list
+ */
+ void insertParameterBefore(
+ const shared_ptr <parameter>& beforeParam,
+ const shared_ptr <parameter>& param
+ );
+
+ /** Insert a new parameter before the specified position.
+ *
+ * @param pos position at which to insert the new parameter (0 to insert at
+ * the beginning of the list)
+ * @param param parameter to insert
+ * @throw std::out_of_range if the position is out of range
+ */
+ void insertParameterBefore(
+ const size_t pos,
+ const shared_ptr <parameter>& param
+ );
+
+ /** Insert a new parameter after the specified parameter.
+ *
+ * @param afterParam parameter after which the new parameter will be inserted
+ * @param param parameter to insert
+ * @throw std::out_of_range if the parameter is not in the list
+ */
+ void insertParameterAfter(
+ const shared_ptr <parameter>& afterParam,
+ const shared_ptr <parameter>& param
+ );
+
+ /** Insert a new parameter after the specified position.
+ *
+ * @param pos position of the parameter before the new parameter
+ * @param param parameter to insert
+ * @throw std::out_of_range if the position is out of range
+ */
+ void insertParameterAfter(
+ const size_t pos,
+ const shared_ptr <parameter>& param
+ );
+
+ /** Remove the specified parameter from the list.
+ *
+ * @param param parameter to remove
+ * @throw std::out_of_range if the parameter is not in the list
+ */
+ void removeParameter(const shared_ptr <parameter>& param);
+
+ /** Remove the parameter at the specified position.
+ *
+ * @param pos position of the parameter to remove
+ */
+ void removeParameter(const size_t pos);
+
+ /** Remove all parameters from the list.
+ */
+ void removeAllParameters();
+
+ /** Return the number of parameters in the list.
+ *
+ * @return number of parameters
+ */
+ size_t getParameterCount() const;
+
+ /** Tests whether the list of parameters is empty.
+ *
+ * @return true if there is no parameter, false otherwise
+ */
+ bool isEmpty() const;
+
+ /** Return the parameter at the specified position.
+ *
+ * @param pos position
+ * @return parameter at position 'pos'
+ */
+ const shared_ptr <parameter> getParameterAt(const size_t pos);
+
+ /** Return the parameter at the specified position.
+ *
+ * @param pos position
+ * @return parameter at position 'pos'
+ */
+ const shared_ptr <const parameter> getParameterAt(const size_t pos) const;
+
+ /** Return the parameter list.
+ *
+ * @return list of parameters
+ */
+ const std::vector <shared_ptr <const parameter> > getParameterList() const;
+
+ /** Return the parameter list.
+ *
+ * @return list of parameters
+ */
+ const std::vector <shared_ptr <parameter> > getParameterList();
+
+ size_t getGeneratedSize(const generationContext& ctx);
+
+ const std::vector <shared_ptr <component> > getChildComponents();
+
+private:
+
+ std::vector <shared_ptr <parameter> > m_params;
+
+protected:
+
+ void parseImpl(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition = NULL
+ );
+
+ void generateImpl(
+ const generationContext& ctx,
+ utility::outputStream& os,
+ const size_t curLinePos = 0,
+ size_t* newLinePos = NULL
+ ) const;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_PARAMETERIZEDHEADERFIELD_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/parsedMessageAttachment.cpp b/vmime-master/src/vmime/parsedMessageAttachment.cpp
new file mode 100644
index 0000000..d50862b
--- /dev/null
+++ b/vmime-master/src/vmime/parsedMessageAttachment.cpp
@@ -0,0 +1,114 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/parsedMessageAttachment.hpp"
+
+#include "vmime/stringContentHandler.hpp"
+#include "vmime/contentDisposition.hpp"
+
+#include "vmime/utility/outputStreamAdapter.hpp"
+
+
+namespace vmime {
+
+
+parsedMessageAttachment::parsedMessageAttachment(const shared_ptr <message>& msg)
+ : m_msg(msg) {
+
+}
+
+
+const mediaType parsedMessageAttachment::getType() const {
+
+ return mediaType(mediaTypes::MESSAGE, mediaTypes::MESSAGE_RFC822);
+}
+
+
+const text parsedMessageAttachment::getDescription() const {
+
+ return text();
+}
+
+
+const word parsedMessageAttachment::getName() const {
+
+ return word();
+}
+
+
+const shared_ptr <const contentHandler> parsedMessageAttachment::getData() const {
+
+ if (!m_data) {
+
+ std::ostringstream oss;
+ utility::outputStreamAdapter os(oss);
+
+ m_msg->generate(os);
+
+ m_data = make_shared <stringContentHandler>(oss.str());
+ }
+
+ return m_data;
+}
+
+
+const encoding parsedMessageAttachment::getEncoding() const {
+
+ return encoding(encodingTypes::EIGHT_BIT); // not important
+}
+
+
+shared_ptr <const object> parsedMessageAttachment::getPart() const {
+
+ return null;
+}
+
+
+shared_ptr <const header> parsedMessageAttachment::getHeader() const {
+
+ return null;
+}
+
+
+shared_ptr <message> parsedMessageAttachment::getMessage() const {
+
+ return m_msg;
+}
+
+
+void parsedMessageAttachment::generateIn(const shared_ptr <bodyPart>& parent) const {
+
+ // Create and append a new part for this attachment
+ shared_ptr <bodyPart> part = make_shared <bodyPart>();
+ parent->getBody()->appendPart(part);
+
+ // Set header fields
+ part->getHeader()->ContentType()->setValue(getType());
+ part->getHeader()->ContentDisposition()->setValue(contentDisposition(contentDispositionTypes::ATTACHMENT));
+
+ // Set contents
+ part->getBody()->setContents(getData());
+}
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/parsedMessageAttachment.hpp b/vmime-master/src/vmime/parsedMessageAttachment.hpp
new file mode 100644
index 0000000..2a5358e
--- /dev/null
+++ b/vmime-master/src/vmime/parsedMessageAttachment.hpp
@@ -0,0 +1,76 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_PARSEDMESSAGEATTACHMENT_HPP_INCLUDED
+#define VMIME_PARSEDMESSAGEATTACHMENT_HPP_INCLUDED
+
+
+#ifndef VMIME_BUILDING_DOC // implementation detail
+
+
+#include "vmime/messageAttachment.hpp"
+
+
+namespace vmime {
+
+
+/** A message attachment that can be generated into a message.
+ */
+class VMIME_EXPORT parsedMessageAttachment : public messageAttachment {
+
+public:
+
+ parsedMessageAttachment(const shared_ptr <message>& msg);
+
+ const mediaType getType() const;
+ const text getDescription() const;
+ const word getName() const;
+
+ const shared_ptr <const contentHandler> getData() const;
+
+ const encoding getEncoding() const;
+
+ shared_ptr <const object> getPart() const;
+
+ shared_ptr <const header> getHeader() const;
+
+ shared_ptr <message> getMessage() const;
+
+protected:
+
+ void generateIn(const shared_ptr <bodyPart>& parent) const;
+
+private:
+
+ shared_ptr <message> m_msg;
+ mutable shared_ptr <contentHandler> m_data;
+};
+
+
+} // vmime
+
+
+#endif // !VMIME_BUILDING_DOC
+
+
+#endif // VMIME_PARSEDMESSAGEATTACHMENT_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/parserHelpers.hpp b/vmime-master/src/vmime/parserHelpers.hpp
new file mode 100644
index 0000000..cba43c6
--- /dev/null
+++ b/vmime-master/src/vmime/parserHelpers.hpp
@@ -0,0 +1,140 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_PARSERHELPERS_HPP_INCLUDED
+#define VMIME_PARSERHELPERS_HPP_INCLUDED
+
+
+#include "vmime/types.hpp"
+#include "vmime/utility/stringUtils.hpp"
+
+#include <algorithm>
+
+
+
+namespace vmime {
+
+
+class parserHelpers {
+
+public:
+
+ static bool isSpace(const char_t c) {
+
+ return c == ' ' || c == '\t' || c == '\n' || c == '\r';
+ }
+
+ static bool isSpaceOrTab(const char_t c) {
+
+ return c == ' ' || c == '\t';
+ }
+
+ static bool isDigit(const char_t c) {
+
+ return c >= '0' && c <= '9';
+ }
+
+ static bool isAlpha(const char_t c) {
+
+ return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
+ }
+
+
+ static char_t toLower(const char_t c) {
+
+ if (c >= 'A' && c <= 'Z') {
+ return ('a' + (c - 'A'));
+ } else {
+ return c;
+ }
+ }
+
+
+ // Checks whether a character is in the 7-bit US-ASCII charset
+
+ static bool isAscii(const char_t c) {
+
+ const unsigned int x = static_cast <unsigned int>(c);
+ return x <= 127;
+ }
+
+
+ // Checks whether a character has a visual representation
+
+ static bool isPrint(const char_t c) {
+
+ const unsigned int x = static_cast <unsigned int>(c);
+ return x >= 0x20 && x <= 0x7E;
+ }
+
+
+ /** Finds the next EOL sequence in the specified buffer.
+ * An EOL sequence may be a CR+LF sequence, or a LF sequence.
+ *
+ * @param buffer search buffer
+ * @param currentPos start searching from this position
+ * @param end stop searching at this position
+ * @param eol will receive the position after the EOL sequence
+ * @return true if an EOL sequence has been found, or false if
+ * no EOL sequence was found before the end of the buffer
+ */
+ static bool findEOL(
+ const string& buffer,
+ const size_t currentPos,
+ const size_t end,
+ size_t* eol
+ ) {
+
+ size_t pos = currentPos;
+
+ if (pos == end) {
+ return false;
+ }
+
+ while (pos < end) {
+
+ if (buffer[pos] == '\r' && pos + 1 < end && buffer[pos + 1] == '\n') {
+
+ *eol = pos + 2;
+ return true;
+
+ } else if (buffer[pos] == '\n') {
+
+ *eol = pos + 1;
+ return true;
+ }
+
+ ++pos;
+ }
+
+ *eol = end;
+
+ return true;
+ }
+};
+
+
+} // vmime
+
+
+#endif // VMIME_PARSERHELPERS_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/parsingContext.cpp b/vmime-master/src/vmime/parsingContext.cpp
new file mode 100644
index 0000000..0975e3d
--- /dev/null
+++ b/vmime-master/src/vmime/parsingContext.cpp
@@ -0,0 +1,64 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/parsingContext.hpp"
+
+
+namespace vmime {
+
+
+parsingContext::parsingContext()
+ : m_headerParseErrorRecovery(vmime::headerParseRecoveryMethod::SKIP_LINE) {
+
+}
+
+
+parsingContext::parsingContext(const parsingContext& ctx)
+ : context(ctx),
+ m_headerParseErrorRecovery(vmime::headerParseRecoveryMethod::SKIP_LINE) {
+
+}
+
+
+parsingContext& parsingContext::getDefaultContext() {
+
+ static parsingContext ctx;
+ return ctx;
+}
+
+
+headerParseRecoveryMethod::headerLineError parsingContext::getHeaderParseErrorRecoveryMethod() const {
+
+ return m_headerParseErrorRecovery;
+}
+
+
+void parsingContext::setHeaderParseErrorRecoveryMethod(
+ const headerParseRecoveryMethod::headerLineError recoveryMethod
+) {
+
+ m_headerParseErrorRecovery = recoveryMethod;
+}
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/parsingContext.hpp b/vmime-master/src/vmime/parsingContext.hpp
new file mode 100644
index 0000000..d13d94e
--- /dev/null
+++ b/vmime-master/src/vmime/parsingContext.hpp
@@ -0,0 +1,82 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_PARSINGCONTEXT_HPP_INCLUDED
+#define VMIME_PARSINGCONTEXT_HPP_INCLUDED
+
+
+#include "vmime/context.hpp"
+
+
+namespace vmime {
+
+/** Provides runtime configurable options to provide flexibility in header parsing
+ */
+struct headerParseRecoveryMethod {
+
+ enum headerLineError {
+ SKIP_LINE = 0,
+ /* APPEND_TO_PREVIOUS_LINE = 1, */
+ ASSUME_END_OF_HEADERS = 2
+ };
+};
+
+/** Holds configuration parameters used for parsing messages.
+ */
+class VMIME_EXPORT parsingContext : public context {
+
+public:
+
+ parsingContext();
+ parsingContext(const parsingContext& ctx);
+
+ /** Returns the default context used for parsing messages.
+ *
+ * @return a reference to the default parsing context
+ */
+ static parsingContext& getDefaultContext();
+
+ /** Sets the recovery method when parsing a header encounters an error
+ * such as a failed fold or missing new line.
+ *
+ * @param recoveryMethod is one of vmime::headerParseRecoveryMethod.
+ * Defaults to vmime::headerParseRecoveryMethod::SKIP_LINE.
+ */
+ void setHeaderParseErrorRecoveryMethod(const headerParseRecoveryMethod::headerLineError recoveryMethod);
+
+ /** Return the recovery method when parsing a header encounters an error.
+ *
+ * @return is an enum from vmime::headerParseRecoveryMethod
+ */
+ headerParseRecoveryMethod::headerLineError getHeaderParseErrorRecoveryMethod() const;
+
+protected:
+
+ headerParseRecoveryMethod::headerLineError m_headerParseErrorRecovery;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_PARSINGCONTEXT_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/path.cpp b/vmime-master/src/vmime/path.cpp
new file mode 100644
index 0000000..f57d128
--- /dev/null
+++ b/vmime-master/src/vmime/path.cpp
@@ -0,0 +1,206 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/path.hpp"
+#include "vmime/parserHelpers.hpp"
+
+
+namespace vmime {
+
+
+path::path() {
+
+}
+
+
+path::path(const string& localPart, const string& domain)
+ : m_localPart(localPart),
+ m_domain(domain) {
+
+}
+
+
+path::path(const path& p)
+ : headerFieldValue(),
+ m_localPart(p.m_localPart),
+ m_domain(p.m_domain) {
+
+}
+
+
+const string& path::getLocalPart() const {
+
+ return m_localPart;
+}
+
+
+void path::setLocalPart(const string& localPart) {
+
+ m_localPart = localPart;
+}
+
+
+const string& path::getDomain() const {
+
+ return m_domain;
+}
+
+
+void path::setDomain(const string& domain) {
+
+ m_domain = domain;
+}
+
+
+bool path::operator==(const path& p) const {
+
+ return m_localPart == p.m_localPart &&
+ m_domain == p.m_domain;
+}
+
+
+bool path::operator!=(const path& p) const {
+
+ return m_localPart != p.m_localPart ||
+ m_domain != p.m_domain;
+}
+
+
+void path::copyFrom(const component& other) {
+
+ const path& p = dynamic_cast <const path&>(other);
+
+ m_localPart = p.m_localPart;
+ m_domain = p.m_domain;
+}
+
+
+shared_ptr <component> path::clone() const {
+
+ return make_shared <path>(*this);
+}
+
+
+path& path::operator=(const path& other) {
+
+ copyFrom(other);
+ return *this;
+}
+
+
+const std::vector <shared_ptr <component> > path::getChildComponents() {
+
+ return std::vector <shared_ptr <component> >();
+}
+
+
+void path::parseImpl(
+ const parsingContext& /* ctx */,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition
+) {
+
+ size_t pos = position;
+
+ while (pos < end && parserHelpers::isSpace(buffer[pos])) {
+ ++pos;
+ }
+
+ string addrSpec;
+
+ if (pos < end && buffer[pos] == '<') {
+
+ // Skip '<'
+ ++pos;
+
+ while (pos < end && parserHelpers::isSpace(buffer[pos])) {
+ ++pos;
+ }
+
+ const size_t addrStart = pos;
+
+ while (pos < end && buffer[pos] != '>') {
+ ++pos;
+ }
+
+ size_t addrEnd = pos;
+
+ while (addrEnd > addrStart && parserHelpers::isSpace(buffer[addrEnd - 1])) {
+ addrEnd--;
+ }
+
+ addrSpec = string(buffer.begin() + addrStart, buffer.begin() + addrEnd);
+
+ } else {
+
+ addrSpec = string(buffer.begin() + position, buffer.begin() + end);
+ }
+
+ const size_t at = addrSpec.find_first_of('@');
+
+ if (at != string::npos) {
+
+ m_localPart = string(addrSpec.begin(), addrSpec.begin() + at);
+ m_domain = string(addrSpec.begin() + at + 1, addrSpec.end());
+
+ } else {
+
+ m_localPart.clear();
+ m_domain = addrSpec;
+ }
+
+ if (newPosition) {
+ *newPosition = end;
+ }
+}
+
+
+void path::generateImpl(
+ const generationContext& /* ctx */,
+ utility::outputStream& os,
+ const size_t curLinePos,
+ size_t* newLinePos
+) const {
+
+ if (m_localPart.empty() && m_domain.empty()) {
+
+ os << "<>";
+
+ if (newLinePos) {
+ *newLinePos = curLinePos + 2;
+ }
+
+ } else {
+
+ os << "<" << m_localPart << "@" << m_domain << ">";
+
+ if (newLinePos) {
+ *newLinePos = curLinePos + m_localPart.length() + m_domain.length() + 3;
+ }
+ }
+}
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/path.hpp b/vmime-master/src/vmime/path.hpp
new file mode 100644
index 0000000..d63ee67
--- /dev/null
+++ b/vmime-master/src/vmime/path.hpp
@@ -0,0 +1,106 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_PATH_HPP_INCLUDED
+#define VMIME_PATH_HPP_INCLUDED
+
+
+#include "vmime/headerFieldValue.hpp"
+
+
+namespace vmime {
+
+
+/** A path: a local part + '@' + a domain.
+ */
+class VMIME_EXPORT path : public headerFieldValue {
+
+public:
+
+ path();
+ path(const string& localPart, const string& domain);
+ path(const path& p);
+
+ /** Return the local part of the address.
+ *
+ * @return local part of the address
+ */
+ const string& getLocalPart() const;
+
+ /** Set the local part of the address.
+ *
+ * @param localPart local part of the address
+ */
+ void setLocalPart(const string& localPart);
+
+ /** Return the domain of the address.
+ *
+ * @return domain of the address
+ */
+ const string& getDomain() const;
+
+ /** Set the domain of the address.
+ *
+ * @param domain domain of the address
+ */
+ void setDomain(const string& domain);
+
+ // Comparison
+ bool operator==(const path& p) const;
+ bool operator!=(const path& p) const;
+
+ // Assignment
+ void copyFrom(const component& other);
+ shared_ptr <component> clone() const;
+ path& operator=(const path& other);
+
+ const std::vector <shared_ptr <component> > getChildComponents();
+
+protected:
+
+ string m_localPart;
+ string m_domain;
+
+
+ // Component parsing & assembling
+ void parseImpl(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition = NULL
+ );
+
+ void generateImpl(
+ const generationContext& ctx,
+ utility::outputStream& os,
+ const size_t curLinePos = 0,
+ size_t* newLinePos = NULL
+ ) const;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_PATH_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/plainTextPart.cpp b/vmime-master/src/vmime/plainTextPart.cpp
new file mode 100644
index 0000000..859a67c
--- /dev/null
+++ b/vmime-master/src/vmime/plainTextPart.cpp
@@ -0,0 +1,121 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/plainTextPart.hpp"
+#include "vmime/header.hpp"
+#include "vmime/exception.hpp"
+
+#include "vmime/contentTypeField.hpp"
+
+#include "vmime/emptyContentHandler.hpp"
+
+
+namespace vmime {
+
+
+plainTextPart::plainTextPart()
+ : m_text(make_shared <emptyContentHandler>()) {
+
+}
+
+
+plainTextPart::~plainTextPart() {
+
+}
+
+
+const mediaType plainTextPart::getType() const {
+
+ return mediaType(mediaTypes::TEXT, mediaTypes::TEXT_PLAIN);
+}
+
+
+size_t plainTextPart::getPartCount() const {
+
+ return 1;
+}
+
+
+void plainTextPart::generateIn(
+ const shared_ptr <bodyPart>& /* message */,
+ const shared_ptr <bodyPart>& parent
+) const {
+
+ // Create a new part
+ shared_ptr <bodyPart> part = make_shared <bodyPart>();
+ parent->getBody()->appendPart(part);
+
+ // Set contents
+ part->getBody()->setContents(
+ m_text,
+ mediaType(mediaTypes::TEXT, mediaTypes::TEXT_PLAIN),
+ m_charset,
+ encoding::decide(m_text, m_charset, encoding::USAGE_TEXT)
+ );
+}
+
+
+void plainTextPart::parse(
+ const shared_ptr <const bodyPart>& /* message */,
+ const shared_ptr <const bodyPart>& /* parent */,
+ const shared_ptr <const bodyPart>& textPart
+) {
+
+ m_text = vmime::clone(textPart->getBody()->getContents());
+
+ shared_ptr <const contentTypeField> ctf =
+ textPart->getHeader()->findField <contentTypeField>(fields::CONTENT_TYPE);
+
+ if (ctf && ctf->hasCharset()) {
+ m_charset = ctf->getCharset();
+ } else {
+ m_charset = charset();
+ }
+}
+
+
+const charset& plainTextPart::getCharset() const {
+
+ return m_charset;
+}
+
+
+void plainTextPart::setCharset(const charset& ch) {
+
+ m_charset = ch;
+}
+
+
+const shared_ptr <const contentHandler> plainTextPart::getText() const{
+
+ return m_text;
+}
+
+
+void plainTextPart::setText(const shared_ptr <contentHandler>& text) {
+
+ m_text = vmime::clone(text);
+}
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/plainTextPart.hpp b/vmime-master/src/vmime/plainTextPart.hpp
new file mode 100644
index 0000000..8a0249e
--- /dev/null
+++ b/vmime-master/src/vmime/plainTextPart.hpp
@@ -0,0 +1,74 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_PLAINTEXTPART_HPP_INCLUDED
+#define VMIME_PLAINTEXTPART_HPP_INCLUDED
+
+
+#include "vmime/textPart.hpp"
+
+
+namespace vmime {
+
+
+/** Text part of type 'text/plain'.
+ */
+class VMIME_EXPORT plainTextPart : public textPart {
+
+public:
+
+ plainTextPart();
+ ~plainTextPart();
+
+ const mediaType getType() const;
+
+ const charset& getCharset() const;
+ void setCharset(const charset& ch);
+
+ const shared_ptr <const contentHandler> getText() const;
+ void setText(const shared_ptr <contentHandler>& text);
+
+ size_t getPartCount() const;
+
+ void generateIn(
+ const shared_ptr <bodyPart>& message,
+ const shared_ptr <bodyPart>& parent
+ ) const;
+
+ void parse(
+ const shared_ptr <const bodyPart>& message,
+ const shared_ptr <const bodyPart>& parent,
+ const shared_ptr <const bodyPart>& textPart
+ );
+
+private:
+
+ shared_ptr <contentHandler> m_text;
+ charset m_charset;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_PLAINTEXTPART_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/platform.cpp b/vmime-master/src/vmime/platform.cpp
new file mode 100644
index 0000000..f2f1e97
--- /dev/null
+++ b/vmime-master/src/vmime/platform.cpp
@@ -0,0 +1,77 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/platform.hpp"
+#include "vmime/config.hpp"
+
+#include "vmime/platforms/posix/posixHandler.hpp"
+#include "vmime/platforms/windows/windowsHandler.hpp"
+
+
+namespace vmime {
+
+
+shared_ptr <platform::handler> platform::sm_handler;
+
+
+platform::handler::~handler() {
+
+}
+
+
+// static
+shared_ptr <platform::handler> platform::getDefaultHandler() {
+
+#if VMIME_PLATFORM_IS_WINDOWS
+ return make_shared <platforms::windows::windowsHandler>();
+#elif VMIME_PLATFORM_IS_POSIX
+ return make_shared <platforms::posix::posixHandler>();
+#else
+ return null;
+#endif
+
+}
+
+
+// static
+shared_ptr <platform::handler> platform::getHandler() {
+
+ // If a custom platform handler is installed, return it
+ if (sm_handler) {
+ return sm_handler;
+ }
+
+ // Else, use the default handler for this platform
+ shared_ptr <handler> defaultHandler = getDefaultHandler();
+
+ if (defaultHandler) {
+ sm_handler = defaultHandler;
+ return sm_handler;
+ }
+
+ // Oops... no platform handler!
+ throw exceptions::no_platform_handler();
+}
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/platform.hpp b/vmime-master/src/vmime/platform.hpp
new file mode 100644
index 0000000..03a7b23
--- /dev/null
+++ b/vmime-master/src/vmime/platform.hpp
@@ -0,0 +1,158 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_PLATFORM_HPP_INCLUDED
+#define VMIME_PLATFORM_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+#include "vmime/dateTime.hpp"
+#include "vmime/exception.hpp"
+#include "vmime/charset.hpp"
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+ #include "vmime/net/socket.hpp"
+ #include "vmime/net/timeoutHandler.hpp"
+#endif
+
+#if VMIME_HAVE_FILESYSTEM_FEATURES
+ #include "vmime/utility/file.hpp"
+ #include "vmime/utility/childProcess.hpp"
+#endif
+
+#include "vmime/utility/sync/criticalSection.hpp"
+
+
+namespace vmime {
+
+
+/** Allow setting or getting the current platform handler.
+ */
+class VMIME_EXPORT platform {
+
+public:
+
+ /** Takes care of all platform-dependent operations. It offers an interface to
+ * access platform-dependent objects: sockets, date/time, file system, etc.
+ */
+ class VMIME_EXPORT handler : public object {
+
+ public:
+
+ virtual ~handler();
+
+ /** Return the current UNIX time (Epoch time): the number of
+ * seconds elapsed since Jan, 1st 1970 00:00.
+ *
+ * @return UNIX Epoch time
+ */
+ virtual unsigned long getUnixTime() const = 0;
+
+ /** Return the current date and time, in the local time zone.
+ *
+ * @return current date and time
+ */
+ virtual const datetime getCurrentLocalTime() const = 0;
+
+ /** Return the host name of the system.
+ * Used when generating message ids.
+ *
+ * @return host name
+ */
+ virtual const string getHostName() const = 0;
+
+ /** Return the current process identifier.
+ * Used when generating random strings (part boundaries or message ids).
+ *
+ * @return current process id
+ */
+ virtual unsigned int getProcessId() const = 0;
+
+ /** Return an unique identifier for the current thread.
+ * Used for multi-threading synchronization.
+ *
+ * @return current thread id
+ */
+ virtual unsigned int getThreadId() const = 0;
+
+ /** Return the charset used on the system.
+ *
+ * @return local charset
+ */
+ virtual const charset getLocalCharset() const = 0;
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+ /** Return a pointer to the default socket factory for
+ * this platform.
+ *
+ * @return socket factory
+ */
+ virtual shared_ptr <net::socketFactory> getSocketFactory() = 0;
+#endif
+
+#if VMIME_HAVE_FILESYSTEM_FEATURES
+ /** Return a pointer to a factory that creates file-system objects.
+ *
+ * @return file-system factory
+ */
+ virtual shared_ptr <utility::fileSystemFactory> getFileSystemFactory() = 0;
+
+ /** Return a pointer to a factory that creates child process objects,
+ * which are used to spawn processes (run executable files).
+ *
+ * @return child process factory
+ */
+ virtual shared_ptr <utility::childProcessFactory> getChildProcessFactory() = 0;
+#endif
+
+ /** Fills a buffer with cryptographically random bytes.
+ *
+ * @param buffer buffer to fill in with random bytes
+ * @param count number of random bytes to write in buffer
+ */
+ virtual void generateRandomBytes(unsigned char* buffer, const unsigned int count) = 0;
+
+ /** Creates and initializes a critical section.
+ */
+ virtual shared_ptr <utility::sync::criticalSection> createCriticalSection() = 0;
+ };
+
+
+ template <class TYPE>
+ static void setHandler() {
+ sm_handler = vmime::make_shared <TYPE>();
+ }
+
+ static shared_ptr <handler> getDefaultHandler();
+ static shared_ptr <handler> getHandler();
+
+private:
+
+ static shared_ptr <handler> sm_handler;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_PLATFORM_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/platforms/posix/posixChildProcess.cpp b/vmime-master/src/vmime/platforms/posix/posixChildProcess.cpp
new file mode 100644
index 0000000..4a9fef3
--- /dev/null
+++ b/vmime-master/src/vmime/platforms/posix/posixChildProcess.cpp
@@ -0,0 +1,410 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_PLATFORM_IS_POSIX && VMIME_HAVE_FILESYSTEM_FEATURES
+
+
+#include "vmime/platforms/posix/posixChildProcess.hpp"
+#include "vmime/platforms/posix/posixFile.hpp"
+
+#include "vmime/exception.hpp"
+
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <sys/wait.h>
+
+
+namespace vmime {
+namespace platforms {
+namespace posix {
+
+
+// posixChildProcessFactory
+
+shared_ptr <utility::childProcess> posixChildProcessFactory::create(const utility::file::path& path) const {
+
+ return make_shared <posixChildProcess>(path);
+}
+
+
+
+#ifndef VMIME_BUILDING_DOC
+
+
+// getPosixSignalMessage
+// Returns the name of a POSIX signal.
+
+static const string getPosixSignalMessage(const int num) {
+
+ switch (num) {
+ case SIGHUP: return "SIGHUP";
+ case SIGINT: return "SIGINT";
+ case SIGQUIT: return "SIGQUIT";
+ case SIGILL: return "SIGILL";
+ case SIGABRT: return "SIGABRT";
+ case SIGFPE: return "SIGFPE";
+ case SIGKILL: return "SIGKILL";
+ case SIGSEGV: return "SIGSEGV";
+ case SIGPIPE: return "SIGPIPE";
+ case SIGALRM: return "SIGALRM";
+ case SIGTERM: return "SIGTERM";
+ case SIGUSR1: return "SIGUSR1";
+ case SIGUSR2: return "SIGUSR2";
+ case SIGCHLD: return "SIGCHLD";
+ case SIGCONT: return "SIGCONT";
+ case SIGSTOP: return "SIGSTOP";
+ case SIGTSTP: return "SIGTSTP";
+ case SIGTTIN: return "SIGTTIN";
+ case SIGTTOU: return "SIGTTOU";
+ }
+
+ return "(unknown)";
+}
+
+
+// getPosixErrorMessage
+// Returns a message corresponding to an error code.
+
+static const string getPosixErrorMessage(const int num) {
+
+#ifdef strerror_r
+ char res[256];
+ res[0] = '\0';
+
+ strerror_r(num, res, sizeof(res));
+
+ return string(res);
+#else
+ return string(strerror(num));
+#endif
+
+}
+
+
+// Output stream adapter for POSIX pipe
+
+class outputStreamPosixPipeAdapter : public utility::outputStream {
+
+public:
+
+ outputStreamPosixPipeAdapter(const int desc)
+ : m_desc(desc) {
+
+ }
+
+ void flush() {
+
+ ::fsync(m_desc);
+ }
+
+protected:
+
+ void writeImpl(const byte_t* const data, const size_t count) {
+
+ if (::write(m_desc, data, count) == -1) {
+ const string errorMsg = getPosixErrorMessage(errno);
+ throw exceptions::system_error(errorMsg);
+ }
+ }
+
+private:
+
+ const int m_desc;
+};
+
+
+// Input stream adapter for POSIX pipe
+
+class inputStreamPosixPipeAdapter : public utility::inputStream {
+
+public:
+
+ inputStreamPosixPipeAdapter(const int desc)
+ : m_desc(desc) {
+ }
+
+ bool eof() const {
+
+ return m_eof;
+ }
+
+ void reset() {
+
+ // Do nothing: unsupported
+ }
+
+ size_t skip(const size_t count) {
+
+ // TODO: not tested
+ byte_t buffer[4096];
+
+ ssize_t bytesSkipped = 0;
+ ssize_t bytesRead = 0;
+
+ while ((bytesRead = ::read(m_desc, buffer,
+ std::min(sizeof(buffer), count - bytesSkipped))) != 0) {
+
+ if (bytesRead == -1) {
+ const string errorMsg = getPosixErrorMessage(errno);
+ throw exceptions::system_error(errorMsg);
+ }
+
+ bytesSkipped += bytesRead;
+ }
+
+ return static_cast <size_t>(bytesSkipped);
+ }
+
+ size_t read(byte_t* const data, const size_t count) {
+
+ ssize_t bytesRead = 0;
+
+ if ((bytesRead = ::read(m_desc, data, count)) == -1) {
+ const string errorMsg = getPosixErrorMessage(errno);
+ throw exceptions::system_error(errorMsg);
+ }
+
+ m_eof = (bytesRead == 0);
+
+ return static_cast <size_t>(bytesRead);
+ }
+
+private:
+
+ const int m_desc;
+
+ bool m_eof;
+};
+
+
+#endif // VMIME_BUILDING_DOC
+
+
+
+// posixChildProcess
+
+posixChildProcess::posixChildProcess(const utility::file::path& path)
+ : m_processPath(path),
+ m_started(false),
+ m_stdIn(null),
+ m_stdOut(null),
+ m_pid(0),
+ m_argArray(NULL) {
+
+ m_pipe[0] = 0;
+ m_pipe[1] = 0;
+
+ sigemptyset(&m_oldProcMask);
+}
+
+
+posixChildProcess::~posixChildProcess() {
+
+ if (m_started) {
+ sigprocmask(SIG_SETMASK, &m_oldProcMask, NULL);
+ }
+
+ if (m_pipe[0] != 0) {
+ close(m_pipe[0]);
+ }
+
+ if (m_pipe[1] != 0) {
+ close(m_pipe[1]);
+ }
+
+ delete [] m_argArray;
+}
+
+
+// The following code is highly inspired and adapted from the 'sendmail'
+// provider module in Evolution data server code.
+//
+// Original authors: Dan Winship <danw@ximian.com>
+// Copyright 2000 Ximian, Inc. (www.ximian.com)
+
+void posixChildProcess::start(const std::vector <string>& args, const int flags) {
+
+ if (m_started) {
+ return;
+ }
+
+ // Construct C-style argument array
+ const char** argv = new const char*[args.size() + 2];
+
+ m_argVector = args; // for c_str() pointer to remain valid
+ m_argArray = argv; // to free later
+
+ argv[0] = m_processPath.getLastComponent().getBuffer().c_str();
+ argv[args.size() + 1] = NULL;
+
+ for (unsigned int i = 0 ; i < m_argVector.size() ; ++i) {
+ argv[i + 1] = m_argVector[i].c_str();
+ }
+
+ // Create a pipe to communicate with the child process
+ int fd[2];
+
+ if (pipe(fd) == -1) {
+ throw exceptions::system_error(getPosixErrorMessage(errno));
+ }
+
+ m_pipe[0] = fd[0];
+ m_pipe[1] = fd[1];
+
+ // Block SIGCHLD so the calling application doesn't notice
+ // process exiting before we do
+ sigset_t mask;
+
+ sigemptyset(&mask);
+ sigaddset(&mask, SIGCHLD);
+ sigprocmask(SIG_BLOCK, &mask, &m_oldProcMask);
+
+ // Spawn process
+ const pid_t pid = fork();
+
+ if (pid == -1) { // error
+
+ const string errorMsg = getPosixErrorMessage(errno);
+
+ sigprocmask(SIG_SETMASK, &m_oldProcMask, NULL);
+
+ close(fd[0]);
+ close(fd[1]);
+
+ throw exceptions::system_error(errorMsg);
+
+ } else if (pid == 0) { // child process
+
+ if (flags & FLAG_REDIRECT_STDIN) {
+ dup2(fd[0], STDIN_FILENO);
+ } else {
+ close(fd[0]);
+ }
+
+ if (flags & FLAG_REDIRECT_STDOUT) {
+ dup2(fd[1], STDOUT_FILENO);
+ } else {
+ close(fd[1]);
+ }
+
+ posixFileSystemFactory* pfsf = new posixFileSystemFactory();
+
+ const string path = pfsf->pathToString(m_processPath);
+
+ delete pfsf;
+
+ execv(path.c_str(), const_cast <char**>(argv));
+ _exit(255);
+ }
+
+ if (flags & FLAG_REDIRECT_STDIN) {
+
+ m_stdIn = make_shared <outputStreamPosixPipeAdapter>(m_pipe[1]);
+
+ } else {
+
+ close(m_pipe[1]);
+ m_pipe[1] = 0;
+ }
+
+ if (flags & FLAG_REDIRECT_STDOUT) {
+
+ m_stdOut = make_shared <inputStreamPosixPipeAdapter>(m_pipe[0]);
+
+ } else {
+
+ close(m_pipe[0]);
+ m_pipe[0] = 0;
+ }
+
+ m_pid = pid;
+ m_started = true;
+}
+
+
+shared_ptr <utility::outputStream> posixChildProcess::getStdIn() {
+
+ return m_stdIn;
+}
+
+
+shared_ptr <utility::inputStream> posixChildProcess::getStdOut() {
+
+ return m_stdOut;
+}
+
+
+void posixChildProcess::waitForFinish() {
+
+ // Close stdin pipe
+ if (m_pipe[1] != 0) {
+ close(m_pipe[1]);
+ m_pipe[1] = 0;
+ }
+
+ int wstat;
+
+ while (waitpid(m_pid, &wstat, 0) == -1 && errno == EINTR) {
+ ;
+ }
+
+ if (!WIFEXITED(wstat)) {
+
+ throw exceptions::system_error("Process exited with signal "
+ + getPosixSignalMessage(WTERMSIG(wstat)));
+
+ } else if (WEXITSTATUS(wstat) != 0) {
+
+ if (WEXITSTATUS(wstat) == 255) {
+
+ scoped_ptr <posixFileSystemFactory> pfsf(new posixFileSystemFactory());
+
+ throw exceptions::system_error("Could not execute '"
+ + pfsf->pathToString(m_processPath) + "'");
+
+ } else {
+
+ std::ostringstream oss;
+ oss.imbue(std::locale::classic());
+
+ oss << "Process exited with status " << WEXITSTATUS(wstat);
+
+ throw exceptions::system_error(oss.str());
+ }
+ }
+}
+
+
+} // posix
+} // platforms
+} // vmime
+
+
+#endif // VMIME_PLATFORM_IS_POSIX && VMIME_HAVE_FILESYSTEM_FEATURES
+
diff --git a/vmime-master/src/vmime/platforms/posix/posixChildProcess.hpp b/vmime-master/src/vmime/platforms/posix/posixChildProcess.hpp
new file mode 100644
index 0000000..b831e8b
--- /dev/null
+++ b/vmime-master/src/vmime/platforms/posix/posixChildProcess.hpp
@@ -0,0 +1,92 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_PLATFORMS_POSIX_POSIXCHILDPROCESS_HPP_INCLUDED
+#define VMIME_PLATFORMS_POSIX_POSIXCHILDPROCESS_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_PLATFORM_IS_POSIX && VMIME_HAVE_FILESYSTEM_FEATURES
+
+
+#include "vmime/utility/childProcess.hpp"
+
+#include <sys/types.h>
+#include <signal.h>
+
+
+namespace vmime {
+namespace platforms {
+namespace posix {
+
+
+class posixChildProcess : public utility::childProcess {
+
+public:
+
+ posixChildProcess(const utility::file::path& path);
+ ~posixChildProcess();
+
+ void start(const std::vector <string>& args, const int flags = 0);
+
+ shared_ptr <utility::outputStream> getStdIn();
+ shared_ptr <utility::inputStream> getStdOut();
+
+ void waitForFinish();
+
+private:
+
+ utility::file::path m_processPath;
+ bool m_started;
+
+ shared_ptr <utility::outputStream> m_stdIn;
+ shared_ptr <utility::inputStream> m_stdOut;
+
+ sigset_t m_oldProcMask;
+ pid_t m_pid;
+ int m_pipe[2];
+
+ std::vector <string> m_argVector;
+ const char** m_argArray;
+};
+
+
+class posixChildProcessFactory : public utility::childProcessFactory {
+
+public:
+
+ shared_ptr <utility::childProcess> create(const utility::file::path& path) const;
+};
+
+
+} // posix
+} // platforms
+} // vmime
+
+
+#endif // VMIME_PLATFORM_IS_POSIX && VMIME_HAVE_FILESYSTEM_FEATURES
+
+#endif // VMIME_PLATFORMS_POSIX_POSIXCHILDPROCESS_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/platforms/posix/posixCriticalSection.cpp b/vmime-master/src/vmime/platforms/posix/posixCriticalSection.cpp
new file mode 100644
index 0000000..2f25cfa
--- /dev/null
+++ b/vmime-master/src/vmime/platforms/posix/posixCriticalSection.cpp
@@ -0,0 +1,67 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_PLATFORM_IS_POSIX
+
+
+#include "vmime/platforms/posix/posixCriticalSection.hpp"
+
+
+namespace vmime {
+namespace platforms {
+namespace posix {
+
+
+posixCriticalSection::posixCriticalSection() {
+
+ pthread_mutex_init(&m_cs, NULL);
+}
+
+
+posixCriticalSection::~posixCriticalSection() {
+
+ pthread_mutex_destroy(&m_cs);
+}
+
+
+void posixCriticalSection::lock() {
+
+ pthread_mutex_lock(&m_cs);
+}
+
+
+void posixCriticalSection::unlock() {
+
+ pthread_mutex_unlock(&m_cs);
+}
+
+
+} // posix
+} // platforms
+} // vmime
+
+
+#endif // VMIME_PLATFORM_IS_POSIX
diff --git a/vmime-master/src/vmime/platforms/posix/posixCriticalSection.hpp b/vmime-master/src/vmime/platforms/posix/posixCriticalSection.hpp
new file mode 100644
index 0000000..9a4bed5
--- /dev/null
+++ b/vmime-master/src/vmime/platforms/posix/posixCriticalSection.hpp
@@ -0,0 +1,69 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_PLATFORMS_POSIX_CRITICALSECTION_HPP_INCLUDED
+#define VMIME_PLATFORMS_POSIX_CRITICALSECTION_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_PLATFORM_IS_POSIX
+
+
+#include "vmime/utility/sync/criticalSection.hpp"
+
+
+#include <unistd.h>
+#include <pthread.h>
+
+
+namespace vmime {
+namespace platforms {
+namespace posix {
+
+
+class posixCriticalSection : public utility::sync::criticalSection {
+
+public:
+
+ posixCriticalSection();
+ ~posixCriticalSection();
+
+ void lock();
+ void unlock();
+
+private:
+
+ pthread_mutex_t m_cs;
+};
+
+
+} // posix
+} // platforms
+} // vmime
+
+
+#endif // VMIME_PLATFORM_IS_POSIX
+
+#endif // VMIME_PLATFORMS_POSIX_CRITICALSECTION_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/platforms/posix/posixFile.cpp b/vmime-master/src/vmime/platforms/posix/posixFile.cpp
new file mode 100644
index 0000000..9773b3a
--- /dev/null
+++ b/vmime-master/src/vmime/platforms/posix/posixFile.cpp
@@ -0,0 +1,715 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_PLATFORM_IS_POSIX && VMIME_HAVE_FILESYSTEM_FEATURES
+
+
+#include "vmime/platforms/posix/posixFile.hpp"
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#include <dirent.h>
+
+#include <stdio.h>
+#include <string.h>
+
+#include "vmime/exception.hpp"
+
+
+namespace vmime {
+namespace platforms {
+namespace posix {
+
+
+//
+// posixFileIterator
+//
+
+posixFileIterator::posixFileIterator(
+ const vmime::utility::file::path& path,
+ const vmime::string& nativePath
+)
+ : m_path(path),
+ m_nativePath(nativePath),
+ m_dir(NULL),
+ m_dirEntry(NULL) {
+
+ if ((m_dir = ::opendir(m_nativePath.c_str())) == NULL) {
+ posixFileSystemFactory::reportError(path, errno);
+ }
+
+ getNextElement();
+}
+
+
+posixFileIterator::~posixFileIterator() {
+
+ if (m_dir) {
+
+ if (::closedir(m_dir) == -1) {
+ posixFileSystemFactory::reportError(m_path, errno);
+ }
+ }
+}
+
+
+bool posixFileIterator::hasMoreElements() const {
+
+ return (m_dirEntry != NULL);
+}
+
+
+shared_ptr <vmime::utility::file> posixFileIterator::nextElement() {
+
+ shared_ptr <posixFile> file = make_shared <posixFile>(
+ m_path / vmime::utility::file::path::component(m_dirEntry->d_name)
+ );
+
+ getNextElement();
+
+ return file;
+}
+
+
+void posixFileIterator::getNextElement() {
+
+ errno = 0;
+
+ while ((m_dirEntry = ::readdir(m_dir)) != NULL) {
+
+ const char* name = m_dirEntry->d_name;
+ const size_t len = ::strlen(name);
+
+ if (!(len == 1 && name[0] == '.') &&
+ !(len == 2 && name[0] == '.' && name[1] == '.')) {
+
+ break;
+ }
+ }
+
+ if (errno) {
+ posixFileSystemFactory::reportError(m_path, errno);
+ }
+}
+
+
+
+//
+// posixFileWriterOutputStream
+//
+
+posixFileWriterOutputStream::posixFileWriterOutputStream(
+ const vmime::utility::file::path& path,
+ const int fd
+)
+ : m_path(path),
+ m_fd(fd) {
+
+}
+
+
+posixFileWriterOutputStream::~posixFileWriterOutputStream() {
+
+ ::close(m_fd);
+}
+
+
+void posixFileWriterOutputStream::writeImpl(
+ const byte_t* const data,
+ const size_t count
+) {
+
+ const byte_t* array = data;
+ size_t size = count;
+
+ while (1) {
+
+ ssize_t ret = ::write(m_fd, array, size);
+
+ if (ret == -1) {
+
+ if (errno == EINTR) {
+ continue;
+ }
+
+ posixFileSystemFactory::reportError(m_path, errno);
+ break;
+
+ } else if (size_t(ret) < size) {
+
+ array += ret;
+ size -= ret;
+ }
+
+ break;
+ }
+}
+
+
+void posixFileWriterOutputStream::flush() {
+
+ if (::fsync(m_fd) == -1) {
+ posixFileSystemFactory::reportError(m_path, errno);
+ }
+}
+
+
+
+//
+// posixFileReaderInputStream
+//
+
+posixFileReaderInputStream::posixFileReaderInputStream(
+ const vmime::utility::file::path& path,
+ const int fd
+)
+ : m_path(path),
+ m_fd(fd),
+ m_eof(false) {
+
+}
+
+
+posixFileReaderInputStream::~posixFileReaderInputStream() {
+
+ if (::close(m_fd) == -1) {
+ posixFileSystemFactory::reportError(m_path, errno);
+ }
+}
+
+
+bool posixFileReaderInputStream::eof() const {
+
+ return m_eof;
+}
+
+
+void posixFileReaderInputStream::reset() {
+
+ if (::lseek(m_fd, 0, SEEK_SET) == off_t(-1)) {
+ posixFileSystemFactory::reportError(m_path, errno);
+ }
+
+ m_eof = false;
+}
+
+
+size_t posixFileReaderInputStream::read(
+ byte_t* const data,
+ const size_t count
+) {
+
+ ssize_t c = 0;
+
+ if ((c = ::read(m_fd, data, count)) == -1) {
+ posixFileSystemFactory::reportError(m_path, errno);
+ }
+
+ if (c == 0 && count != 0) {
+ m_eof = true;
+ }
+
+ return static_cast <size_t>(c);
+}
+
+
+size_t posixFileReaderInputStream::skip(const size_t count) {
+
+ const off_t curPos = ::lseek(m_fd, 0, SEEK_CUR);
+
+ if (curPos == off_t(-1)) {
+ posixFileSystemFactory::reportError(m_path, errno);
+ }
+
+ const off_t newPos = ::lseek(m_fd, count, SEEK_CUR);
+
+ if (newPos == off_t(-1)) {
+ posixFileSystemFactory::reportError(m_path, errno);
+ }
+
+ return static_cast <size_t>(newPos - curPos);
+}
+
+
+size_t posixFileReaderInputStream::getPosition() const {
+
+ const off_t curPos = ::lseek(m_fd, 0, SEEK_CUR);
+
+ if (curPos == off_t(-1)) {
+ posixFileSystemFactory::reportError(m_path, errno);
+ }
+
+ return static_cast <size_t>(curPos);
+}
+
+
+void posixFileReaderInputStream::seek(const size_t pos) {
+
+ const off_t newPos = ::lseek(m_fd, pos, SEEK_SET);
+
+ if (newPos == off_t(-1)) {
+ posixFileSystemFactory::reportError(m_path, errno);
+ }
+}
+
+
+
+//
+// posixFileWriter
+//
+
+posixFileWriter::posixFileWriter(
+ const vmime::utility::file::path& path,
+ const vmime::string& nativePath
+)
+ : m_path(path),
+ m_nativePath(nativePath) {
+
+}
+
+
+shared_ptr <vmime::utility::outputStream> posixFileWriter::getOutputStream() {
+
+ int fd = 0;
+
+ if ((fd = ::open(m_nativePath.c_str(), O_WRONLY, 0660)) == -1) {
+ posixFileSystemFactory::reportError(m_path, errno);
+ }
+
+ return make_shared <posixFileWriterOutputStream>(m_path, fd);
+}
+
+
+
+//
+// posixFileReader
+//
+
+posixFileReader::posixFileReader(
+ const vmime::utility::file::path& path,
+ const vmime::string& nativePath
+)
+ : m_path(path),
+ m_nativePath(nativePath) {
+
+}
+
+
+shared_ptr <vmime::utility::inputStream> posixFileReader::getInputStream() {
+
+ int fd = 0;
+
+ if ((fd = ::open(m_nativePath.c_str(), O_RDONLY, 0640)) == -1) {
+ posixFileSystemFactory::reportError(m_path, errno);
+ }
+
+ return make_shared <posixFileReaderInputStream>(m_path, fd);
+}
+
+
+
+//
+// posixFile
+//
+
+posixFile::posixFile(const vmime::utility::file::path& path)
+ : m_path(path),
+ m_nativePath(posixFileSystemFactory::pathToStringImpl(path)) {
+
+}
+
+
+void posixFile::createFile() {
+
+ int fd = 0;
+
+ if ((fd = ::open(m_nativePath.c_str(), O_CREAT | O_EXCL | O_WRONLY, 0660)) == -1) {
+ posixFileSystemFactory::reportError(m_path, errno);
+ }
+
+ if (::fsync(fd) == -1) {
+ posixFileSystemFactory::reportError(m_path, errno);
+ }
+
+ if (::close(fd) == -1) {
+ posixFileSystemFactory::reportError(m_path, errno);
+ }
+}
+
+
+void posixFile::createDirectory(const bool createAll) {
+
+ createDirectoryImpl(m_path, m_path, createAll);
+}
+
+
+bool posixFile::isFile() const {
+
+ struct stat buf;
+
+ if (::stat(m_nativePath.c_str(), &buf) == -1) {
+
+ if (errno == ENOENT) {
+ return false;
+ }
+
+ posixFileSystemFactory::reportError(m_path, errno);
+ return false;
+ }
+
+ return S_ISREG(buf.st_mode);
+}
+
+
+bool posixFile::isDirectory() const {
+
+ struct stat buf;
+
+ if (::stat(m_nativePath.c_str(), &buf) == -1) {
+
+ if (errno == ENOENT) {
+ return false;
+ }
+
+ posixFileSystemFactory::reportError(m_path, errno);
+ return false;
+ }
+
+ return S_ISDIR(buf.st_mode);
+}
+
+
+bool posixFile::canRead() const {
+
+ struct stat buf;
+
+ if (::stat(m_nativePath.c_str(), &buf) == -1) {
+
+ if (errno == ENOENT) {
+ return false;
+ }
+
+ posixFileSystemFactory::reportError(m_path, errno);
+ return false;
+ }
+
+ return S_ISREG(buf.st_mode)
+ && ::access(m_nativePath.c_str(), R_OK | F_OK) == 0;
+}
+
+
+bool posixFile::canWrite() const {
+
+ struct stat buf;
+
+ if (::stat(m_nativePath.c_str(), &buf) == -1) {
+
+ if (errno == ENOENT) {
+ return false;
+ }
+
+ posixFileSystemFactory::reportError(m_path, errno);
+ return false;
+ }
+
+ return S_ISREG(buf.st_mode)
+ && ::access(m_nativePath.c_str(), W_OK | F_OK) == 0;
+}
+
+
+posixFile::length_type posixFile::getLength() {
+
+ struct stat buf;
+
+ if (::stat(m_nativePath.c_str(), &buf) == -1) {
+ posixFileSystemFactory::reportError(m_path, errno);
+ }
+
+ return static_cast <length_type>(buf.st_size);
+}
+
+
+const posixFile::path& posixFile::getFullPath() const {
+
+ return m_path;
+}
+
+
+bool posixFile::exists() const {
+
+ struct stat buf;
+ return ::stat(m_nativePath.c_str(), &buf) == 0;
+}
+
+
+shared_ptr <vmime::utility::file> posixFile::getParent() const {
+
+ if (m_path.isEmpty()) {
+ return null;
+ } else {
+ return make_shared <posixFile>(m_path.getParent());
+ }
+}
+
+
+void posixFile::rename(const path& newName) {
+
+ const vmime::string newNativePath = posixFileSystemFactory::pathToStringImpl(newName);
+
+ posixFile dest(newName);
+
+ if (isDirectory()) {
+ dest.createDirectory();
+ } else {
+ dest.createFile();
+ }
+
+ if (::rename(m_nativePath.c_str(), newNativePath.c_str()) == -1) {
+ posixFileSystemFactory::reportError(m_path, errno);
+ }
+
+ m_path = newName;
+ m_nativePath = newNativePath;
+}
+
+
+void posixFile::remove() {
+
+ struct stat buf;
+
+ if (::stat(m_nativePath.c_str(), &buf) == -1) {
+ posixFileSystemFactory::reportError(m_path, errno);
+ }
+
+ if (S_ISDIR(buf.st_mode)) {
+
+ if (::rmdir(m_nativePath.c_str()) == -1) {
+ posixFileSystemFactory::reportError(m_path, errno);
+ }
+
+ } else if (S_ISREG(buf.st_mode)) {
+
+ if (::unlink(m_nativePath.c_str()) == -1) {
+ posixFileSystemFactory::reportError(m_path, errno);
+ }
+ }
+}
+
+
+shared_ptr <vmime::utility::fileWriter> posixFile::getFileWriter() {
+
+ return make_shared <posixFileWriter>(m_path, m_nativePath);
+}
+
+
+shared_ptr <vmime::utility::fileReader> posixFile::getFileReader() {
+
+ return make_shared <posixFileReader>(m_path, m_nativePath);
+}
+
+
+shared_ptr <vmime::utility::fileIterator> posixFile::getFiles() const {
+
+ if (!isDirectory()) {
+ throw vmime::exceptions::not_a_directory(m_path);
+ }
+
+ return make_shared <posixFileIterator>(m_path, m_nativePath);
+}
+
+
+void posixFile::createDirectoryImpl(
+ const vmime::utility::file::path& fullPath,
+ const vmime::utility::file::path& path,
+ const bool recursive
+) {
+
+ const vmime::string nativePath = posixFileSystemFactory::pathToStringImpl(path);
+ struct stat buf;
+
+ if (::stat(nativePath.c_str(), &buf) == 0 && S_ISDIR(buf.st_mode)) {
+ return;
+ }
+
+ if (!path.isEmpty() && recursive) {
+ createDirectoryImpl(fullPath, path.getParent(), true);
+ }
+
+ if (::mkdir(nativePath.c_str(), 0750) == -1) {
+ posixFileSystemFactory::reportError(fullPath, errno);
+ }
+}
+
+
+
+//
+// posixFileSystemFactory
+//
+
+shared_ptr <vmime::utility::file> posixFileSystemFactory::create(
+ const vmime::utility::file::path& path
+) const {
+
+ return make_shared <posixFile>(path);
+}
+
+
+const vmime::utility::file::path posixFileSystemFactory::stringToPath(
+ const vmime::string& str
+) const {
+
+ return stringToPathImpl(str);
+}
+
+
+const vmime::string posixFileSystemFactory::pathToString(
+ const vmime::utility::file::path& path
+) const {
+
+ return pathToStringImpl(path);
+}
+
+
+const vmime::utility::file::path posixFileSystemFactory::stringToPathImpl(
+ const vmime::string& str
+) {
+
+ vmime::size_t offset = 0;
+ vmime::size_t prev = 0;
+
+ vmime::utility::file::path path;
+
+ while ((offset = str.find_first_of("/", offset)) != vmime::string::npos) {
+
+ if (offset != prev) {
+
+ path.appendComponent(
+ vmime::utility::file::path::component(
+ vmime::string(str.begin() + prev, str.begin() + offset)
+ )
+ );
+ }
+
+ prev = offset + 1;
+ offset++;
+ }
+
+ if (prev < str.length()) {
+
+ path.appendComponent(
+ vmime::utility::file::path::component(
+ vmime::string(str.begin() + prev, str.end())
+ )
+ );
+ }
+
+ return path;
+}
+
+
+const vmime::string posixFileSystemFactory::pathToStringImpl(const vmime::utility::file::path& path) {
+
+ vmime::string native = "/";
+
+ for (size_t i = 0 ; i < path.getSize() ; ++i) {
+
+ if (i > 0) {
+ native += "/";
+ }
+
+ native += path[i].getBuffer();
+ }
+
+ return native;
+}
+
+
+bool posixFileSystemFactory::isValidPathComponent(
+ const vmime::utility::file::path::component& comp
+) const {
+
+ return comp.getBuffer().find_first_of("/*") == vmime::string::npos;
+}
+
+
+bool posixFileSystemFactory::isValidPath(const vmime::utility::file::path& path) const {
+
+ for (size_t i = 0 ; i < path.getSize() ; ++i) {
+
+ if (!isValidPathComponent(path[i])) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+void posixFileSystemFactory::reportError(const vmime::utility::path& path, const int err) {
+
+ vmime::string desc;
+
+ switch (err) {
+ case EEXIST: desc = "EEXIST: file already exists."; break;
+ case EISDIR: desc = "EISDIR: path refers to a directory."; break;
+ case EACCES: desc = "EACCES: permission denied"; break;
+ case ENAMETOOLONG: desc = "ENAMETOOLONG: path too long."; break;
+ case ENOENT: desc = "ENOENT: a directory in the path does not exist."; break;
+ case ENOTDIR: desc = "ENOTDIR: path is not a directory."; break;
+ case EROFS: desc = "EROFS: read-only filesystem."; break;
+ case ELOOP: desc = "ELOOP: too many symbolic links."; break;
+ case ENOSPC: desc = "ENOSPC: no space left on device."; break;
+ case ENOMEM: desc = "ENOMEM: insufficient kernel memory."; break;
+ case EMFILE: desc = "ENFILE: limit on number of files open by the process has been reached."; break;
+ case ENFILE: desc = "ENFILE: limit on number of files open on the system has been reached."; break;
+#ifndef AIX
+ case ENOTEMPTY: desc = "ENOTEMPTY: directory is not empty."; break;
+#endif
+
+ default:
+
+ std::ostringstream oss;
+ oss << ::strerror(err) << ".";
+
+ desc = oss.str();
+ break;
+ }
+
+ throw vmime::exceptions::filesystem_exception(desc, path);
+}
+
+
+} // posix
+} // platforms
+} // vmime
+
+
+#endif // VMIME_PLATFORM_IS_POSIX && VMIME_HAVE_FILESYSTEM_FEATURES
diff --git a/vmime-master/src/vmime/platforms/posix/posixFile.hpp b/vmime-master/src/vmime/platforms/posix/posixFile.hpp
new file mode 100644
index 0000000..d1fda9e
--- /dev/null
+++ b/vmime-master/src/vmime/platforms/posix/posixFile.hpp
@@ -0,0 +1,224 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_PLATFORMS_POSIX_FILE_HPP_INCLUDED
+#define VMIME_PLATFORMS_POSIX_FILE_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_PLATFORM_IS_POSIX && VMIME_HAVE_FILESYSTEM_FEATURES
+
+
+#include "vmime/utility/file.hpp"
+#include "vmime/utility/seekableInputStream.hpp"
+
+
+#include <dirent.h>
+
+
+namespace vmime {
+namespace platforms {
+namespace posix {
+
+
+class posixFileWriterOutputStream : public vmime::utility::outputStream {
+
+public:
+
+ posixFileWriterOutputStream(const vmime::utility::file::path& path, const int fd);
+ ~posixFileWriterOutputStream();
+
+ void flush();
+
+protected:
+
+ void writeImpl(const byte_t* const data, const size_t count);
+
+private:
+
+ const vmime::utility::file::path m_path;
+ const int m_fd;
+};
+
+
+
+class posixFileReaderInputStream : public vmime::utility::seekableInputStream {
+
+public:
+
+ posixFileReaderInputStream(const vmime::utility::file::path& path, const int fd);
+ ~posixFileReaderInputStream();
+
+ bool eof() const;
+
+ void reset();
+
+ size_t read(byte_t* const data, const size_t count);
+
+ size_t skip(const size_t count);
+
+ size_t getPosition() const;
+ void seek(const size_t pos);
+
+private:
+
+ const vmime::utility::file::path m_path;
+ const int m_fd;
+
+ bool m_eof;
+};
+
+
+
+class posixFileWriter : public vmime::utility::fileWriter {
+
+public:
+
+ posixFileWriter(const vmime::utility::file::path& path, const vmime::string& nativePath);
+
+ shared_ptr <vmime::utility::outputStream> getOutputStream();
+
+private:
+
+ vmime::utility::file::path m_path;
+ vmime::string m_nativePath;
+};
+
+
+
+class posixFileReader : public vmime::utility::fileReader {
+
+public:
+
+ posixFileReader(const vmime::utility::file::path& path, const vmime::string& nativePath);
+
+ shared_ptr <vmime::utility::inputStream> getInputStream();
+
+private:
+
+ vmime::utility::file::path m_path;
+ vmime::string m_nativePath;
+};
+
+
+
+class posixFileIterator : public vmime::utility::fileIterator {
+
+public:
+
+ posixFileIterator(const vmime::utility::file::path& path, const vmime::string& nativePath);
+ ~posixFileIterator();
+
+ bool hasMoreElements() const;
+ shared_ptr <vmime::utility::file> nextElement();
+
+private:
+
+ void getNextElement();
+
+ vmime::utility::file::path m_path;
+ vmime::string m_nativePath;
+
+ DIR* m_dir;
+ struct dirent* m_dirEntry;
+};
+
+
+
+class posixFile : public vmime::utility::file {
+
+public:
+
+ posixFile(const vmime::utility::file::path& path);
+
+ void createFile();
+ void createDirectory(const bool createAll = false);
+
+ bool isFile() const;
+ bool isDirectory() const;
+
+ bool canRead() const;
+ bool canWrite() const;
+
+ length_type getLength();
+
+ const path& getFullPath() const;
+
+ bool exists() const;
+
+ shared_ptr <vmime::utility::file> getParent() const;
+
+ void rename(const path& newName);
+
+ void remove();
+
+ shared_ptr <vmime::utility::fileWriter> getFileWriter();
+ shared_ptr <vmime::utility::fileReader> getFileReader();
+
+ shared_ptr <vmime::utility::fileIterator> getFiles() const;
+
+private:
+
+ static void createDirectoryImpl(
+ const vmime::utility::file::path& fullPath,
+ const vmime::utility::file::path& path,
+ const bool recursive = false
+ );
+
+private:
+
+ vmime::utility::file::path m_path;
+ vmime::string m_nativePath;
+};
+
+
+
+class posixFileSystemFactory : public vmime::utility::fileSystemFactory {
+
+public:
+
+ shared_ptr <vmime::utility::file> create(const vmime::utility::file::path& path) const;
+
+ const vmime::utility::file::path stringToPath(const vmime::string& str) const;
+ const vmime::string pathToString(const vmime::utility::file::path& path) const;
+
+ static const vmime::utility::file::path stringToPathImpl(const vmime::string& str);
+ static const vmime::string pathToStringImpl(const vmime::utility::file::path& path);
+
+ bool isValidPathComponent(const vmime::utility::file::path::component& comp) const;
+ bool isValidPath(const vmime::utility::file::path& path) const;
+
+ static void reportError(const vmime::utility::path& path, const int err);
+};
+
+
+} // posix
+} // platforms
+} // vmime
+
+
+#endif // VMIME_PLATFORM_IS_POSIX && VMIME_HAVE_FILESYSTEM_FEATURES
+
+#endif // VMIME_PLATFORMS_POSIX_FILE_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/platforms/posix/posixHandler.cpp b/vmime-master/src/vmime/platforms/posix/posixHandler.cpp
new file mode 100644
index 0000000..eecdbea
--- /dev/null
+++ b/vmime-master/src/vmime/platforms/posix/posixHandler.cpp
@@ -0,0 +1,292 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_PLATFORM_IS_POSIX
+
+
+#include "vmime/platforms/posix/posixHandler.hpp"
+
+#include "vmime/platforms/posix/posixCriticalSection.hpp"
+
+#include "vmime/utility/stringUtils.hpp"
+
+#include <time.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <locale.h>
+#include <langinfo.h>
+#include <errno.h>
+#include <limits.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+
+#if VMIME_HAVE_SYSCALL
+# include <sys/syscall.h>
+#endif
+
+#include <netdb.h>
+
+#include <string.h>
+#include <cassert>
+#include <cstdlib>
+
+
+/*
+#ifdef _POSIX_PRIORITY_SCHEDULING
+ #include <sched.h>
+#endif // _POSIX_PRIORITY_SCHEDULING
+*/
+
+
+namespace vmime {
+namespace platforms {
+namespace posix {
+
+
+posixHandler::posixHandler() {
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+ m_socketFactory = make_shared <posixSocketFactory>();
+#endif
+#if VMIME_HAVE_FILESYSTEM_FEATURES
+ m_fileSysFactory = make_shared <posixFileSystemFactory>();
+ m_childProcFactory = make_shared <posixChildProcessFactory>();
+#endif
+
+}
+
+
+posixHandler::~posixHandler() {
+
+}
+
+
+unsigned long posixHandler::getUnixTime() const {
+
+ return static_cast <unsigned long>(::time(NULL));
+}
+
+
+const vmime::datetime posixHandler::getCurrentLocalTime() const {
+
+ const time_t t(::time(NULL));
+
+ // Get the local time
+#if VMIME_HAVE_LOCALTIME_R
+ tm local;
+ ::localtime_r(&t, &local);
+#else
+ tm local = *::localtime(&t); // WARNING: this is not thread-safe!
+#endif
+
+ // Get the UTC time
+#if VMIME_HAVE_GMTIME_R
+ tm gmt;
+ ::gmtime_r(&t, &gmt);
+#else
+ tm gmt = *::gmtime(&t); // WARNING: this is not thread-safe!
+#endif
+
+ // "A negative value for tm_isdst causes mktime() to attempt
+ // to determine whether Daylight Saving Time is in effect
+ // for the specified time."
+ local.tm_isdst = -1;
+ gmt.tm_isdst = -1;
+
+ // Calculate the difference (in seconds)
+ const time_t diff = ::mktime(&local) - ::mktime(&gmt);
+
+ // Return the date
+ return vmime::datetime(
+ local.tm_year + 1900, local.tm_mon + 1, local.tm_mday,
+ local.tm_hour, local.tm_min, local.tm_sec, static_cast <int>(diff / 60)
+ );
+}
+
+
+const vmime::charset posixHandler::getLocalCharset() const {
+
+ // Note: nl_langinfo() might be affected by calls to setlocale()
+ // in a multithread environment. There is not MT-safe alternative
+ // to nl_langinfo().
+ auto codeset = ::nl_langinfo(CODESET);
+
+ if (codeset) {
+ return vmime::charset(codeset);
+ }
+
+ return vmime::charset();
+}
+
+
+static inline bool isAcceptableHostname(const vmime::string& str) {
+
+ // At least, try to find something better than "localhost"
+ if (utility::stringUtils::isStringEqualNoCase(str, "localhost", 9) ||
+ utility::stringUtils::isStringEqualNoCase(str, "localhost.localdomain", 21)) {
+
+ return false;
+ }
+
+ // Anything else will be OK, as long as it is a valid hostname
+ return utility::stringUtils::isValidHostname(str);
+}
+
+
+const vmime::string posixHandler::getHostName() const {
+ char hostname[256];
+
+ ::gethostname(hostname, sizeof(hostname));
+ hostname[sizeof(hostname)-1] = '\0';
+
+ // Try to get official canonical name of this host
+ struct addrinfo hints;
+ memset(&hints, 0, sizeof hints);
+ hints.ai_family = AF_UNSPEC; // either IPV4 or IPV6
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_flags = AI_CANONNAME;
+
+ struct addrinfo* info;
+
+ if (getaddrinfo(hostname, "http", &hints, &info) == 0) {
+ // First, try to get a Fully-Qualified Domain Name (FQDN)
+ for (struct addrinfo* p = info ; p != NULL ; p = p->ai_next) {
+
+ if (p->ai_canonname) {
+
+ const string hn(p->ai_canonname);
+
+ if (utility::stringUtils::isValidFQDN(hn)) {
+ freeaddrinfo(info);
+ return hn;
+ }
+ }
+ }
+
+ // Then, try to find an acceptable host name
+ for (struct addrinfo* p = info ; p != NULL ; p = p->ai_next) {
+
+ if (p->ai_canonname) {
+
+ const string hn(p->ai_canonname);
+
+ if (isAcceptableHostname(hn)) {
+ freeaddrinfo(info);
+ return hn;
+ }
+ }
+ }
+
+ freeaddrinfo(info);
+ }
+
+ if (::strlen(hostname) == 0 || !isAcceptableHostname(hostname)) {
+ ::strcpy(hostname, "localhost.localdomain");
+ }
+
+ return hostname;
+}
+
+
+unsigned int posixHandler::getProcessId() const {
+
+ return ::getpid();
+}
+
+
+unsigned int posixHandler::getThreadId() const {
+
+#if VMIME_HAVE_GETTID
+ return static_cast <unsigned int>(::gettid());
+#elif VMIME_HAVE_SYSCALL && VMIME_HAVE_SYSCALL_GETTID
+ return static_cast <unsigned int>(::syscall(SYS_gettid));
+#elif VMIME_HAVE_GETTHRID // OpenBSD
+ return static_cast <unsigned int>(::getthrid());
+#else
+ #error We have no implementation of getThreadId() for this platform!
+#endif
+
+}
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+shared_ptr <vmime::net::socketFactory> posixHandler::getSocketFactory() {
+
+ return m_socketFactory;
+}
+
+#endif
+
+
+#if VMIME_HAVE_FILESYSTEM_FEATURES
+
+shared_ptr <vmime::utility::fileSystemFactory> posixHandler::getFileSystemFactory() {
+
+ return m_fileSysFactory;
+}
+
+
+shared_ptr <vmime::utility::childProcessFactory> posixHandler::getChildProcessFactory() {
+
+ return m_childProcFactory;
+}
+
+#endif
+
+
+void posixHandler::generateRandomBytes(unsigned char* buffer, const unsigned int count) {
+
+ int fd = open("/dev/urandom", O_RDONLY);
+
+ if (fd != -1) {
+
+ read(fd, buffer, count);
+ close(fd);
+
+ } else { // fallback
+
+ for (unsigned int i = 0 ; i < count ; ++i) {
+ buffer[i] = static_cast <unsigned char>(rand() % 255);
+ }
+ }
+}
+
+
+shared_ptr <utility::sync::criticalSection> posixHandler::createCriticalSection() {
+
+ return make_shared <posixCriticalSection>();
+}
+
+
+} // posix
+} // platforms
+} // vmime
+
+
+#endif // VMIME_PLATFORM_IS_POSIX
diff --git a/vmime-master/src/vmime/platforms/posix/posixHandler.hpp b/vmime-master/src/vmime/platforms/posix/posixHandler.hpp
new file mode 100644
index 0000000..30417f1
--- /dev/null
+++ b/vmime-master/src/vmime/platforms/posix/posixHandler.hpp
@@ -0,0 +1,103 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_PLATFORMS_POSIX_HANDLER_HPP_INCLUDED
+#define VMIME_PLATFORMS_POSIX_HANDLER_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_PLATFORM_IS_POSIX
+
+
+#include "vmime/platform.hpp"
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+ #include "vmime/platforms/posix/posixSocket.hpp"
+#endif
+
+#if VMIME_HAVE_FILESYSTEM_FEATURES
+ #include "vmime/platforms/posix/posixFile.hpp"
+ #include "vmime/platforms/posix/posixChildProcess.hpp"
+#endif
+
+
+namespace vmime {
+namespace platforms {
+namespace posix {
+
+
+class VMIME_EXPORT posixHandler : public vmime::platform::handler {
+
+public:
+
+ posixHandler();
+ ~posixHandler();
+
+ unsigned long getUnixTime() const;
+
+ const vmime::datetime getCurrentLocalTime() const;
+
+ const vmime::charset getLocalCharset() const;
+
+ const vmime::string getHostName() const;
+
+ unsigned int getProcessId() const;
+ unsigned int getThreadId() const;
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+ shared_ptr <vmime::net::socketFactory> getSocketFactory();
+#endif
+
+#if VMIME_HAVE_FILESYSTEM_FEATURES
+ shared_ptr <vmime::utility::fileSystemFactory> getFileSystemFactory();
+
+ shared_ptr <vmime::utility::childProcessFactory> getChildProcessFactory();
+#endif
+
+ void generateRandomBytes(unsigned char* buffer, const unsigned int count);
+
+ shared_ptr <utility::sync::criticalSection> createCriticalSection();
+
+private:
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+ shared_ptr <posixSocketFactory> m_socketFactory;
+#endif
+
+#if VMIME_HAVE_FILESYSTEM_FEATURES
+ shared_ptr <posixFileSystemFactory> m_fileSysFactory;
+ shared_ptr <posixChildProcessFactory> m_childProcFactory;
+#endif
+};
+
+
+} // posix
+} // platforms
+} // vmime
+
+
+#endif // VMIME_PLATFORM_IS_POSIX
+
+#endif // VMIME_PLATFORMS_POSIX_HANDLER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/platforms/posix/posixSocket.cpp b/vmime-master/src/vmime/platforms/posix/posixSocket.cpp
new file mode 100644
index 0000000..aec6a83
--- /dev/null
+++ b/vmime-master/src/vmime/platforms/posix/posixSocket.cpp
@@ -0,0 +1,969 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_PLATFORM_IS_POSIX && VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/platforms/posix/posixSocket.hpp"
+#include "vmime/platforms/posix/posixHandler.hpp"
+
+#ifndef _GNU_SOURCE
+#define _GNU_SOURCE // for getaddrinfo_a() in <netdb.h>
+#endif
+
+#include <unistd.h>
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <poll.h>
+
+#include "vmime/utility/stringUtils.hpp"
+
+#include "vmime/exception.hpp"
+
+
+#if defined(EWOULDBLOCK)
+# define IS_EAGAIN(x) ((x) == EAGAIN || (x) == EWOULDBLOCK || (x) == EINTR || (x) == EINPROGRESS)
+#else
+# define IS_EAGAIN(x) ((x) == EAGAIN || (x) == EINTR || (x) == EINPROGRESS)
+#endif
+
+
+// Workaround for detection of strerror_r variants
+#if VMIME_HAVE_STRERROR_R
+
+namespace {
+
+char* vmime_strerror_r_result(int /* res */, char* buf) {
+
+ // XSI-compliant prototype:
+ // int strerror_r(int errnum, char *buf, size_t buflen);
+ return buf;
+}
+
+char* vmime_strerror_r_result(char* res, char* /* buf */) {
+
+ // GNU-specific prototype:
+ // char *strerror_r(int errnum, char *buf, size_t buflen);
+ return res;
+}
+
+}
+
+#endif // VMIME_HAVE_STRERROR_R
+
+
+
+namespace vmime {
+namespace platforms {
+namespace posix {
+
+
+//
+// posixSocket
+//
+
+posixSocket::posixSocket(shared_ptr <vmime::net::timeoutHandler> th)
+ : m_timeoutHandler(th),
+ m_desc(-1),
+ m_status(0) {
+
+}
+
+
+posixSocket::~posixSocket() {
+
+ if (m_desc != -1) {
+ ::close(m_desc);
+ }
+}
+
+
+void posixSocket::connect(const vmime::string& address, const vmime::port_t port) {
+
+ // Close current connection, if any
+ if (m_desc != -1) {
+ ::close(m_desc);
+ m_desc = -1;
+ }
+
+ if (m_tracer) {
+
+ std::ostringstream trace;
+ trace << "Connecting to " << address << ", port " << port;
+
+ m_tracer->traceSend(trace.str());
+ }
+
+#if VMIME_HAVE_GETADDRINFO // use thread-safe and IPv6-aware getaddrinfo() if available
+
+ // Resolve address, if needed
+ m_serverAddress = address;
+
+ struct ::addrinfo* addrInfo = NULL; // resolved addresses
+ resolve(&addrInfo, address, port);
+
+ // Connect to host
+ int sock = -1;
+ int connectErrno = 0;
+
+ if (m_timeoutHandler != NULL) {
+ m_timeoutHandler->resetTimeOut();
+ }
+
+ for (struct ::addrinfo* curAddrInfo = addrInfo ;
+ sock == -1 && curAddrInfo != NULL ;
+ curAddrInfo = curAddrInfo->ai_next, connectErrno = ETIMEDOUT) {
+
+ if (curAddrInfo->ai_family != AF_INET && curAddrInfo->ai_family != AF_INET6) {
+ continue;
+ }
+
+ sock = ::socket(curAddrInfo->ai_family, curAddrInfo->ai_socktype, curAddrInfo->ai_protocol);
+
+ if (sock < 0) {
+ connectErrno = errno;
+ continue; // try next
+ }
+
+#if VMIME_HAVE_SO_KEEPALIVE
+
+ // Enable TCP Keepalive
+ int keepAlive_optval = 1;
+ socklen_t keepAlive_optlen = sizeof(keepAlive_optval);
+
+ ::setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &keepAlive_optval, keepAlive_optlen);
+
+#endif // VMIME_HAVE_SO_KEEPALIVE
+
+#if VMIME_HAVE_SO_NOSIGPIPE
+
+ // Return EPIPE instead of generating SIGPIPE
+ int nosigpipe_optval = 1;
+ socklen_t nosigpipe_optlen = sizeof(nosigpipe_optval);
+
+ ::setsockopt(sock, SOL_SOCKET, SO_NOSIGPIPE, &nosigpipe_optval, nosigpipe_optlen);
+
+#endif // VMIME_HAVE_SO_NOSIGPIPE
+
+
+ if (m_timeoutHandler) {
+
+ ::fcntl(sock, F_SETFL, ::fcntl(sock, F_GETFL) | O_NONBLOCK);
+
+ if (::connect(sock, curAddrInfo->ai_addr, curAddrInfo->ai_addrlen) < 0) {
+
+ switch (errno) {
+
+ case 0:
+ case EINPROGRESS:
+ case EINTR:
+#if defined(EAGAIN)
+ case EAGAIN:
+#endif // EAGAIN
+#if defined(EWOULDBLOCK) && (!defined(EAGAIN) || (EWOULDBLOCK != EAGAIN))
+ case EWOULDBLOCK:
+#endif // EWOULDBLOCK
+
+ // Connection in progress
+ break;
+
+ default:
+
+ connectErrno = errno;
+ ::close(sock);
+ sock = -1;
+ continue; // try next
+ }
+
+ // Wait for socket to be connected.
+ bool connected = false;
+
+ const int pollTimeout = 1000; // poll() timeout (ms)
+ const int tryNextTimeout = 5000; // maximum time before trying next (ms)
+
+ timeval startTime = { 0, 0 };
+ gettimeofday(&startTime, /* timezone */ NULL);
+
+ do {
+
+ pollfd fds[1];
+ fds[0].fd = sock;
+ fds[0].events = POLLIN | POLLOUT;
+
+ const int ret = ::poll(fds, sizeof(fds) / sizeof(fds[0]), pollTimeout);
+
+ // Success
+ if (ret > 0) {
+
+ if (fds[0].revents & (POLLIN | POLLOUT)) {
+
+ int error = 0;
+ socklen_t len = sizeof(error);
+
+ if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &error, &len) < 0) {
+
+ connectErrno = errno;
+
+ } else {
+
+ if (error != 0) {
+ connectErrno = error;
+ } else {
+ connected = true;
+ }
+ }
+ }
+
+ break;
+
+ // Error
+ } else if (ret < -1) {
+
+ if (errno != EAGAIN && errno != EINTR) {
+
+ // Cancel connection
+ connectErrno = errno;
+ break;
+ }
+ }
+
+ // Check for timeout
+ if (m_timeoutHandler->isTimeOut()) {
+
+ if (!m_timeoutHandler->handleTimeOut()) {
+
+ // Cancel connection
+ connectErrno = ETIMEDOUT;
+ break;
+
+ } else {
+
+ // Reset timeout and keep waiting for connection
+ m_timeoutHandler->resetTimeOut();
+ }
+
+ } else {
+
+ // Keep waiting for connection
+ }
+
+ timeval curTime = { 0, 0 };
+ gettimeofday(&curTime, /* timezone */ NULL);
+
+ if (curAddrInfo->ai_next != NULL &&
+ curTime.tv_usec - startTime.tv_usec >= tryNextTimeout * 1000) {
+
+ connectErrno = ETIMEDOUT;
+ break;
+ }
+
+ } while (true);
+
+ if (!connected) {
+
+ ::close(sock);
+ sock = -1;
+ continue; // try next
+ }
+
+ break;
+
+ } else {
+
+ // Connection successful
+ break;
+ }
+
+ } else {
+
+ if (::connect(sock, curAddrInfo->ai_addr, curAddrInfo->ai_addrlen) < 0) {
+
+ connectErrno = errno;
+ ::close(sock);
+ sock = -1;
+ continue; // try next
+ }
+ }
+ }
+
+ ::freeaddrinfo(addrInfo);
+
+ if (sock == -1) {
+
+ try {
+ throwSocketError(connectErrno);
+ } catch (exceptions::socket_exception& e) { // wrap
+ throw vmime::exceptions::connection_error("Error while connecting socket.", e);
+ }
+ }
+
+ m_desc = sock;
+
+#else // !VMIME_HAVE_GETADDRINFO
+
+ // Resolve address
+ ::sockaddr_in addr;
+
+ memset(&addr, 0, sizeof(addr));
+
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(static_cast <unsigned short>(port));
+ addr.sin_addr.s_addr = ::inet_addr(address.c_str());
+
+ if (addr.sin_addr.s_addr == static_cast <in_addr_t>(-1)) {
+
+ ::hostent* hostInfo = ::gethostbyname(address.c_str());
+
+ if (hostInfo == NULL) {
+ // Error: cannot resolve address
+ throw vmime::exceptions::connection_error("Cannot resolve address.");
+ }
+
+ ::memcpy(reinterpret_cast <char*>(&addr.sin_addr), hostInfo->h_addr, hostInfo->h_length);
+ }
+
+ m_serverAddress = address;
+
+ // Get a new socket
+ m_desc = ::socket(AF_INET, SOCK_STREAM, 0);
+
+ if (m_desc == -1) {
+
+ try {
+ throwSocketError(errno);
+ } catch (exceptions::socket_exception& e) { // wrap
+ throw vmime::exceptions::connection_error("Error while creating socket.", e);
+ }
+ }
+
+ // Start connection
+ if (::connect(m_desc, reinterpret_cast <sockaddr*>(&addr), sizeof(addr)) == -1) {
+
+ try {
+
+ throwSocketError(errno);
+
+ } catch (exceptions::socket_exception& e) { // wrap
+
+ ::close(m_desc);
+ m_desc = -1;
+
+ // Error
+ throw vmime::exceptions::connection_error("Error while connecting socket.", e);
+ }
+ }
+
+#endif // VMIME_HAVE_GETADDRINFO
+
+ ::fcntl(m_desc, F_SETFL, ::fcntl(m_desc, F_GETFL) | O_NONBLOCK);
+}
+
+
+void posixSocket::resolve(
+ struct ::addrinfo** addrInfo,
+ const vmime::string& address,
+ const vmime::port_t port
+) {
+
+ char portStr[16];
+ snprintf(portStr, sizeof(portStr), "%u", static_cast <unsigned int>(port));
+
+
+ struct ::addrinfo hints;
+ memset(&hints, 0, sizeof(hints));
+
+ hints.ai_flags = AI_CANONNAME | AI_NUMERICSERV;
+ hints.ai_family = PF_UNSPEC;
+ hints.ai_socktype = SOCK_STREAM;
+
+#if VMIME_HAVE_GETADDRINFO_A
+
+ // If getaddrinfo_a() is available, use asynchronous resolving to allow
+ // the timeout handler to cancel the operation
+
+ struct ::gaicb gaiRequest;
+ memset(&gaiRequest, 0, sizeof(gaiRequest));
+
+ gaiRequest.ar_name = address.c_str();
+ gaiRequest.ar_service = portStr;
+ gaiRequest.ar_request = &hints;
+
+ struct ::gaicb* gaiRequests = &gaiRequest;
+ int gaiError;
+
+ if ((gaiError = getaddrinfo_a(GAI_NOWAIT, &gaiRequests, 1, NULL)) != 0) {
+
+ throw vmime::exceptions::connection_error(
+ "getaddrinfo_a() failed: " + std::string(gai_strerror(gaiError))
+ );
+ }
+
+ if (m_timeoutHandler) {
+ m_timeoutHandler->resetTimeOut();
+ }
+
+ while (true) {
+
+ struct timespec gaiTimeout;
+ gaiTimeout.tv_sec = 1; // query timeout handler every second
+ gaiTimeout.tv_nsec = 0;
+
+ gaiError = gai_suspend(&gaiRequests, 1, &gaiTimeout);
+
+ if (gaiError == 0 || gaiError == EAI_ALLDONE) {
+
+ const int ret = gai_error(&gaiRequest);
+
+ if (ret != 0) {
+
+ throw vmime::exceptions::connection_error(
+ "getaddrinfo_a() request failed: " + std::string(gai_strerror(ret))
+ );
+
+ } else {
+
+ *addrInfo = gaiRequest.ar_result;
+ break;
+ }
+
+ } else if (gaiError != EAI_AGAIN) {
+
+ if (gaiError == EAI_SYSTEM) {
+
+ const int ret = gai_error(&gaiRequest);
+
+ if (ret != EAI_INPROGRESS && errno != 0) {
+
+ try {
+ throwSocketError(errno);
+ } catch (exceptions::socket_exception& e) { // wrap
+ throw vmime::exceptions::connection_error("Error while connecting socket.", e);
+ }
+ }
+
+ } else {
+
+ throw vmime::exceptions::connection_error(
+ "gai_suspend() failed: " + std::string(gai_strerror(gaiError))
+ );
+ }
+ }
+
+ // Check for timeout
+ if (m_timeoutHandler && m_timeoutHandler->isTimeOut()) {
+
+ if (!m_timeoutHandler->handleTimeOut()) {
+
+ throw exceptions::operation_timed_out();
+
+ } else {
+
+ // Reset timeout and keep waiting for connection
+ m_timeoutHandler->resetTimeOut();
+ }
+ }
+ }
+
+#else // !VMIME_HAVE_GETADDRINFO_A
+
+ if (::getaddrinfo(address.c_str(), portStr, &hints, addrInfo) != 0) {
+
+ // Error: cannot resolve address
+ throw vmime::exceptions::connection_error("Cannot resolve address.");
+ }
+
+#endif // VMIME_HAVE_GETADDRINFO_A
+
+}
+
+
+bool posixSocket::isConnected() const {
+
+ if (m_desc == -1) {
+ return false;
+ }
+
+ char buff;
+
+ return ::recv(m_desc, &buff, 1, MSG_PEEK) != 0;
+}
+
+
+void posixSocket::disconnect() {
+
+ if (m_desc != -1) {
+
+ if (m_tracer) {
+ m_tracer->traceSend("Disconnecting");
+ }
+
+ ::shutdown(m_desc, SHUT_RDWR);
+ ::close(m_desc);
+
+ m_desc = -1;
+ }
+}
+
+
+static bool isNumericAddress(const char* address) {
+
+#if VMIME_HAVE_GETADDRINFO
+
+ struct addrinfo hint, *info = NULL;
+ memset(&hint, 0, sizeof(hint));
+
+ hint.ai_family = AF_UNSPEC;
+ hint.ai_flags = AI_NUMERICHOST;
+
+ if (getaddrinfo(address, 0, &hint, &info) == 0) {
+
+ freeaddrinfo(info);
+ return true;
+
+ } else {
+
+ return false;
+ }
+
+#else
+
+ return inet_addr(address) != INADDR_NONE;
+
+#endif
+
+}
+
+
+const string posixSocket::getPeerAddress() const {
+
+ // Get address of connected peer
+ sockaddr peer;
+ socklen_t peerLen = sizeof(peer);
+
+ if (getpeername(m_desc, &peer, &peerLen) != 0) {
+ throwSocketError(errno);
+ }
+
+ // Convert to numerical presentation format
+ char buf[INET6_ADDRSTRLEN];
+
+ if (!inet_ntop(peer.sa_family, &(reinterpret_cast <struct sockaddr_in *>(&peer))->sin_addr, buf, sizeof(buf))) {
+ throwSocketError(errno);
+ }
+
+ return string(buf);
+}
+
+
+const string posixSocket::getPeerName() const {
+
+ // Get address of connected peer
+ sockaddr peer;
+ socklen_t peerLen = sizeof(peer);
+
+ if (getpeername(m_desc, &peer, &peerLen) != 0) {
+ throwSocketError(errno);
+ }
+
+ // If server address as specified when connecting is a numeric
+ // address, try to get a host name for it
+ if (isNumericAddress(m_serverAddress.c_str())) {
+
+#if VMIME_HAVE_GETNAMEINFO
+
+ char host[NI_MAXHOST + 1];
+ char service[NI_MAXSERV + 1];
+
+ if (getnameinfo(reinterpret_cast <sockaddr *>(&peer), peerLen,
+ host, sizeof(host), service, sizeof(service),
+ /* flags */ NI_NAMEREQD) == 0) {
+
+ return string(host);
+ }
+
+#else
+
+ struct hostent *hp;
+
+ if ((hp = gethostbyaddr(reinterpret_cast <const void *>(&peer),
+ sizeof(peer), peer.sa_family)) != NULL) {
+
+ return string(hp->h_name);
+ }
+
+#endif
+
+ }
+
+ return m_serverAddress;
+}
+
+
+size_t posixSocket::getBlockSize() const {
+
+ return 16384; // 16 KB
+}
+
+
+bool posixSocket::waitForData(const bool read, const bool write, const int msecs) {
+
+ for (int i = 0 ; i <= msecs / 10 ; ++i) {
+
+ // Check whether data is available
+ pollfd fds[1];
+ fds[0].fd = m_desc;
+ fds[0].events = 0;
+
+ if (read) {
+ fds[0].events |= POLLIN;
+ }
+
+ if (write) {
+ fds[0].events |= POLLOUT;
+ }
+
+ const int ret = ::poll(fds, sizeof(fds) / sizeof(fds[0]), 10 /* ms */);
+
+ if (ret < 0) {
+
+ if (errno != EAGAIN && errno != EINTR) {
+ throwSocketError(errno);
+ }
+
+ } else if (ret > 0) {
+
+ if (fds[0].revents & (POLLIN | POLLOUT)) {
+ return true;
+ }
+ }
+
+ // No data available at this time
+ // Check if we are timed out
+ if (m_timeoutHandler &&
+ m_timeoutHandler->isTimeOut()) {
+
+ if (!m_timeoutHandler->handleTimeOut()) {
+
+ // Server did not react within timeout delay
+ throw exceptions::operation_timed_out();
+
+ } else {
+
+ // Reset timeout
+ m_timeoutHandler->resetTimeOut();
+ }
+ }
+ }
+
+ return false; // time out
+}
+
+
+bool posixSocket::waitForRead(const int msecs) {
+
+ return waitForData(/* read */ true, /* write */ false, msecs);
+}
+
+
+bool posixSocket::waitForWrite(const int msecs) {
+
+ return waitForData(/* read */ false, /* write */ true, msecs);
+}
+
+
+void posixSocket::receive(vmime::string& buffer) {
+
+ const size_t size = receiveRaw(m_buffer, sizeof(m_buffer));
+ buffer = utility::stringUtils::makeStringFromBytes(m_buffer, size);
+}
+
+
+size_t posixSocket::receiveRaw(byte_t* buffer, const size_t count) {
+
+ m_status &= ~STATUS_WOULDBLOCK;
+
+ // Check whether data is available
+ if (!waitForRead(50 /* msecs */)) {
+
+ m_status |= STATUS_WOULDBLOCK;
+
+ // Continue waiting for data
+ return 0;
+ }
+
+ // Read available data
+ ssize_t ret = ::recv(m_desc, buffer, count, 0);
+
+ if (ret < 0) {
+
+ if (!IS_EAGAIN(errno)) {
+ throwSocketError(errno);
+ }
+
+ // Check if we are timed out
+ if (m_timeoutHandler &&
+ m_timeoutHandler->isTimeOut()) {
+
+ if (!m_timeoutHandler->handleTimeOut()) {
+
+ // Server did not react within timeout delay
+ throwSocketError(errno);
+
+ } else {
+
+ // Reset timeout
+ m_timeoutHandler->resetTimeOut();
+ }
+ }
+
+ m_status |= STATUS_WOULDBLOCK;
+
+ // No data available at this time
+ return 0;
+
+ } else if (ret == 0) {
+
+ // Host shutdown
+ throwSocketError(ENOTCONN);
+
+ } else {
+
+ // Data received, reset timeout
+ if (m_timeoutHandler) {
+ m_timeoutHandler->resetTimeOut();
+ }
+ }
+
+ return ret;
+}
+
+
+void posixSocket::send(const vmime::string& buffer) {
+
+ sendRaw(reinterpret_cast <const byte_t*>(buffer.data()), buffer.length());
+}
+
+
+void posixSocket::send(const char* str) {
+
+ sendRaw(reinterpret_cast <const byte_t*>(str), ::strlen(str));
+}
+
+
+void posixSocket::sendRaw(const byte_t* buffer, const size_t count) {
+
+ m_status &= ~STATUS_WOULDBLOCK;
+
+ size_t size = count;
+
+ while (size > 0) {
+
+#if VMIME_HAVE_MSG_NOSIGNAL
+ const ssize_t ret = ::send(m_desc, buffer, size, MSG_NOSIGNAL);
+#else
+ const ssize_t ret = ::send(m_desc, buffer, size, 0);
+#endif
+
+ if (ret <= 0) {
+
+ if (ret < 0 && !IS_EAGAIN(errno)) {
+ throwSocketError(errno);
+ }
+
+ waitForWrite(50 /* msecs */);
+
+ } else {
+
+ buffer += ret;
+ size -= ret;
+ }
+ }
+
+ // Reset timeout
+ if (m_timeoutHandler) {
+ m_timeoutHandler->resetTimeOut();
+ }
+}
+
+
+size_t posixSocket::sendRawNonBlocking(const byte_t* buffer, const size_t count) {
+
+ m_status &= ~STATUS_WOULDBLOCK;
+
+#if VMIME_HAVE_MSG_NOSIGNAL
+ const ssize_t ret = ::send(m_desc, buffer, count, MSG_NOSIGNAL);
+#else
+ const ssize_t ret = ::send(m_desc, buffer, count, 0);
+#endif
+
+ if (ret <= 0) {
+
+ if (ret < 0 && !IS_EAGAIN(errno)) {
+ throwSocketError(errno);
+ }
+
+ // Check if we are timed out
+ if (m_timeoutHandler &&
+ m_timeoutHandler->isTimeOut()) {
+
+ if (!m_timeoutHandler->handleTimeOut()) {
+
+ // Could not send data within timeout delay
+ throw exceptions::operation_timed_out();
+
+ } else {
+
+ // Reset timeout
+ m_timeoutHandler->resetTimeOut();
+ }
+ }
+
+ m_status |= STATUS_WOULDBLOCK;
+
+ // No data can be written at this time
+ return 0;
+ }
+
+ // Reset timeout
+ if (m_timeoutHandler) {
+ m_timeoutHandler->resetTimeOut();
+ }
+
+ return ret;
+}
+
+
+void posixSocket::throwSocketError(const int err) {
+
+ const char* msg = NULL;
+
+ switch (err) {
+
+ case EACCES: msg = "EACCES: permission denied"; break;
+ case EAFNOSUPPORT: msg = "EAFNOSUPPORT: address family not supported"; break;
+ case EMFILE: msg = "EMFILE: process file table overflow"; break;
+ case ENFILE: msg = "ENFILE: system limit reached"; break;
+ case EPROTONOSUPPORT: msg = "EPROTONOSUPPORT: protocol not supported"; break;
+ case EAGAIN: msg = "EGAIN: blocking operation"; break;
+ case EBADF: msg = "EBADF: invalid descriptor"; break;
+ case ECONNRESET: msg = "ECONNRESET: connection reset by peer"; break;
+ case EFAULT: msg = "EFAULT: bad user space address"; break;
+ case EINTR: msg = "EINTR: signal occurred before transmission"; break;
+ case EINVAL: msg = "EINVAL: invalid argument"; break;
+ case EMSGSIZE: msg = "EMSGSIZE: message cannot be sent atomically"; break;
+ case ENOBUFS: msg = "ENOBUFS: output queue is full"; break;
+ case ENOMEM: msg = "ENOMEM: out of memory"; break;
+ case EPIPE: msg = "EPIPE: broken pipe"; break;
+ case ENOTCONN: msg = "ENOTCONN: not connected"; break;
+ case ECONNREFUSED: msg = "ECONNREFUSED: connection refused"; break;
+ }
+
+ if (msg) {
+
+ throw exceptions::socket_exception(msg);
+
+ } else {
+
+ // Use strerror() to get string describing error number
+
+#if VMIME_HAVE_STRERROR_R
+
+ char errbuf[512];
+
+ throw exceptions::socket_exception(
+ vmime_strerror_r_result(
+ strerror_r(err, errbuf, sizeof(errbuf)),
+ errbuf
+ )
+ );
+
+#else // !VMIME_HAVE_STRERROR_R
+
+ const std::string strmsg(strerror(err));
+ throw exceptions::socket_exception(strmsg);
+
+#endif // VMIME_HAVE_STRERROR_R
+
+ }
+}
+
+
+unsigned int posixSocket::getStatus() const {
+
+ return m_status;
+}
+
+
+shared_ptr <net::timeoutHandler> posixSocket::getTimeoutHandler() {
+
+ return m_timeoutHandler;
+}
+
+
+void posixSocket::setTracer(const shared_ptr <net::tracer>& tracer) {
+
+ m_tracer = tracer;
+}
+
+
+shared_ptr <net::tracer> posixSocket::getTracer() {
+
+ return m_tracer;
+}
+
+
+
+//
+// posixSocketFactory
+//
+
+shared_ptr <vmime::net::socket> posixSocketFactory::create() {
+
+ shared_ptr <vmime::net::timeoutHandler> th;
+ return make_shared <posixSocket>(th);
+}
+
+
+shared_ptr <vmime::net::socket> posixSocketFactory::create(const shared_ptr <vmime::net::timeoutHandler>& th) {
+
+ return make_shared <posixSocket>(th);
+}
+
+
+} // posix
+} // platforms
+} // vmime
+
+
+#endif // VMIME_PLATFORM_IS_POSIX && VMIME_HAVE_MESSAGING_FEATURES
diff --git a/vmime-master/src/vmime/platforms/posix/posixSocket.hpp b/vmime-master/src/vmime/platforms/posix/posixSocket.hpp
new file mode 100644
index 0000000..7d732b7
--- /dev/null
+++ b/vmime-master/src/vmime/platforms/posix/posixSocket.hpp
@@ -0,0 +1,118 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_PLATFORMS_POSIX_SOCKET_HPP_INCLUDED
+#define VMIME_PLATFORMS_POSIX_SOCKET_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_PLATFORM_IS_POSIX && VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/net/socket.hpp"
+
+
+struct addrinfo;
+
+
+namespace vmime {
+namespace platforms {
+namespace posix {
+
+
+class posixSocket : public vmime::net::socket {
+
+public:
+
+ posixSocket(shared_ptr <vmime::net::timeoutHandler> th);
+ ~posixSocket();
+
+ void connect(const vmime::string& address, const vmime::port_t port);
+ bool isConnected() const;
+ void disconnect();
+
+ bool waitForRead(const int msecs = 30000);
+ bool waitForWrite(const int msecs = 30000);
+
+ void receive(vmime::string& buffer);
+ size_t receiveRaw(byte_t* buffer, const size_t count);
+
+ void send(const vmime::string& buffer);
+ void send(const char* str);
+ void sendRaw(const byte_t* buffer, const size_t count);
+ size_t sendRawNonBlocking(const byte_t* buffer, const size_t count);
+
+ size_t getBlockSize() const;
+
+ unsigned int getStatus() const;
+
+ const string getPeerName() const;
+ const string getPeerAddress() const;
+
+ shared_ptr <net::timeoutHandler> getTimeoutHandler();
+
+ void setTracer(const shared_ptr <net::tracer>& tracer);
+ shared_ptr <net::tracer> getTracer();
+
+protected:
+
+ void resolve(struct ::addrinfo** addrInfo, const vmime::string& address, const vmime::port_t port);
+
+ bool waitForData(const bool read, const bool write, const int msecs);
+
+ static void throwSocketError(const int err);
+
+private:
+
+ shared_ptr <vmime::net::timeoutHandler> m_timeoutHandler;
+ shared_ptr <net::tracer> m_tracer;
+
+ byte_t m_buffer[65536];
+ int m_desc;
+
+ unsigned int m_status;
+
+ string m_serverAddress;
+};
+
+
+
+class posixSocketFactory : public vmime::net::socketFactory {
+
+public:
+
+ shared_ptr <vmime::net::socket> create();
+ shared_ptr <vmime::net::socket> create(const shared_ptr <vmime::net::timeoutHandler>& th);
+};
+
+
+} // posix
+} // platforms
+} // vmime
+
+
+#endif // VMIME_PLATFORM_IS_POSIX && VMIME_HAVE_MESSAGING_FEATURES
+
+#endif // VMIME_PLATFORMS_POSIX_SOCKET_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/platforms/windows/windowsCodepages.hpp b/vmime-master/src/vmime/platforms/windows/windowsCodepages.hpp
new file mode 100644
index 0000000..1457c59
--- /dev/null
+++ b/vmime-master/src/vmime/platforms/windows/windowsCodepages.hpp
@@ -0,0 +1,197 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_PLATFORMS_WINDOWS_CODEPAGES_HPP_INCLUDED
+#define VMIME_PLATFORMS_WINDOWS_CODEPAGES_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_PLATFORM_IS_WINDOWS
+
+
+#include <string.h>
+
+
+namespace vmime {
+namespace platforms {
+namespace windows {
+
+
+struct windowsCodepages {
+
+ static int getByName(const char* s8_Name) {
+
+ if (stricmp(s8_Name, "ASMO-708") == 0) return 708;
+ if (stricmp(s8_Name, "big5") == 0) return 950;
+ if (stricmp(s8_Name, "cp1025") == 0) return 21025;
+ if (stricmp(s8_Name, "cp866") == 0) return 866;
+ if (stricmp(s8_Name, "cp875") == 0) return 875;
+ if (stricmp(s8_Name, "DOS-720") == 0) return 720;
+ if (stricmp(s8_Name, "DOS-862") == 0) return 862;
+ if (stricmp(s8_Name, "EUC-CN") == 0) return 51936;
+ if (stricmp(s8_Name, "euc-jp") == 0) return 51932;
+ if (stricmp(s8_Name, "EUC-JP") == 0) return 20932;
+ if (stricmp(s8_Name, "euc-kr") == 0) return 51949;
+ if (stricmp(s8_Name, "GB18030") == 0) return 54936;
+ if (stricmp(s8_Name, "GBK") == 0) return 54936;
+ if (stricmp(s8_Name, "gb2312") == 0) return 936;
+ if (stricmp(s8_Name, "hz-gb-2312") == 0) return 52936;
+ if (stricmp(s8_Name, "IBM00858") == 0) return 858;
+ if (stricmp(s8_Name, "IBM00924") == 0) return 20924;
+ if (stricmp(s8_Name, "IBM01047") == 0) return 1047;
+ if (stricmp(s8_Name, "IBM01140") == 0) return 1140;
+ if (stricmp(s8_Name, "IBM01141") == 0) return 1141;
+ if (stricmp(s8_Name, "IBM01142") == 0) return 1142;
+ if (stricmp(s8_Name, "IBM01143") == 0) return 1143;
+ if (stricmp(s8_Name, "IBM01144") == 0) return 1144;
+ if (stricmp(s8_Name, "IBM01145") == 0) return 1145;
+ if (stricmp(s8_Name, "IBM01146") == 0) return 1146;
+ if (stricmp(s8_Name, "IBM01147") == 0) return 1147;
+ if (stricmp(s8_Name, "IBM01148") == 0) return 1148;
+ if (stricmp(s8_Name, "IBM01149") == 0) return 1149;
+ if (stricmp(s8_Name, "IBM037") == 0) return 37;
+ if (stricmp(s8_Name, "IBM1026") == 0) return 1026;
+ if (stricmp(s8_Name, "IBM273") == 0) return 20273;
+ if (stricmp(s8_Name, "IBM277") == 0) return 20277;
+ if (stricmp(s8_Name, "IBM278") == 0) return 20278;
+ if (stricmp(s8_Name, "IBM280") == 0) return 20280;
+ if (stricmp(s8_Name, "IBM284") == 0) return 20284;
+ if (stricmp(s8_Name, "IBM285") == 0) return 20285;
+ if (stricmp(s8_Name, "IBM290") == 0) return 20290;
+ if (stricmp(s8_Name, "IBM297") == 0) return 20297;
+ if (stricmp(s8_Name, "IBM420") == 0) return 20420;
+ if (stricmp(s8_Name, "IBM423") == 0) return 20423;
+ if (stricmp(s8_Name, "IBM424") == 0) return 20424;
+ if (stricmp(s8_Name, "IBM437") == 0) return 437;
+ if (stricmp(s8_Name, "IBM500") == 0) return 500;
+ if (stricmp(s8_Name, "ibm737") == 0) return 737;
+ if (stricmp(s8_Name, "ibm775") == 0) return 775;
+ if (stricmp(s8_Name, "ibm850") == 0) return 850;
+ if (stricmp(s8_Name, "ibm852") == 0) return 852;
+ if (stricmp(s8_Name, "IBM855") == 0) return 855;
+ if (stricmp(s8_Name, "ibm857") == 0) return 857;
+ if (stricmp(s8_Name, "IBM860") == 0) return 860;
+ if (stricmp(s8_Name, "ibm861") == 0) return 861;
+ if (stricmp(s8_Name, "IBM863") == 0) return 863;
+ if (stricmp(s8_Name, "IBM864") == 0) return 864;
+ if (stricmp(s8_Name, "IBM865") == 0) return 865;
+ if (stricmp(s8_Name, "ibm869") == 0) return 869;
+ if (stricmp(s8_Name, "IBM870") == 0) return 870;
+ if (stricmp(s8_Name, "IBM871") == 0) return 20871;
+ if (stricmp(s8_Name, "IBM880") == 0) return 20880;
+ if (stricmp(s8_Name, "IBM905") == 0) return 20905;
+ if (stricmp(s8_Name, "IBM-Thai") == 0) return 20838;
+ if (stricmp(s8_Name, "iso-2022-jp") == 0) return 50222;
+ if (stricmp(s8_Name, "iso-2022-kr") == 0) return 50225;
+ if (stricmp(s8_Name, "iso-8859-1") == 0) return 28591;
+ if (stricmp(s8_Name, "iso-8859-13") == 0) return 28603;
+ if (stricmp(s8_Name, "iso-8859-15") == 0) return 28605;
+ if (stricmp(s8_Name, "iso-8859-2") == 0) return 28592;
+ if (stricmp(s8_Name, "iso-8859-3") == 0) return 28593;
+ if (stricmp(s8_Name, "iso-8859-4") == 0) return 28594;
+ if (stricmp(s8_Name, "iso-8859-5") == 0) return 28595;
+ if (stricmp(s8_Name, "iso-8859-6") == 0) return 28596;
+ if (stricmp(s8_Name, "iso-8859-7") == 0) return 28597;
+ if (stricmp(s8_Name, "iso-8859-8") == 0) return 28598;
+ if (stricmp(s8_Name, "iso-8859-8-i") == 0) return 38598;
+ if (stricmp(s8_Name, "iso-8859-9") == 0) return 28599;
+ if (stricmp(s8_Name, "Johab") == 0) return 1361;
+ if (stricmp(s8_Name, "koi8-r") == 0) return 20866;
+ if (stricmp(s8_Name, "koi8-u") == 0) return 21866;
+ if (stricmp(s8_Name, "ks_c_5601-1987") == 0) return 949;
+ if (stricmp(s8_Name, "macintosh") == 0) return 10000;
+ if (stricmp(s8_Name, "unicodeFFFE") == 0) return 1201;
+ if (stricmp(s8_Name, "us-ascii") == 0) return 20127;
+ if (stricmp(s8_Name, "utf-16") == 0) return 1200;
+ if (stricmp(s8_Name, "utf-32") == 0) return 12000;
+ if (stricmp(s8_Name, "utf-32BE") == 0) return 12001;
+ if (stricmp(s8_Name, "utf-7") == 0) return 65000;
+ if (stricmp(s8_Name, "utf-8") == 0) return 65001;
+ if (stricmp(s8_Name, "windows-1250") == 0) return 1250;
+ if (stricmp(s8_Name, "windows-1251") == 0) return 1251;
+ if (stricmp(s8_Name, "Windows-1252") == 0) return 1252;
+ if (stricmp(s8_Name, "windows-1253") == 0) return 1253;
+ if (stricmp(s8_Name, "windows-1254") == 0) return 1254;
+ if (stricmp(s8_Name, "windows-1255") == 0) return 1255;
+ if (stricmp(s8_Name, "windows-1256") == 0) return 1256;
+ if (stricmp(s8_Name, "windows-1257") == 0) return 1257;
+ if (stricmp(s8_Name, "windows-1258") == 0) return 1258;
+ if (stricmp(s8_Name, "windows-874") == 0) return 874;
+ if (stricmp(s8_Name, "x-Chinese-CNS") == 0) return 20000;
+ if (stricmp(s8_Name, "x-Chinese-Eten") == 0) return 20002;
+ if (stricmp(s8_Name, "x-cp20001") == 0) return 20001;
+ if (stricmp(s8_Name, "x-cp20003") == 0) return 20003;
+ if (stricmp(s8_Name, "x-cp20004") == 0) return 20004;
+ if (stricmp(s8_Name, "x-cp20005") == 0) return 20005;
+ if (stricmp(s8_Name, "x-cp20261") == 0) return 20261;
+ if (stricmp(s8_Name, "x-cp20269") == 0) return 20269;
+ if (stricmp(s8_Name, "x-cp20936") == 0) return 20936;
+ if (stricmp(s8_Name, "x-cp20949") == 0) return 20949;
+ if (stricmp(s8_Name, "x-cp50227") == 0) return 50227;
+ if (stricmp(s8_Name, "x-EBCDIC-KoreanExtended") == 0) return 20833;
+ if (stricmp(s8_Name, "x-Europa") == 0) return 29001;
+ if (stricmp(s8_Name, "x-IA5") == 0) return 20105;
+ if (stricmp(s8_Name, "x-IA5-German") == 0) return 20106;
+ if (stricmp(s8_Name, "x-IA5-Norwegian") == 0) return 20108;
+ if (stricmp(s8_Name, "x-IA5-Swedish") == 0) return 20107;
+ if (stricmp(s8_Name, "x-iscii-as") == 0) return 57006;
+ if (stricmp(s8_Name, "x-iscii-be") == 0) return 57003;
+ if (stricmp(s8_Name, "x-iscii-de") == 0) return 57002;
+ if (stricmp(s8_Name, "x-iscii-gu") == 0) return 57010;
+ if (stricmp(s8_Name, "x-iscii-ka") == 0) return 57008;
+ if (stricmp(s8_Name, "x-iscii-ma") == 0) return 57009;
+ if (stricmp(s8_Name, "x-iscii-or") == 0) return 57007;
+ if (stricmp(s8_Name, "x-iscii-pa") == 0) return 57011;
+ if (stricmp(s8_Name, "x-iscii-ta") == 0) return 57004;
+ if (stricmp(s8_Name, "x-iscii-te") == 0) return 57005;
+ if (stricmp(s8_Name, "x-mac-arabic") == 0) return 10004;
+ if (stricmp(s8_Name, "x-mac-ce") == 0) return 10029;
+ if (stricmp(s8_Name, "x-mac-chinesesimp") == 0) return 10008;
+ if (stricmp(s8_Name, "x-mac-chinesetrad") == 0) return 10002;
+ if (stricmp(s8_Name, "x-mac-croatian") == 0) return 10082;
+ if (stricmp(s8_Name, "x-mac-cyrillic") == 0) return 10007;
+ if (stricmp(s8_Name, "x-mac-greek") == 0) return 10006;
+ if (stricmp(s8_Name, "x-mac-hebrew") == 0) return 10005;
+ if (stricmp(s8_Name, "x-mac-icelandic") == 0) return 10079;
+ if (stricmp(s8_Name, "x-mac-japanese") == 0) return 10001;
+ if (stricmp(s8_Name, "x-mac-korean") == 0) return 10003;
+ if (stricmp(s8_Name, "x-mac-romanian") == 0) return 10010;
+ if (stricmp(s8_Name, "x-mac-thai") == 0) return 10021;
+ if (stricmp(s8_Name, "x-mac-turkish") == 0) return 10081;
+ if (stricmp(s8_Name, "x-mac-ukrainian") == 0) return 10017;
+
+ throw exception(std::string("Unknown charset: ") + s8_Name);
+ }
+};
+
+
+} // windows
+} // platforms
+} // vmime
+
+
+#endif // VMIME_PLATFORM_IS_WINDOWS
+
+#endif // VMIME_PLATFORMS_WINDOWS_CODEPAGES_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/platforms/windows/windowsCriticalSection.cpp b/vmime-master/src/vmime/platforms/windows/windowsCriticalSection.cpp
new file mode 100644
index 0000000..c0a0bec
--- /dev/null
+++ b/vmime-master/src/vmime/platforms/windows/windowsCriticalSection.cpp
@@ -0,0 +1,67 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_PLATFORM_IS_WINDOWS
+
+
+#include "vmime/platforms/windows/windowsCriticalSection.hpp"
+
+
+namespace vmime {
+namespace platforms {
+namespace windows {
+
+
+windowsCriticalSection::windowsCriticalSection() {
+
+ InitializeCriticalSectionAndSpinCount(&m_cs, 0x400);
+}
+
+
+windowsCriticalSection::~windowsCriticalSection() {
+
+ DeleteCriticalSection(&m_cs);
+}
+
+
+void windowsCriticalSection::lock() {
+
+ EnterCriticalSection(&m_cs);
+}
+
+
+void windowsCriticalSection::unlock() {
+
+ LeaveCriticalSection(&m_cs);
+}
+
+
+} // windows
+} // platforms
+} // vmime
+
+
+#endif // VMIME_PLATFORM_IS_WINDOWS
diff --git a/vmime-master/src/vmime/platforms/windows/windowsCriticalSection.hpp b/vmime-master/src/vmime/platforms/windows/windowsCriticalSection.hpp
new file mode 100644
index 0000000..ffe8294
--- /dev/null
+++ b/vmime-master/src/vmime/platforms/windows/windowsCriticalSection.hpp
@@ -0,0 +1,68 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_PLATFORMS_WINDOWS_CRITICALSECTION_HPP_INCLUDED
+#define VMIME_PLATFORMS_WINDOWS_CRITICALSECTION_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_PLATFORM_IS_WINDOWS
+
+
+#include "vmime/utility/sync/criticalSection.hpp"
+
+
+#include <windows.h>
+
+
+namespace vmime {
+namespace platforms {
+namespace windows {
+
+
+class windowsCriticalSection : public utility::sync::criticalSection {
+
+public:
+
+ windowsCriticalSection();
+ ~windowsCriticalSection();
+
+ void lock();
+ void unlock();
+
+private:
+
+ CRITICAL_SECTION m_cs;
+};
+
+
+} // windows
+} // platforms
+} // vmime
+
+
+#endif // VMIME_PLATFORM_IS_WINDOWS
+
+#endif // VMIME_PLATFORMS_WINDOWS_CRITICALSECTION_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/platforms/windows/windowsFile.cpp b/vmime-master/src/vmime/platforms/windows/windowsFile.cpp
new file mode 100644
index 0000000..774731c
--- /dev/null
+++ b/vmime-master/src/vmime/platforms/windows/windowsFile.cpp
@@ -0,0 +1,712 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_PLATFORM_IS_WINDOWS && VMIME_HAVE_FILESYSTEM_FEATURES
+
+
+#include "vmime/platforms/windows/windowsFile.hpp"
+
+#include <windows.h>
+#include <string.h>
+
+#include "vmime/exception.hpp"
+#include "vmime/utility/stringUtils.hpp"
+
+
+namespace vmime {
+namespace platforms {
+namespace windows {
+
+
+shared_ptr <vmime::utility::file> windowsFileSystemFactory::create(
+ const vmime::utility::file::path& path
+) const {
+
+ return make_shared <windowsFile>(path);
+}
+
+
+const vmime::utility::file::path windowsFileSystemFactory::stringToPath(
+ const vmime::string& str
+) const {
+
+ return stringToPathImpl(str);
+}
+
+
+const vmime::string windowsFileSystemFactory::pathToString(
+ const vmime::utility::file::path& path
+) const {
+
+ return pathToStringImpl(path);
+}
+
+
+const vmime::utility::file::path windowsFileSystemFactory::stringToPathImpl(
+ const vmime::string& str
+) {
+
+ vmime::size_t offset = 0;
+ vmime::size_t prev = 0;
+
+ vmime::utility::file::path path;
+
+ while ((offset = str.find_first_of("\\", offset)) != vmime::string::npos) {
+
+ if (offset != prev) {
+
+ path.appendComponent(
+ vmime::utility::file::path::component(
+ vmime::string(str.begin() + prev, str.begin() + offset)
+ )
+ );
+ }
+
+ prev = offset + 1;
+ offset++;
+ }
+
+ if (prev < str.length()) {
+
+ path.appendComponent(
+ vmime::utility::file::path::component(
+ vmime::string(str.begin() + prev, str.end())
+ )
+ );
+ }
+
+ return path;
+}
+
+
+const vmime::string windowsFileSystemFactory::pathToStringImpl(
+ const vmime::utility::file::path& path
+) {
+
+ vmime::string native = "";
+
+ for (int i = 0 ; i < path.getSize() ; ++i) {
+
+ if (i > 0) {
+ native += "\\";
+ }
+
+ native += path[i].getBuffer();
+ }
+
+ return native;
+}
+
+
+bool windowsFileSystemFactory::isValidPathComponent(
+ const vmime::utility::file::path::component& comp
+) const {
+
+ return isValidPathComponent(comp, false);
+}
+
+
+bool windowsFileSystemFactory::isValidPathComponent(
+ const vmime::utility::file::path::component& comp,
+ bool firstComponent
+) const {
+
+ const string& buffer = comp.getBuffer();
+
+ // If first component, check if component is a drive
+ if (firstComponent && (buffer.length() == 2) && (buffer[1] == ':')) {
+
+ char drive = tolower(buffer[0]);
+
+ if ((drive >= 'a') && (drive <= 'z')) {
+ return true;
+ }
+ }
+
+ // Check for invalid characters
+ for (size_t i = 0 ; i < buffer.length() ; ++i) {
+
+ const unsigned char c = buffer[i];
+
+ switch (c) {
+
+ // Reserved characters
+ case '<': case '>': case ':':
+ case '"': case '/': case '\\':
+ case '|': case '$': case '*':
+
+ return false;
+
+ default:
+
+ if (c <= 31) {
+ return false;
+ }
+ }
+ }
+
+ string upperBuffer = vmime::utility::stringUtils::toUpper(buffer);
+
+ // Check for reserved names
+ if (upperBuffer.length() == 3) {
+
+ if (upperBuffer == "CON" || buffer == "PRN" || buffer == "AUX" || buffer == "NUL") {
+ return false;
+ }
+
+ } else if (upperBuffer.length() == 4) {
+
+ if ((upperBuffer.substr(0, 3) == "COM") && // COM0 to COM9
+ (upperBuffer[3] >= '0') && (upperBuffer[3] <= '9')) {
+
+ return false;
+
+ } else if ((upperBuffer.substr(0, 3) == "LPT") && // LPT0 to LPT9
+ (upperBuffer[3] >= '0') && (upperBuffer[3] <= '9')) {
+
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+bool windowsFileSystemFactory::isValidPath(const vmime::utility::file::path& path) const {
+
+ for (int i = 0 ; i < path.getSize() ; ++i) {
+
+ if (!isValidPathComponent(path[i], (i == 0))) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+
+void windowsFileSystemFactory::reportError(const vmime::utility::path& path, const int err) {
+
+ vmime::string desc;
+
+ LPVOID lpMsgBuf;
+
+ if (FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER |
+ FORMAT_MESSAGE_FROM_SYSTEM |
+ FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ err,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPTSTR) &lpMsgBuf,
+ 0,
+ NULL)) {
+
+ desc = (char*) lpMsgBuf;
+ LocalFree(lpMsgBuf);
+ }
+
+ throw vmime::exceptions::filesystem_exception(desc, path);
+}
+
+
+
+
+windowsFile::windowsFile(const vmime::utility::file::path& path)
+ : m_path(path),
+ m_nativePath(windowsFileSystemFactory::pathToStringImpl(path)) {
+
+}
+
+
+void windowsFile::createFile() {
+
+ HANDLE hFile = CreateFile(
+ m_nativePath.c_str(),
+ GENERIC_WRITE,
+ FILE_SHARE_READ | FILE_SHARE_WRITE,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL
+ );
+
+ if (hFile == INVALID_HANDLE_VALUE) {
+ windowsFileSystemFactory::reportError(m_path, GetLastError());
+ }
+
+ CloseHandle(hFile);
+}
+
+
+void windowsFile::createDirectory(const bool createAll) {
+
+ createDirectoryImpl(m_path, m_path, createAll);
+}
+
+
+bool windowsFile::isFile() const {
+
+ DWORD dwFileAttribute = GetFileAttributes(m_nativePath.c_str());
+
+ if (dwFileAttribute == INVALID_FILE_ATTRIBUTES) {
+ return false;
+ }
+
+ return (dwFileAttribute & FILE_ATTRIBUTE_DIRECTORY) == 0;
+}
+
+
+bool windowsFile::isDirectory() const {
+
+ DWORD dwFileAttribute = GetFileAttributes(m_nativePath.c_str());
+
+ if (dwFileAttribute == INVALID_FILE_ATTRIBUTES) {
+ return false;
+ }
+
+ return (dwFileAttribute & FILE_ATTRIBUTE_DIRECTORY) == FILE_ATTRIBUTE_DIRECTORY;
+}
+
+
+bool windowsFile::canRead() const {
+
+ HANDLE hFile = CreateFile(
+ m_nativePath.c_str(),
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL
+ );
+
+ if (hFile == INVALID_HANDLE_VALUE) {
+ return false;
+ }
+
+ CloseHandle(hFile);
+
+ return true;
+}
+
+
+bool windowsFile::canWrite() const {
+
+ HANDLE hFile = CreateFile(
+ m_nativePath.c_str(),
+ GENERIC_WRITE,
+ FILE_SHARE_WRITE,
+ NULL,
+ OPEN_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL
+ );
+
+ if (hFile == INVALID_HANDLE_VALUE) {
+ return false;
+ }
+
+ CloseHandle(hFile);
+
+ return true;
+}
+
+
+windowsFile::length_type windowsFile::getLength() {
+
+ HANDLE hFile = CreateFile(
+ m_nativePath.c_str(),
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL
+ );
+
+ if (hFile == INVALID_HANDLE_VALUE) {
+ windowsFileSystemFactory::reportError(m_path, GetLastError());
+ }
+
+ DWORD dwSize = GetFileSize(hFile, NULL);
+
+ CloseHandle(hFile);
+
+ return dwSize;
+}
+
+
+const vmime::utility::path& windowsFile::getFullPath() const {
+
+ return m_path;
+}
+
+
+bool windowsFile::exists() const {
+
+ WIN32_FIND_DATA findData;
+ HANDLE hFind = FindFirstFile(m_nativePath.c_str(), &findData);
+
+ if (hFind != INVALID_HANDLE_VALUE) {
+ FindClose(hFind);
+ return true;
+ }
+
+ return false;
+}
+
+
+shared_ptr <vmime::utility::file> windowsFile::getParent() const {
+
+ if (m_path.isEmpty()) {
+ return null;
+ } else {
+ return make_shared <windowsFile>(m_path.getParent());
+ }
+}
+
+
+void windowsFile::rename(const path& newName) {
+
+ const vmime::string newNativeName = windowsFileSystemFactory::pathToStringImpl(newName);
+
+ if (MoveFile(m_nativePath.c_str(), newNativeName.c_str())) {
+
+ m_path = newName;
+ m_nativePath = newNativeName;
+
+ } else {
+
+ windowsFileSystemFactory::reportError(m_path, GetLastError());
+ }
+}
+
+
+void windowsFile::remove() {
+
+ if (!DeleteFile(m_nativePath.c_str())) {
+ windowsFileSystemFactory::reportError(m_path, GetLastError());
+ }
+}
+
+
+shared_ptr <vmime::utility::fileWriter> windowsFile::getFileWriter() {
+
+ return make_shared <windowsFileWriter>(m_path, m_nativePath);
+}
+
+
+shared_ptr <vmime::utility::fileReader> windowsFile::getFileReader() {
+
+ return make_shared <windowsFileReader>(m_path, m_nativePath);
+}
+
+
+shared_ptr <vmime::utility::fileIterator> windowsFile::getFiles() const {
+
+ return make_shared <windowsFileIterator>(m_path, m_nativePath);
+}
+
+
+void windowsFile::createDirectoryImpl(
+ const vmime::utility::file::path& fullPath,
+ const vmime::utility::file::path& path,
+ const bool recursive
+) {
+
+ const vmime::string nativePath = windowsFileSystemFactory::pathToStringImpl(path);
+
+ windowsFile tmp(path);
+
+ if (tmp.isDirectory()) {
+ return;
+ }
+
+ if (!path.isEmpty() && recursive) {
+ createDirectoryImpl(fullPath, path.getParent(), true);
+ }
+
+ if (!CreateDirectory(nativePath.c_str(), NULL)) {
+ windowsFileSystemFactory::reportError(fullPath, GetLastError());
+ }
+}
+
+
+
+windowsFileIterator::windowsFileIterator(
+ const vmime::utility::file::path& path,
+ const vmime::string& nativePath
+)
+ : m_path(path),
+ m_nativePath(nativePath),
+ m_moreElements(false),
+ m_hFind(INVALID_HANDLE_VALUE) {
+
+ findFirst();
+}
+
+
+windowsFileIterator::~windowsFileIterator() {
+
+ if (m_hFind != INVALID_HANDLE_VALUE) {
+ FindClose(m_hFind);
+ }
+}
+
+
+bool windowsFileIterator::hasMoreElements() const {
+
+ return m_moreElements;
+}
+
+
+shared_ptr <vmime::utility::file> windowsFileIterator::nextElement() {
+
+ shared_ptr <vmime::utility::file> pFile = make_shared <windowsFile>(
+ m_path / vmime::utility::file::path::component(m_findData.cFileName)
+ );
+
+ findNext();
+
+ return pFile;
+}
+
+
+void windowsFileIterator::findFirst() {
+
+ m_hFind = FindFirstFile(m_nativePath.c_str(), &m_findData);
+
+ if (m_hFind == INVALID_HANDLE_VALUE) {
+ m_moreElements = false;
+ return;
+ }
+
+ m_moreElements = true;
+
+ if (isCurrentOrParentDir()) {
+ findNext();
+ }
+}
+
+
+void windowsFileIterator::findNext() {
+
+ do {
+
+ if (!FindNextFile(m_hFind, &m_findData)) {
+ m_moreElements = false;
+ return;
+ }
+
+ } while (isCurrentOrParentDir());
+}
+
+
+bool windowsFileIterator::isCurrentOrParentDir() const {
+
+ vmime::string s(m_findData.cFileName);
+
+ if ((s == ".") || (s == "..")) {
+ return true;
+ }
+
+ return false;
+}
+
+
+
+windowsFileReader::windowsFileReader(
+ const vmime::utility::file::path& path,
+ const vmime::string& nativePath
+)
+ : m_path(path),
+ m_nativePath(nativePath) {
+
+}
+
+
+shared_ptr <vmime::utility::inputStream> windowsFileReader::getInputStream() {
+
+ HANDLE hFile = CreateFile(
+ m_nativePath.c_str(),
+ GENERIC_READ,
+ FILE_SHARE_READ,
+ NULL,
+ OPEN_EXISTING,
+ 0,
+ NULL
+ );
+
+ if (hFile == INVALID_HANDLE_VALUE) {
+ windowsFileSystemFactory::reportError(m_path, GetLastError());
+ }
+
+ return make_shared <windowsFileReaderInputStream>(m_path, hFile);
+}
+
+
+windowsFileReaderInputStream::windowsFileReaderInputStream(
+ const vmime::utility::file::path& path,
+ HANDLE hFile
+)
+ : m_path(path),
+ m_hFile(hFile) {
+
+}
+
+windowsFileReaderInputStream::~windowsFileReaderInputStream() {
+
+ CloseHandle(m_hFile);
+}
+
+
+bool windowsFileReaderInputStream::eof() const {
+
+ DWORD dwSize = GetFileSize(m_hFile, NULL);
+ DWORD dwPosition = SetFilePointer(m_hFile, 0, NULL, FILE_CURRENT);
+
+ return dwSize == dwPosition;
+}
+
+
+void windowsFileReaderInputStream::reset() {
+
+ SetFilePointer(m_hFile, 0, NULL, FILE_BEGIN);
+}
+
+
+size_t windowsFileReaderInputStream::read(byte_t* const data, const size_t count) {
+
+ DWORD dwBytesRead;
+
+ if (!ReadFile(m_hFile, (LPVOID) data, (DWORD) count, &dwBytesRead, NULL)) {
+ windowsFileSystemFactory::reportError(m_path, GetLastError());
+ }
+
+ return dwBytesRead;
+}
+
+
+size_t windowsFileReaderInputStream::skip(const size_t count) {
+
+ DWORD dwCurPos = SetFilePointer(m_hFile, 0, NULL, FILE_CURRENT);
+ DWORD dwNewPos = SetFilePointer(m_hFile, (LONG) count, NULL, FILE_CURRENT);
+
+ return dwNewPos - dwCurPos;
+}
+
+
+size_t windowsFileReaderInputStream::getPosition() const {
+
+ DWORD dwCurPos = SetFilePointer(m_hFile, 0, NULL, FILE_CURRENT);
+
+ if (dwCurPos == INVALID_SET_FILE_POINTER) {
+ windowsFileSystemFactory::reportError(m_path, GetLastError());
+ }
+
+ return static_cast <size_t>(dwCurPos);
+}
+
+void windowsFileReaderInputStream::seek(const size_t pos) {
+
+ DWORD dwNewPos = SetFilePointer(m_hFile, (LONG) pos, NULL, FILE_BEGIN);
+
+ if (dwNewPos == INVALID_SET_FILE_POINTER) {
+ windowsFileSystemFactory::reportError(m_path, GetLastError());
+ }
+}
+
+
+
+windowsFileWriter::windowsFileWriter(
+ const vmime::utility::file::path& path,
+ const vmime::string& nativePath
+)
+ : m_path(path),
+ m_nativePath(nativePath) {
+
+}
+
+shared_ptr <vmime::utility::outputStream> windowsFileWriter::getOutputStream() {
+
+ HANDLE hFile = CreateFile(
+ m_nativePath.c_str(),
+ GENERIC_WRITE,
+ FILE_SHARE_WRITE,
+ NULL,
+ CREATE_ALWAYS,
+ FILE_ATTRIBUTE_NORMAL,
+ NULL
+ );
+
+ if (hFile == INVALID_HANDLE_VALUE) {
+ windowsFileSystemFactory::reportError(m_path, GetLastError());
+ }
+
+ return make_shared <windowsFileWriterOutputStream>(m_path, hFile);
+}
+
+
+windowsFileWriterOutputStream::windowsFileWriterOutputStream(
+ const vmime::utility::file::path& path,
+ HANDLE hFile
+)
+ : m_path(path),
+ m_hFile(hFile) {
+
+}
+
+
+windowsFileWriterOutputStream::~windowsFileWriterOutputStream() {
+
+ CloseHandle(m_hFile);
+}
+
+
+void windowsFileWriterOutputStream::writeImpl(const byte_t* const data, const size_t count) {
+
+ DWORD dwBytesWritten;
+
+ if (!WriteFile(m_hFile, data, (DWORD) count, &dwBytesWritten, NULL)) {
+ windowsFileSystemFactory::reportError(m_path, GetLastError());
+ }
+}
+
+
+void windowsFileWriterOutputStream::flush() {
+
+ // TODO
+}
+
+
+} // windows
+} // platforms
+} // vmime
+
+
+#endif // VMIME_PLATFORM_IS_WINDOWS && VMIME_HAVE_FILESYSTEM_FEATURES
+
diff --git a/vmime-master/src/vmime/platforms/windows/windowsFile.hpp b/vmime-master/src/vmime/platforms/windows/windowsFile.hpp
new file mode 100644
index 0000000..dc4b5ed
--- /dev/null
+++ b/vmime-master/src/vmime/platforms/windows/windowsFile.hpp
@@ -0,0 +1,225 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_PLATFORMS_WINDOWS_FILE_HPP_INCLUDED
+#define VMIME_PLATFORMS_WINDOWS_FILE_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_PLATFORM_IS_WINDOWS && VMIME_HAVE_FILESYSTEM_FEATURES
+
+
+#include "vmime/utility/file.hpp"
+#include "vmime/utility/seekableInputStream.hpp"
+
+#include <windows.h>
+
+
+namespace vmime {
+namespace platforms {
+namespace windows {
+
+
+class windowsFileSystemFactory : public vmime::utility::fileSystemFactory {
+
+public:
+
+ shared_ptr <vmime::utility::file> create(const vmime::utility::file::path& path) const;
+
+ const vmime::utility::file::path stringToPath(const vmime::string& str) const;
+ const vmime::string pathToString(const vmime::utility::file::path& path) const;
+
+ static const vmime::utility::file::path stringToPathImpl(const vmime::string& str);
+ static const vmime::string pathToStringImpl(const vmime::utility::file::path& path);
+
+ bool isValidPathComponent(const vmime::utility::file::path::component& comp) const;
+ bool isValidPathComponent(const vmime::utility::file::path::component& comp,
+ bool firstComponent) const;
+ bool isValidPath(const vmime::utility::file::path& path) const;
+
+ static void reportError(const vmime::utility::path& path, const int err);
+};
+
+
+class windowsFile : public vmime::utility::file {
+
+public:
+
+ windowsFile(const vmime::utility::file::path& path);
+
+ void createFile();
+ void createDirectory(const bool createAll = false);
+
+ bool isFile() const;
+ bool isDirectory() const;
+
+ bool canRead() const;
+ bool canWrite() const;
+
+ length_type getLength();
+
+ const path& getFullPath() const;
+
+ bool exists() const;
+
+ shared_ptr <file> getParent() const;
+
+ void rename(const path& newName);
+ void remove();
+
+ shared_ptr <vmime::utility::fileWriter> getFileWriter();
+
+ shared_ptr <vmime::utility::fileReader> getFileReader();
+
+ shared_ptr <vmime::utility::fileIterator> getFiles() const;
+
+private:
+
+ static void createDirectoryImpl(
+ const vmime::utility::file::path& fullPath,
+ const vmime::utility::file::path& path,
+ const bool recursive = false
+ );
+
+private:
+
+ vmime::utility::file::path m_path;
+ vmime::string m_nativePath;
+};
+
+
+class windowsFileIterator : public vmime::utility::fileIterator {
+
+public:
+
+ windowsFileIterator(const vmime::utility::file::path& path, const vmime::string& nativePath);
+ ~windowsFileIterator();
+
+ bool hasMoreElements() const;
+ shared_ptr <vmime::utility::file> nextElement();
+
+private:
+
+ void findFirst();
+ void findNext();
+ bool isCurrentOrParentDir() const;
+
+private:
+
+ vmime::utility::file::path m_path;
+ vmime::string m_nativePath;
+ WIN32_FIND_DATA m_findData;
+ bool m_moreElements;
+ HANDLE m_hFind;
+};
+
+
+class windowsFileReader : public vmime::utility::fileReader {
+
+public:
+
+ windowsFileReader(const vmime::utility::file::path& path, const vmime::string& nativePath);
+
+public:
+
+ shared_ptr <vmime::utility::inputStream> getInputStream();
+
+private:
+
+ vmime::utility::file::path m_path;
+ vmime::string m_nativePath;
+};
+
+
+class windowsFileReaderInputStream : public vmime::utility::inputStream {
+
+public:
+
+ windowsFileReaderInputStream(const vmime::utility::file::path& path, HANDLE hFile);
+ ~windowsFileReaderInputStream();
+
+public:
+
+ bool eof() const;
+ void reset();
+ size_t read(byte_t* const data, const size_t count);
+ size_t skip(const size_t count);
+ size_t getPosition() const;
+ void seek(const size_t pos);
+
+private:
+
+ const vmime::utility::file::path m_path;
+ HANDLE m_hFile;
+};
+
+
+class windowsFileWriter : public vmime::utility::fileWriter {
+
+public:
+
+ windowsFileWriter(const vmime::utility::file::path& path, const vmime::string& nativePath);
+
+public:
+
+ shared_ptr <vmime::utility::outputStream> getOutputStream();
+
+private:
+
+ vmime::utility::file::path m_path;
+ vmime::string m_nativePath;
+};
+
+
+class windowsFileWriterOutputStream : public vmime::utility::outputStream {
+
+public:
+
+ windowsFileWriterOutputStream(const vmime::utility::file::path& path, HANDLE hFile);
+ ~windowsFileWriterOutputStream();
+
+public:
+
+ void flush();
+
+protected:
+
+ void writeImpl(const byte_t* const data, const size_t count);
+
+private:
+
+ const vmime::utility::file::path m_path;
+ HANDLE m_hFile;
+};
+
+
+} // windows
+} // platforms
+} // vmime
+
+
+#endif // VMIME_PLATFORM_IS_WINDOWS && VMIME_HAVE_FILESYSTEM_FEATURES
+
+#endif // VMIME_PLATFORMS_WINDOWS_FILE_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/platforms/windows/windowsHandler.cpp b/vmime-master/src/vmime/platforms/windows/windowsHandler.cpp
new file mode 100644
index 0000000..551f672
--- /dev/null
+++ b/vmime-master/src/vmime/platforms/windows/windowsHandler.cpp
@@ -0,0 +1,315 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_PLATFORM_IS_WINDOWS
+
+
+#include "vmime/platforms/windows/windowsHandler.hpp"
+
+#include "vmime/platforms/windows/windowsCriticalSection.hpp"
+
+#include "vmime/utility/stringUtils.hpp"
+
+#include <time.h>
+#include <locale.h>
+#include <process.h>
+#include <winsock2.h> // for WSAStartup()
+#include <windows.h> // for winnls.h
+#include <ws2tcpip.h>
+#include <wincrypt.h>
+
+#if VMIME_HAVE_MLANG
+# include <mlang.h>
+#endif
+
+
+namespace vmime {
+namespace platforms {
+namespace windows {
+
+
+windowsHandler::windowsHandler() {
+
+ WSAData wsaData;
+ WSAStartup(MAKEWORD(1, 1), &wsaData);
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+ m_socketFactory = make_shared <windowsSocketFactory>();
+#endif
+#if VMIME_HAVE_FILESYSTEM_FEATURES
+ m_fileSysFactory = make_shared <windowsFileSystemFactory>();
+#endif
+
+}
+
+
+windowsHandler::~windowsHandler() {
+
+ WSACleanup();
+}
+
+
+unsigned long windowsHandler::getUnixTime() const {
+
+ return static_cast <unsigned long>(::time(NULL));
+}
+
+
+const vmime::datetime windowsHandler::getCurrentLocalTime() const {
+
+ const time_t t(::time(NULL));
+
+ // Get the local time
+#if VMIME_HAVE_LOCALTIME_S
+ tm local;
+ ::localtime_s(&local, &t);
+#elif VMIME_HAVE_LOCALTIME_R
+ tm local;
+ ::localtime_r(&t, &local);
+#else
+ tm local = *::localtime(&t); // WARNING: this is not thread-safe!
+#endif
+
+ // Get the UTC time
+#if VMIME_HAVE_GMTIME_S
+ tm gmt;
+ ::gmtime_s(&gmt, &t);
+#elif VMIME_HAVE_GMTIME_R
+ tm gmt;
+ ::gmtime_r(&t, &gmt);
+#else
+ tm gmt = *::gmtime(&t); // WARNING: this is not thread-safe!
+#endif
+
+ // "A negative value for tm_isdst causes mktime() to attempt
+ // to determine whether Daylight Saving Time is in effect
+ // for the specified time."
+ local.tm_isdst = -1;
+ gmt.tm_isdst = -1;
+
+ // Calculate the difference (in seconds)
+ const int diff = (const int)(::mktime(&local) - ::mktime(&gmt));
+
+ // Return the date
+ return vmime::datetime(
+ local.tm_year + 1900, local.tm_mon + 1, local.tm_mday,
+ local.tm_hour, local.tm_min, local.tm_sec, diff / 60 // minutes needed
+ );
+}
+
+
+const vmime::charset windowsHandler::getLocalCharset() const {
+
+#if VMIME_HAVE_MLANG
+
+ char szCharset[256];
+
+ CoInitialize(NULL);
+ {
+ IMultiLanguage* pMultiLanguage;
+
+ CoCreateInstance(
+ CLSID_CMultiLanguage,
+ NULL,
+ CLSCTX_INPROC_SERVER,
+ IID_IMultiLanguage,
+ (void**) &pMultiLanguage
+ );
+
+ UINT codePage = GetACP();
+ MIMECPINFO cpInfo;
+ pMultiLanguage->GetCodePageInfo(codePage, &cpInfo);
+
+ int nLengthW = lstrlenW(cpInfo.wszBodyCharset) + 1;
+
+ WideCharToMultiByte(
+ codePage, 0, cpInfo.wszBodyCharset, nLengthW,
+ szCharset, sizeof(szCharset), NULL, NULL
+ );
+
+ pMultiLanguage->Release();
+ }
+ CoUninitialize();
+
+ return vmime::charset(szCharset);
+
+#else // VMIME_HAVE_MLANG
+
+ vmime::string ch = vmime::charsets::ISO8859_1; // default
+
+ switch (GetACP()) {
+
+ case 437: ch = vmime::charsets::CP_437; break;
+ case 737: ch = vmime::charsets::CP_737; break;
+ case 775: ch = vmime::charsets::CP_775; break;
+ case 850: ch = vmime::charsets::CP_850; break;
+ case 852: ch = vmime::charsets::CP_852; break;
+ case 853: ch = vmime::charsets::CP_853; break;
+ case 855: ch = vmime::charsets::CP_855; break;
+ case 857: ch = vmime::charsets::CP_857; break;
+ case 858: ch = vmime::charsets::CP_858; break;
+ case 860: ch = vmime::charsets::CP_860; break;
+ case 861: ch = vmime::charsets::CP_861; break;
+ case 862: ch = vmime::charsets::CP_862; break;
+ case 863: ch = vmime::charsets::CP_863; break;
+ case 864: ch = vmime::charsets::CP_864; break;
+ case 865: ch = vmime::charsets::CP_865; break;
+ case 866: ch = vmime::charsets::CP_866; break;
+ case 869: ch = vmime::charsets::CP_869; break;
+ case 874: ch = vmime::charsets::CP_874; break;
+
+ case 1125: ch = vmime::charsets::CP_1125; break;
+ case 1250: ch = vmime::charsets::CP_1250; break;
+ case 1251: ch = vmime::charsets::CP_1251; break;
+ case 1252: ch = vmime::charsets::CP_1252; break;
+ case 1253: ch = vmime::charsets::CP_1253; break;
+ case 1254: ch = vmime::charsets::CP_1254; break;
+ case 1255: ch = vmime::charsets::CP_1255; break;
+ case 1256: ch = vmime::charsets::CP_1256; break;
+ case 1257: ch = vmime::charsets::CP_1257; break;
+
+ case 28591: ch = vmime::charsets::ISO8859_1; break;
+ case 28592: ch = vmime::charsets::ISO8859_2; break;
+ case 28593: ch = vmime::charsets::ISO8859_3; break;
+ case 28594: ch = vmime::charsets::ISO8859_4; break;
+ case 28595: ch = vmime::charsets::ISO8859_5; break;
+ case 28596: ch = vmime::charsets::ISO8859_6; break;
+ case 28597: ch = vmime::charsets::ISO8859_7; break;
+ case 28598: ch = vmime::charsets::ISO8859_8; break;
+ case 28599: ch = vmime::charsets::ISO8859_9; break;
+ case 28605: ch = vmime::charsets::ISO8859_15; break;
+
+ case 65000: ch = vmime::charsets::UTF_7; break;
+ case 65001: ch = vmime::charsets::UTF_8; break;
+ }
+
+ return vmime::charset(ch);
+
+#endif
+
+}
+
+
+const vmime::string windowsHandler::getHostName() const {
+
+ char hostname[1024];
+ DWORD hostnameLen;
+
+ // First, try to get a Fully-Qualified Domain Name (FQDN)
+ for (int cnf = ComputerNameDnsHostname ; cnf <= ComputerNameDnsFullyQualified ; ++cnf) {
+
+ hostnameLen = sizeof(hostname);
+
+ if (GetComputerNameEx((COMPUTER_NAME_FORMAT) cnf, hostname, &hostnameLen)) {
+
+ const vmime::string hostnameStr(hostname);
+
+ if (utility::stringUtils::isValidFQDN(hostnameStr)) {
+ return hostnameStr;
+ }
+ }
+ }
+
+ // Anything else will be OK, as long as it is a valid hostname
+ for (int cnf = 0 ; cnf < ComputerNameMax ; ++cnf) {
+
+ hostnameLen = sizeof(hostname);
+
+ if (GetComputerNameEx((COMPUTER_NAME_FORMAT) cnf, hostname, &hostnameLen)) {
+
+ const vmime::string hostnameStr(hostname);
+
+ if (utility::stringUtils::isValidHostname(hostnameStr)) {
+ return hostnameStr;
+ }
+ }
+ }
+
+ return "localhost.localdomain";
+}
+
+
+unsigned int windowsHandler::getProcessId() const {
+
+ return static_cast <unsigned int>(::GetCurrentProcessId());
+}
+
+
+unsigned int windowsHandler::getThreadId() const {
+
+ return static_cast <unsigned int>(::GetCurrentThreadId());
+}
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+shared_ptr <vmime::net::socketFactory> windowsHandler::getSocketFactory() {
+
+ return m_socketFactory;
+}
+
+#endif
+
+
+#if VMIME_HAVE_FILESYSTEM_FEATURES
+
+shared_ptr <vmime::utility::fileSystemFactory> windowsHandler::getFileSystemFactory() {
+
+ return m_fileSysFactory;
+}
+
+
+shared_ptr <vmime::utility::childProcessFactory> windowsHandler::getChildProcessFactory() {
+
+ // TODO: Not implemented
+ return null;
+}
+
+#endif
+
+
+void windowsHandler::generateRandomBytes(unsigned char* buffer, const unsigned int count) {
+
+ HCRYPTPROV cryptProvider = 0;
+ CryptAcquireContext(&cryptProvider, 0, 0, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT);
+ CryptGenRandom(cryptProvider, static_cast <unsigned long>(count), static_cast <unsigned char*>(buffer));
+ CryptReleaseContext(cryptProvider, 0);
+}
+
+
+shared_ptr <utility::sync::criticalSection> windowsHandler::createCriticalSection() {
+
+ return make_shared <windowsCriticalSection>();
+}
+
+
+} // posix
+} // platforms
+} // vmime
+
+
+#endif // VMIME_PLATFORM_IS_WINDOWS
+
diff --git a/vmime-master/src/vmime/platforms/windows/windowsHandler.hpp b/vmime-master/src/vmime/platforms/windows/windowsHandler.hpp
new file mode 100644
index 0000000..9dda256
--- /dev/null
+++ b/vmime-master/src/vmime/platforms/windows/windowsHandler.hpp
@@ -0,0 +1,101 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_PLATFORMS_WINDOWS_HANDLER_HPP_INCLUDED
+#define VMIME_PLATFORMS_WINDOWS_HANDLER_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_PLATFORM_IS_WINDOWS
+
+
+#include "vmime/platform.hpp"
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+ #include "vmime/platforms/windows/windowsSocket.hpp"
+#endif
+
+#if VMIME_HAVE_FILESYSTEM_FEATURES
+ #include "vmime/platforms/windows/windowsFile.hpp"
+#endif
+
+
+namespace vmime {
+namespace platforms {
+namespace windows {
+
+
+class VMIME_EXPORT windowsHandler : public vmime::platform::handler {
+
+public:
+
+ windowsHandler();
+ ~windowsHandler();
+
+ unsigned long getUnixTime() const;
+
+ const vmime::datetime getCurrentLocalTime() const;
+
+ const vmime::charset getLocalCharset() const;
+
+ const vmime::string getHostName() const;
+
+ unsigned int getProcessId() const;
+ unsigned int getThreadId() const;
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+ shared_ptr <vmime::net::socketFactory> getSocketFactory();
+#endif
+
+#if VMIME_HAVE_FILESYSTEM_FEATURES
+ shared_ptr <vmime::utility::fileSystemFactory> getFileSystemFactory();
+
+ shared_ptr <vmime::utility::childProcessFactory> getChildProcessFactory();
+#endif
+
+ void generateRandomBytes(unsigned char* buffer, const unsigned int count);
+
+ shared_ptr <utility::sync::criticalSection> createCriticalSection();
+
+private:
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+ shared_ptr <windowsSocketFactory> m_socketFactory;
+#endif
+
+#if VMIME_HAVE_FILESYSTEM_FEATURES
+ shared_ptr <windowsFileSystemFactory> m_fileSysFactory;
+#endif
+};
+
+
+} // windows
+} // platforms
+} // vmime
+
+
+#endif // VMIME_PLATFORM_IS_WINDOWS
+
+#endif // VMIME_PLATFORMS_WINDOWS_HANDLER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/platforms/windows/windowsSocket.cpp b/vmime-master/src/vmime/platforms/windows/windowsSocket.cpp
new file mode 100644
index 0000000..3a93c53
--- /dev/null
+++ b/vmime-master/src/vmime/platforms/windows/windowsSocket.cpp
@@ -0,0 +1,547 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_PLATFORM_IS_WINDOWS && VMIME_HAVE_MESSAGING_FEATURES
+
+
+#pragma warning(disable: 4267)
+
+#include "vmime/platforms/windows/windowsSocket.hpp"
+
+#include "vmime/utility/stringUtils.hpp"
+#include "vmime/exception.hpp"
+
+#include <ws2tcpip.h>
+
+
+namespace vmime {
+namespace platforms {
+namespace windows {
+
+
+//
+// windowsSocket
+//
+
+windowsSocket::windowsSocket(shared_ptr <vmime::net::timeoutHandler> th)
+ : m_timeoutHandler(th),
+ m_desc(INVALID_SOCKET),
+ m_status(0) {
+
+ WSAData wsaData;
+ WSAStartup(MAKEWORD(1, 1), &wsaData);
+}
+
+
+windowsSocket::~windowsSocket() {
+
+ if (m_desc != INVALID_SOCKET) {
+ ::closesocket(m_desc);
+ }
+
+ WSACleanup();
+}
+
+
+void windowsSocket::connect(const vmime::string& address, const vmime::port_t port) {
+
+ // Close current connection, if any
+ if (m_desc != INVALID_SOCKET) {
+ ::closesocket(m_desc);
+ m_desc = INVALID_SOCKET;
+ }
+
+ // Resolve address
+ ::sockaddr_in addr;
+
+ memset(&addr, 0, sizeof(addr));
+
+ addr.sin_family = AF_INET;
+ addr.sin_port = htons(static_cast <unsigned short>(port));
+ addr.sin_addr.s_addr = ::inet_addr(address.c_str());
+
+ if (m_tracer) {
+
+ std::ostringstream trace;
+ trace << "Connecting to " << address << ", port " << port;
+
+ m_tracer->traceSend(trace.str());
+ }
+
+ if (addr.sin_addr.s_addr == static_cast <int>(-1)) {
+
+ ::hostent* hostInfo = ::gethostbyname(address.c_str());
+
+ if (!hostInfo) {
+ // Error: cannot resolve address
+ throw vmime::exceptions::connection_error("Cannot resolve address.");
+ }
+
+ memcpy(reinterpret_cast <char*>(&addr.sin_addr), hostInfo->h_addr, hostInfo->h_length);
+ }
+
+ m_serverAddress = address;
+
+ // Get a new socket
+ m_desc = ::socket(AF_INET, SOCK_STREAM, 0);
+
+ if (m_desc == INVALID_SOCKET) {
+
+ try {
+
+ int err = WSAGetLastError();
+ throwSocketError(err);
+
+ } catch (exceptions::socket_exception& e) {
+
+ throw vmime::exceptions::connection_error("Error while creating socket.", e);
+ }
+ }
+
+ // Start connection
+ if (::connect(m_desc, reinterpret_cast <sockaddr*>(&addr), sizeof(addr)) == -1) {
+
+ try {
+
+ int err = WSAGetLastError();
+ throwSocketError(err);
+
+ } catch (exceptions::socket_exception& e) {
+
+ ::closesocket(m_desc);
+ m_desc = INVALID_SOCKET;
+
+ // Error
+ throw vmime::exceptions::connection_error("Error while connecting socket.", e);
+ }
+ }
+
+ // Set socket to non-blocking
+ unsigned long non_blocking = 1;
+ ::ioctlsocket(m_desc, FIONBIO, &non_blocking);
+}
+
+
+bool windowsSocket::isConnected() const {
+
+ if (m_desc == INVALID_SOCKET) {
+ return false;
+ }
+
+ char buff;
+
+ return ::recv(m_desc, &buff, 1, MSG_PEEK) != 0;
+}
+
+
+void windowsSocket::disconnect() {
+
+ if (m_desc != INVALID_SOCKET) {
+
+ if (m_tracer) {
+ m_tracer->traceSend("Disconnecting");
+ }
+
+ ::shutdown(m_desc, SD_BOTH);
+ ::closesocket(m_desc);
+
+ m_desc = INVALID_SOCKET;
+ }
+}
+
+
+static bool isNumericAddress(const char* address) {
+
+ struct addrinfo hint, *info = NULL;
+ memset(&hint, 0, sizeof(hint));
+
+ hint.ai_family = AF_UNSPEC;
+ hint.ai_flags = AI_NUMERICHOST;
+
+ if (getaddrinfo(address, 0, &hint, &info) == 0) {
+
+ freeaddrinfo(info);
+ return true;
+
+ } else {
+
+ return false;
+ }
+}
+
+
+const string windowsSocket::getPeerAddress() const {
+
+ // Get address of connected peer
+ sockaddr peer;
+ socklen_t peerLen = sizeof(peer);
+
+ getpeername(m_desc, reinterpret_cast <sockaddr*>(&peer), &peerLen);
+
+ // Convert to numerical presentation format
+ char host[NI_MAXHOST + 1];
+ char service[NI_MAXSERV + 1];
+
+ if (getnameinfo(reinterpret_cast <sockaddr *>(&peer), peerLen,
+ host, sizeof(host), service, sizeof(service),
+ /* flags */ NI_NUMERICHOST) == 0) {
+
+ return string(host);
+ }
+
+ return ""; // should not happen
+}
+
+
+const string windowsSocket::getPeerName() const {
+
+ // Get address of connected peer
+ sockaddr peer;
+ socklen_t peerLen = sizeof(peer);
+
+ getpeername(m_desc, reinterpret_cast <sockaddr*>(&peer), &peerLen);
+
+ // If server address as specified when connecting is a numeric
+ // address, try to get a host name for it
+ if (isNumericAddress(m_serverAddress.c_str())) {
+
+ char host[NI_MAXHOST + 1];
+ char service[NI_MAXSERV + 1];
+
+ if (getnameinfo(reinterpret_cast <sockaddr *>(&peer), peerLen,
+ host, sizeof(host), service, sizeof(service),
+ /* flags */ NI_NAMEREQD) == 0) {
+
+ return string(host);
+ }
+ }
+
+ return m_serverAddress;
+}
+
+
+size_t windowsSocket::getBlockSize() const {
+
+ return 16384; // 16 KB
+}
+
+
+void windowsSocket::receive(vmime::string& buffer) {
+
+ const size_t size = receiveRaw(m_buffer, sizeof(m_buffer));
+ buffer = utility::stringUtils::makeStringFromBytes(m_buffer, size);
+}
+
+
+size_t windowsSocket::receiveRaw(byte_t* buffer, const size_t count) {
+
+ m_status &= ~STATUS_WOULDBLOCK;
+
+ // Check whether data is available
+ if (!waitForRead(50 /* msecs */)) {
+
+ // No data available at this time
+ // Check if we are timed out
+ if (m_timeoutHandler &&
+ m_timeoutHandler->isTimeOut()) {
+
+ if (!m_timeoutHandler->handleTimeOut()) {
+
+ // Server did not react within timeout delay
+ throwSocketError(WSAETIMEDOUT);
+
+ } else {
+
+ // Reset timeout
+ m_timeoutHandler->resetTimeOut();
+ }
+ }
+
+ // Continue waiting for data
+ return 0;
+ }
+
+ // Read available data
+ int ret = ::recv(m_desc, reinterpret_cast <char*>(buffer), count, 0);
+
+ if (ret == SOCKET_ERROR) {
+
+ int err = WSAGetLastError();
+
+ if (err != WSAEWOULDBLOCK) {
+ throwSocketError(err);
+ }
+
+ m_status |= STATUS_WOULDBLOCK;
+
+ // Error or no data
+ return 0;
+
+ } else if (ret == 0) {
+
+ // Host shutdown
+ throwSocketError(WSAENOTCONN);
+
+ } else {
+
+ // Data received, reset timeout
+ if (m_timeoutHandler) {
+ m_timeoutHandler->resetTimeOut();
+ }
+
+ return ret;
+ }
+}
+
+
+void windowsSocket::send(const vmime::string& buffer) {
+
+ sendRaw(reinterpret_cast <const byte_t*>(buffer.data()), buffer.length());
+}
+
+
+void windowsSocket::send(const char* str) {
+
+ sendRaw(reinterpret_cast <const byte_t*>(str), strlen(str));
+}
+
+
+void windowsSocket::sendRaw(const byte_t* buffer, const size_t count) {
+
+ m_status &= ~STATUS_WOULDBLOCK;
+
+ size_t size = count;
+
+ while (size > 0) {
+
+ const int ret = ::send(m_desc, reinterpret_cast <const char*>(buffer), size, 0);
+
+ if (ret == SOCKET_ERROR) {
+
+ int err = WSAGetLastError();
+
+ if (err != WSAEWOULDBLOCK) {
+ throwSocketError(err);
+ }
+
+ waitForWrite(50 /* msecs */);
+
+ } else {
+
+ buffer += ret;
+ size -= ret;
+ }
+ }
+
+ // Reset timeout
+ if (m_timeoutHandler) {
+ m_timeoutHandler->resetTimeOut();
+ }
+}
+
+
+size_t windowsSocket::sendRawNonBlocking(const byte_t* buffer, const size_t count) {
+
+ m_status &= ~STATUS_WOULDBLOCK;
+
+ const int ret = ::send(m_desc, reinterpret_cast <const char*>(buffer), count, 0);
+
+ if (ret == SOCKET_ERROR) {
+
+ int err = WSAGetLastError();
+
+ if (err == WSAEWOULDBLOCK) {
+
+ // Check if we are timed out
+ if (m_timeoutHandler &&
+ m_timeoutHandler->isTimeOut()) {
+
+ if (!m_timeoutHandler->handleTimeOut()) {
+
+ // Could not send data within timeout delay
+ throwSocketError(err);
+
+ } else {
+
+ // Reset timeout
+ m_timeoutHandler->resetTimeOut();
+ }
+ }
+
+ m_status |= STATUS_WOULDBLOCK;
+
+ // No data can be written at this time
+ return 0;
+
+ } else {
+
+ throwSocketError(err);
+ }
+ }
+
+ // Reset timeout
+ if (m_timeoutHandler) {
+ m_timeoutHandler->resetTimeOut();
+ }
+
+ return ret;
+}
+
+
+unsigned int windowsSocket::getStatus() const {
+
+ return m_status;
+}
+
+
+void windowsSocket::throwSocketError(const int err) {
+
+ std::ostringstream oss;
+ string msg;
+
+ LPTSTR str;
+
+ if (::FormatMessage(
+ FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM,
+ NULL, err, 0, (LPTSTR) &str, 0, NULL) == 0) {
+
+ // Failed getting message
+ oss << "Unknown socket error (code " << err << ")";
+
+ } else {
+
+ oss << str;
+ ::LocalFree(str);
+ }
+
+ msg = oss.str();
+
+ throw exceptions::socket_exception(msg);
+}
+
+
+bool windowsSocket::waitForData(const bool read, const bool write, const int msecs) {
+
+ for (int i = 0 ; i <= msecs / 10 ; ++i) {
+
+ // Check whether data is available
+ fd_set fds;
+ FD_ZERO(&fds);
+ FD_SET(m_desc, &fds);
+
+ struct timeval tv;
+ tv.tv_sec = 0;
+ tv.tv_usec = 10000; // 10 ms
+
+ int ret = ::select(m_desc + 1, read ? &fds : NULL, write ? &fds : NULL, NULL, &tv);
+
+ if (ret == SOCKET_ERROR) {
+
+ int err = WSAGetLastError();
+ throwSocketError(err);
+
+ } else if (ret > 0) {
+
+ return true;
+ }
+
+ // No data available at this time
+ // Check if we are timed out
+ if (m_timeoutHandler &&
+ m_timeoutHandler->isTimeOut()) {
+
+ if (!m_timeoutHandler->handleTimeOut()) {
+
+ // Server did not react within timeout delay
+ throw exceptions::operation_timed_out();
+
+ } else {
+
+ // Reset timeout
+ m_timeoutHandler->resetTimeOut();
+ }
+ }
+ }
+
+ return false; // time out
+}
+
+
+bool windowsSocket::waitForRead(const int msecs) {
+
+ return waitForData(/* read */ true, /* write */ false, msecs);
+}
+
+
+bool windowsSocket::waitForWrite(const int msecs) {
+
+ return waitForData(/* read */ false, /* write */ true, msecs);
+}
+
+
+shared_ptr <net::timeoutHandler> windowsSocket::getTimeoutHandler() {
+
+ return m_timeoutHandler;
+}
+
+
+void windowsSocket::setTracer(const shared_ptr <net::tracer>& tracer) {
+
+ m_tracer = tracer;
+}
+
+
+shared_ptr <net::tracer> windowsSocket::getTracer() {
+
+ return m_tracer;
+}
+
+
+
+//
+// posixSocketFactory
+//
+
+shared_ptr <vmime::net::socket> windowsSocketFactory::create() {
+
+ shared_ptr <vmime::net::timeoutHandler> th;
+ return make_shared <windowsSocket>(th);
+}
+
+
+shared_ptr <vmime::net::socket> windowsSocketFactory::create(const shared_ptr <vmime::net::timeoutHandler>& th) {
+
+ return make_shared <windowsSocket>(th);
+}
+
+
+} // posix
+} // platforms
+} // vmime
+
+
+#endif // VMIME_PLATFORM_IS_WINDOWS && VMIME_HAVE_MESSAGING_FEATURES
+
diff --git a/vmime-master/src/vmime/platforms/windows/windowsSocket.hpp b/vmime-master/src/vmime/platforms/windows/windowsSocket.hpp
new file mode 100644
index 0000000..ddb82da
--- /dev/null
+++ b/vmime-master/src/vmime/platforms/windows/windowsSocket.hpp
@@ -0,0 +1,117 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_PLATFORMS_WINDOWS_SOCKET_HPP_INCLUDED
+#define VMIME_PLATFORMS_WINDOWS_SOCKET_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_PLATFORM_IS_WINDOWS && VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include <winsock2.h>
+#include "vmime/net/socket.hpp"
+
+
+namespace vmime {
+namespace platforms {
+namespace windows {
+
+
+class windowsSocket : public vmime::net::socket {
+
+public:
+
+ windowsSocket();
+ windowsSocket(shared_ptr <vmime::net::timeoutHandler> th);
+ ~windowsSocket();
+
+public:
+
+ void connect(const vmime::string& address, const vmime::port_t port);
+ bool isConnected() const;
+ void disconnect();
+
+ bool waitForRead(const int msecs = 30000);
+ bool waitForWrite(const int msecs = 30000);
+
+ void receive(vmime::string& buffer);
+ size_t receiveRaw(byte_t* buffer, const size_t count);
+
+ void send(const vmime::string& buffer);
+ void send(const char* str);
+ void sendRaw(const byte_t* buffer, const size_t count);
+ size_t sendRawNonBlocking(const byte_t* buffer, const size_t count);
+
+ size_t getBlockSize() const;
+
+ unsigned int getStatus() const;
+
+ const string getPeerName() const;
+ const string getPeerAddress() const;
+
+ shared_ptr <net::timeoutHandler> getTimeoutHandler();
+ shared_ptr <net::tracer> m_tracer;
+
+ void setTracer(const shared_ptr <net::tracer>& tracer);
+ shared_ptr <net::tracer> getTracer();
+
+protected:
+
+ void throwSocketError(const int err);
+
+ bool waitForData(const bool read, const bool write, const int msecs);
+
+private:
+
+ shared_ptr <vmime::net::timeoutHandler> m_timeoutHandler;
+
+ byte_t m_buffer[65536];
+ SOCKET m_desc;
+
+ unsigned int m_status;
+
+ string m_serverAddress;
+};
+
+
+
+class windowsSocketFactory : public vmime::net::socketFactory {
+
+public:
+
+ shared_ptr <vmime::net::socket> create();
+ shared_ptr <vmime::net::socket> create(const shared_ptr <vmime::net::timeoutHandler>& th);
+};
+
+
+} // windows
+} // platforms
+} // vmime
+
+
+#endif // VMIME_PLATFORM_IS_WINDOWS && VMIME_HAVE_MESSAGING_FEATURES
+
+#endif // VMIME_PLATFORMS_WINDOWS_SOCKET_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/propertySet.cpp b/vmime-master/src/vmime/propertySet.cpp
new file mode 100644
index 0000000..e0d4848
--- /dev/null
+++ b/vmime-master/src/vmime/propertySet.cpp
@@ -0,0 +1,399 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/propertySet.hpp"
+#include "vmime/parserHelpers.hpp"
+
+
+namespace vmime {
+
+
+propertySet::propertySet() {
+
+}
+
+
+propertySet::propertySet(const string& props) {
+
+ parse(props);
+}
+
+
+propertySet::propertySet(const propertySet& set)
+ : object() {
+
+ for (std::list <shared_ptr <property> >::const_iterator it = set.m_props.begin() ;
+ it != set.m_props.end() ; ++it) {
+
+ m_props.push_back(make_shared <property>(**it));
+ }
+}
+
+
+propertySet::~propertySet() {
+
+ removeAllProperties();
+}
+
+
+propertySet& propertySet::operator=(const propertySet& set) {
+
+ removeAllProperties();
+
+ for (std::list <shared_ptr <property> >::const_iterator it = set.m_props.begin() ;
+ it != set.m_props.end() ; ++it) {
+
+ m_props.push_back(make_shared <property>(**it));
+ }
+
+ return *this;
+}
+
+
+void propertySet::setFromString(const string& props) {
+
+ parse(props);
+}
+
+
+void propertySet::removeAllProperties() {
+
+ m_props.clear();
+}
+
+
+void propertySet::removeProperty(const string& name) {
+
+ std::list <shared_ptr <property> >::iterator it =
+ std::find_if(m_props.begin(), m_props.end(), propFinder(name));
+
+ if (it != m_props.end()) {
+ m_props.erase(it);
+ }
+}
+
+
+void propertySet::parse(const string& props) {
+
+ const string::const_iterator end = props.end();
+ string::const_iterator pos = props.begin();
+
+ for ( ; pos != end ; ) {
+
+ // Skip white-spaces
+ for ( ; pos != end && parserHelpers::isSpace(*pos) ; ++pos) {}
+
+ if (pos != end) {
+
+ if (*pos == ';') {
+ ++pos;
+ continue;
+ }
+
+ // Extract the property name
+ const string::const_iterator optStart = pos;
+
+ for ( ; pos != end && *pos != '=' ; ++pos) {}
+
+ string::const_iterator optEnd = pos;
+
+ for ( ; optEnd != optStart && parserHelpers::isSpace(*(optEnd - 1)) ; --optEnd) {}
+
+ const string option(optStart, optEnd);
+ string value = "1";
+
+ if (pos != end) {
+
+ ++pos; // skip '='
+
+ // Extract the value
+ for ( ; pos != end && parserHelpers::isSpace(*pos) ; ++pos) {}
+
+ if (pos != end) {
+
+ // A quoted-string
+ if (*pos == '"' || *pos == '\'') {
+
+ value.reserve(50);
+
+ const char quoteChar = *pos;
+ bool theEnd = false;
+ bool escape = false;
+
+ for ( ; (pos != end) && !theEnd ; ++pos) {
+
+ if (escape) {
+
+ value += *pos;
+ escape = false;
+
+ } else {
+
+ if (*pos == '\\') {
+ escape = true;
+ } else if (*pos == quoteChar) {
+ theEnd = true;
+ } else {
+ value += *pos;
+ }
+ }
+ }
+
+ if (pos != end) {
+ ++pos;
+ }
+
+ // Simple value
+ } else {
+
+ const string::const_iterator valStart = pos;
+
+ for ( ; pos != end && !parserHelpers::isSpace(*pos) ; ++pos) {}
+
+ value = string(valStart, pos);
+ }
+
+ // Advance to the next ';'
+ for ( ; pos != end && (*pos != ';') ; ++pos) {}
+
+ if (pos != end) {
+ ++pos; // skip ';'
+ }
+ }
+ }
+
+ m_props.push_back(make_shared <property>(option, value));
+ }
+ }
+}
+
+
+shared_ptr <propertySet::property> propertySet::find(const string& name) const {
+
+ std::list <shared_ptr <property> >::const_iterator it =
+ std::find_if(m_props.begin(), m_props.end(), propFinder(name));
+
+ return it != m_props.end() ? *it : null;
+}
+
+
+shared_ptr <propertySet::property> propertySet::findOrCreate(const string& name) {
+
+ std::list <shared_ptr <property> >::const_iterator it =
+ std::find_if(m_props.begin(), m_props.end(), propFinder(name));
+
+ if (it != m_props.end()) {
+
+ return *it;
+
+ } else {
+
+ shared_ptr <property> prop = make_shared <property>(name, "");
+ m_props.push_back(prop);
+ return prop;
+ }
+}
+
+
+propertySet::propertyProxy propertySet::operator[](const string& name) {
+
+ return propertyProxy(name, this);
+}
+
+
+const propertySet::constPropertyProxy propertySet::operator[](const string& name) const {
+
+ return constPropertyProxy(name, this);
+}
+
+
+bool propertySet::hasProperty(const string& name) const {
+
+ return find(name) != NULL;
+}
+
+
+const std::vector <shared_ptr <const propertySet::property> > propertySet::getPropertyList() const {
+
+ std::vector <shared_ptr <const property> > res;
+
+ for (list_type::const_iterator it = m_props.begin() ; it != m_props.end() ; ++it) {
+ res.push_back(*it);
+ }
+
+ return res;
+}
+
+
+const std::vector <shared_ptr <propertySet::property> > propertySet::getPropertyList() {
+
+ std::vector <shared_ptr <property> > res;
+
+ for (list_type::const_iterator it = m_props.begin() ; it != m_props.end() ; ++it) {
+ res.push_back(*it);
+ }
+
+ return res;
+}
+
+
+//
+// propertySet::property
+//
+
+propertySet::property::property(const string& name, const string& value)
+ : m_name(name),
+ m_value(value) {
+
+}
+
+
+propertySet::property::property(const string& name)
+ : m_name(name) {
+
+}
+
+
+propertySet::property::property(const property& prop)
+ : object(),
+ m_name(prop.m_name),
+ m_value(prop.m_value) {
+
+}
+
+
+const string& propertySet::property::getName() const {
+
+ return m_name;
+}
+
+
+#ifndef _MSC_VER
+
+
+const string& propertySet::property::getValue() const {
+
+ return m_value;
+}
+
+
+void propertySet::property::setValue(const string& value) {
+
+ m_value = value;
+}
+
+
+#endif // !_MSC_VER
+
+
+#ifndef VMIME_INLINE_TEMPLATE_SPECIALIZATION
+
+template <>
+void propertySet::property::setValue(const string& value) {
+
+ m_value = value;
+}
+
+
+template <>
+void propertySet::property::setValue(const bool& value) {
+
+ m_value = value ? "true" : "false";
+}
+
+
+template <>
+string propertySet::property::getValue() const {
+
+ return m_value;
+}
+
+
+template <>
+bool propertySet::property::getValue() const {
+
+ if (utility::stringUtils::toLower(m_value) == "true") {
+
+ return true;
+
+ } else {
+
+ int val = 0;
+
+ std::istringstream iss(m_value);
+ iss.imbue(std::locale::classic()); // no formatting
+
+ iss >> val;
+
+ return !iss.fail() && val != 0;
+ }
+}
+
+
+
+
+template <>
+string propertySet::valueFromString(const string& value) {
+
+ return value;
+}
+
+
+template <>
+string propertySet::valueToString(const string& value) {
+
+ return value;
+}
+
+
+template <>
+bool propertySet::valueFromString(const string& value) {
+
+ if (utility::stringUtils::toLower(value) == "true") {
+
+ return true;
+
+ } else {
+
+ int val = 0;
+
+ std::istringstream iss(value);
+ iss.imbue(std::locale::classic()); // no formatting
+
+ iss >> val;
+
+ return !iss.fail() && val != 0;
+ }
+}
+
+
+template <>
+string propertySet::valueToString(const bool& value) {
+
+ return value ? "true" : "false";
+}
+
+#endif // VMIME_INLINE_TEMPLATE_SPECIALIZATION
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/propertySet.hpp b/vmime-master/src/vmime/propertySet.hpp
new file mode 100644
index 0000000..20eb9de
--- /dev/null
+++ b/vmime-master/src/vmime/propertySet.hpp
@@ -0,0 +1,461 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_PROPERTY_HPP_INCLUDED
+#define VMIME_PROPERTY_HPP_INCLUDED
+
+#include <list>
+#include <functional>
+#include <algorithm>
+#include <sstream>
+
+#include "vmime/base.hpp"
+#include "vmime/exception.hpp"
+
+#include "vmime/utility/stringUtils.hpp"
+
+
+namespace vmime {
+
+
+/** Manage a list of (name,value) pairs.
+ */
+class VMIME_EXPORT propertySet : public object {
+
+public:
+
+ /** A property holds a (name,value) pair.
+ */
+ class property : public object {
+
+ public:
+
+ property(const string& name, const string& value);
+ property(const string& name);
+ property(const property& prop);
+
+ /** Return the name of the property.
+ *
+ * @return property name
+ */
+ const string& getName() const;
+
+#ifndef _MSC_VER
+
+ // Visual Studio errors on linking with these 2 functions,
+ // whereas GCC and CLang need them.
+
+ /** Return the value of the property as a string.
+ *
+ * @return current value of the property
+ */
+ const string& getValue() const;
+
+ /** Set the value of the property as a string.
+ *
+ * @param value new value for property
+ */
+ void setValue(const string& value);
+
+#endif // !_MSC_VER
+
+ /** Set the value of the property as a generic type.
+ *
+ * @param value new value for property
+ */
+ template <class TYPE> void setValue(const TYPE& value) {
+
+ std::ostringstream oss;
+ oss.imbue(std::locale::classic()); // no formatting
+
+ oss << value;
+
+ m_value = oss.str();
+ }
+
+ /** Get the value of the property as a generic type.
+ *
+ * @throw exceptions::invalid_property_type if the specified
+ * type is incompatible with the string value (cannot be
+ * converted using std::istringstream)
+ * @return current value of the property
+ */
+ template <class TYPE> TYPE getValue() const {
+
+ TYPE val = TYPE();
+
+ std::istringstream iss(m_value);
+ iss.imbue(std::locale::classic()); // no formatting
+
+ iss >> val;
+
+ if (iss.fail()) {
+ throw exceptions::invalid_property_type();
+ }
+
+ return (val);
+ }
+
+
+#ifdef VMIME_INLINE_TEMPLATE_SPECIALIZATION
+
+ template <>
+ void propertySet::property::setValue(const string& value) {
+
+ m_value = value;
+ }
+
+ template <>
+ void propertySet::property::setValue(const bool& value) {
+
+ m_value = value ? "true" : "false";
+ }
+
+ template <>
+ string propertySet::property::getValue() const {
+
+ return (m_value);
+ }
+
+ template <>
+ bool propertySet::property::getValue() const {
+
+ if (utility::stringUtils::toLower(m_value) == "true") {
+
+ return true;
+
+ } else {
+
+ int val = 0;
+
+ std::istringstream iss(m_value);
+ iss.imbue(std::locale::classic()); // no formatting
+
+ iss >> val;
+
+ return !iss.fail() && val != 0;
+ }
+ }
+
+#endif // VMIME_INLINE_TEMPLATE_SPECIALIZATION
+
+ private:
+
+ const string m_name;
+ string m_value;
+ };
+
+protected:
+
+ class propertyProxy {
+
+ public:
+
+ propertyProxy(const string& name, propertySet* set)
+ : m_name(name),
+ m_set(set) {
+
+ }
+
+ template <class TYPE>
+ propertyProxy& operator=(const TYPE& value) {
+
+ m_set->setProperty(m_name, value);
+ return *this;
+ }
+
+ template <class TYPE>
+ void setValue(const TYPE& value) {
+
+ m_set->setProperty(m_name, value);
+ }
+
+ template <class TYPE>
+ const TYPE getValue() const {
+
+ return m_set->getProperty <TYPE>(m_name);
+ }
+
+ operator string() const {
+
+ return m_set->getProperty <string>(m_name);
+ }
+
+ private:
+
+ const string m_name;
+ propertySet* m_set;
+ };
+
+ class constPropertyProxy {
+
+ public:
+
+ constPropertyProxy(const string& name, const propertySet* set)
+ : m_name(name),
+ m_set(set) {
+
+ }
+
+ template <class TYPE>
+ const TYPE getValue() const {
+
+ return m_set->getProperty <TYPE>(m_name);
+ }
+
+ operator string() const {
+
+ return m_set->getProperty <string>(m_name);
+ }
+
+ private:
+
+ const string m_name;
+ const propertySet* m_set;
+ };
+
+public:
+
+ propertySet();
+ propertySet(const string& props);
+ propertySet(const propertySet& set);
+
+ ~propertySet();
+
+ propertySet& operator=(const propertySet& set);
+
+ /** Parse a string and extract one or more properties.
+ * The string format is: name[=value](;name[=value])*.
+ *
+ * @param props string representing a list of properties
+ */
+ void setFromString(const string& props);
+
+ /** Remove all properties from the list.
+ */
+ void removeAllProperties();
+
+ /** Remove the specified property.
+ *
+ * @param name name of the property to remove
+ */
+ void removeProperty(const string& name);
+
+ /** Test whether the specified property is set.
+ *
+ * @param name name of the property to test
+ * @return true if the property is set (has a value),
+ * false otherwise
+ */
+ bool hasProperty(const string& name) const;
+
+ /** Get the value of the specified property.
+ *
+ * @throw exceptions::no_such_property if the property does not exist
+ * @param name property name
+ * @return value of the specified property
+ */
+ template <class TYPE>
+ const TYPE getProperty(const string& name) const {
+
+ const shared_ptr <property> prop = find(name);
+ if (!prop) throw exceptions::no_such_property(name);
+
+ return (prop->template getValue <TYPE>());
+ }
+
+ /** Get the value of the specified property.
+ * A default value can be returned if the property is not set.
+ *
+ * @param name property name
+ * @param defaultValue value to return if the specified property
+ * does not exist
+ * @return value of the specified property or default value
+ * if if does not exist
+ */
+ template <class TYPE>
+ const TYPE getProperty(const string& name, const TYPE defaultValue) const {
+
+ const shared_ptr <property> prop = find(name);
+ return prop ? prop->template getValue <TYPE>() : defaultValue;
+ }
+
+ /** Change the value of the specified property or create
+ * a new property set to the specified a value.
+ *
+ * @param name property name
+ * @param value property value
+ */
+ template <class TYPE>
+ void setProperty(const string& name, const TYPE& value) {
+ findOrCreate(name)->setValue(value);
+ }
+
+ /** Return a proxy object to access the specified property
+ * suitable for reading or writing. If the property does not
+ * exist and the value is changed, a new property will
+ * be created.
+ *
+ * @param name property name
+ * @return proxy object for the specified property
+ */
+ propertyProxy operator[](const string& name);
+
+ /** Return a proxy object to access the specified property
+ * suitable for reading only.
+ *
+ * @throw exceptions::no_such_property if the property does not exist
+ * @return read-only proxy object for the specified property
+ */
+ const constPropertyProxy operator[](const string& name) const;
+
+private:
+
+ void parse(const string& props);
+
+
+ class propFinder : public std::unary_function <shared_ptr <property>, bool> {
+
+ public:
+
+ propFinder(const string& name) : m_name(utility::stringUtils::toLower(name)) { }
+
+ bool operator()(const shared_ptr <property>& p) const {
+
+ return (utility::stringUtils::toLower(p->getName()) == m_name);
+ }
+
+ private:
+
+ const string m_name;
+ };
+
+ shared_ptr <property> find(const string& name) const;
+ shared_ptr <property> findOrCreate(const string& name);
+
+ typedef std::list <shared_ptr <property> > list_type;
+ list_type m_props;
+
+public:
+
+ template <typename TYPE>
+ static TYPE valueFromString(const string& value) {
+
+ TYPE v = TYPE();
+
+ std::istringstream iss(value);
+ iss.imbue(std::locale::classic()); // no formatting
+
+ iss >> v;
+
+ return v;
+ }
+
+ template <typename TYPE>
+ static string valueToString(const TYPE& value) {
+
+ std::ostringstream oss(value);
+ oss.imbue(std::locale::classic()); // no formatting
+
+ oss << value;
+
+ return oss.str();
+ }
+
+#ifdef VMIME_INLINE_TEMPLATE_SPECIALIZATION
+
+ template <>
+ static string valueFromString(const string& value) {
+
+ return value;
+ }
+
+ template <>
+ static string valueToString(const string& value) {
+
+ return value;
+ }
+
+ template <>
+ static bool valueFromString(const string& value) {
+
+ if (utility::stringUtils::toLower(value) == "true") {
+
+ return true;
+
+ } else {
+
+ int val = 0;
+
+ std::istringstream iss(value);
+ iss.imbue(std::locale::classic()); // no formatting
+
+ iss >> val;
+
+ return !iss.fail() && val != 0;
+ }
+ }
+
+ template <>
+ static string valueToString(const bool& value) {
+
+ return value ? "true" : "false";
+ }
+
+#endif // VMIME_INLINE_TEMPLATE_SPECIALIZATION
+
+ /** Return the property list.
+ *
+ * @return list of properties
+ */
+ const std::vector <shared_ptr <const property> > getPropertyList() const;
+
+ /** Return the property list.
+ *
+ * @return list of properties
+ */
+ const std::vector <shared_ptr <property> > getPropertyList();
+};
+
+
+#ifndef VMIME_INLINE_TEMPLATE_SPECIALIZATION
+
+template <> VMIME_EXPORT void propertySet::property::setValue <string>(const string& value);
+template <> VMIME_EXPORT void propertySet::property::setValue(const bool& value);
+
+template <> VMIME_EXPORT string propertySet::property::getValue() const;
+template <> VMIME_EXPORT bool propertySet::property::getValue() const;
+
+template <> VMIME_EXPORT string propertySet::valueFromString(const string& value);
+template <> VMIME_EXPORT string propertySet::valueToString(const string& value);
+
+template <> VMIME_EXPORT bool propertySet::valueFromString(const string& value);
+template <> VMIME_EXPORT string propertySet::valueToString(const bool& value);
+
+#endif // VMIME_INLINE_TEMPLATE_SPECIALIZATION
+
+
+} // vmime
+
+
+#endif // VMIME_PROPERTY_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/relay.cpp b/vmime-master/src/vmime/relay.cpp
new file mode 100644
index 0000000..b0a6b60
--- /dev/null
+++ b/vmime-master/src/vmime/relay.cpp
@@ -0,0 +1,363 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/relay.hpp"
+#include "vmime/text.hpp"
+#include "vmime/parserHelpers.hpp"
+#include "vmime/utility/outputStreamAdapter.hpp"
+
+#include <sstream>
+
+
+namespace vmime {
+
+
+relay::relay() {
+
+}
+
+
+relay::relay(const relay& r)
+ : headerFieldValue() {
+
+ copyFrom(r);
+}
+
+
+/*
+
+ RFC #2822:
+
+ received = "Received" ":" ; one per relay
+ ["from" domain] ; sending host
+ ["by" domain] ; receiving host
+ ["via" atom] ; physical path
+ *("with" atom) ; link/mail protocol
+ ["id" msg-id] ; receiver msg id
+ ["for" addr-spec] ; initial form
+*/
+
+void relay::parseImpl(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition
+) {
+
+ const char* const pend = buffer.data() + end;
+ const char* const pstart = buffer.data() + position;
+ const char* p = pend - 1;
+
+ // Find the beginning of the date part
+ while (p >= pstart && *p != ';') {
+ --p;
+ }
+
+ if (p >= pstart) {
+
+ // Parse the date/time part
+ m_date.parse(ctx, buffer, position + (p - pstart) + 1, end);
+
+ // Parse the components
+ std::istringstream iss(
+ string(buffer.begin() + position, buffer.begin() + position + (p - pstart))
+ );
+
+ iss.imbue(std::locale::classic());
+
+ string word;
+ std::vector <string> previous;
+
+ enum Parts {
+ Part_None,
+ Part_From, // The "from" part
+ Part_By, // The "by" part
+ Part_Via, // The "via" part
+ Part_With, // One "with" part
+ Part_Id, // The "id" part
+ Part_For, // The "for" part
+ Part_End
+ };
+
+ Parts part = Part_None;
+ bool cont = true;
+ bool inComment = false;
+
+ while (cont) {
+
+ Parts newPart = Part_None;
+
+ if ((cont = !(iss >> word).fail())) {
+
+ // A little hack for handling comments
+ if (inComment) {
+
+ size_t par = word.find(')');
+
+ if (par != string::npos) {
+
+ previous.push_back(string(word.begin(), word.begin() + par + 1));
+ word.erase(word.begin(), word.begin() + par + 1);
+ inComment = false;
+ }
+ }
+
+ bool keyword = false;
+
+ if (!inComment) {
+
+ if (utility::stringUtils::isStringEqualNoCase(word, "from", 4)) {
+
+ newPart = Part_From;
+ keyword = true;
+
+ } else if (utility::stringUtils::isStringEqualNoCase(word, "by", 2)) {
+
+ newPart = Part_By;
+ keyword = true;
+
+ } else if (utility::stringUtils::isStringEqualNoCase(word, "via", 2)) {
+
+ newPart = Part_Via;
+ keyword = true;
+
+ } else if (utility::stringUtils::isStringEqualNoCase(word, "with", 2)) {
+
+ newPart = Part_With;
+ keyword = true;
+
+ } else if (utility::stringUtils::isStringEqualNoCase(word, "id", 2)) {
+
+ newPart = Part_Id;
+ keyword = true;
+
+ } else if (utility::stringUtils::isStringEqualNoCase(word, "for", 2)) {
+
+ newPart = Part_For;
+ keyword = true;
+ }
+ }
+
+ if (!keyword) {
+
+ if (word.find('(') != string::npos) {
+ inComment = true;
+ }
+
+ previous.push_back(word);
+ }
+ }
+
+ if (!cont || newPart != Part_None) {
+
+ if (part != Part_None) {
+
+ std::ostringstream value;
+
+ for (std::vector <string>::const_iterator
+ it = previous.begin() ; it != previous.end() ; ++it) {
+
+ if (it != previous.begin()) value << " ";
+ value << *it;
+ }
+
+ switch (part) {
+ case Part_From: m_from = value.str(); break;
+ case Part_By: m_by = value.str(); break;
+ case Part_Via: m_via = value.str(); break;
+ case Part_With: m_with.push_back(value.str()); break;
+ case Part_Id: m_id = value.str(); break;
+ case Part_For: m_for = value.str(); break;
+ default: break; // Should never happen...
+ }
+ }
+
+ previous.clear();
+ part = newPart;
+ }
+ }
+ }
+
+ setParsedBounds(position, end);
+
+ if (newPosition) {
+ *newPosition = end;
+ }
+}
+
+
+void relay::generateImpl(
+ const generationContext& ctx,
+ utility::outputStream& os,
+ const size_t curLinePos,
+ size_t* newLinePos
+) const {
+
+ std::ostringstream oss;
+ int count = 0;
+
+ if (m_from.length()) oss << (count++ > 0 ? " " : "") << "from " << m_from;
+ if (m_by.length()) oss << (count++ > 0 ? " " : "") << "by " << m_by;
+ if (m_via.length()) oss << (count++ > 0 ? " " : "") << "via " << m_via;
+
+ for (std::vector <string>::const_iterator
+ it = m_with.begin() ; it != m_with.end() ; ++it) {
+
+ oss << (count++ > 0 ? " " : "") << "with " << *it;
+ }
+
+ if (m_id.length()) oss << (count++ > 0 ? " " : "") << "id " << m_id;
+ if (m_for.length()) oss << (count++ > 0 ? " " : "") << "for " << m_for;
+
+ oss << "; ";
+
+ vmime::utility::outputStreamAdapter dos(oss);
+ m_date.generate(ctx, dos, 0, NULL);
+
+ text(oss.str()).encodeAndFold(ctx, os, curLinePos, newLinePos, text::FORCE_NO_ENCODING);
+}
+
+
+void relay::copyFrom(const component& other) {
+
+ const relay& r = dynamic_cast <const relay&>(other);
+
+ m_from = r.m_from;
+ m_via = r.m_via;
+ m_by = r.m_by;
+ m_id = r.m_id;
+ m_for = r.m_for;
+
+ m_with.resize(r.m_with.size());
+ std::copy(r.m_with.begin(), r.m_with.end(), m_with.begin());
+
+ m_date = r.m_date;
+}
+
+
+relay& relay::operator=(const relay& other) {
+
+ copyFrom(other);
+ return *this;
+}
+
+
+shared_ptr <component> relay::clone() const {
+
+ return make_shared <relay>(*this);
+}
+
+
+const string& relay::getFrom() const {
+
+ return m_from;
+}
+
+
+void relay::setFrom(const string& from) {
+
+ m_from = from;
+}
+
+
+const string& relay::getVia() const {
+
+ return m_via;
+}
+
+
+void relay::setVia(const string& via) {
+
+ m_via = via;
+}
+
+
+const string& relay::getBy() const {
+
+ return m_by;
+}
+
+
+void relay::setBy(const string& by) {
+
+ m_by = by;
+}
+
+
+const string& relay::getId() const {
+
+ return m_id;
+}
+
+
+void relay::setId(const string& id) {
+
+ m_id = id;
+}
+
+
+const string& relay::getFor() const {
+
+ return m_for;
+}
+
+
+void relay::setFor(const string& for_) {
+
+ m_for = for_;
+}
+
+
+const datetime& relay::getDate() const {
+
+ return m_date;
+}
+
+
+void relay::setDate(const datetime& date) {
+
+ m_date = date;
+}
+
+
+const std::vector <string>& relay::getWithList() const {
+
+ return m_with;
+}
+
+
+std::vector <string>& relay::getWithList() {
+
+ return m_with;
+}
+
+
+const std::vector <shared_ptr <component> > relay::getChildComponents() {
+
+ // TODO: should fields inherit from 'component'? (using typeAdapter)
+ return std::vector <shared_ptr <component> >();
+}
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/relay.hpp b/vmime-master/src/vmime/relay.hpp
new file mode 100644
index 0000000..f467602
--- /dev/null
+++ b/vmime-master/src/vmime/relay.hpp
@@ -0,0 +1,108 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_RELAY_HPP_INCLUDED
+#define VMIME_RELAY_HPP_INCLUDED
+
+
+#include "vmime/base.hpp"
+#include "vmime/headerFieldValue.hpp"
+
+#include "vmime/dateTime.hpp"
+
+
+namespace vmime {
+
+
+/** Trace information about a relay (basic type).
+ */
+class VMIME_EXPORT relay : public headerFieldValue {
+
+public:
+
+ relay();
+ relay(const relay& r);
+
+public:
+
+ shared_ptr <component> clone() const;
+ void copyFrom(const component& other);
+ relay& operator=(const relay& other);
+
+ const std::vector <shared_ptr <component> > getChildComponents();
+
+ const string& getFrom() const;
+ void setFrom(const string& from);
+
+ const string& getVia() const;
+ void setVia(const string& via);
+
+ const string& getBy() const;
+ void setBy(const string& by);
+
+ const string& getId() const;
+ void setId(const string& id);
+
+ const string& getFor() const;
+ void setFor(const string& for_);
+
+ const datetime& getDate() const;
+ void setDate(const datetime& date);
+
+ const std::vector <string>& getWithList() const;
+ std::vector <string>& getWithList();
+
+private:
+
+ string m_from;
+ string m_via;
+ string m_by;
+ string m_id;
+ string m_for;
+ std::vector <string> m_with;
+
+ datetime m_date;
+
+protected:
+
+ void parseImpl(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition = NULL
+ );
+
+ void generateImpl(
+ const generationContext& ctx,
+ utility::outputStream& os,
+ const size_t curLinePos = 0,
+ size_t* newLinePos = NULL
+ ) const;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_RELAY_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/security/authenticator.hpp b/vmime-master/src/vmime/security/authenticator.hpp
new file mode 100644
index 0000000..03bca73
--- /dev/null
+++ b/vmime-master/src/vmime/security/authenticator.hpp
@@ -0,0 +1,136 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_SECURITY_AUTHENTICATOR_HPP_INCLUDED
+#define VMIME_SECURITY_AUTHENTICATOR_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/types.hpp"
+
+
+// Forward declarations
+namespace vmime {
+namespace net {
+
+class service;
+
+} // net
+} // vmime
+
+
+namespace vmime {
+namespace security {
+
+
+/** Provides required information for user authentication. The same
+ * information can be requested multiple time (eg. in IMAP, there is a
+ * new connection started each time a folder is open), so the object is
+ * responsible for caching the information to avoid useless interactions
+ * with the user.
+ *
+ * Usually, you should not inherit from this class, but instead from the
+ * more convenient defaultAuthenticator class.
+ *
+ * WARNING: an authenticator should be used with one and ONLY ONE messaging
+ * service at a time.
+ */
+class VMIME_EXPORT authenticator : public object {
+
+public:
+
+ /** Return the authentication identity (usually, this
+ * is the username).
+ *
+ * @return username
+ * @throw exceptions::no_auth_information if the information
+ * could not be provided
+ */
+ virtual const string getUsername() const = 0;
+
+ /** Return the password of the authentication identity.
+ *
+ * @return password
+ * @throw exceptions::no_auth_information if the information
+ * could not be provided
+ */
+ virtual const string getPassword() const = 0;
+
+ /** Return the optional access token for authentication. This is
+ * used for example with XOAuth2 SASL authentication.
+ *
+ * @return access token
+ * @throw exceptions::no_auth_information if the information
+ * could not be provided
+ */
+ virtual const string getAccessToken() const = 0;
+
+ /** Return the local host name of the machine.
+ *
+ * @return hostname
+ * @throw exceptions::no_auth_information if the information
+ * could not be provided
+ */
+ virtual const string getHostname() const = 0;
+
+ /** Return the anonymous token (usually, this is the user's
+ * email address).
+ *
+ * @return anonymous token
+ * @throw exceptions::no_auth_information if the information
+ * could not be provided
+ */
+ virtual const string getAnonymousToken() const = 0;
+
+ /** Return the registered service name of the application
+ * service (eg: "imap"). This can be used by GSSAPI or DIGEST-MD5
+ * mechanisms with SASL.
+ *
+ * @return service name
+ * @throw exceptions::no_auth_information if the information
+ * could not be provided
+ */
+ virtual const string getServiceName() const = 0;
+
+ /** Called by the messaging service to allow this authenticator to
+ * know which service is currently using it. This is called just
+ * before the service starts the authentication process.
+ *
+ * @param serv messaging service instance
+ */
+ virtual void setService(const shared_ptr <net::service>& serv) = 0;
+};
+
+
+} // security
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+#endif // VMIME_SECURITY_AUTHENTICATOR_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/security/cert/X509Certificate.cpp b/vmime-master/src/vmime/security/cert/X509Certificate.cpp
new file mode 100644
index 0000000..128fac1
--- /dev/null
+++ b/vmime-master/src/vmime/security/cert/X509Certificate.cpp
@@ -0,0 +1,72 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+
+#include "vmime/security/cert/X509Certificate.hpp"
+
+#include "vmime/security/cert/certificateNotYetValidException.hpp"
+#include "vmime/security/cert/certificateExpiredException.hpp"
+
+
+namespace vmime {
+namespace security {
+namespace cert {
+
+
+X509Certificate::~X509Certificate() {
+
+}
+
+
+void X509Certificate::checkValidity() {
+
+ const datetime now = datetime::now();
+
+ if (now < getActivationDate()) {
+
+ certificateNotYetValidException ex;
+ ex.setCertificate(dynamicCast <certificate>(shared_from_this()));
+
+ throw ex;
+
+ } else if (now > getExpirationDate()) {
+
+ certificateExpiredException ex;
+ ex.setCertificate(dynamicCast <certificate>(shared_from_this()));
+
+ throw ex;
+ }
+}
+
+
+} // cert
+} // security
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
diff --git a/vmime-master/src/vmime/security/cert/X509Certificate.hpp b/vmime-master/src/vmime/security/cert/X509Certificate.hpp
new file mode 100644
index 0000000..5434b45
--- /dev/null
+++ b/vmime-master/src/vmime/security/cert/X509Certificate.hpp
@@ -0,0 +1,197 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_SECURITY_CERT_X509CERTIFICATE_HPP_INCLUDED
+#define VMIME_SECURITY_CERT_X509CERTIFICATE_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+
+#include "vmime/security/cert/certificate.hpp"
+
+#include "vmime/utility/stream.hpp"
+
+#include "vmime/base.hpp"
+#include "vmime/types.hpp"
+#include "vmime/dateTime.hpp"
+
+
+namespace vmime {
+namespace security {
+namespace cert {
+
+
+/** Identity certificate based on X.509 standard.
+ */
+class VMIME_EXPORT X509Certificate : public certificate {
+
+public:
+
+ ~X509Certificate();
+
+ /** Supported encodings for X.509 certificates. */
+ enum Format {
+ FORMAT_DER, /**< DER encoding */
+ FORMAT_PEM /**< PEM encoding */
+ };
+
+ /** Supported digest algorithms (used for fingerprint). */
+ enum DigestAlgorithm {
+ DIGEST_MD5, /**< MD5 digest */
+ DIGEST_SHA1 /**< SHA1 digest */
+ };
+
+
+ /** Imports a DER or PEM encoded X.509 certificate.
+ *
+ * @param is input stream to read data from
+ * @return a X.509 certificate, or NULL if the given data does not
+ * represent a valid certificate
+ */
+ static shared_ptr <X509Certificate> import(utility::inputStream& is);
+
+ /** Imports a DER or PEM encoded X.509 certificate.
+ *
+ * @param data points to raw data
+ * @param length size of data
+ * @return a X.509 certificate, or NULL if the given data does not
+ * represent a valid certificate
+ */
+ static shared_ptr <X509Certificate> import(const byte_t* data, const size_t length);
+
+ /** Import sveral DER or PEM encoded X.509 certificates.
+ *
+ * @param is input stream to read data from
+ * @param certs the resulting list of certificates
+ */
+ static void import(
+ utility::inputStream& is,
+ std::vector <shared_ptr <X509Certificate> >& certs
+ );
+
+ /** Import several DER or PEM encoded X.509 certificates.
+ *
+ * @param data points to raw data
+ * @param length size of data
+ * @param certs the resulting list of certificates
+ */
+ static void import(
+ const byte_t* data,
+ const size_t length,
+ std::vector <shared_ptr <X509Certificate> >& certs
+ );
+
+ /** Exports this X.509 certificate to the specified format.
+ *
+ * @param os output stream into which write data
+ * @param format output format
+ */
+ virtual void write(utility::outputStream& os, const Format format) const = 0;
+
+ /** Returns the X.509 certificate's serial number. This is obtained
+ * by the X.509 Certificate 'serialNumber' field. Serial is not
+ * always a 32 or 64bit number. Some CAs use large serial numbers,
+ * thus it may be wise to handle it as something opaque.
+ *
+ * @return serial number of this certificate
+ */
+ virtual const byteArray getSerialNumber() const = 0;
+
+ /** Returns the distinguished name of the issuer of this certificate.
+ * Eg. "C=US,O=VeriSign\, Inc.,OU=Class 1 Public Primary Certification Authority"
+ *
+ * @return distinguished name of the certificate issuer, as a string
+ */
+ virtual const string getIssuerString() const = 0;
+
+ /** Checks if this certificate has the given issuer.
+ *
+ * @param issuer certificate of a possible issuer
+ * @return true if this certificate was issued by the given issuer,
+ * false otherwise
+ */
+ virtual bool checkIssuer(const shared_ptr <const X509Certificate>& issuer) const = 0;
+
+ /** Verifies this certificate against a given trusted one.
+ *
+ * @param caCert a certificate that is considered to be trusted one
+ * @return true if the verification succeeded, false otherwise
+ */
+ virtual bool verify(const shared_ptr <const X509Certificate>& caCert) const = 0;
+
+ /** Verify certificate's subject name against the given hostname.
+ *
+ * @param hostname DNS name of the server
+ * @param nonMatchingNames if not NULL, will contain the names that do
+ * not match the identities in the certificate
+ * @return true if the match is successful, false otherwise
+ */
+ virtual bool verifyHostName(
+ const string& hostname,
+ std::vector <std::string>* nonMatchingNames = NULL
+ ) const = 0;
+
+ /** Gets the expiration date of this certificate. This is the date
+ * at which this certificate will not be valid anymore.
+ *
+ * @return expiration date of this certificate
+ */
+ virtual const datetime getExpirationDate() const = 0;
+
+ /** Gets the activation date of this certificate. This is the date
+ * at which this certificate will be valid.
+ *
+ * @return activation date of this certificate
+ */
+ virtual const datetime getActivationDate() const = 0;
+
+ /** Returns the fingerprint of this certificate.
+ *
+ * @return the fingerprint of this certificate
+ */
+ virtual const byteArray getFingerprint(const DigestAlgorithm algo) const = 0;
+
+ /** Checks that the certificate is currently valid. For the certificate
+ * to be valid, the current date and time must be in the validity period
+ * specified in the certificate.
+ *
+ * @throw certificateExpiredException if the certificate has expired
+ * @throw certificateNotYetValidException if the certificate is not yet valid
+ */
+ virtual void checkValidity();
+};
+
+
+} // cert
+} // security
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+#endif // VMIME_SECURITY_CERT_X509CERTIFICATE_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/security/cert/certificate.hpp b/vmime-master/src/vmime/security/cert/certificate.hpp
new file mode 100644
index 0000000..ed0f175
--- /dev/null
+++ b/vmime-master/src/vmime/security/cert/certificate.hpp
@@ -0,0 +1,84 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_SECURITY_CERT_CERTIFICATE_HPP_INCLUDED
+#define VMIME_SECURITY_CERT_CERTIFICATE_HPP_INCLUDED
+
+
+#include "vmime/types.hpp"
+
+
+namespace vmime {
+namespace security {
+namespace cert {
+
+
+/** Identity certificate for a peer.
+ */
+class VMIME_EXPORT certificate : public object, public enable_shared_from_this <certificate> {
+
+public:
+
+ /** Returns the encoded form of this certificate (for example,
+ * X.509 certificates are encoded as ASN.1 DER).
+ *
+ * @return the encoded form of this certificate
+ */
+ virtual const byteArray getEncoded() const = 0;
+
+ /** Return the type of this certificate.
+ *
+ * @return the type of this certificate
+ */
+ virtual const string getType() const = 0;
+
+ /** Return the version of this certificate.
+ *
+ * @return the version of this certificate
+ */
+ virtual int getVersion() const = 0;
+
+ /** Checks if two certificates are the same.
+ *
+ * @param other certificate to compare with
+ * @return true if the two certificates are the same,
+ * false otherwise
+ */
+ virtual bool equals(const shared_ptr <const certificate>& other) const = 0;
+
+ /** Returns a pointer to internal binary data for this certificate.
+ * The actual type of data depends on the library used for TLS support.
+ *
+ * @return pointer to underlying data
+ */
+ virtual void* getInternalData() = 0;
+};
+
+
+} // cert
+} // security
+} // vmime
+
+
+#endif // VMIME_SECURITY_CERT_CERTIFICATE_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/security/cert/certificateChain.cpp b/vmime-master/src/vmime/security/cert/certificateChain.cpp
new file mode 100644
index 0000000..c506913
--- /dev/null
+++ b/vmime-master/src/vmime/security/cert/certificateChain.cpp
@@ -0,0 +1,53 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/security/cert/certificateChain.hpp"
+
+
+namespace vmime {
+namespace security {
+namespace cert {
+
+
+certificateChain::certificateChain(const std::vector <shared_ptr <certificate> >& certs)
+ : m_certs(certs) {
+
+}
+
+
+size_t certificateChain::getCount() const {
+
+ return m_certs.size();
+}
+
+
+const shared_ptr <certificate>& certificateChain::getAt(const size_t index) {
+
+ return m_certs[index];
+}
+
+
+} // cert
+} // security
+} // vmime
+
diff --git a/vmime-master/src/vmime/security/cert/certificateChain.hpp b/vmime-master/src/vmime/security/cert/certificateChain.hpp
new file mode 100644
index 0000000..f8c363e
--- /dev/null
+++ b/vmime-master/src/vmime/security/cert/certificateChain.hpp
@@ -0,0 +1,79 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_SECURITY_CERT_CERTIFICATECHAIN_HPP_INCLUDED
+#define VMIME_SECURITY_CERT_CERTIFICATECHAIN_HPP_INCLUDED
+
+
+#include "vmime/types.hpp"
+
+#include "vmime/security/cert/certificate.hpp"
+
+
+namespace vmime {
+namespace security {
+namespace cert {
+
+
+/** An ordered list of certificates, from the subject certificate to
+ * the issuer certificate.
+ */
+class VMIME_EXPORT certificateChain : public object {
+
+public:
+
+ /** Construct a new certificateChain object given an ordered list
+ * of certificates.
+ *
+ * @param certs chain of certificates
+ */
+ certificateChain(const std::vector <shared_ptr <certificate> >& certs);
+
+ /** Return the number of certificates in the chain.
+ *
+ * @return number of certificates in the chain
+ */
+ size_t getCount() const;
+
+ /** Return the certificate at the specified position. 0 is the
+ * subject certificate, 1 is the issuer's certificate, 2 is
+ * the issuer's issuer, etc.
+ *
+ * @param index position at which to retrieve certificate
+ * @return certificate at the specified position
+ */
+ const shared_ptr <certificate>& getAt(const size_t index);
+
+protected:
+
+ std::vector <shared_ptr <certificate> > m_certs;
+};
+
+
+} // cert
+} // security
+} // vmime
+
+
+#endif // VMIME_SECURITY_CERT_CERTIFICATECHAIN_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/security/cert/certificateException.cpp b/vmime-master/src/vmime/security/cert/certificateException.cpp
new file mode 100644
index 0000000..51a4f03
--- /dev/null
+++ b/vmime-master/src/vmime/security/cert/certificateException.cpp
@@ -0,0 +1,84 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+
+#include "vmime/security/cert/certificateException.hpp"
+
+
+namespace vmime {
+namespace security {
+namespace cert {
+
+
+certificateException::certificateException()
+ : exception("A problem occurred with a certificate.") {
+
+}
+
+
+certificateException::certificateException(const std::string& what)
+ : exception(what) {
+
+}
+
+
+certificateException::~certificateException() throw() {
+
+}
+
+
+exception* certificateException::clone() const {
+
+ return new certificateException(what());
+}
+
+
+void certificateException::setCertificate(const shared_ptr <certificate>& cert) {
+
+ m_cert = cert;
+}
+
+
+shared_ptr <certificate> certificateException::getCertificate() {
+
+ return m_cert;
+}
+
+
+shared_ptr <const certificate> certificateException::getCertificate() const {
+
+ return m_cert;
+}
+
+
+} // cert
+} // security
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
diff --git a/vmime-master/src/vmime/security/cert/certificateException.hpp b/vmime-master/src/vmime/security/cert/certificateException.hpp
new file mode 100644
index 0000000..9dd5443
--- /dev/null
+++ b/vmime-master/src/vmime/security/cert/certificateException.hpp
@@ -0,0 +1,95 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_SECURITY_CERT_CERTIFICATEEXCEPTION_HPP_INCLUDED
+#define VMIME_SECURITY_CERT_CERTIFICATEEXCEPTION_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+
+#include "vmime/security/cert/certificate.hpp"
+
+#include "vmime/exception.hpp"
+
+
+namespace vmime {
+namespace security {
+namespace cert {
+
+
+/** Thrown to indicate a problem with a certificate or certificate verification.
+ */
+class VMIME_EXPORT certificateException : public exception {
+
+public:
+
+ /** Constructs a certificateException with no detail message.
+ */
+ certificateException();
+
+ /** Constructs a certificateException with a detail message.
+ *
+ * @param what a message that describes this exception
+ */
+ certificateException(const std::string& what);
+
+ ~certificateException() throw();
+
+ exception* clone() const;
+
+ /** Sets the certificate on which the problem occured.
+ *
+ * @param cert certificate
+ */
+ void setCertificate(const shared_ptr <certificate>& cert);
+
+ /** Returns the certificate on which the problem occured.
+ *
+ * @return certificate
+ */
+ shared_ptr <certificate> getCertificate();
+
+ /** Returns the certificate on which the problem occured.
+ *
+ * @return certificate
+ */
+ shared_ptr <const certificate> getCertificate() const;
+
+private:
+
+ shared_ptr <certificate> m_cert;
+};
+
+
+} // cert
+} // security
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+#endif // VMIME_SECURITY_CERT_CERTIFICATEEXCEPTION_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/security/cert/certificateExpiredException.cpp b/vmime-master/src/vmime/security/cert/certificateExpiredException.cpp
new file mode 100644
index 0000000..1aa248e
--- /dev/null
+++ b/vmime-master/src/vmime/security/cert/certificateExpiredException.cpp
@@ -0,0 +1,55 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+
+#include "vmime/security/cert/certificateExpiredException.hpp"
+
+
+namespace vmime {
+namespace security {
+namespace cert {
+
+
+certificateExpiredException::certificateExpiredException()
+ : certificateException("The certificate has expired.") {
+
+}
+
+
+exception* certificateExpiredException::clone() const
+{
+ return new certificateExpiredException();
+}
+
+
+} // cert
+} // security
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
diff --git a/vmime-master/src/vmime/security/cert/certificateExpiredException.hpp b/vmime-master/src/vmime/security/cert/certificateExpiredException.hpp
new file mode 100644
index 0000000..4db0a1e
--- /dev/null
+++ b/vmime-master/src/vmime/security/cert/certificateExpiredException.hpp
@@ -0,0 +1,65 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_SECURITY_CERT_CERTIFICATEEXPIREDEXCEPTION_HPP_INCLUDED
+#define VMIME_SECURITY_CERT_CERTIFICATEEXPIREDEXCEPTION_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+
+#include "vmime/security/cert/certificate.hpp"
+#include "vmime/security/cert/certificateException.hpp"
+
+
+namespace vmime {
+namespace security {
+namespace cert {
+
+
+/** Thrown when the current date and time is after the validity period
+ * specified in the certificate.
+ */
+class VMIME_EXPORT certificateExpiredException : public certificateException {
+
+public:
+
+ /** Constructs a certificateExpiredException with no detail message.
+ */
+ certificateExpiredException();
+
+ exception* clone() const;
+};
+
+
+} // cert
+} // security
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+#endif // VMIME_SECURITY_CERT_CERTIFICATEEXPIREDEXCEPTION_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/security/cert/certificateIssuerVerificationException.cpp b/vmime-master/src/vmime/security/cert/certificateIssuerVerificationException.cpp
new file mode 100644
index 0000000..adf5049
--- /dev/null
+++ b/vmime-master/src/vmime/security/cert/certificateIssuerVerificationException.cpp
@@ -0,0 +1,55 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+
+#include "vmime/security/cert/certificateIssuerVerificationException.hpp"
+
+
+namespace vmime {
+namespace security {
+namespace cert {
+
+
+certificateIssuerVerificationException::certificateIssuerVerificationException()
+ : certificateException("Certificate subject/issuer verification failed.") {
+
+}
+
+
+exception* certificateIssuerVerificationException::clone() const {
+
+ return new certificateIssuerVerificationException();
+}
+
+
+} // cert
+} // security
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
diff --git a/vmime-master/src/vmime/security/cert/certificateIssuerVerificationException.hpp b/vmime-master/src/vmime/security/cert/certificateIssuerVerificationException.hpp
new file mode 100644
index 0000000..e22bd92
--- /dev/null
+++ b/vmime-master/src/vmime/security/cert/certificateIssuerVerificationException.hpp
@@ -0,0 +1,65 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_SECURITY_CERT_CERTIFICATEISSUERVERIFICATIONEXCEPTION_HPP_INCLUDED
+#define VMIME_SECURITY_CERT_CERTIFICATEISSUERVERIFICATIONEXCEPTION_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+
+#include "vmime/security/cert/certificate.hpp"
+#include "vmime/security/cert/certificateException.hpp"
+
+
+namespace vmime {
+namespace security {
+namespace cert {
+
+
+/** Thrown when a certificate in a certificate chain cannot be verified
+ * against the next certificate in the chain (the issuer).
+ */
+class VMIME_EXPORT certificateIssuerVerificationException : public certificateException {
+
+public:
+
+ /** Constructs a certificateIssuerVerificationException with no detail message.
+ */
+ certificateIssuerVerificationException();
+
+ exception* clone() const;
+};
+
+
+} // cert
+} // security
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+#endif // VMIME_SECURITY_CERT_CERTIFICATEISSUERVERIFICATIONEXCEPTION_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/security/cert/certificateNotTrustedException.cpp b/vmime-master/src/vmime/security/cert/certificateNotTrustedException.cpp
new file mode 100644
index 0000000..a5ebb99
--- /dev/null
+++ b/vmime-master/src/vmime/security/cert/certificateNotTrustedException.cpp
@@ -0,0 +1,55 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+
+#include "vmime/security/cert/certificateNotTrustedException.hpp"
+
+
+namespace vmime {
+namespace security {
+namespace cert {
+
+
+certificateNotTrustedException::certificateNotTrustedException()
+ : certificateException("Cannot verify certificate against trusted certificates.") {
+
+}
+
+
+exception* certificateNotTrustedException::clone() const {
+
+ return new certificateNotTrustedException();
+}
+
+
+} // cert
+} // security
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
diff --git a/vmime-master/src/vmime/security/cert/certificateNotTrustedException.hpp b/vmime-master/src/vmime/security/cert/certificateNotTrustedException.hpp
new file mode 100644
index 0000000..8cdb2f0
--- /dev/null
+++ b/vmime-master/src/vmime/security/cert/certificateNotTrustedException.hpp
@@ -0,0 +1,65 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_SECURITY_CERT_CERTIFICATENOTTRUSTEDEXCEPTION_HPP_INCLUDED
+#define VMIME_SECURITY_CERT_CERTIFICATENOTTRUSTEDEXCEPTION_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+
+#include "vmime/security/cert/certificate.hpp"
+#include "vmime/security/cert/certificateException.hpp"
+
+
+namespace vmime {
+namespace security {
+namespace cert {
+
+
+/** Thrown when a certificate cannot be verified against root and/or
+ * trusted certificates.
+ */
+class VMIME_EXPORT certificateNotTrustedException : public certificateException {
+
+public:
+
+ /** Constructs a certificateNotTrustedException with no detail message.
+ */
+ certificateNotTrustedException();
+
+ exception* clone() const;
+};
+
+
+} // cert
+} // security
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+#endif // VMIME_SECURITY_CERT_CERTIFICATENOTTRUSTEDEXCEPTION_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/security/cert/certificateNotYetValidException.cpp b/vmime-master/src/vmime/security/cert/certificateNotYetValidException.cpp
new file mode 100644
index 0000000..ed8ca79
--- /dev/null
+++ b/vmime-master/src/vmime/security/cert/certificateNotYetValidException.cpp
@@ -0,0 +1,55 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+
+#include "vmime/security/cert/certificateNotYetValidException.hpp"
+
+
+namespace vmime {
+namespace security {
+namespace cert {
+
+
+certificateNotYetValidException::certificateNotYetValidException()
+ : certificateException("The certificate is not yet valid.") {
+
+}
+
+
+exception* certificateNotYetValidException::clone() const {
+
+ return new certificateNotYetValidException();
+}
+
+
+} // cert
+} // security
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
diff --git a/vmime-master/src/vmime/security/cert/certificateNotYetValidException.hpp b/vmime-master/src/vmime/security/cert/certificateNotYetValidException.hpp
new file mode 100644
index 0000000..8f321eb
--- /dev/null
+++ b/vmime-master/src/vmime/security/cert/certificateNotYetValidException.hpp
@@ -0,0 +1,65 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_SECURITY_CERT_CERTIFICATENOTYETVALIDEXCEPTION_HPP_INCLUDED
+#define VMIME_SECURITY_CERT_CERTIFICATENOTYETVALIDEXCEPTION_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+
+#include "vmime/security/cert/certificate.hpp"
+#include "vmime/security/cert/certificateException.hpp"
+
+
+namespace vmime {
+namespace security {
+namespace cert {
+
+
+/** Thrown when the current date and time is before the validity period
+ * specified in the certificate.
+ */
+class VMIME_EXPORT certificateNotYetValidException : public certificateException {
+
+public:
+
+ /** Constructs a certificateNotYetValidException with no detail message.
+ */
+ certificateNotYetValidException();
+
+ exception* clone() const;
+};
+
+
+} // cert
+} // security
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+#endif // VMIME_SECURITY_CERT_CERTIFICATENOTYETVALIDEXCEPTION_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/security/cert/certificateVerifier.hpp b/vmime-master/src/vmime/security/cert/certificateVerifier.hpp
new file mode 100644
index 0000000..7e2913a
--- /dev/null
+++ b/vmime-master/src/vmime/security/cert/certificateVerifier.hpp
@@ -0,0 +1,76 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_SECURITY_CERT_CERTIFICATEVERIFIER_HPP_INCLUDED
+#define VMIME_SECURITY_CERT_CERTIFICATEVERIFIER_HPP_INCLUDED
+
+
+#include "vmime/types.hpp"
+
+#include "vmime/security/cert/certificateChain.hpp"
+
+#include "vmime/security/cert/unsupportedCertificateTypeException.hpp"
+#include "vmime/security/cert/certificateIssuerVerificationException.hpp"
+#include "vmime/security/cert/certificateNotTrustedException.hpp"
+#include "vmime/security/cert/serverIdentityException.hpp"
+
+
+namespace vmime {
+namespace security {
+namespace cert {
+
+
+/** Verify that a certificate path issued by a server can be trusted.
+ */
+class VMIME_EXPORT certificateVerifier : public object {
+
+public:
+
+ /** Verify that the specified certificate chain is trusted.
+ *
+ * @param chain certificate chain
+ * @param hostname server hostname
+ * @throw unsupportedCertificateTypeException if a certificate in the
+ * chain is of unsupported format
+ * @throw certificateExpiredException if a certificate in the chain
+ * has expired
+ * @throw certificateNotYetValidException if a certificate in the chain
+ * is not yet valid
+ * @throw certificateNotTrustedException if a certificate in the chain
+ * cannot be verified against root and/or trusted certificates
+ * @throw certificateIssuerVerificationException if a certificate in the
+ * chain cannot be verified against the next certificate (issuer)
+ * @throw serverIdentityException if the subject name of the certificate
+ * does not match the hostname of the server
+ */
+ virtual void verify(const shared_ptr <certificateChain>& chain, const string& hostname) = 0;
+};
+
+
+} // cert
+} // security
+} // vmime
+
+
+#endif // VMIME_SECURITY_CERT_CERTIFICATEVERIFIER_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/security/cert/defaultCertificateVerifier.cpp b/vmime-master/src/vmime/security/cert/defaultCertificateVerifier.cpp
new file mode 100644
index 0000000..a67052e
--- /dev/null
+++ b/vmime-master/src/vmime/security/cert/defaultCertificateVerifier.cpp
@@ -0,0 +1,191 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+
+#include "vmime/security/cert/defaultCertificateVerifier.hpp"
+
+#include "vmime/security/cert/X509Certificate.hpp"
+
+#include "vmime/exception.hpp"
+
+
+namespace vmime {
+namespace security {
+namespace cert {
+
+
+defaultCertificateVerifier::defaultCertificateVerifier() {
+
+}
+
+
+defaultCertificateVerifier::~defaultCertificateVerifier() {
+
+}
+
+
+defaultCertificateVerifier::defaultCertificateVerifier(const defaultCertificateVerifier&)
+ : certificateVerifier() {
+
+ // Not used
+}
+
+
+void defaultCertificateVerifier::verify(
+ const shared_ptr <certificateChain>& chain,
+ const string& hostname
+) {
+
+ if (chain->getCount() == 0) {
+ return;
+ }
+
+ const string type = chain->getAt(0)->getType();
+
+ if (type == "X.509") {
+ verifyX509(chain, hostname);
+ } else {
+ throw unsupportedCertificateTypeException(type);
+ }
+}
+
+
+void defaultCertificateVerifier::verifyX509(
+ const shared_ptr <certificateChain>& chain,
+ const string& hostname
+) {
+
+ // For every certificate in the chain, verify that the certificate
+ // has been issued by the next certificate in the chain
+ if (chain->getCount() >= 2) {
+
+ for (size_t i = 0 ; i < chain->getCount() - 1 ; ++i) {
+
+ shared_ptr <X509Certificate> cert =
+ dynamicCast <X509Certificate>(chain->getAt(i));
+
+ shared_ptr <X509Certificate> next =
+ dynamicCast <X509Certificate>(chain->getAt(i + 1));
+
+ if (!cert->checkIssuer(next)) {
+
+ certificateIssuerVerificationException ex;
+ ex.setCertificate(cert);
+
+ throw ex;
+ }
+ }
+ }
+
+ // For every certificate in the chain, verify that the certificate
+ // is valid at the current time
+ for (size_t i = 0 ; i < chain->getCount() ; ++i) {
+
+ shared_ptr <X509Certificate> cert =
+ dynamicCast <X509Certificate>(chain->getAt(i));
+
+ cert->checkValidity();
+ }
+
+ // Check whether the certificate can be trusted
+
+ // -- First, verify that the the last certificate in the chain was
+ // -- issued by a third-party that we trust
+ shared_ptr <X509Certificate> lastCert =
+ dynamicCast <X509Certificate>(chain->getAt(chain->getCount() - 1));
+
+ bool trusted = false;
+
+ for (size_t i = 0 ; !trusted && i < m_x509RootCAs.size() ; ++i) {
+
+ shared_ptr <X509Certificate> rootCa = m_x509RootCAs[i];
+
+ // printf("rootCAs size is %d, i is %d\n", m_x509RootCAs.size(), i);
+ // printf("will cal verify with %p\n", rootCa.get());
+ if (lastCert->verify(rootCa)) {
+ trusted = true;
+ }
+ // printf("called verify");
+ }
+
+ // -- Next, if the issuer certificate cannot be verified against
+ // -- root CAs, compare the subject's certificate against the
+ // -- trusted certificates
+ shared_ptr <X509Certificate> firstCert =
+ dynamicCast <X509Certificate>(chain->getAt(0));
+
+ for (size_t i = 0 ; !trusted && i < m_x509TrustedCerts.size() ; ++i) {
+
+ shared_ptr <X509Certificate> cert = m_x509TrustedCerts[i];
+
+ if (firstCert->equals(cert)) {
+ trusted = true;
+ }
+ }
+
+ if (!trusted) {
+
+ certificateNotTrustedException ex;
+ ex.setCertificate(firstCert);
+
+ throw ex;
+ }
+
+ // Ensure the first certificate's subject name matches server hostname
+ if (!firstCert->verifyHostName(hostname)) {
+
+ serverIdentityException ex;
+ ex.setCertificate(firstCert);
+
+ throw ex;
+ }
+}
+
+
+void defaultCertificateVerifier::setX509RootCAs(
+ const std::vector <shared_ptr <X509Certificate> >& caCerts
+) {
+
+ m_x509RootCAs = caCerts;
+}
+
+
+void defaultCertificateVerifier::setX509TrustedCerts(
+ const std::vector <shared_ptr <X509Certificate> >& trustedCerts
+) {
+
+ m_x509TrustedCerts = trustedCerts;
+}
+
+
+} // cert
+} // security
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
diff --git a/vmime-master/src/vmime/security/cert/defaultCertificateVerifier.hpp b/vmime-master/src/vmime/security/cert/defaultCertificateVerifier.hpp
new file mode 100644
index 0000000..4aa4445
--- /dev/null
+++ b/vmime-master/src/vmime/security/cert/defaultCertificateVerifier.hpp
@@ -0,0 +1,98 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_SECURITY_CERT_DEFAULTCERTIFICATEVERIFIER_HPP_INCLUDED
+#define VMIME_SECURITY_CERT_DEFAULTCERTIFICATEVERIFIER_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+
+#include "vmime/security/cert/certificateVerifier.hpp"
+
+
+namespace vmime {
+namespace security {
+namespace cert {
+
+
+class X509Certificate;
+
+
+/** Default implementation for certificate verification.
+ */
+class VMIME_EXPORT defaultCertificateVerifier : public certificateVerifier {
+
+private:
+
+ defaultCertificateVerifier(const defaultCertificateVerifier&);
+
+public:
+
+ defaultCertificateVerifier();
+ ~defaultCertificateVerifier();
+
+ /** Sets a list of X.509 certificates that are trusted.
+ *
+ * @param trustedCerts list of trusted certificates
+ */
+ void setX509TrustedCerts(const std::vector <shared_ptr <X509Certificate> >& trustedCerts);
+
+ /** Sets the X.509 root CAs used for certificate verification.
+ *
+ * @param caCerts list of root CAs
+ */
+ void setX509RootCAs(const std::vector <shared_ptr <X509Certificate> >& caCerts);
+
+
+ // Implementation of 'certificateVerifier'
+ void verify(const shared_ptr <certificateChain>& chain, const string& hostname);
+
+private:
+
+ /** Verify a chain of X.509 certificates.
+ *
+ * @param chain list of X.509 certificates
+ * @param hostname server hostname
+ */
+ void verifyX509(const shared_ptr <certificateChain>& chain, const string& hostname);
+
+
+ std::vector <shared_ptr <X509Certificate> > m_x509RootCAs;
+ std::vector <shared_ptr <X509Certificate> > m_x509TrustedCerts;
+};
+
+
+} // cert
+} // security
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+
+#endif // VMIME_SECURITY_CERT_DEFAULTCERTIFICATEVERIFIER_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/security/cert/gnutls/X509Certificate_GnuTLS.cpp b/vmime-master/src/vmime/security/cert/gnutls/X509Certificate_GnuTLS.cpp
new file mode 100644
index 0000000..3dfa1c6
--- /dev/null
+++ b/vmime-master/src/vmime/security/cert/gnutls/X509Certificate_GnuTLS.cpp
@@ -0,0 +1,395 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
+
+
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+
+#include <ctime>
+
+#include "vmime/security/cert/gnutls/X509Certificate_GnuTLS.hpp"
+
+#include "vmime/utility/outputStreamByteArrayAdapter.hpp"
+
+
+namespace vmime {
+namespace security {
+namespace cert {
+
+
+#ifndef VMIME_BUILDING_DOC
+
+struct GnuTLSX509CertificateInternalData {
+
+ GnuTLSX509CertificateInternalData() {
+
+ gnutls_x509_crt_init(&cert);
+ }
+
+ ~GnuTLSX509CertificateInternalData() {
+
+ gnutls_x509_crt_deinit(cert);
+ }
+
+ void swap(gnutls_x509_crt_t to) {
+ gnutls_x509_crt_deinit(cert);
+ cert = to;
+ }
+
+
+ gnutls_x509_crt_t cert;
+};
+
+#endif // VMIME_BUILDING_DOC
+
+
+X509Certificate_GnuTLS::X509Certificate_GnuTLS()
+ : m_data(new GnuTLSX509CertificateInternalData) {
+
+}
+
+
+X509Certificate_GnuTLS::X509Certificate_GnuTLS(const X509Certificate&)
+ : X509Certificate(), m_data(NULL) {
+
+ // Not used
+}
+
+
+X509Certificate_GnuTLS::~X509Certificate_GnuTLS() {
+
+ delete m_data;
+}
+
+
+void* X509Certificate_GnuTLS::getInternalData() {
+
+ return &m_data->cert;
+}
+
+
+// static
+shared_ptr <X509Certificate> X509Certificate::import(
+ utility::inputStream& is
+) {
+
+ byteArray bytes;
+ byte_t chunk[4096];
+
+ while (!is.eof()) {
+ const size_t len = is.read(chunk, sizeof(chunk));
+ bytes.insert(bytes.end(), chunk, chunk + len);
+ }
+
+ return import(&bytes[0], bytes.size());
+}
+
+
+// static
+shared_ptr <X509Certificate> X509Certificate::import(
+ const byte_t* data,
+ const size_t length
+) {
+
+ gnutls_datum_t buffer;
+ buffer.data = const_cast <byte_t*>(data);
+ buffer.size = static_cast <unsigned int>(length);
+
+ // Try DER format
+ shared_ptr <X509Certificate_GnuTLS> derCert = make_shared <X509Certificate_GnuTLS>();
+
+ if (gnutls_x509_crt_import(derCert->m_data->cert, &buffer, GNUTLS_X509_FMT_DER) >= 0) {
+ return derCert;
+ }
+
+ // Try PEM format
+ shared_ptr <X509Certificate_GnuTLS> pemCert = make_shared <X509Certificate_GnuTLS>();
+
+ if (gnutls_x509_crt_import(pemCert->m_data->cert, &buffer, GNUTLS_X509_FMT_PEM) >= 0) {
+ return pemCert;
+ }
+
+ return null;
+}
+
+
+// static
+void X509Certificate::import(
+ utility::inputStream& is,
+ std::vector <shared_ptr <X509Certificate> >& certs
+) {
+
+ byteArray bytes;
+ byte_t chunk[4096];
+
+ while (!is.eof()) {
+ const size_t len = is.read(chunk, sizeof(chunk));
+ bytes.insert(bytes.end(), chunk, chunk + len);
+ }
+
+ import(&bytes[0], bytes.size(), certs);
+}
+
+
+// static
+void X509Certificate::import(
+ const byte_t* data,
+ const size_t length,
+ std::vector <shared_ptr <X509Certificate> >& certs
+) {
+
+ gnutls_datum_t buffer;
+ buffer.data = const_cast <byte_t*>(data);
+ buffer.size = static_cast <unsigned int>(length);
+
+ unsigned int size = 1024;
+ gnutls_x509_crt_t x509[1024];
+
+ // Try DER format
+ if (gnutls_x509_crt_list_import(x509, &size, &buffer, GNUTLS_X509_FMT_DER, 0) < 0) {
+
+ // Try PEM format
+ if (gnutls_x509_crt_list_import(x509, &size, &buffer, GNUTLS_X509_FMT_PEM, 0) < 0) {
+ return;
+ }
+ }
+
+ for (unsigned int i = 0 ; i < size ; i += 1) {
+
+ auto c = make_shared <X509Certificate_GnuTLS>();
+ c->m_data->swap(x509[i]);
+ certs.push_back(c);
+ }
+}
+
+
+void X509Certificate_GnuTLS::write(
+ utility::outputStream& os,
+ const Format format
+) const {
+
+ size_t dataSize = 0;
+ gnutls_x509_crt_fmt_t fmt = GNUTLS_X509_FMT_DER;
+
+ switch (format) {
+ case FORMAT_DER: fmt = GNUTLS_X509_FMT_DER; break;
+ case FORMAT_PEM: fmt = GNUTLS_X509_FMT_PEM; break;
+ }
+
+ gnutls_x509_crt_export(m_data->cert, fmt, NULL, &dataSize);
+
+ std::vector <byte_t> data(dataSize);
+
+ gnutls_x509_crt_export(m_data->cert, fmt, &data[0], &dataSize);
+
+ os.write(reinterpret_cast <byte_t*>(&data[0]), dataSize);
+}
+
+
+const byteArray X509Certificate_GnuTLS::getSerialNumber() const {
+
+ char serial[64];
+ size_t serialSize = sizeof(serial);
+
+ gnutls_x509_crt_get_serial(m_data->cert, serial, &serialSize);
+
+ return byteArray(serial, serial + serialSize);
+}
+
+
+bool X509Certificate_GnuTLS::checkIssuer(const shared_ptr <const X509Certificate>& issuer_) const {
+
+ shared_ptr <const X509Certificate_GnuTLS> issuer =
+ dynamicCast <const X509Certificate_GnuTLS>(issuer_);
+
+ return gnutls_x509_crt_check_issuer(m_data->cert, issuer->m_data->cert) >= 1;
+}
+
+
+bool X509Certificate_GnuTLS::verify(const shared_ptr <const X509Certificate>& caCert_) const {
+
+ shared_ptr <const X509Certificate_GnuTLS> caCert =
+ dynamicCast <const X509Certificate_GnuTLS>(caCert_);
+
+ unsigned int verify = 0;
+
+ const int res = gnutls_x509_crt_verify(
+ m_data->cert, &(caCert->m_data->cert), 1,
+ GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT,
+ &verify
+ );
+
+ return res == 0 && verify == 0;
+}
+
+
+bool X509Certificate_GnuTLS::verifyHostName(
+ const string& hostname,
+ std::vector <std::string>* nonMatchingNames
+) const {
+
+ if (gnutls_x509_crt_check_hostname(m_data->cert, hostname.c_str()) != 0) {
+ return true;
+ }
+
+ if (nonMatchingNames) {
+
+ const int MAX_CN = 256;
+ const char* OID_X520_COMMON_NAME = "2.5.4.3";
+
+ char dnsName[MAX_CN];
+ size_t dnsNameLength;
+
+ dnsNameLength = sizeof(dnsName);
+
+ if (gnutls_x509_crt_get_dn_by_oid(m_data->cert, OID_X520_COMMON_NAME, 0, 0, dnsName, &dnsNameLength) >= 0) {
+ nonMatchingNames->push_back(dnsName);
+ }
+
+ for (int i = 0, ret = 0 ; ret >= 0 ; ++i) {
+
+ dnsNameLength = sizeof(dnsName);
+ ret = gnutls_x509_crt_get_subject_alt_name(m_data->cert, i, dnsName, &dnsNameLength, NULL);
+
+ if (ret == GNUTLS_SAN_DNSNAME) {
+ nonMatchingNames->push_back(dnsName);
+ }
+ }
+ }
+
+ return false;
+}
+
+
+const datetime X509Certificate_GnuTLS::getActivationDate() const {
+
+ const time_t t = gnutls_x509_crt_get_activation_time(m_data->cert);
+ return datetime(t);
+}
+
+
+const datetime X509Certificate_GnuTLS::getExpirationDate() const {
+
+ const time_t t = gnutls_x509_crt_get_expiration_time(m_data->cert);
+ return datetime(t);
+}
+
+
+const byteArray X509Certificate_GnuTLS::getFingerprint(const DigestAlgorithm algo) const {
+
+ gnutls_digest_algorithm_t galgo;
+
+ switch (algo) {
+
+ case DIGEST_MD5:
+
+ galgo = GNUTLS_DIG_MD5;
+ break;
+
+ default:
+ case DIGEST_SHA1:
+
+ galgo = GNUTLS_DIG_SHA;
+ break;
+ }
+
+ size_t bufferSize = 0;
+ gnutls_x509_crt_get_fingerprint(m_data->cert, galgo, NULL, &bufferSize);
+
+ std::vector <byte_t> buffer(bufferSize);
+
+ if (gnutls_x509_crt_get_fingerprint(m_data->cert, galgo, &buffer[0], &bufferSize) == 0) {
+
+ byteArray res;
+ res.insert(res.end(), &buffer[0], &buffer[0] + bufferSize);
+
+ return res;
+ }
+
+ return byteArray();
+}
+
+
+const byteArray X509Certificate_GnuTLS::getEncoded() const {
+
+ byteArray bytes;
+ utility::outputStreamByteArrayAdapter os(bytes);
+
+ write(os, FORMAT_DER);
+
+ return bytes;
+}
+
+
+const string X509Certificate_GnuTLS::getIssuerString() const {
+
+ char buffer[4096];
+ size_t bufferSize = sizeof(buffer);
+
+ if (gnutls_x509_crt_get_issuer_dn(m_data->cert, buffer, &bufferSize) != GNUTLS_E_SUCCESS) {
+ return "";
+ }
+
+ return buffer;
+}
+
+
+const string X509Certificate_GnuTLS::getType() const {
+
+ return "X.509";
+}
+
+
+int X509Certificate_GnuTLS::getVersion() const {
+
+ return gnutls_x509_crt_get_version(m_data->cert);
+}
+
+
+bool X509Certificate_GnuTLS::equals(const shared_ptr <const certificate>& other) const {
+
+ shared_ptr <const X509Certificate_GnuTLS> otherX509 =
+ dynamicCast <const X509Certificate_GnuTLS>(other);
+
+ if (!otherX509) {
+ return false;
+ }
+
+ const byteArray fp1 = getFingerprint(DIGEST_MD5);
+ const byteArray fp2 = otherX509->getFingerprint(DIGEST_MD5);
+
+ return fp1 == fp2;
+}
+
+
+} // cert
+} // security
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
diff --git a/vmime-master/src/vmime/security/cert/gnutls/X509Certificate_GnuTLS.hpp b/vmime-master/src/vmime/security/cert/gnutls/X509Certificate_GnuTLS.hpp
new file mode 100644
index 0000000..c7c6c48
--- /dev/null
+++ b/vmime-master/src/vmime/security/cert/gnutls/X509Certificate_GnuTLS.hpp
@@ -0,0 +1,96 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_SECURITY_CERT_X509CERTIFICATE_GNUTLS_HPP_INCLUDED
+#define VMIME_SECURITY_CERT_X509CERTIFICATE_GNUTLS_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
+
+
+#include "vmime/security/cert/X509Certificate.hpp"
+
+
+namespace vmime {
+namespace security {
+namespace cert {
+
+
+class X509Certificate_GnuTLS : public X509Certificate {
+
+ friend class X509Certificate;
+
+ X509Certificate_GnuTLS(const X509Certificate&);
+
+public:
+
+ X509Certificate_GnuTLS();
+
+ ~X509Certificate_GnuTLS();
+
+
+ void write(utility::outputStream& os, const Format format) const;
+
+ const byteArray getSerialNumber() const;
+
+ const string getIssuerString() const;
+ bool checkIssuer(const shared_ptr <const X509Certificate>& issuer) const;
+
+ bool verify(const shared_ptr <const X509Certificate>& caCert) const;
+
+ bool verifyHostName(
+ const string& hostname,
+ std::vector <std::string>* nonMatchingNames = NULL
+ ) const;
+
+ const datetime getExpirationDate() const;
+ const datetime getActivationDate() const;
+
+ const byteArray getFingerprint(const DigestAlgorithm algo) const;
+
+
+ // Implementation of 'certificate'
+ const byteArray getEncoded() const;
+ const string getType() const;
+ int getVersion() const;
+ bool equals(const shared_ptr <const certificate>& other) const;
+ void* getInternalData();
+
+private:
+
+ struct GnuTLSX509CertificateInternalData* m_data;
+};
+
+
+} // cert
+} // security
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_GNUTLS
+
+#endif // VMIME_SECURITY_CERT_X509CERTIFICATE_GNUTLS_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/security/cert/openssl/X509Certificate_OpenSSL.cpp b/vmime-master/src/vmime/security/cert/openssl/X509Certificate_OpenSSL.cpp
new file mode 100644
index 0000000..5488801
--- /dev/null
+++ b/vmime-master/src/vmime/security/cert/openssl/X509Certificate_OpenSSL.cpp
@@ -0,0 +1,655 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+
+
+#include <cstdio>
+#include <ctime>
+#include <map>
+#include <algorithm>
+
+#include "vmime/security/cert/openssl/X509Certificate_OpenSSL.hpp"
+
+#include "vmime/net/tls/openssl/OpenSSLInitializer.hpp"
+
+#include "vmime/utility/outputStreamByteArrayAdapter.hpp"
+
+#include "vmime/security/cert/certificateException.hpp"
+#include "vmime/security/cert/unsupportedCertificateTypeException.hpp"
+
+#include <openssl/x509.h>
+#include <openssl/x509v3.h>
+#include <openssl/conf.h>
+#include <openssl/bio.h>
+#include <openssl/pem.h>
+#include <openssl/err.h>
+
+
+#ifdef _WIN32
+# define strcasecmp _stricmp
+# define strncasecmp _strnicmp
+#endif
+
+
+namespace vmime {
+namespace security {
+namespace cert {
+
+
+static net::tls::OpenSSLInitializer::autoInitializer openSSLInitializer;
+
+
+#ifndef VMIME_BUILDING_DOC
+
+class monthMap {
+
+public:
+
+ monthMap() {
+
+ m_monthMap["jan"] = vmime::datetime::JAN;
+ m_monthMap["feb"] = vmime::datetime::FEB;
+ m_monthMap["mar"] = vmime::datetime::MAR;
+ m_monthMap["apr"] = vmime::datetime::APR;
+ m_monthMap["may"] = vmime::datetime::MAY;
+ m_monthMap["jun"] = vmime::datetime::JUN;
+ m_monthMap["jul"] = vmime::datetime::JUL;
+ m_monthMap["aug"] = vmime::datetime::AUG;
+ m_monthMap["sep"] = vmime::datetime::SEP;
+ m_monthMap["oct"] = vmime::datetime::OCT;
+ m_monthMap["nov"] = vmime::datetime::NOV;
+ m_monthMap["dec"] = vmime::datetime::DEC;
+ }
+
+ int getMonth(vmime::string mstr) {
+
+ std::transform(mstr.begin(), mstr.end(), mstr.begin(), ::tolower);
+
+ std::map <vmime::string, vmime::datetime::Months>::const_iterator
+ c_it = m_monthMap.find(mstr);
+
+ if (c_it != m_monthMap.end()) {
+ return c_it->second;
+ }
+
+ return -1;
+ }
+
+private:
+
+ std::map<vmime::string, vmime::datetime::Months> m_monthMap;
+};
+
+static monthMap sg_monthMap;
+
+
+
+struct OpenSSLX509CertificateInternalData {
+
+ OpenSSLX509CertificateInternalData() {
+
+ cert = 0;
+ }
+
+ ~OpenSSLX509CertificateInternalData() {
+
+ if (cert) {
+ X509_free(cert);
+ }
+ }
+
+ X509* cert;
+};
+
+
+// Workaround for i2v() taking either a const or a non-const 'method' on some platforms
+STACK_OF(CONF_VALUE)* call_i2v(const X509V3_EXT_METHOD* m, void* p1, STACK_OF(CONF_VALUE)* p2) {
+
+ return m->i2v(m, p1, p2);
+}
+
+
+STACK_OF(CONF_VALUE)* call_i2v(X509V3_EXT_METHOD* m, void* p1, STACK_OF(CONF_VALUE)* p2) {
+
+ return m->i2v(m, p1, p2);
+}
+
+
+#endif // VMIME_BUILDING_DOC
+
+
+X509Certificate_OpenSSL::X509Certificate_OpenSSL()
+ : m_data(new OpenSSLX509CertificateInternalData) {
+
+}
+
+
+X509Certificate_OpenSSL::X509Certificate_OpenSSL(X509* cert)
+ : m_data(new OpenSSLX509CertificateInternalData) {
+
+ m_data->cert = X509_dup(cert);
+}
+
+
+X509Certificate_OpenSSL::X509Certificate_OpenSSL(const X509Certificate_OpenSSL&)
+ : X509Certificate(), m_data(NULL) {
+
+ // Not used
+}
+
+
+X509Certificate_OpenSSL::~X509Certificate_OpenSSL() {
+
+ delete m_data;
+}
+
+
+void* X509Certificate_OpenSSL::getInternalData() {
+
+ return &m_data->cert;
+}
+
+
+// static
+shared_ptr <X509Certificate> X509Certificate_OpenSSL::importInternal(X509* cert) {
+
+ if (cert) {
+ return make_shared <X509Certificate_OpenSSL>(reinterpret_cast <X509 *>(cert));
+ }
+
+ return null;
+}
+
+
+// static
+shared_ptr <X509Certificate> X509Certificate::import(utility::inputStream& is) {
+
+ byteArray bytes;
+ byte_t chunk[4096];
+
+ while (!is.eof()) {
+ const size_t len = is.read(chunk, sizeof(chunk));
+ bytes.insert(bytes.end(), chunk, chunk + len);
+ }
+
+ return import(&bytes[0], bytes.size());
+}
+
+
+// static
+shared_ptr <X509Certificate> X509Certificate::import(
+ const byte_t* data,
+ const size_t length
+) {
+
+ shared_ptr <X509Certificate_OpenSSL> cert = make_shared <X509Certificate_OpenSSL>();
+
+ BIO* membio = BIO_new_mem_buf(const_cast <byte_t*>(data), static_cast <int>(length));
+
+ if (!(cert->m_data->cert = d2i_X509_bio(membio, NULL))
+ /*!PEM_read_bio_X509(membio, &(cert->m_data->cert), 0, 0)*/) {
+ BIO_vfree(membio);
+ return null;
+ }
+
+ BIO_vfree(membio);
+
+ return cert;
+}
+
+
+// static
+void X509Certificate::import(
+ utility::inputStream& is,
+ std::vector <shared_ptr <X509Certificate> >& certs
+) {
+
+ byteArray bytes;
+ byte_t chunk[4096];
+
+ while (!is.eof()) {
+ const size_t len = is.read(chunk, sizeof(chunk));
+ bytes.insert(bytes.end(), chunk, chunk + len);
+ }
+
+ import(&bytes[0], bytes.size(), certs);
+}
+
+
+// static
+void X509Certificate::import(
+ const byte_t* data,
+ const size_t length,
+ std::vector <shared_ptr <X509Certificate> >& certs
+) {
+
+ BIO* membio = BIO_new_mem_buf(const_cast <byte_t*>(data), static_cast <int>(length));
+ shared_ptr <X509Certificate_OpenSSL> cert = null;
+
+ while (true) {
+
+ cert = make_shared <X509Certificate_OpenSSL>();
+
+ if (!PEM_read_bio_X509(membio, &(cert->m_data->cert), 0, 0)) {
+ break;
+ }
+
+ certs.push_back(cert);
+ }
+
+ BIO_vfree(membio);
+}
+
+
+void X509Certificate_OpenSSL::write(
+ utility::outputStream& os,
+ const Format format
+) const {
+
+ BIO* membio = 0;
+ long dataSize = 0;
+ unsigned char* out = 0;
+
+ if (format == FORMAT_DER) {
+
+ if ((dataSize = i2d_X509(m_data->cert, &out)) < 0) {
+ goto err;
+ }
+
+ os.write(reinterpret_cast <byte_t*>(out), dataSize);
+ os.flush();
+ OPENSSL_free(out);
+
+ } else if (format == FORMAT_PEM) {
+
+ membio = BIO_new(BIO_s_mem());
+ BIO_set_close(membio, BIO_CLOSE);
+
+ if (!PEM_write_bio_X509(membio, m_data->cert)) {
+ goto pem_err;
+ }
+
+ dataSize = BIO_get_mem_data(membio, &out);
+ os.write(reinterpret_cast <byte_t*>(out), dataSize);
+ os.flush();
+ BIO_vfree(membio);
+
+ } else {
+
+ throw unsupportedCertificateTypeException("Unknown format");
+ }
+
+ return; // #### Early Return ####
+
+pem_err:
+ {
+ if (membio) {
+ BIO_vfree(membio);
+ }
+ }
+
+err:
+ {
+ char errstr[256];
+ long ec = ERR_get_error();
+ ERR_error_string(ec, errstr);
+ throw certificateException("OpenSSLX509Certificate_OpenSSL::write exception - " + string(errstr));
+ }
+}
+
+
+const byteArray X509Certificate_OpenSSL::getSerialNumber() const {
+
+ ASN1_INTEGER *serial = X509_get_serialNumber(m_data->cert);
+ BIGNUM *bnser = ASN1_INTEGER_to_BN(serial, NULL);
+ int n = BN_num_bytes(bnser);
+ byte_t* outbuf = new byte_t[n];
+ BN_bn2bin(bnser, outbuf);
+ byteArray ser(outbuf, outbuf + n);
+ delete [] outbuf;
+ BN_free(bnser);
+ return ser;
+}
+
+
+bool X509Certificate_OpenSSL::checkIssuer(const shared_ptr <const X509Certificate>& cert_) const {
+
+ shared_ptr <const X509Certificate_OpenSSL> cert =
+ dynamicCast <const X509Certificate_OpenSSL>(cert_);
+
+ // Get issuer for this cert
+ BIO *out;
+ unsigned char *issuer;
+
+ out = BIO_new(BIO_s_mem());
+ X509_NAME_print_ex(out, X509_get_issuer_name(m_data->cert), 0, XN_FLAG_RFC2253);
+ long n = BIO_get_mem_data(out, &issuer);
+ vmime::string thisIssuerName((char*)issuer, n);
+ BIO_free(out);
+
+ // Get subject of issuer
+ unsigned char *subject;
+ out = BIO_new(BIO_s_mem());
+ X509_NAME_print_ex(out, X509_get_subject_name(cert->m_data->cert), 0, XN_FLAG_RFC2253);
+ n = BIO_get_mem_data(out, &subject);
+ vmime::string subjOfIssuer((char*)subject, n);
+ BIO_free(out);
+
+ return subjOfIssuer == thisIssuerName;
+}
+
+
+bool X509Certificate_OpenSSL::verify(const shared_ptr <const X509Certificate>& caCert_) const {
+
+ shared_ptr <const X509Certificate_OpenSSL> caCert =
+ dynamicCast <const X509Certificate_OpenSSL>(caCert_);
+
+// printf("ptr before cast is %p\n", caCert_.get());
+// printf("ptr is %p\n", caCert.get());
+
+ bool verified = false;
+ bool error = true;
+
+ X509_STORE *store = X509_STORE_new();
+
+ if (store) {
+
+ X509_STORE_CTX *verifyCtx = X509_STORE_CTX_new();
+
+ if (verifyCtx) {
+
+ if (X509_STORE_add_cert(store, caCert->m_data->cert)) {
+
+ X509_STORE_CTX_init(verifyCtx, store, m_data->cert, NULL);
+
+ int ret = X509_verify_cert(verifyCtx);
+
+ if (ret == 1) {
+
+ verified = true;
+ error = false;
+
+ } else if (ret == 0) {
+
+ verified = false;
+ error = false;
+ }
+
+ //X509_verify_cert_error_string(vrfy_ctx->error)
+
+ X509_STORE_CTX_free(verifyCtx);
+ }
+ }
+
+ X509_STORE_free(store);
+ }
+
+ return verified && !error;
+}
+
+
+// static
+bool X509Certificate_OpenSSL::cnMatch(const char* cnBuf, const char* host) {
+
+ // Right-to-left match, looking for a '*' wildcard
+ const bool hasWildcard = (strlen(cnBuf) > 1 && cnBuf[0] == '*' && cnBuf[1] == '.');
+ const char* cnBufReverseEndPtr = (cnBuf + (hasWildcard ? 2 : 0));
+ const char* hostPtr = host + strlen(host);
+ const char* cnPtr = cnBuf + strlen(cnBuf);
+
+ bool matches = true;
+
+ while (matches && --hostPtr >= host && --cnPtr >= cnBufReverseEndPtr) {
+ matches = (toupper(*hostPtr) == toupper(*cnPtr));
+ }
+
+ return matches;
+}
+
+
+bool X509Certificate_OpenSSL::verifyHostName(
+ const string& hostname,
+ std::vector <std::string>* nonMatchingNames
+) const {
+
+ // First, check subject common name against hostname
+ char CNBuffer[1024];
+ CNBuffer[sizeof(CNBuffer) - 1] = '\0';
+
+ X509_NAME* xname = X509_get_subject_name(m_data->cert);
+
+ if (X509_NAME_get_text_by_NID(xname, NID_commonName, CNBuffer, sizeof(CNBuffer)) != -1) {
+
+ if (cnMatch(CNBuffer, hostname.c_str())) {
+ return true;
+ }
+
+ if (nonMatchingNames) {
+ nonMatchingNames->push_back(CNBuffer);
+ }
+ }
+
+ // Now, look in subject alternative names
+ bool verify = false;
+
+ STACK_OF(GENERAL_NAME)* altNames = static_cast <GENERAL_NAMES*>
+ (X509_get_ext_d2i(m_data->cert, NID_subject_alt_name, NULL, NULL));
+
+ if (altNames == NULL) {
+ return false;
+ }
+
+ // Check each name within the extension
+ for (int i = 0, n = sk_GENERAL_NAME_num(altNames) ; i < n ; ++i) {
+
+ const GENERAL_NAME* currentName = sk_GENERAL_NAME_value(altNames, i);
+
+ if (currentName->type == GEN_DNS) {
+
+ // Current name is a DNS name, let's check it
+ char *DNSName = (char *) ASN1_STRING_data(currentName->d.dNSName);
+
+ // Make sure there isn't an embedded NUL character in the DNS name
+ if (ASN1_STRING_length(currentName->d.dNSName) != strlen(DNSName)) {
+ // Malformed certificate
+ break;
+ }
+
+ if (cnMatch(DNSName, hostname.c_str())) {
+ verify = true;
+ break;
+ }
+
+ if (nonMatchingNames) {
+ nonMatchingNames->push_back(DNSName);
+ }
+ }
+ }
+
+ sk_GENERAL_NAME_pop_free(altNames, GENERAL_NAME_free);
+
+ return verify;
+}
+
+
+const datetime X509Certificate_OpenSSL::convertX509Date(void* time) const {
+
+ char* buffer;
+ BIO* out = BIO_new(BIO_s_mem());
+ BIO_set_close(out, BIO_CLOSE);
+
+ ASN1_TIME* asn1_time = reinterpret_cast<ASN1_TIME*>(time);
+ ASN1_TIME_print(out, asn1_time);
+
+ const long sz = BIO_get_mem_data(out, &buffer);
+ char* dest = new char[sz + 1];
+ dest[sz] = 0;
+ memcpy(dest, buffer, sz);
+ vmime::string t(dest);
+
+ BIO_free(out);
+ delete [] dest;
+
+ if (t.size() > 0) {
+
+ char month[4] = {0};
+ char zone[4] = {0};
+ int day, hour, minute, second, year;
+ int nrconv = sscanf(t.c_str(), "%s %2d %02d:%02d:%02d %d%s", month, &day, &hour, &minute, &second,&year,zone);
+
+ if (nrconv >= 6) {
+ return datetime(year, sg_monthMap.getMonth(vmime::string(month)), day, hour, minute, second);
+ }
+ }
+
+ // let datetime try and parse it
+ return datetime(t);
+}
+
+
+const datetime X509Certificate_OpenSSL::getActivationDate() const {
+
+ return convertX509Date(X509_get_notBefore(m_data->cert));
+}
+
+
+const datetime X509Certificate_OpenSSL::getExpirationDate() const {
+
+ return convertX509Date(X509_get_notAfter(m_data->cert));
+}
+
+
+const byteArray X509Certificate_OpenSSL::getFingerprint(const DigestAlgorithm algo) const {
+
+ BIO *out;
+ int j;
+ unsigned int n;
+ const EVP_MD *digest;
+ unsigned char * fingerprint;
+ unsigned char md[EVP_MAX_MD_SIZE];
+
+ switch (algo) {
+
+ case DIGEST_MD5:
+
+ digest = EVP_md5();
+ break;
+
+ default:
+ case DIGEST_SHA1:
+
+ digest = EVP_sha1();
+ break;
+ }
+
+ out = BIO_new(BIO_s_mem());
+ BIO_set_close(out, BIO_CLOSE);
+
+ if (X509_digest(m_data->cert, digest, md, &n)) {
+
+ for (j = 0 ; j < (int) n ; j++) {
+ BIO_printf(out, "%02X", md[j]);
+ if (j + 1 != (int) n) BIO_printf(out, ":");
+ }
+ }
+
+ const long resultLen = BIO_get_mem_data(out, &fingerprint);
+ unsigned char* result = new unsigned char[resultLen];
+ memcpy(result, fingerprint, resultLen);
+ BIO_free(out);
+
+ byteArray res;
+ res.insert(res.end(), &result[0], &result[0] + resultLen);
+
+ delete [] result;
+
+ return res;
+}
+
+
+const byteArray X509Certificate_OpenSSL::getEncoded() const {
+
+ byteArray bytes;
+ utility::outputStreamByteArrayAdapter os(bytes);
+
+ write(os, FORMAT_DER);
+
+ return bytes;
+}
+
+
+const string X509Certificate_OpenSSL::getIssuerString() const {
+
+ // Get issuer for this cert
+ BIO* out = BIO_new(BIO_s_mem());
+ X509_NAME_print_ex(out, X509_get_issuer_name(m_data->cert), 0, XN_FLAG_RFC2253);
+
+ unsigned char* issuer;
+ const long n = BIO_get_mem_data(out, &issuer);
+
+ vmime::string name(reinterpret_cast <char*>(issuer), n);
+ BIO_free(out);
+
+ return name;
+}
+
+
+const string X509Certificate_OpenSSL::getType() const {
+
+ return "X.509";
+}
+
+
+int X509Certificate_OpenSSL::getVersion() const {
+
+ return (int) X509_get_version(m_data->cert);
+}
+
+
+bool X509Certificate_OpenSSL::equals(const shared_ptr <const certificate>& other) const {
+
+ shared_ptr <const X509Certificate_OpenSSL> otherX509 =
+ dynamicCast <const X509Certificate_OpenSSL>(other);
+
+ if (!otherX509) {
+ return false;
+ }
+
+ const byteArray fp1 = getFingerprint(DIGEST_MD5);
+ const byteArray fp2 = otherX509->getFingerprint(DIGEST_MD5);
+
+ return fp1 == fp2;
+}
+
+
+} // cert
+} // security
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+
diff --git a/vmime-master/src/vmime/security/cert/openssl/X509Certificate_OpenSSL.hpp b/vmime-master/src/vmime/security/cert/openssl/X509Certificate_OpenSSL.hpp
new file mode 100644
index 0000000..c0ebf3c
--- /dev/null
+++ b/vmime-master/src/vmime/security/cert/openssl/X509Certificate_OpenSSL.hpp
@@ -0,0 +1,119 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_SECURITY_CERT_X509CERTIFICATE_OPENSSL_HPP_INCLUDED
+#define VMIME_SECURITY_CERT_X509CERTIFICATE_OPENSSL_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+
+
+#include "vmime/security/cert/X509Certificate.hpp"
+
+#include <openssl/x509.h>
+
+
+namespace vmime {
+namespace security {
+namespace cert {
+
+
+class X509Certificate_OpenSSL : public X509Certificate {
+
+ friend class X509Certificate;
+
+ X509Certificate_OpenSSL(const X509Certificate_OpenSSL&);
+
+public:
+
+ X509Certificate_OpenSSL();
+ X509Certificate_OpenSSL(X509* cert);
+
+ ~X509Certificate_OpenSSL();
+
+
+ void write(utility::outputStream& os, const Format format) const;
+
+ const byteArray getSerialNumber() const;
+
+ const string getIssuerString() const;
+ bool checkIssuer(const shared_ptr <const X509Certificate>& issuer) const;
+
+ bool verify(const shared_ptr <const X509Certificate>& caCert) const;
+
+ bool verifyHostName(
+ const string& hostname,
+ std::vector <std::string>* nonMatchingNames = NULL
+ ) const;
+
+ const datetime getExpirationDate() const;
+ const datetime getActivationDate() const;
+
+ const byteArray getFingerprint(const DigestAlgorithm algo) const;
+
+
+ static shared_ptr <X509Certificate> importInternal(X509* cert);
+
+
+ // Implementation of 'certificate'
+ const byteArray getEncoded() const;
+ const string getType() const;
+ int getVersion() const;
+ bool equals(const shared_ptr <const certificate>& other) const;
+ void* getInternalData();
+
+private:
+
+ /** Internal utility function to test whether a hostname matches
+ * the specified X509 Common Name (wildcard is supported).
+ *
+ * @param cnBuf pointer to buffer holding Common Name
+ * @param host pointer to buffer holding host name
+ * @return true if the hostname matches the Common Name, or
+ * false otherwise
+ */
+ static bool cnMatch(const char* cnBuf, const char* host);
+
+ /** Internal utility function to convert ASN1_TIME
+ * structs to vmime::datetime
+ *
+ * @param pointer to ASN1_TIME struct to convert
+ */
+ const datetime convertX509Date(void* time) const;
+
+ struct OpenSSLX509CertificateInternalData* m_data;
+};
+
+
+} // cert
+} // security
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT && VMIME_TLS_SUPPORT_LIB_IS_OPENSSL
+
+#endif // VMIME_SECURITY_CERT_X509CERTIFICATE_OPENSSL_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/security/cert/serverIdentityException.cpp b/vmime-master/src/vmime/security/cert/serverIdentityException.cpp
new file mode 100644
index 0000000..fcbe571
--- /dev/null
+++ b/vmime-master/src/vmime/security/cert/serverIdentityException.cpp
@@ -0,0 +1,55 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+
+#include "vmime/security/cert/serverIdentityException.hpp"
+
+
+namespace vmime {
+namespace security {
+namespace cert {
+
+
+serverIdentityException::serverIdentityException()
+ : certificateException("Server identity cannot be verified.") {
+
+}
+
+
+exception* serverIdentityException::clone() const {
+
+ return new serverIdentityException();
+}
+
+
+} // cert
+} // security
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
diff --git a/vmime-master/src/vmime/security/cert/serverIdentityException.hpp b/vmime-master/src/vmime/security/cert/serverIdentityException.hpp
new file mode 100644
index 0000000..358553e
--- /dev/null
+++ b/vmime-master/src/vmime/security/cert/serverIdentityException.hpp
@@ -0,0 +1,65 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_SECURITY_CERT_SERVERIDENTITYEXCEPTION_HPP_INCLUDED
+#define VMIME_SECURITY_CERT_SERVERIDENTITYEXCEPTION_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+
+#include "vmime/security/cert/certificate.hpp"
+#include "vmime/security/cert/certificateException.hpp"
+
+
+namespace vmime {
+namespace security {
+namespace cert {
+
+
+/** Thrown when the subject name of a certificate does not match
+ * the hostname of the server.
+ */
+class VMIME_EXPORT serverIdentityException : public certificateException {
+
+public:
+
+ /** Constructs a serverIdentityException with no detail message.
+ */
+ serverIdentityException();
+
+ exception* clone() const;
+};
+
+
+} // cert
+} // security
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+#endif // VMIME_SECURITY_CERT_SERVERIDENTITYEXCEPTION_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/security/cert/unsupportedCertificateTypeException.cpp b/vmime-master/src/vmime/security/cert/unsupportedCertificateTypeException.cpp
new file mode 100644
index 0000000..5765651
--- /dev/null
+++ b/vmime-master/src/vmime/security/cert/unsupportedCertificateTypeException.cpp
@@ -0,0 +1,61 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+
+#include "vmime/security/cert/unsupportedCertificateTypeException.hpp"
+
+
+namespace vmime {
+namespace security {
+namespace cert {
+
+
+unsupportedCertificateTypeException::unsupportedCertificateTypeException(const string& type)
+ : certificateException(string("Unsupported certificate type: '") + type + "'."),
+ m_type(type) {
+
+}
+
+
+unsupportedCertificateTypeException::~unsupportedCertificateTypeException() throw() {
+
+}
+
+
+exception* unsupportedCertificateTypeException::clone() const {
+
+ return new unsupportedCertificateTypeException(m_type);
+}
+
+
+} // cert
+} // security
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
diff --git a/vmime-master/src/vmime/security/cert/unsupportedCertificateTypeException.hpp b/vmime-master/src/vmime/security/cert/unsupportedCertificateTypeException.hpp
new file mode 100644
index 0000000..725035f
--- /dev/null
+++ b/vmime-master/src/vmime/security/cert/unsupportedCertificateTypeException.hpp
@@ -0,0 +1,72 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_SECURITY_CERT_UNSUPPORTEDCERTIFICATETYPEEXCEPTION_HPP_INCLUDED
+#define VMIME_SECURITY_CERT_UNSUPPORTEDCERTIFICATETYPEEXCEPTION_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+
+#include "vmime/security/cert/certificate.hpp"
+#include "vmime/security/cert/certificateException.hpp"
+
+
+namespace vmime {
+namespace security {
+namespace cert {
+
+
+/** Thrown when a certificate is of unsupported format.
+ */
+class VMIME_EXPORT unsupportedCertificateTypeException : public certificateException {
+
+public:
+
+ /** Constructs a unsupportedCertificateTypeException.
+ *
+ * @param type certificate type
+ */
+ unsupportedCertificateTypeException(const string& type);
+
+ ~unsupportedCertificateTypeException() throw();
+
+ exception* clone() const;
+
+private:
+
+ string m_type;
+};
+
+
+} // cert
+} // security
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_TLS_SUPPORT
+
+#endif // VMIME_SECURITY_CERT_UNSUPPORTEDCERTIFICATETYPEEXCEPTION_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/security/defaultAuthenticator.cpp b/vmime-master/src/vmime/security/defaultAuthenticator.cpp
new file mode 100644
index 0000000..86c29d3
--- /dev/null
+++ b/vmime-master/src/vmime/security/defaultAuthenticator.cpp
@@ -0,0 +1,130 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+#include "vmime/security/defaultAuthenticator.hpp"
+
+#include "vmime/net/service.hpp"
+
+#include "vmime/platform.hpp"
+
+
+namespace vmime {
+namespace security {
+
+
+defaultAuthenticator::defaultAuthenticator() {
+
+}
+
+
+defaultAuthenticator::~defaultAuthenticator() {
+
+}
+
+
+const string defaultAuthenticator::getUsername() const {
+
+ shared_ptr <const net::service> service = m_service.lock();
+
+ const string prefix = service->getInfos().getPropertyPrefix();
+ const propertySet& props = service->getSession()->getProperties();
+
+ if (props.hasProperty(prefix + net::serviceInfos::property::AUTH_USERNAME.getName())) {
+ return props[prefix + net::serviceInfos::property::AUTH_USERNAME.getName()];
+ }
+
+ throw exceptions::no_auth_information();
+}
+
+
+const string defaultAuthenticator::getPassword() const {
+
+ shared_ptr <const net::service> service = m_service.lock();
+
+ const string prefix = service->getInfos().getPropertyPrefix();
+ const propertySet& props = service->getSession()->getProperties();
+
+ if (props.hasProperty(prefix + net::serviceInfos::property::AUTH_PASSWORD.getName())) {
+ return props[prefix + net::serviceInfos::property::AUTH_PASSWORD.getName()];
+ }
+
+ throw exceptions::no_auth_information();
+}
+
+
+const string defaultAuthenticator::getAccessToken() const {
+
+ shared_ptr <const net::service> service = m_service.lock();
+
+ const string prefix = service->getInfos().getPropertyPrefix();
+ const propertySet& props = service->getSession()->getProperties();
+
+ if (props.hasProperty(prefix + net::serviceInfos::property::AUTH_ACCESS_TOKEN.getName())) {
+ return props[prefix + net::serviceInfos::property::AUTH_ACCESS_TOKEN.getName()];
+ }
+
+ throw exceptions::no_auth_information();
+}
+
+
+const string defaultAuthenticator::getHostname() const {
+
+ return platform::getHandler()->getHostName();
+}
+
+
+const string defaultAuthenticator::getAnonymousToken() const {
+
+ return "anonymous@" + platform::getHandler()->getHostName();
+}
+
+
+const string defaultAuthenticator::getServiceName() const {
+
+ // Information cannot be provided
+ throw exceptions::no_auth_information();
+}
+
+
+void defaultAuthenticator::setService(const shared_ptr <net::service>& serv) {
+
+ m_service = serv;
+}
+
+
+weak_ptr <net::service> defaultAuthenticator::getService() const {
+
+ return m_service;
+}
+
+
+} // security
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
diff --git a/vmime-master/src/vmime/security/defaultAuthenticator.hpp b/vmime-master/src/vmime/security/defaultAuthenticator.hpp
new file mode 100644
index 0000000..e053f9e
--- /dev/null
+++ b/vmime-master/src/vmime/security/defaultAuthenticator.hpp
@@ -0,0 +1,73 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_SECURITY_DEFAULTAUTHENTICATOR_HPP_INCLUDED
+#define VMIME_SECURITY_DEFAULTAUTHENTICATOR_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/security/authenticator.hpp"
+
+
+namespace vmime {
+namespace security {
+
+
+/** An authenticator that can provide some basic information by
+ * reading in the messaging session properties.
+ */
+class VMIME_EXPORT defaultAuthenticator : public authenticator {
+
+public:
+
+ defaultAuthenticator();
+ ~defaultAuthenticator();
+
+ const string getUsername() const;
+ const string getPassword() const;
+ const string getHostname() const;
+ const string getAnonymousToken() const;
+ const string getServiceName() const;
+ const string getAccessToken() const;
+
+ void setService(const shared_ptr <net::service>& serv);
+ weak_ptr <net::service> getService() const;
+
+private:
+
+ weak_ptr <net::service> m_service;
+};
+
+
+} // security
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+#endif // VMIME_SECURITY_DEFAULTAUTHENTICATOR_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/security/digest/md5/md5MessageDigest.cpp b/vmime-master/src/vmime/security/digest/md5/md5MessageDigest.cpp
new file mode 100644
index 0000000..9a07b57
--- /dev/null
+++ b/vmime-master/src/vmime/security/digest/md5/md5MessageDigest.cpp
@@ -0,0 +1,349 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+//
+// Derived from cryptoapi implementation, originally based on the
+// public domain implementation written by Colin Plumb in 1993.
+//
+// Copyright (C) Cryptoapi developers.
+//
+// Algorithm Copyright:
+//
+// Copyright (C) 1991-2, RSA Data Security, Inc. Created 1991. All
+// rights reserved.
+//
+// License to copy and use this software is granted provided that it
+// is identified as the "RSA Data Security, Inc. MD5 Message-Digest
+// Algorithm" in all material mentioning or referencing this software
+// or this function.
+//
+// License is also granted to make and use derivative works provided
+// that such works are identified as "derived from the RSA Data
+// Security, Inc. MD5 Message-Digest Algorithm" in all material
+// mentioning or referencing the derived work.
+//
+// RSA Data Security, Inc. makes no representations concerning either
+// the merchantability of this software or the suitability of this
+// software forany particular purpose. It is provided "as is"
+// without express or implied warranty of any kind.
+// These notices must be retained in any copies of any part of this
+// documentation and/or software.
+
+#include "vmime/security/digest/md5/md5MessageDigest.hpp"
+
+#include <cstring>
+
+
+namespace vmime {
+namespace security {
+namespace digest {
+namespace md5 {
+
+
+md5MessageDigest::md5MessageDigest() {
+
+ init();
+}
+
+
+void md5MessageDigest::reset() {
+
+ init();
+}
+
+
+void md5MessageDigest::init() {
+
+ m_hash[0] = 0x67452301;
+ m_hash[1] = 0xefcdab89;
+ m_hash[2] = 0x98badcfe;
+ m_hash[3] = 0x10325476;
+
+ m_byteCount = 0;
+ m_finalized = false;
+}
+
+
+static void copyUint8Array(vmime_uint8* dest, const vmime_uint8* src, size_t count) {
+
+ for ( ; count >= 4 ; count -= 4, dest += 4, src += 4) {
+ dest[0] = src[0];
+ dest[1] = src[1];
+ dest[2] = src[2];
+ dest[3] = src[3];
+ }
+
+ for ( ; count ; --count, ++dest, ++src) {
+ dest[0] = src[0];
+ }
+}
+
+
+static inline vmime_uint32 swapUint32(const vmime_uint32 D) {
+
+ return ((D << 24) | ((D << 8) & 0x00FF0000) | ((D >> 8) & 0x0000FF00) | (D >> 24));
+}
+
+
+static inline void swapUint32Array(vmime_uint32* buf, size_t words) {
+
+ for ( ; words >= 4 ; words -= 4, buf += 4) {
+ buf[0] = swapUint32(buf[0]);
+ buf[1] = swapUint32(buf[1]);
+ buf[2] = swapUint32(buf[2]);
+ buf[3] = swapUint32(buf[3]);
+ }
+
+ for ( ; words ; --words, ++buf) {
+ buf[0] = swapUint32(buf[0]);
+ }
+}
+
+
+void md5MessageDigest::update(const byte_t b) {
+
+ update(&b, 1);
+}
+
+
+void md5MessageDigest::update(const string& s) {
+
+ update(reinterpret_cast <const byte_t*>(s.data()), s.length());
+}
+
+
+void md5MessageDigest::update(const byte_t* data, const size_t offset, const size_t len) {
+
+ update(data + offset, len);
+}
+
+
+void md5MessageDigest::update(const byte_t* data, const size_t length) {
+
+ const size_t avail = 64 - (m_byteCount & 0x3f);
+ size_t len = length;
+
+ m_byteCount += len;
+
+ if (avail > len) {
+ copyUint8Array(m_block.b8 + (64 - avail), data, len);
+ return;
+ }
+
+ copyUint8Array(m_block.b8 + (64 - avail), data, avail);
+ transformHelper();
+
+ data += avail;
+ len -= avail;
+
+ while (len >= 64) {
+
+ copyUint8Array(m_block.b8, data, 64);
+ transformHelper();
+
+ data += 64;
+ len -= 64;
+ }
+
+ copyUint8Array(m_block.b8, data, len);
+}
+
+
+void md5MessageDigest::finalize(const string& s) {
+
+ update(s);
+ finalize();
+}
+
+
+void md5MessageDigest::finalize(const byte_t* buffer, const size_t len) {
+
+ update(buffer, len);
+ finalize();
+}
+
+
+void md5MessageDigest::finalize(
+ const byte_t* buffer,
+ const size_t offset,
+ const size_t len
+) {
+
+ update(buffer, offset, len);
+ finalize();
+}
+
+
+void md5MessageDigest::finalize() {
+
+ const long offset = m_byteCount & 0x3f;
+
+ vmime_uint8* p = m_block.b8 + offset;
+ long padding = 56 - (offset + 1);
+
+ *p++ = 0x80;
+
+ if (padding < 0) {
+
+ memset(p, 0x00, padding + 8);
+ transformHelper();
+ p = m_block.b8;
+ padding = 56;
+ }
+
+ memset(p, 0, padding);
+
+ m_block.b32[14] = static_cast <vmime_uint32>(m_byteCount << 3);
+ m_block.b32[15] = static_cast <vmime_uint32>(m_byteCount >> 29);
+
+#if VMIME_BYTE_ORDER_BIG_ENDIAN
+ swapUint32Array(m_block.b32, (64 - 8) / 4);
+#endif
+
+ transform();
+
+#if VMIME_BYTE_ORDER_BIG_ENDIAN
+ swapUint32Array(m_hash, 4);
+#endif
+
+ m_finalized = true;
+}
+
+
+void md5MessageDigest::transformHelper() {
+
+#if VMIME_BYTE_ORDER_BIG_ENDIAN
+ swapUint32Array(m_block.b32, 64 / 4);
+#endif
+ transform();
+}
+
+
+void md5MessageDigest::transform() {
+
+ const vmime_uint32* const in = m_block.b32;
+
+ vmime_uint32 a = m_hash[0];
+ vmime_uint32 b = m_hash[1];
+ vmime_uint32 c = m_hash[2];
+ vmime_uint32 d = m_hash[3];
+
+#define F1(x, y, z) (z ^ (x & (y ^ z)))
+#define F2(x, y, z) F1(z, x, y)
+#define F3(x, y, z) (x ^ y ^ z)
+#define F4(x, y, z) (y ^ (x | ~z))
+
+#define MD5STEP(f, w, x, y, z, in, s) \
+ (w += f(x, y, z) + in, w = (w<<s | w>>(32-s)) + x)
+
+ MD5STEP(F1, a, b, c, d, in[0] + 0xd76aa478, 7);
+ MD5STEP(F1, d, a, b, c, in[1] + 0xe8c7b756, 12);
+ MD5STEP(F1, c, d, a, b, in[2] + 0x242070db, 17);
+ MD5STEP(F1, b, c, d, a, in[3] + 0xc1bdceee, 22);
+ MD5STEP(F1, a, b, c, d, in[4] + 0xf57c0faf, 7);
+ MD5STEP(F1, d, a, b, c, in[5] + 0x4787c62a, 12);
+ MD5STEP(F1, c, d, a, b, in[6] + 0xa8304613, 17);
+ MD5STEP(F1, b, c, d, a, in[7] + 0xfd469501, 22);
+ MD5STEP(F1, a, b, c, d, in[8] + 0x698098d8, 7);
+ MD5STEP(F1, d, a, b, c, in[9] + 0x8b44f7af, 12);
+ MD5STEP(F1, c, d, a, b, in[10] + 0xffff5bb1, 17);
+ MD5STEP(F1, b, c, d, a, in[11] + 0x895cd7be, 22);
+ MD5STEP(F1, a, b, c, d, in[12] + 0x6b901122, 7);
+ MD5STEP(F1, d, a, b, c, in[13] + 0xfd987193, 12);
+ MD5STEP(F1, c, d, a, b, in[14] + 0xa679438e, 17);
+ MD5STEP(F1, b, c, d, a, in[15] + 0x49b40821, 22);
+
+ MD5STEP(F2, a, b, c, d, in[1] + 0xf61e2562, 5);
+ MD5STEP(F2, d, a, b, c, in[6] + 0xc040b340, 9);
+ MD5STEP(F2, c, d, a, b, in[11] + 0x265e5a51, 14);
+ MD5STEP(F2, b, c, d, a, in[0] + 0xe9b6c7aa, 20);
+ MD5STEP(F2, a, b, c, d, in[5] + 0xd62f105d, 5);
+ MD5STEP(F2, d, a, b, c, in[10] + 0x02441453, 9);
+ MD5STEP(F2, c, d, a, b, in[15] + 0xd8a1e681, 14);
+ MD5STEP(F2, b, c, d, a, in[4] + 0xe7d3fbc8, 20);
+ MD5STEP(F2, a, b, c, d, in[9] + 0x21e1cde6, 5);
+ MD5STEP(F2, d, a, b, c, in[14] + 0xc33707d6, 9);
+ MD5STEP(F2, c, d, a, b, in[3] + 0xf4d50d87, 14);
+ MD5STEP(F2, b, c, d, a, in[8] + 0x455a14ed, 20);
+ MD5STEP(F2, a, b, c, d, in[13] + 0xa9e3e905, 5);
+ MD5STEP(F2, d, a, b, c, in[2] + 0xfcefa3f8, 9);
+ MD5STEP(F2, c, d, a, b, in[7] + 0x676f02d9, 14);
+ MD5STEP(F2, b, c, d, a, in[12] + 0x8d2a4c8a, 20);
+
+ MD5STEP(F3, a, b, c, d, in[5] + 0xfffa3942, 4);
+ MD5STEP(F3, d, a, b, c, in[8] + 0x8771f681, 11);
+ MD5STEP(F3, c, d, a, b, in[11] + 0x6d9d6122, 16);
+ MD5STEP(F3, b, c, d, a, in[14] + 0xfde5380c, 23);
+ MD5STEP(F3, a, b, c, d, in[1] + 0xa4beea44, 4);
+ MD5STEP(F3, d, a, b, c, in[4] + 0x4bdecfa9, 11);
+ MD5STEP(F3, c, d, a, b, in[7] + 0xf6bb4b60, 16);
+ MD5STEP(F3, b, c, d, a, in[10] + 0xbebfbc70, 23);
+ MD5STEP(F3, a, b, c, d, in[13] + 0x289b7ec6, 4);
+ MD5STEP(F3, d, a, b, c, in[0] + 0xeaa127fa, 11);
+ MD5STEP(F3, c, d, a, b, in[3] + 0xd4ef3085, 16);
+ MD5STEP(F3, b, c, d, a, in[6] + 0x04881d05, 23);
+ MD5STEP(F3, a, b, c, d, in[9] + 0xd9d4d039, 4);
+ MD5STEP(F3, d, a, b, c, in[12] + 0xe6db99e5, 11);
+ MD5STEP(F3, c, d, a, b, in[15] + 0x1fa27cf8, 16);
+ MD5STEP(F3, b, c, d, a, in[2] + 0xc4ac5665, 23);
+
+ MD5STEP(F4, a, b, c, d, in[0] + 0xf4292244, 6);
+ MD5STEP(F4, d, a, b, c, in[7] + 0x432aff97, 10);
+ MD5STEP(F4, c, d, a, b, in[14] + 0xab9423a7, 15);
+ MD5STEP(F4, b, c, d, a, in[5] + 0xfc93a039, 21);
+ MD5STEP(F4, a, b, c, d, in[12] + 0x655b59c3, 6);
+ MD5STEP(F4, d, a, b, c, in[3] + 0x8f0ccc92, 10);
+ MD5STEP(F4, c, d, a, b, in[10] + 0xffeff47d, 15);
+ MD5STEP(F4, b, c, d, a, in[1] + 0x85845dd1, 21);
+ MD5STEP(F4, a, b, c, d, in[8] + 0x6fa87e4f, 6);
+ MD5STEP(F4, d, a, b, c, in[15] + 0xfe2ce6e0, 10);
+ MD5STEP(F4, c, d, a, b, in[6] + 0xa3014314, 15);
+ MD5STEP(F4, b, c, d, a, in[13] + 0x4e0811a1, 21);
+ MD5STEP(F4, a, b, c, d, in[4] + 0xf7537e82, 6);
+ MD5STEP(F4, d, a, b, c, in[11] + 0xbd3af235, 10);
+ MD5STEP(F4, c, d, a, b, in[2] + 0x2ad7d2bb, 15);
+ MD5STEP(F4, b, c, d, a, in[9] + 0xeb86d391, 21);
+
+ m_hash[0] += a;
+ m_hash[1] += b;
+ m_hash[2] += c;
+ m_hash[3] += d;
+}
+
+
+size_t md5MessageDigest::getDigestLength() const {
+
+ return 16;
+}
+
+
+const byte_t* md5MessageDigest::getDigest() const {
+
+ return reinterpret_cast <const byte_t*>(m_hash);
+}
+
+
+} // md5
+} // digest
+} // security
+} // vmime
+
diff --git a/vmime-master/src/vmime/security/digest/md5/md5MessageDigest.hpp b/vmime-master/src/vmime/security/digest/md5/md5MessageDigest.hpp
new file mode 100644
index 0000000..bdb730a
--- /dev/null
+++ b/vmime-master/src/vmime/security/digest/md5/md5MessageDigest.hpp
@@ -0,0 +1,85 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_SECURITY_DIGEST_MD5_MD5MESSAGEDIGEST_HPP_INCLUDED
+#define VMIME_SECURITY_DIGEST_MD5_MD5MESSAGEDIGEST_HPP_INCLUDED
+
+
+#include "vmime/security/digest/messageDigest.hpp"
+
+
+namespace vmime {
+namespace security {
+namespace digest {
+namespace md5 {
+
+
+class md5MessageDigest : public messageDigest {
+
+public:
+
+ md5MessageDigest();
+
+ void update(const byte_t b);
+ void update(const string& s);
+ void update(const byte_t* buffer, const size_t len);
+ void update(const byte_t* buffer, const size_t offset, const size_t len);
+
+ void finalize();
+ void finalize(const string& s);
+ void finalize(const byte_t* buffer, const size_t len);
+ void finalize(const byte_t* buffer, const size_t offset, const size_t len);
+
+ size_t getDigestLength() const;
+ const byte_t* getDigest() const;
+
+ void reset();
+
+protected:
+
+ void init();
+ void transformHelper();
+ void transform();
+
+ vmime_uint32 m_hash[4];
+
+ union BlockType {
+ vmime_uint32 b32[16];
+ vmime_uint8 b8[64];
+ };
+
+ size_t m_byteCount;
+ BlockType m_block;
+
+ bool m_finalized;
+};
+
+
+} // md5
+} // digest
+} // security
+} // vmime
+
+
+#endif // VMIME_SECURITY_DIGEST_MD5_MD5MESSAGEDIGEST_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/security/digest/messageDigest.cpp b/vmime-master/src/vmime/security/digest/messageDigest.cpp
new file mode 100644
index 0000000..d7e394f
--- /dev/null
+++ b/vmime-master/src/vmime/security/digest/messageDigest.cpp
@@ -0,0 +1,56 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/security/digest/messageDigest.hpp"
+
+#include <sstream>
+
+
+namespace vmime {
+namespace security {
+namespace digest {
+
+
+const string messageDigest::getHexDigest() const {
+
+ const byte_t* hash = getDigest();
+ const size_t len = getDigestLength();
+
+ static const unsigned char hex[] = "0123456789abcdef";
+
+ std::ostringstream oss;
+ oss.imbue(std::locale::classic());
+
+ for (size_t i = 0 ; i < len ; ++i) {
+ oss << hex[(hash[i] & 0xf0) >> 4];
+ oss << hex[(hash[i] & 0x0f)];
+ }
+
+ return oss.str();
+}
+
+
+} // digest
+} // security
+} // vmime
+
diff --git a/vmime-master/src/vmime/security/digest/messageDigest.hpp b/vmime-master/src/vmime/security/digest/messageDigest.hpp
new file mode 100644
index 0000000..0413810
--- /dev/null
+++ b/vmime-master/src/vmime/security/digest/messageDigest.hpp
@@ -0,0 +1,142 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_SECURITY_DIGEST_MESSAGEDIGEST_HPP_INCLUDED
+#define VMIME_SECURITY_DIGEST_MESSAGEDIGEST_HPP_INCLUDED
+
+
+#include "vmime/object.hpp"
+#include "vmime/types.hpp"
+
+
+namespace vmime {
+namespace security {
+namespace digest {
+
+
+/** Computes message digests using standard algorithms,
+ * such as MD5 or SHA.
+ */
+class VMIME_EXPORT messageDigest : public object {
+
+public:
+
+ /** Updates the digest using the specified string.
+ *
+ * @param s the string with which to update the digest.
+ */
+ virtual void update(const string& s) = 0;
+
+ /** Updates the digest using the specified byte.
+ *
+ * @param b the byte with which to update the digest.
+ */
+ virtual void update(const byte_t b) = 0;
+
+ /** Updates the digest using the specified array of bytes.
+ *
+ * @param buffer array of bytes
+ * @param len number of bytes to use in the buffer
+ */
+ virtual void update(const byte_t* buffer, const size_t len) = 0;
+
+ /** Updates the digest using the specified array of bytes,
+ * starting at the specified offset.
+ *
+ * @param buffer array of bytes
+ * @param offset offset to start from in the array of bytes
+ * @param len number of bytes to use, starting at offset
+ */
+ virtual void update(
+ const byte_t* buffer,
+ const size_t offset,
+ const size_t len
+ ) = 0;
+
+ /** Completes the hash computation by performing final operations
+ * such as padding.
+ */
+ virtual void finalize() = 0;
+
+ /** Completes the hash computation by performing final operations
+ * such as padding. This is equivalent to calling update() and
+ * then finalize().
+ */
+ virtual void finalize(const string& s) = 0;
+
+ /** Completes the hash computation by performing final operations
+ * such as padding. This is equivalent to calling update() and
+ * then finalize().
+ */
+ virtual void finalize(
+ const byte_t* buffer,
+ const size_t len
+ ) = 0;
+
+ /** Completes the hash computation by performing final operations
+ * such as padding. This is equivalent to calling update() and
+ * then finalize().
+ */
+ virtual void finalize(
+ const byte_t* buffer,
+ const size_t offset,
+ const size_t len
+ ) = 0;
+
+ /** Returns the length of the hash.
+ * This is the length of the array returned by getDigest().
+ *
+ * @return length of computed hash
+ */
+ virtual size_t getDigestLength() const = 0;
+
+ /** Returns the hash, as computed by the algorithm.
+ * You must call finalize() before using this function, or the
+ * hash will not be correct.
+ * To get the size of the returned array, call getDigestLength().
+ *
+ * @return computed hash
+ */
+ virtual const byte_t* getDigest() const = 0;
+
+ /** Returns the hash as an hexadecimal string.
+ * You must call finalize() before using this function, or the
+ * hash will not be correct.
+ *
+ * @return computed hash, in hexadecimal format
+ */
+ virtual const string getHexDigest() const;
+
+ /** Resets the algorithm to its initial state, so that you can
+ * compute a new hash using the same object.
+ */
+ virtual void reset() = 0;
+};
+
+
+} // digest
+} // security
+} // vmime
+
+
+#endif // VMIME_SECURITY_DIGEST_MESSAGEDIGEST_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/security/digest/messageDigestFactory.cpp b/vmime-master/src/vmime/security/digest/messageDigestFactory.cpp
new file mode 100644
index 0000000..2e49968
--- /dev/null
+++ b/vmime-master/src/vmime/security/digest/messageDigestFactory.cpp
@@ -0,0 +1,81 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/security/digest/messageDigestFactory.hpp"
+#include "vmime/exception.hpp"
+
+#include "vmime/security/digest/md5/md5MessageDigest.hpp"
+#include "vmime/security/digest/sha1/sha1MessageDigest.hpp"
+
+
+namespace vmime {
+namespace security {
+namespace digest {
+
+
+messageDigestFactory::messageDigestFactory() {
+
+ registerAlgorithm <md5::md5MessageDigest>("md5");
+ registerAlgorithm <sha1::sha1MessageDigest>("sha1");
+}
+
+
+messageDigestFactory::~messageDigestFactory() {
+
+}
+
+
+messageDigestFactory* messageDigestFactory::getInstance() {
+
+ static messageDigestFactory instance;
+ return &instance;
+}
+
+
+shared_ptr <messageDigest> messageDigestFactory::create(const string& name) {
+
+ const MapType::const_iterator it = m_algos.find(utility::stringUtils::toLower(name));
+
+ if (it != m_algos.end()) {
+ return (*it).second->create();
+ }
+
+ throw exceptions::no_digest_algorithm_available(name);
+}
+
+
+const std::vector <string> messageDigestFactory::getSupportedAlgorithms() const {
+
+ std::vector <string> res;
+
+ for (MapType::const_iterator it = m_algos.begin() ; it != m_algos.end() ; ++it) {
+ res.push_back((*it).first);
+ }
+
+ return res;
+}
+
+
+} // digest
+} // security
+} // vmime
diff --git a/vmime-master/src/vmime/security/digest/messageDigestFactory.hpp b/vmime-master/src/vmime/security/digest/messageDigestFactory.hpp
new file mode 100644
index 0000000..56a0cfe
--- /dev/null
+++ b/vmime-master/src/vmime/security/digest/messageDigestFactory.hpp
@@ -0,0 +1,110 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_SECURITY_DIGEST_MESSAGEDIGESTFACTORY_HPP_INCLUDED
+#define VMIME_SECURITY_DIGEST_MESSAGEDIGESTFACTORY_HPP_INCLUDED
+
+
+#include "vmime/types.hpp"
+#include "vmime/security/digest/messageDigest.hpp"
+#include "vmime/utility/stringUtils.hpp"
+
+
+namespace vmime {
+namespace security {
+namespace digest {
+
+
+/** Creates instances of message digest algorithms.
+ */
+
+class VMIME_EXPORT messageDigestFactory {
+
+private:
+
+ messageDigestFactory();
+ ~messageDigestFactory();
+
+public:
+
+ static messageDigestFactory* getInstance();
+
+private:
+
+ struct digestAlgorithmFactory : public object {
+
+ virtual shared_ptr <messageDigest> create() const = 0;
+ };
+
+ template <class E>
+ struct digestAlgorithmFactoryImpl : public digestAlgorithmFactory {
+
+ shared_ptr <messageDigest> create() const {
+ return vmime::make_shared <E>();
+ }
+ };
+
+
+ typedef std::map <string, shared_ptr <digestAlgorithmFactory> > MapType;
+ MapType m_algos;
+
+public:
+
+ /** Register a new digest algorithm by its name.
+ *
+ * @param name algorithm name
+ */
+ template <class E>
+ void registerAlgorithm(const string& name) {
+
+ m_algos.insert(
+ MapType::value_type(
+ utility::stringUtils::toLower(name),
+ vmime::make_shared <digestAlgorithmFactoryImpl <E> >()
+ )
+ );
+ }
+
+ /** Create a new algorithm instance from its name.
+ *
+ * @param name algorithm name (eg. "md5")
+ * @return a new algorithm instance for the specified name
+ * @throw exceptions::no_digest_algorithm_available if no algorithm is
+ * registered with this name
+ */
+ shared_ptr <messageDigest> create(const string& name);
+
+ /** Return a list of supported digest algorithms.
+ *
+ * @return list of supported digest algorithms
+ */
+ const std::vector <string> getSupportedAlgorithms() const;
+};
+
+
+} // digest
+} // security
+} // vmime
+
+
+#endif // VMIME_SECURITY_DIGEST_MESSAGEDIGESTFACTORY_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/security/digest/sha1/sha1MessageDigest.cpp b/vmime-master/src/vmime/security/digest/sha1/sha1MessageDigest.cpp
new file mode 100644
index 0000000..c098f14
--- /dev/null
+++ b/vmime-master/src/vmime/security/digest/sha1/sha1MessageDigest.cpp
@@ -0,0 +1,276 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+//
+// This is an implementation by Steve Reid <steve@edmweb.com>
+// 100% public domain.
+
+#include "vmime/security/digest/sha1/sha1MessageDigest.hpp"
+
+#include <cstring>
+#include <cassert>
+
+
+namespace vmime {
+namespace security {
+namespace digest {
+namespace sha1 {
+
+
+#define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits))))
+
+// blk0() and blk() perform the initial expand.
+// I got the idea of expanding during the round function from SSLeay
+#if VMIME_BYTE_ORDER_LITTLE_ENDIAN
+ #define blk0(i) (block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) \
+ | (rol(block->l[i], 8) & 0x00FF00FF))
+#else
+ #define blk0(i) block->l[i]
+#endif
+
+#define blk(i) (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ block->l[(i + 8) & 15] \
+ ^ block->l[(i + 2) & 15] ^ block->l[i & 15], 1))
+
+// (R0+R1), R2, R3, R4 are the different operations used in SHA1
+#define R0(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk0(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R1(v,w,x,y,z,i) z+=((w&(x^y))^y)+blk(i)+0x5A827999+rol(v,5);w=rol(w,30);
+#define R2(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0x6ED9EBA1+rol(v,5);w=rol(w,30);
+#define R3(v,w,x,y,z,i) z+=(((w|x)&y)|(w&x))+blk(i)+0x8F1BBCDC+rol(v,5);w=rol(w,30);
+#define R4(v,w,x,y,z,i) z+=(w^x^y)+blk(i)+0xCA62C1D6+rol(v,5);w=rol(w,30);
+
+
+sha1MessageDigest::sha1MessageDigest() {
+
+ init();
+}
+
+
+void sha1MessageDigest::reset() {
+
+ init();
+}
+
+
+void sha1MessageDigest::init() {
+
+ m_state[0] = 0x67452301;
+ m_state[1] = 0xefcdab89;
+ m_state[2] = 0x98badcfe;
+ m_state[3] = 0x10325476;
+ m_state[4] = 0xc3d2e1f0;
+
+ m_count[0] = 0;
+ m_count[1] = 0;
+}
+
+
+void sha1MessageDigest::update(const byte_t b) {
+
+ update(&b, 1);
+}
+
+
+void sha1MessageDigest::update(const string& s) {
+
+ update(reinterpret_cast <const byte_t*>(s.data()), s.length());
+}
+
+
+void sha1MessageDigest::update(const byte_t* buffer, const size_t offset, const size_t len) {
+
+ update(buffer + offset, len);
+}
+
+
+void sha1MessageDigest::update(const byte_t* buffer, const size_t len) {
+
+ unsigned int i, j;
+
+ j = (m_count[0] >> 3) & 63;
+
+ if ((m_count[0] += static_cast <unsigned int>(len << 3)) < static_cast <unsigned int>(len << 3)) {
+ m_count[1]++;
+ }
+
+ m_count[1] += static_cast <unsigned int>(len >> 29);
+
+ if ((j + len) > 63) {
+
+ memcpy(&m_buffer[j], buffer, (i = 64 - j));
+
+ transform(m_state, m_buffer);
+
+ for ( ; i + 63 < len ; i += 64) {
+ transform(m_state, &buffer[i]);
+ }
+
+ j = 0;
+
+ } else {
+
+ i = 0;
+ }
+
+ std::memcpy(&m_buffer[j], &buffer[i], len - i);
+}
+
+
+void sha1MessageDigest::finalize() {
+
+ unsigned int i, j;
+ unsigned char finalcount[8];
+
+ for (i = 0 ; i < 8 ; i++) {
+
+ finalcount[i] = static_cast <unsigned char>(
+ (m_count[(i >= 4 ? 0 : 1)] >> ((3 - (i & 3)) * 8)) & 255 // Endian independent
+ );
+ }
+
+ update(reinterpret_cast <const byte_t*>("\200"), 1);
+
+ while ((m_count[0] & 504) != 448) {
+ update(reinterpret_cast <const byte_t*>("\0"), 1);
+ }
+
+ update(finalcount, 8); // Should cause a transform()
+
+ for (i = 0 ; i < 20 ; i++) {
+
+ m_digest[i] = static_cast <unsigned char>(
+ (m_state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255
+ );
+ }
+
+ // Wipe variables
+ i = j = 0;
+
+ std::memset(m_buffer, 0, 64);
+ std::memset(m_state, 0, 5 * sizeof(unsigned int));
+ std::memset(m_count, 0, 2 * sizeof(unsigned int));
+ std::memset(&finalcount, 0, 8);
+}
+
+
+void sha1MessageDigest::finalize(const string& s) {
+
+ finalize(reinterpret_cast <const byte_t*>(s.data()), s.length());
+}
+
+
+void sha1MessageDigest::finalize(const byte_t* buffer, const size_t len) {
+
+ update(buffer, len);
+ finalize();
+}
+
+
+void sha1MessageDigest::finalize(
+ const byte_t* buffer,
+ const size_t offset,
+ const size_t len
+) {
+
+ finalize(buffer + offset, len);
+}
+
+
+/** Hash a single 512-bit block.
+ * This is the core of the algorithm.
+ */
+void sha1MessageDigest::transform(
+ unsigned int state[5],
+ const unsigned char buffer[64]
+) {
+
+ unsigned int a, b, c, d, e;
+
+ typedef union {
+ unsigned char c[64];
+ unsigned int l[16];
+ } CHAR64LONG16;
+
+ assert(sizeof(unsigned int) == 4);
+
+ CHAR64LONG16* block;
+ static unsigned char workspace[64];
+
+ block = reinterpret_cast <CHAR64LONG16*>(workspace);
+ memcpy(block, buffer, 64);
+
+ // Copy context->state[] to working vars
+ a = state[0];
+ b = state[1];
+ c = state[2];
+ d = state[3];
+ e = state[4];
+
+ // 4 rounds of 20 operations each. Loop unrolled.
+ R0(a,b,c,d,e, 0); R0(e,a,b,c,d, 1); R0(d,e,a,b,c, 2); R0(c,d,e,a,b, 3);
+ R0(b,c,d,e,a, 4); R0(a,b,c,d,e, 5); R0(e,a,b,c,d, 6); R0(d,e,a,b,c, 7);
+ R0(c,d,e,a,b, 8); R0(b,c,d,e,a, 9); R0(a,b,c,d,e,10); R0(e,a,b,c,d,11);
+ R0(d,e,a,b,c,12); R0(c,d,e,a,b,13); R0(b,c,d,e,a,14); R0(a,b,c,d,e,15);
+ R1(e,a,b,c,d,16); R1(d,e,a,b,c,17); R1(c,d,e,a,b,18); R1(b,c,d,e,a,19);
+ R2(a,b,c,d,e,20); R2(e,a,b,c,d,21); R2(d,e,a,b,c,22); R2(c,d,e,a,b,23);
+ R2(b,c,d,e,a,24); R2(a,b,c,d,e,25); R2(e,a,b,c,d,26); R2(d,e,a,b,c,27);
+ R2(c,d,e,a,b,28); R2(b,c,d,e,a,29); R2(a,b,c,d,e,30); R2(e,a,b,c,d,31);
+ R2(d,e,a,b,c,32); R2(c,d,e,a,b,33); R2(b,c,d,e,a,34); R2(a,b,c,d,e,35);
+ R2(e,a,b,c,d,36); R2(d,e,a,b,c,37); R2(c,d,e,a,b,38); R2(b,c,d,e,a,39);
+ R3(a,b,c,d,e,40); R3(e,a,b,c,d,41); R3(d,e,a,b,c,42); R3(c,d,e,a,b,43);
+ R3(b,c,d,e,a,44); R3(a,b,c,d,e,45); R3(e,a,b,c,d,46); R3(d,e,a,b,c,47);
+ R3(c,d,e,a,b,48); R3(b,c,d,e,a,49); R3(a,b,c,d,e,50); R3(e,a,b,c,d,51);
+ R3(d,e,a,b,c,52); R3(c,d,e,a,b,53); R3(b,c,d,e,a,54); R3(a,b,c,d,e,55);
+ R3(e,a,b,c,d,56); R3(d,e,a,b,c,57); R3(c,d,e,a,b,58); R3(b,c,d,e,a,59);
+ R4(a,b,c,d,e,60); R4(e,a,b,c,d,61); R4(d,e,a,b,c,62); R4(c,d,e,a,b,63);
+ R4(b,c,d,e,a,64); R4(a,b,c,d,e,65); R4(e,a,b,c,d,66); R4(d,e,a,b,c,67);
+ R4(c,d,e,a,b,68); R4(b,c,d,e,a,69); R4(a,b,c,d,e,70); R4(e,a,b,c,d,71);
+ R4(d,e,a,b,c,72); R4(c,d,e,a,b,73); R4(b,c,d,e,a,74); R4(a,b,c,d,e,75);
+ R4(e,a,b,c,d,76); R4(d,e,a,b,c,77); R4(c,d,e,a,b,78); R4(b,c,d,e,a,79);
+
+ // Add the working vars back into context.state[]
+ state[0] += a;
+ state[1] += b;
+ state[2] += c;
+ state[3] += d;
+ state[4] += e;
+
+ // Wipe variables
+ a = b = c = d = e = 0;
+}
+
+
+size_t sha1MessageDigest::getDigestLength() const {
+
+ return 20;
+}
+
+
+const byte_t* sha1MessageDigest::getDigest() const {
+
+ return m_digest;
+}
+
+
+} // sha1
+} // digest
+} // security
+} // vmime
diff --git a/vmime-master/src/vmime/security/digest/sha1/sha1MessageDigest.hpp b/vmime-master/src/vmime/security/digest/sha1/sha1MessageDigest.hpp
new file mode 100644
index 0000000..1906236
--- /dev/null
+++ b/vmime-master/src/vmime/security/digest/sha1/sha1MessageDigest.hpp
@@ -0,0 +1,79 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_SECURITY_DIGEST_SHA1_SHA1MESSAGEDIGEST_HPP_INCLUDED
+#define VMIME_SECURITY_DIGEST_SHA1_SHA1MESSAGEDIGEST_HPP_INCLUDED
+
+
+#include "vmime/security/digest/messageDigest.hpp"
+
+
+namespace vmime {
+namespace security {
+namespace digest {
+namespace sha1 {
+
+
+class sha1MessageDigest : public messageDigest {
+
+public:
+
+ sha1MessageDigest();
+
+ void update(const byte_t b);
+ void update(const string& s);
+ void update(const byte_t* buffer, const size_t len);
+ void update(const byte_t* buffer, const size_t offset, const size_t len);
+
+ void finalize();
+ void finalize(const string& s);
+ void finalize(const byte_t* buffer, const size_t len);
+ void finalize(const byte_t* buffer, const size_t offset, const size_t len);
+
+ size_t getDigestLength() const;
+ const byte_t* getDigest() const;
+
+ void reset();
+
+protected:
+
+ void init();
+
+ static void transform(unsigned int state[5], const byte_t buffer[64]);
+
+ unsigned int m_state[5];
+ unsigned int m_count[2];
+ byte_t m_buffer[64];
+
+ byte_t m_digest[20];
+};
+
+
+} // sha1
+} // digest
+} // security
+} // vmime
+
+
+#endif // VMIME_SECURITY_DIGEST_SHA1_SHA1MESSAGEDIGEST_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/security/sasl/SASLAuthenticator.hpp b/vmime-master/src/vmime/security/sasl/SASLAuthenticator.hpp
new file mode 100644
index 0000000..a75bfa0
--- /dev/null
+++ b/vmime-master/src/vmime/security/sasl/SASLAuthenticator.hpp
@@ -0,0 +1,96 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_SECURITY_SASL_SASLAUTHENTICATOR_HPP_INCLUDED
+#define VMIME_SECURITY_SASL_SASLAUTHENTICATOR_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_SASL_SUPPORT
+
+
+#include "vmime/types.hpp"
+
+#include "vmime/security/authenticator.hpp"
+
+
+namespace vmime {
+namespace security {
+namespace sasl {
+
+
+class SASLMechanism;
+class SASLSession;
+
+
+/** SASL-aware authenticator.
+ *
+ * Usually, you should not inherit from this class, but instead from the
+ * more convenient defaultSASLAuthenticator class.
+ */
+class VMIME_EXPORT SASLAuthenticator : public authenticator {
+
+public:
+
+ /** This method is called to allow the client to choose the
+ * authentication mechanisms that will be used. By default,
+ * the most secure mechanisms are chosen.
+ *
+ * @param available available mechanisms
+ * @param suggested suggested mechanism (or NULL if the system
+ * could not suggest a mechanism)
+ * @return ordered list of mechanism to use among the available
+ * mechanisms (from the first to try to the last)
+ */
+ virtual const std::vector <shared_ptr <SASLMechanism> > getAcceptableMechanisms(
+ const std::vector <shared_ptr <SASLMechanism> >& available,
+ const shared_ptr <SASLMechanism>& suggested
+ ) const = 0;
+
+ /** Set the SASL session which is using this authenticator.
+ *
+ * @param sess SASL session
+ */
+ virtual void setSASLSession(const shared_ptr <SASLSession>& sess) = 0;
+
+ /** Set the SASL mechanism which has been selected for the
+ * SASL authentication process. This may be called several times
+ * if the multiple mechanisms are tried by the service which
+ * use this authentication.
+ *
+ * @param mech SASL mechanism
+ */
+ virtual void setSASLMechanism(const shared_ptr <SASLMechanism>& mech) = 0;
+};
+
+
+} // sasl
+} // security
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_SASL_SUPPORT
+
+#endif // VMIME_SECURITY_SASL_SASLAUTHENTICATOR_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/security/sasl/SASLContext.cpp b/vmime-master/src/vmime/security/sasl/SASLContext.cpp
new file mode 100644
index 0000000..2174541
--- /dev/null
+++ b/vmime-master/src/vmime/security/sasl/SASLContext.cpp
@@ -0,0 +1,221 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_SASL_SUPPORT
+
+
+#include <sstream>
+
+#include <gsasl.h>
+
+#include "vmime/security/sasl/SASLContext.hpp"
+#include "vmime/security/sasl/SASLMechanism.hpp"
+
+#include "vmime/base.hpp"
+
+#include "vmime/utility/encoder/encoderFactory.hpp"
+
+#include "vmime/utility/stream.hpp"
+#include "vmime/utility/outputStreamStringAdapter.hpp"
+#include "vmime/utility/inputStreamStringAdapter.hpp"
+#include "vmime/utility/inputStreamByteBufferAdapter.hpp"
+
+
+namespace vmime {
+namespace security {
+namespace sasl {
+
+
+SASLContext::SASLContext() {
+
+ if (gsasl_init(&m_gsaslContext) != GSASL_OK) {
+ throw std::bad_alloc();
+ }
+}
+
+
+SASLContext::~SASLContext() {
+
+ gsasl_done(m_gsaslContext);
+}
+
+
+// static
+shared_ptr <SASLContext> SASLContext::create() {
+
+ return shared_ptr <SASLContext>(new SASLContext());
+}
+
+
+shared_ptr <SASLSession> SASLContext::createSession(
+ const string& serviceName,
+ const shared_ptr <authenticator>& auth,
+ const shared_ptr <SASLMechanism>& mech
+) {
+
+ return SASLSession::create
+ (serviceName, dynamicCast <SASLContext>(shared_from_this()), auth, mech);
+}
+
+
+shared_ptr <SASLMechanism> SASLContext::createMechanism(const string& name) {
+
+ return SASLMechanismFactory::getInstance()->create(
+ dynamicCast <SASLContext>(shared_from_this()), name
+ );
+}
+
+
+shared_ptr <SASLMechanism> SASLContext::suggestMechanism(
+ const std::vector <shared_ptr <SASLMechanism> >& mechs
+) {
+
+ if (mechs.empty()) {
+ return null;
+ }
+
+ std::ostringstream oss;
+
+ for (unsigned int i = 0 ; i < mechs.size() ; ++i) {
+ oss << mechs[i]->getName() << " ";
+ }
+
+ const string mechList = oss.str();
+ const char* suggested = gsasl_client_suggest_mechanism(m_gsaslContext, mechList.c_str());
+
+ if (suggested) {
+
+ for (unsigned int i = 0 ; i < mechs.size() ; ++i) {
+
+ if (mechs[i]->getName() == suggested) {
+ return mechs[i];
+ }
+ }
+ }
+
+ return null;
+}
+
+
+void SASLContext::decodeB64(const string& input, byte_t** output, size_t* outputLen) {
+
+ string res;
+
+ utility::inputStreamStringAdapter is(input);
+ utility::outputStreamStringAdapter os(res);
+
+ shared_ptr <utility::encoder::encoder> dec =
+ utility::encoder::encoderFactory::getInstance()->create("base64");
+
+ dec->decode(is, os);
+
+ byte_t* out = new byte_t[res.length()];
+
+ std::copy(res.begin(), res.end(), out);
+
+ *output = out;
+ *outputLen = res.length();
+}
+
+
+const string SASLContext::encodeB64(const byte_t* input, const size_t inputLen) {
+
+ string res;
+
+ utility::inputStreamByteBufferAdapter is(input, inputLen);
+ utility::outputStreamStringAdapter os(res);
+
+ shared_ptr <utility::encoder::encoder> enc =
+ utility::encoder::encoderFactory::getInstance()->create("base64");
+
+ enc->encode(is, os);
+
+ return res;
+}
+
+
+const string SASLContext::getErrorMessage(const string& fname, const int code) {
+
+ string msg = fname + "() returned ";
+
+#define ERROR(x) \
+ case x: msg += #x; break;
+
+ switch (code)
+ {
+ ERROR(GSASL_NEEDS_MORE)
+ ERROR(GSASL_UNKNOWN_MECHANISM)
+ ERROR(GSASL_MECHANISM_CALLED_TOO_MANY_TIMES)
+ ERROR(GSASL_MALLOC_ERROR)
+ ERROR(GSASL_BASE64_ERROR)
+ ERROR(GSASL_CRYPTO_ERROR)
+ ERROR(GSASL_SASLPREP_ERROR)
+ ERROR(GSASL_MECHANISM_PARSE_ERROR)
+ ERROR(GSASL_AUTHENTICATION_ERROR)
+ ERROR(GSASL_INTEGRITY_ERROR)
+ ERROR(GSASL_NO_CLIENT_CODE)
+ ERROR(GSASL_NO_SERVER_CODE)
+ ERROR(GSASL_NO_CALLBACK)
+ ERROR(GSASL_NO_ANONYMOUS_TOKEN)
+ ERROR(GSASL_NO_AUTHID)
+ ERROR(GSASL_NO_AUTHZID)
+ ERROR(GSASL_NO_PASSWORD)
+ ERROR(GSASL_NO_PASSCODE)
+ ERROR(GSASL_NO_PIN)
+ ERROR(GSASL_NO_SERVICE)
+ ERROR(GSASL_NO_HOSTNAME)
+ ERROR(GSASL_GSSAPI_RELEASE_BUFFER_ERROR)
+ ERROR(GSASL_GSSAPI_IMPORT_NAME_ERROR)
+ ERROR(GSASL_GSSAPI_INIT_SEC_CONTEXT_ERROR)
+ ERROR(GSASL_GSSAPI_ACCEPT_SEC_CONTEXT_ERROR)
+ ERROR(GSASL_GSSAPI_UNWRAP_ERROR)
+ ERROR(GSASL_GSSAPI_WRAP_ERROR)
+ ERROR(GSASL_GSSAPI_ACQUIRE_CRED_ERROR)
+ ERROR(GSASL_GSSAPI_DISPLAY_NAME_ERROR)
+ ERROR(GSASL_GSSAPI_UNSUPPORTED_PROTECTION_ERROR)
+ ERROR(GSASL_KERBEROS_V5_INIT_ERROR)
+ ERROR(GSASL_KERBEROS_V5_INTERNAL_ERROR)
+ ERROR(GSASL_SECURID_SERVER_NEED_ADDITIONAL_PASSCODE)
+ ERROR(GSASL_SECURID_SERVER_NEED_NEW_PIN)
+
+ default:
+
+ msg += "unknown error";
+ break;
+ }
+
+#undef ERROR
+
+ return msg;
+}
+
+
+} // sasl
+} // security
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_SASL_SUPPORT
diff --git a/vmime-master/src/vmime/security/sasl/SASLContext.hpp b/vmime-master/src/vmime/security/sasl/SASLContext.hpp
new file mode 100644
index 0000000..93d80ff
--- /dev/null
+++ b/vmime-master/src/vmime/security/sasl/SASLContext.hpp
@@ -0,0 +1,136 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_SECURITY_SASL_SASLCONTEXT_HPP_INCLUDED
+#define VMIME_SECURITY_SASL_SASLCONTEXT_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_SASL_SUPPORT
+
+
+#include "vmime/types.hpp"
+
+#include "vmime/security/sasl/SASLSession.hpp"
+#include "vmime/security/sasl/SASLMechanismFactory.hpp"
+
+
+namespace vmime {
+namespace security {
+namespace sasl {
+
+
+/** An SASL client context.
+ */
+class VMIME_EXPORT SASLContext : public object, public enable_shared_from_this <SASLContext> {
+
+ friend class SASLSession;
+ friend class builtinSASLMechanism;
+
+public:
+
+ ~SASLContext();
+
+ /** Construct and initialize a new SASL context.
+ *
+ * @return pointer to a new SASL context
+ */
+ static shared_ptr <SASLContext> create();
+
+ /** Create and initialize a new SASL session.
+ *
+ * @param serviceName name of the service which will use the session
+ * @param auth authenticator object to use during the session
+ * @param mech SASL mechanism
+ * @return a new SASL session
+ */
+ shared_ptr <SASLSession> createSession(
+ const string& serviceName,
+ const shared_ptr <authenticator>& auth,
+ const shared_ptr <SASLMechanism>& mech
+ );
+
+ /** Create an instance of an SASL mechanism.
+ *
+ * @param name mechanism name
+ * @return a new instance of the specified SASL mechanism
+ * @throw exceptions::no_such_mechanism if no mechanism is
+ * registered for the specified name
+ */
+ shared_ptr <SASLMechanism> createMechanism(const string& name);
+
+ /** Suggests an SASL mechanism among a set of mechanisms
+ * supported by the server.
+ *
+ * @param mechs list of mechanisms
+ * @return suggested mechanism (usually the safest mechanism
+ * supported by both the client and the server)
+ */
+ shared_ptr <SASLMechanism> suggestMechanism(
+ const std::vector <shared_ptr <SASLMechanism> >& mechs
+ );
+
+ /** Helper function for decoding Base64-encoded challenge.
+ *
+ * @param input input buffer
+ * @param output output buffer
+ * @param outputLen length of output buffer
+ */
+ void decodeB64(const string& input, byte_t** output, size_t* outputLen);
+
+ /** Helper function for encoding challenge in Base64.
+ *
+ * @param input input buffer
+ * @param inputLen length of input buffer
+ * @return Base64-encoded challenge
+ */
+ const string encodeB64(const byte_t* input, const size_t inputLen);
+
+private:
+
+ SASLContext();
+ SASLContext(SASLContext&);
+
+
+ static const string getErrorMessage(const string& fname, const int code);
+
+
+#ifdef GSASL_VERSION
+ Gsasl* m_gsaslContext;
+#else
+ void* m_gsaslContext;
+#endif // GSASL_VERSION
+
+};
+
+
+} // sasl
+} // security
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_SASL_SUPPORT
+
+#endif // VMIME_SECURITY_SASL_SASLCONTEXT_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/security/sasl/SASLMechanism.hpp b/vmime-master/src/vmime/security/sasl/SASLMechanism.hpp
new file mode 100644
index 0000000..a6e056d
--- /dev/null
+++ b/vmime-master/src/vmime/security/sasl/SASLMechanism.hpp
@@ -0,0 +1,153 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_SECURITY_SASL_SASLMECHANISM_HPP_INCLUDED
+#define VMIME_SECURITY_SASL_SASLMECHANISM_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_SASL_SUPPORT
+
+
+#include "vmime/types.hpp"
+
+
+namespace vmime {
+namespace security {
+namespace sasl {
+
+
+class SASLSession;
+
+
+/** An SASL mechanism.
+ */
+class VMIME_EXPORT SASLMechanism : public object {
+
+public:
+
+ /** Return the name of this mechanism.
+ *
+ * @return mechanism name
+ */
+ virtual const string getName() const = 0;
+
+ /** Perform one step of SASL authentication. Accept data from the
+ * server (challenge), process it and return data to be returned
+ * in response to the server.
+ *
+ * If the challenge is empty (challengeLen == 0), the initial
+ * response is returned, if this mechanism has one.
+ *
+ * @param sess SASL session
+ * @param challenge challenge sent from the server
+ * @param challengeLen length of challenge
+ * @param response response to send to the server (allocated by
+ * this function, free with delete[])
+ * @param responseLen length of response buffer
+ * @return true if authentication terminated successfully, or
+ * false if the authentication process should continue
+ * @throw exceptions::sasl_exception if an error occurred during
+ * authentication (in this case, the values in 'response' and
+ * 'responseLen' are undetermined)
+ */
+ virtual bool step(
+ const shared_ptr <SASLSession>& sess,
+ const byte_t* challenge,
+ const size_t challengeLen,
+ byte_t** response,
+ size_t* responseLen
+ ) = 0;
+
+ /** Check whether authentication has completed. If false, more
+ * calls to evaluateChallenge() are needed to complete the
+ * authentication process).
+ *
+ * @return true if the authentication has finished, or false
+ * otherwise
+ */
+ virtual bool isComplete() const = 0;
+
+ /** Determine if this mechanism has an optional initial response.
+ * If true, caller should call step() with an empty challenge to
+ * get the initial response.
+ *
+ * @return true if this mechanism has an initial response, or
+ * false otherwise
+ */
+ virtual bool hasInitialResponse() const = 0;
+
+ /** Encode data according to negotiated SASL mechanism. This
+ * might mean that data is integrity or privacy protected.
+ *
+ * @param sess SASL session
+ * @param input input buffer
+ * @param inputLen length of input buffer
+ * @param output output buffer (allocated bu the function,
+ * free with delete[])
+ * @param outputLen length of output buffer
+ * @throw exceptions::sasl_exception if an error occurred during
+ * the encoding of data (in this case, the values in 'output' and
+ * 'outputLen' are undetermined)
+ */
+ virtual void encode(
+ const shared_ptr <SASLSession>& sess,
+ const byte_t* input,
+ const size_t inputLen,
+ byte_t** output,
+ size_t* outputLen
+ ) = 0;
+
+ /** Decode data according to negotiated SASL mechanism. This
+ * might mean that data is integrity or privacy protected.
+ *
+ * @param sess SASL session
+ * @param input input buffer
+ * @param inputLen length of input buffer
+ * @param output output buffer (allocated bu the function,
+ * free with delete[])
+ * @param outputLen length of output buffer
+ * @throw exceptions::sasl_exception if an error occurred during
+ * the encoding of data (in this case, the values in 'output' and
+ * 'outputLen' are undetermined)
+ */
+ virtual void decode(
+ const shared_ptr <SASLSession>& sess,
+ const byte_t* input,
+ const size_t inputLen,
+ byte_t** output,
+ size_t* outputLen
+ ) = 0;
+};
+
+
+} // sasl
+} // security
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_SASL_SUPPORT
+
+#endif // VMIME_SECURITY_SASL_SASLMECHANISM_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/security/sasl/SASLMechanismFactory.cpp b/vmime-master/src/vmime/security/sasl/SASLMechanismFactory.cpp
new file mode 100644
index 0000000..a2fbedb
--- /dev/null
+++ b/vmime-master/src/vmime/security/sasl/SASLMechanismFactory.cpp
@@ -0,0 +1,149 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_SASL_SUPPORT
+
+
+#include <stdexcept>
+#include <new>
+
+#include <gsasl.h>
+
+#include "vmime/security/sasl/SASLMechanismFactory.hpp"
+#include "vmime/security/sasl/builtinSASLMechanism.hpp"
+#include "vmime/security/sasl/SASLContext.hpp"
+
+#include "vmime/utility/stringUtils.hpp"
+
+#include "vmime/base.hpp"
+#include "vmime/exception.hpp"
+
+
+namespace vmime {
+namespace security {
+namespace sasl {
+
+
+SASLMechanismFactory::SASLMechanismFactory() {
+
+ if (gsasl_init(&m_gsaslContext) != GSASL_OK) {
+ throw std::bad_alloc();
+ }
+}
+
+
+SASLMechanismFactory::~SASLMechanismFactory() {
+
+ gsasl_done(m_gsaslContext);
+}
+
+
+// static
+SASLMechanismFactory* SASLMechanismFactory::getInstance() {
+
+ static SASLMechanismFactory instance;
+ return &instance;
+}
+
+
+shared_ptr <SASLMechanism> SASLMechanismFactory::create(
+ const shared_ptr <SASLContext>& ctx,
+ const string& name_
+) {
+
+ const string name(utility::stringUtils::toUpper(name_));
+
+ // Check for registered mechanisms
+ MapType::iterator it = m_mechs.find(name);
+
+ if (it != m_mechs.end()) {
+ return (*it).second->create(ctx, name);
+ }
+
+ // Check for built-in mechanisms
+ if (isBuiltinMechanism(name)) {
+ return make_shared <builtinSASLMechanism>(ctx, name);
+ }
+
+ throw exceptions::no_such_mechanism(name);
+ return null;
+}
+
+
+const std::vector <string> SASLMechanismFactory::getSupportedMechanisms() const {
+
+ std::vector <string> list;
+
+ // Registered mechanisms
+ for (MapType::const_iterator it = m_mechs.begin() ;
+ it != m_mechs.end() ; ++it) {
+
+ list.push_back((*it).first);
+ }
+
+ // Built-in mechanisms
+ char* out = 0;
+
+ if (gsasl_client_mechlist(m_gsaslContext, &out) == GSASL_OK) {
+
+ // 'out' contains SASL mechanism names, separated by spaces
+ for (char *start = out, *p = out ; ; ++p) {
+
+ if (*p == ' ' || !*p) {
+
+ list.push_back(string(start, p));
+ start = p + 1;
+
+ // End of string
+ if (!*p) break;
+ }
+ }
+
+ gsasl_free(out);
+ }
+
+ return list;
+}
+
+
+bool SASLMechanismFactory::isMechanismSupported(const string& name) const {
+
+ return isBuiltinMechanism(name) || m_mechs.find(name) != m_mechs.end();
+}
+
+
+bool SASLMechanismFactory::isBuiltinMechanism(const string& name) const {
+
+ return gsasl_client_support_p(m_gsaslContext, name.c_str()) != 0;
+}
+
+
+} // sasl
+} // security
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_SASL_SUPPORT
diff --git a/vmime-master/src/vmime/security/sasl/SASLMechanismFactory.hpp b/vmime-master/src/vmime/security/sasl/SASLMechanismFactory.hpp
new file mode 100644
index 0000000..af76c96
--- /dev/null
+++ b/vmime-master/src/vmime/security/sasl/SASLMechanismFactory.hpp
@@ -0,0 +1,155 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_SECURITY_SASL_SASLMECHANISMFACTORY_HPP_INCLUDED
+#define VMIME_SECURITY_SASL_SASLMECHANISMFACTORY_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_SASL_SUPPORT
+
+
+#include "vmime/types.hpp"
+#include "vmime/base.hpp"
+
+#include "vmime/security/sasl/SASLMechanism.hpp"
+
+#include <map>
+
+
+namespace vmime {
+namespace security {
+namespace sasl {
+
+
+class SASLContext;
+
+
+/** Constructs SASL mechanism objects.
+ */
+class VMIME_EXPORT SASLMechanismFactory : public object {
+
+private:
+
+ SASLMechanismFactory();
+ ~SASLMechanismFactory();
+
+
+ struct registeredMechanism : public object {
+
+ virtual shared_ptr <SASLMechanism> create(
+ const shared_ptr <SASLContext>& ctx, const string& name
+ ) = 0;
+ };
+
+ template <typename T>
+ struct registeredMechanismImpl : public registeredMechanism {
+
+ shared_ptr <SASLMechanism> create(
+ const shared_ptr <SASLContext>& ctx,
+ const string& name
+ ) {
+
+ return vmime::make_shared <T>(ctx, name);
+ }
+ };
+
+ typedef std::map <string, shared_ptr <registeredMechanism> > MapType;
+ MapType m_mechs;
+
+public:
+
+ static SASLMechanismFactory* getInstance();
+
+ /** Register a mechanism into this factory, so that subsequent
+ * calls to create return a valid object for this mechanism.
+ *
+ * @param name mechanism name
+ */
+ template <typename MECH_CLASS>
+ void registerMechanism(const string& name) {
+
+ m_mechs.insert(
+ MapType::value_type(
+ name,
+ vmime::make_shared <registeredMechanismImpl <MECH_CLASS> >()
+ )
+ );
+ }
+
+ /** Create a mechanism object given its name.
+ *
+ * @param ctx SASL context
+ * @param name mechanism name
+ * @return a new mechanism object
+ * @throw exceptions::no_such_mechanism if no mechanism is
+ * registered for the specified name
+ */
+ shared_ptr <SASLMechanism> create(const shared_ptr <SASLContext>& ctx, const string& name);
+
+ /** Return a list of supported mechanisms. This includes mechanisms
+ * registered using registerMechanism() as well as the ones that
+ * are built-in.
+ *
+ * @return list of supported mechanisms
+ */
+ const std::vector <string> getSupportedMechanisms() const;
+
+ /** Test whether an authentication mechanism is supported.
+ *
+ * @param name mechanism name
+ * @return true if the specified mechanism is supported,
+ * false otherwise
+ */
+ bool isMechanismSupported(const string& name) const;
+
+ /** Test whether an authentication mechanism is directly supported
+ * by the underlying SASL library.
+ *
+ * @param name mechanism name
+ * @return true if the specified mechanism is built-in,
+ * or false otherwise
+ */
+ bool isBuiltinMechanism(const string& name) const;
+
+private:
+
+#ifdef GSASL_VERSION
+ Gsasl* m_gsaslContext;
+#else
+ void* m_gsaslContext;
+#endif // GSASL_VERSION
+
+};
+
+
+} // sasl
+} // security
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_SASL_SUPPORT
+
+#endif // VMIME_SECURITY_SASL_SASLMECHANISMFACTORY_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/security/sasl/SASLSession.cpp b/vmime-master/src/vmime/security/sasl/SASLSession.cpp
new file mode 100644
index 0000000..7498b46
--- /dev/null
+++ b/vmime-master/src/vmime/security/sasl/SASLSession.cpp
@@ -0,0 +1,221 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_SASL_SUPPORT
+
+
+#include <sstream>
+
+#include <gsasl.h>
+
+#include "vmime/security/sasl/SASLSession.hpp"
+
+#include "vmime/security/sasl/SASLContext.hpp"
+#include "vmime/security/sasl/SASLSocket.hpp"
+#include "vmime/security/sasl/SASLAuthenticator.hpp"
+
+
+namespace vmime {
+namespace security {
+namespace sasl {
+
+
+SASLSession::SASLSession(
+ const string& serviceName,
+ const shared_ptr <SASLContext>& ctx,
+ const shared_ptr <authenticator>& auth,
+ const shared_ptr <SASLMechanism>& mech
+)
+ : m_serviceName(serviceName),
+ m_context(ctx),
+ m_auth(auth),
+ m_mech(mech),
+ m_gsaslContext(0),
+ m_gsaslSession(0) {
+
+ if (gsasl_init(&m_gsaslContext) != GSASL_OK) {
+ throw std::bad_alloc();
+ }
+
+ gsasl_client_start(m_gsaslContext, mech->getName().c_str(), &m_gsaslSession);
+
+ gsasl_callback_set(m_gsaslContext, gsaslCallback);
+ gsasl_callback_hook_set(m_gsaslContext, this);
+}
+
+
+SASLSession::~SASLSession() {
+
+ gsasl_finish(m_gsaslSession);
+ m_gsaslSession = NULL;
+
+ gsasl_done(m_gsaslContext);
+ m_gsaslContext = NULL;
+}
+
+
+// static
+shared_ptr <SASLSession> SASLSession::create(
+ const string& serviceName,
+ const shared_ptr <SASLContext>& ctx,
+ const shared_ptr <authenticator>& auth,
+ const shared_ptr <SASLMechanism>& mech
+) {
+
+ return shared_ptr <SASLSession>(new SASLSession(serviceName, ctx, auth, mech));
+}
+
+
+void SASLSession::init() {
+
+ shared_ptr <SASLAuthenticator> saslAuth = dynamicCast <SASLAuthenticator>(m_auth);
+
+ if (saslAuth) {
+ saslAuth->setSASLMechanism(m_mech);
+ saslAuth->setSASLSession(dynamicCast <SASLSession>(shared_from_this()));
+ }
+}
+
+
+shared_ptr <authenticator> SASLSession::getAuthenticator() {
+
+ return m_auth;
+}
+
+
+shared_ptr <SASLMechanism> SASLSession::getMechanism() {
+
+ return m_mech;
+}
+
+
+shared_ptr <SASLContext> SASLSession::getContext() {
+
+ return m_context;
+}
+
+
+bool SASLSession::evaluateChallenge(
+ const byte_t* challenge,
+ const size_t challengeLen,
+ byte_t** response,
+ size_t* responseLen
+) {
+
+ return m_mech->step(
+ dynamicCast <SASLSession>(shared_from_this()),
+ challenge, challengeLen, response, responseLen
+ );
+}
+
+
+shared_ptr <net::socket> SASLSession::getSecuredSocket(const shared_ptr <net::socket>& sok) {
+
+ return make_shared <SASLSocket>(dynamicCast <SASLSession>(shared_from_this()), sok);
+}
+
+
+const string SASLSession::getServiceName() const {
+
+ return m_serviceName;
+}
+
+
+// static
+int SASLSession::gsaslCallback(
+ Gsasl* ctx,
+ Gsasl_session* sctx,
+ Gsasl_property prop
+) {
+
+ SASLSession* sess = reinterpret_cast <SASLSession*>(gsasl_callback_hook_get(ctx));
+
+ if (!sess) {
+ return GSASL_AUTHENTICATION_ERROR;
+ }
+
+ shared_ptr <authenticator> auth = sess->getAuthenticator();
+
+ try {
+
+ string res;
+
+ switch (prop) {
+
+ case GSASL_AUTHID:
+
+ res = auth->getUsername();
+ break;
+
+ case GSASL_PASSWORD:
+
+ res = auth->getPassword();
+ break;
+
+ case GSASL_ANONYMOUS_TOKEN:
+
+ res = auth->getAnonymousToken();
+ break;
+
+ case GSASL_HOSTNAME:
+
+ res = auth->getHostname();
+ break;
+
+ case GSASL_SERVICE:
+
+ res = auth->getServiceName();
+ break;
+
+ case GSASL_AUTHZID:
+ case GSASL_GSSAPI_DISPLAY_NAME:
+ case GSASL_PASSCODE:
+ case GSASL_SUGGESTED_PIN:
+ case GSASL_PIN:
+ case GSASL_REALM:
+
+ default:
+
+ return GSASL_NO_CALLBACK;
+ }
+
+ gsasl_property_set(sctx, prop, res.c_str());
+
+ return GSASL_OK;
+
+ } catch (...) {
+
+ return GSASL_NO_CALLBACK;
+ }
+}
+
+
+} // sasl
+} // security
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_SASL_SUPPORT
diff --git a/vmime-master/src/vmime/security/sasl/SASLSession.hpp b/vmime-master/src/vmime/security/sasl/SASLSession.hpp
new file mode 100644
index 0000000..7fc7225
--- /dev/null
+++ b/vmime-master/src/vmime/security/sasl/SASLSession.hpp
@@ -0,0 +1,180 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_SECURITY_SASL_SASLSESSION_HPP_INCLUDED
+#define VMIME_SECURITY_SASL_SASLSESSION_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_SASL_SUPPORT
+
+
+#include "vmime/types.hpp"
+
+#include "vmime/net/socket.hpp"
+
+#include "vmime/security/sasl/SASLAuthenticator.hpp"
+#include "vmime/security/sasl/SASLMechanism.hpp"
+
+
+namespace vmime {
+namespace security {
+namespace sasl {
+
+
+class SASLContext;
+
+
+/** An SASL client session.
+ */
+class VMIME_EXPORT SASLSession : public object, public enable_shared_from_this <SASLSession> {
+
+ friend class builtinSASLMechanism;
+ friend class SASLSocket;
+
+public:
+
+ ~SASLSession();
+
+ /** Construct a new SASL session.
+ *
+ * @param serviceName name of the service using this session
+ * @param ctx SASL context
+ * @param auth authenticator to use for this session
+ * @param mech SASL mechanism
+ */
+ static shared_ptr <SASLSession> create(
+ const string& serviceName,
+ const shared_ptr <SASLContext>& ctx,
+ const shared_ptr <authenticator>& auth,
+ const shared_ptr <SASLMechanism>& mech
+ );
+
+ /** Initialize this SASL session. This must be called before
+ * calling any other method on this object (except accessors).
+ */
+ void init();
+
+ /** Return the authenticator used for this session. This is the
+ * authenticator which has been previously set with a call to
+ * setAuthenticator().
+ *
+ * @return authenticator object
+ */
+ shared_ptr <authenticator> getAuthenticator();
+
+ /** Return the mechanism used for this session.
+ *
+ * @return SASL mechanism
+ */
+ shared_ptr <SASLMechanism> getMechanism();
+
+ /** Return the SASL context.
+ *
+ * @return SASL context
+ */
+ shared_ptr <SASLContext> getContext();
+
+ /** Perform one step of SASL authentication. Accept data from the
+ * server (challenge), process it and return data to be returned
+ * in response to the server.
+ *
+ * If the challenge is empty (challengeLen == 0), the initial
+ * response is returned, if the mechanism has one.
+ *
+ * @param challenge challenge sent from the server
+ * @param challengeLen length of challenge
+ * @param response response to send to the server (allocated by
+ * this function, free with delete[])
+ * @param responseLen length of response buffer
+ * @return true if authentication terminated successfully, or
+ * false if the authentication process should continue
+ * @throw exceptions::sasl_exception if an error occurred during
+ * authentication (in this case, the values in 'response' and
+ * 'responseLen' are undetermined)
+ */
+ bool evaluateChallenge(
+ const byte_t* challenge,
+ const size_t challengeLen,
+ byte_t** response,
+ size_t* responseLen
+ );
+
+ /** Return a socket in which transmitted data is integrity
+ * and/or privacy protected, depending on the QOP (Quality of
+ * Protection) negotiated during the SASL authentication.
+ *
+ * @param sok socket to wrap
+ * @return secured socket
+ */
+ shared_ptr <net::socket> getSecuredSocket(const shared_ptr <net::socket>& sok);
+
+ /** Return the name of the service which is using this
+ * SASL session (eg. "imap"). This value should be returned
+ * by the authenticator when INFO_SERVICE is requested.
+ *
+ * @return service name
+ */
+ const string getServiceName() const;
+
+private:
+
+ SASLSession(
+ const string& serviceName,
+ const shared_ptr <SASLContext>& ctx,
+ const shared_ptr <authenticator>& auth,
+ const shared_ptr <SASLMechanism>& mech
+ );
+
+
+ const string m_serviceName;
+
+ shared_ptr <SASLContext> m_context;
+ shared_ptr <authenticator> m_auth;
+ shared_ptr <SASLMechanism> m_mech;
+
+#ifdef GSASL_VERSION
+ Gsasl* m_gsaslContext;
+ Gsasl_session* m_gsaslSession;
+
+ static int gsaslCallback(Gsasl* ctx, Gsasl_session* sctx, Gsasl_property prop);
+#else
+ void* m_gsaslContext;
+ void* m_gsaslSession;
+
+ static int gsaslCallback(void* ctx, void* sctx, int prop);
+#endif // GSASL_VERSION
+
+};
+
+
+} // sasl
+} // security
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_SASL_SUPPORT
+
+#endif // VMIME_SECURITY_SASL_SASLSESSION_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/security/sasl/SASLSocket.cpp b/vmime-master/src/vmime/security/sasl/SASLSocket.cpp
new file mode 100644
index 0000000..0dbafd8
--- /dev/null
+++ b/vmime-master/src/vmime/security/sasl/SASLSocket.cpp
@@ -0,0 +1,273 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_SASL_SUPPORT
+
+
+#include "vmime/security/sasl/SASLSocket.hpp"
+#include "vmime/security/sasl/SASLSession.hpp"
+
+#include "vmime/utility/stringUtils.hpp"
+
+#include "vmime/exception.hpp"
+
+#include <algorithm>
+#include <cstring>
+
+#include <gsasl.h>
+
+
+namespace vmime {
+namespace security {
+namespace sasl {
+
+
+
+SASLSocket::SASLSocket(
+ const shared_ptr <SASLSession>& sess,
+ const shared_ptr <net::socket>& wrapped
+)
+ : m_session(sess),
+ m_wrapped(wrapped),
+ m_pendingBuffer(0),
+ m_pendingPos(0),
+ m_pendingLen(0) {
+
+}
+
+
+SASLSocket::~SASLSocket() {
+
+ if (m_pendingBuffer) {
+ delete [] m_pendingBuffer;
+ }
+}
+
+
+void SASLSocket::connect(const string& address, const port_t port) {
+
+ m_wrapped->connect(address, port);
+}
+
+
+void SASLSocket::disconnect() {
+
+ m_wrapped->disconnect();
+}
+
+
+bool SASLSocket::isConnected() const {
+
+ return m_wrapped->isConnected();
+}
+
+
+size_t SASLSocket::getBlockSize() const {
+
+ return m_wrapped->getBlockSize();
+}
+
+
+const string SASLSocket::getPeerName() const {
+
+ return m_wrapped->getPeerName();
+}
+
+
+const string SASLSocket::getPeerAddress() const {
+
+ return m_wrapped->getPeerAddress();
+}
+
+
+shared_ptr <net::timeoutHandler> SASLSocket::getTimeoutHandler() {
+
+ return m_wrapped->getTimeoutHandler();
+}
+
+
+void SASLSocket::setTracer(const shared_ptr <net::tracer>& tracer) {
+
+ m_wrapped->setTracer(tracer);
+}
+
+
+shared_ptr <net::tracer> SASLSocket::getTracer() {
+
+ return m_wrapped->getTracer();
+}
+
+
+bool SASLSocket::waitForRead(const int msecs) {
+
+ return m_wrapped->waitForRead(msecs);
+}
+
+
+bool SASLSocket::waitForWrite(const int msecs) {
+
+ return m_wrapped->waitForWrite(msecs);
+}
+
+
+void SASLSocket::receive(string& buffer) {
+
+ const size_t n = receiveRaw(m_recvBuffer, sizeof(m_recvBuffer));
+
+ buffer = utility::stringUtils::makeStringFromBytes(m_recvBuffer, n);
+}
+
+
+size_t SASLSocket::receiveRaw(byte_t* buffer, const size_t count) {
+
+ if (m_pendingLen != 0) {
+
+ const size_t copyLen =
+ (count >= m_pendingLen ? m_pendingLen : count);
+
+ std::copy(
+ m_pendingBuffer + m_pendingPos,
+ m_pendingBuffer + m_pendingPos + copyLen,
+ buffer
+ );
+
+ m_pendingLen -= copyLen;
+ m_pendingPos += copyLen;
+
+ if (m_pendingLen == 0) {
+
+ delete [] m_pendingBuffer;
+
+ m_pendingBuffer = 0;
+ m_pendingPos = 0;
+ m_pendingLen = 0;
+ }
+
+ return copyLen;
+ }
+
+ const size_t n = m_wrapped->receiveRaw(buffer, count);
+
+ byte_t* output = 0;
+ size_t outputLen = 0;
+
+ m_session->getMechanism()->decode(m_session, buffer, n, &output, &outputLen);
+
+ // If we can not copy all decoded data into the output buffer, put
+ // remaining data into a pending buffer for next calls to receive()
+ if (outputLen > count) {
+
+ std::copy(output, output + count, buffer);
+
+ m_pendingBuffer = output;
+ m_pendingLen = outputLen;
+ m_pendingPos = count;
+
+ return count;
+
+ } else {
+
+ std::copy(output, output + outputLen, buffer);
+
+ delete [] output;
+
+ return outputLen;
+ }
+}
+
+
+void SASLSocket::send(const string& buffer) {
+
+ sendRaw(reinterpret_cast <const byte_t*>(buffer.data()), buffer.length());
+}
+
+
+void SASLSocket::send(const char* str) {
+
+ sendRaw(reinterpret_cast <const byte_t*>(str), strlen(str));
+}
+
+
+void SASLSocket::sendRaw(const byte_t* buffer, const size_t count) {
+
+ byte_t* output = 0;
+ size_t outputLen = 0;
+
+ m_session->getMechanism()->encode(
+ m_session, buffer, count, &output, &outputLen
+ );
+
+ try {
+
+ m_wrapped->sendRaw(output, outputLen);
+
+ } catch (...) {
+
+ delete [] output;
+ throw;
+ }
+
+ delete [] output;
+}
+
+
+size_t SASLSocket::sendRawNonBlocking(const byte_t* buffer, const size_t count) {
+
+ byte_t* output = 0;
+ size_t outputLen = 0;
+
+ m_session->getMechanism()->encode(m_session, buffer, count, &output, &outputLen);
+
+ size_t bytesSent = 0;
+
+ try {
+
+ bytesSent = m_wrapped->sendRawNonBlocking(output, outputLen);
+
+ } catch (...) {
+
+ delete [] output;
+ throw;
+ }
+
+ delete [] output;
+
+ return bytesSent;
+}
+
+
+unsigned int SASLSocket::getStatus() const {
+
+ return m_wrapped->getStatus();
+}
+
+
+} // sasl
+} // security
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_SASL_SUPPORT
diff --git a/vmime-master/src/vmime/security/sasl/SASLSocket.hpp b/vmime-master/src/vmime/security/sasl/SASLSocket.hpp
new file mode 100644
index 0000000..ac0e89e
--- /dev/null
+++ b/vmime-master/src/vmime/security/sasl/SASLSocket.hpp
@@ -0,0 +1,108 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_SECURITY_SASL_SASLSOCKET_HPP_INCLUDED
+#define VMIME_SECURITY_SASL_SASLSOCKET_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_SASL_SUPPORT
+
+
+#include "vmime/types.hpp"
+
+#include "vmime/net/socket.hpp"
+
+
+namespace vmime {
+namespace security {
+namespace sasl {
+
+
+class SASLSession;
+
+
+/** A socket which provides data integrity and/or privacy protection.
+ */
+class VMIME_EXPORT SASLSocket : public net::socket {
+
+public:
+
+ SASLSocket(
+ const shared_ptr <SASLSession>& sess,
+ const shared_ptr <net::socket>& wrapped
+ );
+
+ ~SASLSocket();
+
+ void connect(const string& address, const port_t port);
+ void disconnect();
+
+ bool isConnected() const;
+
+ bool waitForRead(const int msecs = 30000);
+ bool waitForWrite(const int msecs = 30000);
+
+ void receive(string& buffer);
+ size_t receiveRaw(byte_t* buffer, const size_t count);
+
+ void send(const string& buffer);
+ void send(const char* str);
+ void sendRaw(const byte_t* buffer, const size_t count);
+ size_t sendRawNonBlocking(const byte_t* buffer, const size_t count);
+
+ size_t getBlockSize() const;
+
+ unsigned int getStatus() const;
+
+ const string getPeerName() const;
+ const string getPeerAddress() const;
+
+ shared_ptr <net::timeoutHandler> getTimeoutHandler();
+
+ void setTracer(const shared_ptr <net::tracer>& tracer);
+ shared_ptr <net::tracer> getTracer();
+
+private:
+
+ shared_ptr <SASLSession> m_session;
+ shared_ptr <net::socket> m_wrapped;
+
+ byte_t* m_pendingBuffer;
+ size_t m_pendingPos;
+ size_t m_pendingLen;
+
+ byte_t m_recvBuffer[65536];
+};
+
+
+} // sasl
+} // security
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_SASL_SUPPORT
+
+#endif // VMIME_SECURITY_SASL_SASLSOCKET_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/security/sasl/XOAuth2SASLAuthenticator.cpp b/vmime-master/src/vmime/security/sasl/XOAuth2SASLAuthenticator.cpp
new file mode 100644
index 0000000..ecc715a
--- /dev/null
+++ b/vmime-master/src/vmime/security/sasl/XOAuth2SASLAuthenticator.cpp
@@ -0,0 +1,99 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_SASL_SUPPORT
+
+
+#include "vmime/security/sasl/XOAuth2SASLAuthenticator.hpp"
+
+#include "vmime/security/sasl/SASLMechanism.hpp"
+#include "vmime/security/sasl/SASLSession.hpp"
+#include "vmime/security/sasl/SASLContext.hpp"
+
+
+namespace vmime {
+namespace security {
+namespace sasl {
+
+
+XOAuth2SASLAuthenticator::XOAuth2SASLAuthenticator(const Mode mode)
+ : m_mode(mode) {
+
+}
+
+
+XOAuth2SASLAuthenticator::~XOAuth2SASLAuthenticator() {
+
+}
+
+
+const std::vector <shared_ptr <SASLMechanism> >
+ XOAuth2SASLAuthenticator::getAcceptableMechanisms(
+ const std::vector <shared_ptr <SASLMechanism> >& available,
+ const shared_ptr <SASLMechanism>& suggested
+ ) const {
+
+ if (m_mode == MODE_EXCLUSIVE) {
+
+ std::vector <shared_ptr <SASLMechanism> > mechs;
+
+ for (size_t i = available.size() ; i != 0 ; --i) {
+
+ shared_ptr <SASLMechanism> mech = available[i - 1];
+
+ if ("XOAUTH2" == mech->getName()) {
+ // Only allow XOAuth2
+ mechs.push_back(mech);
+ }
+ }
+
+ return mechs;
+
+ } else {
+
+ shared_ptr <SASLMechanism> newSuggested(suggested);
+
+ for (size_t i = available.size() ; i != 0 ; --i) {
+
+ shared_ptr <SASLMechanism> mech = available[i - 1];
+
+ if ("XOAUTH2" == mech->getName()) {
+ // Suggest using XOAuth2
+ newSuggested = mech;
+ }
+ }
+
+ return defaultSASLAuthenticator::getAcceptableMechanisms(available, newSuggested);
+ }
+}
+
+
+} // sasl
+} // security
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_SASL_SUPPORT
diff --git a/vmime-master/src/vmime/security/sasl/XOAuth2SASLAuthenticator.hpp b/vmime-master/src/vmime/security/sasl/XOAuth2SASLAuthenticator.hpp
new file mode 100644
index 0000000..e4d3d83
--- /dev/null
+++ b/vmime-master/src/vmime/security/sasl/XOAuth2SASLAuthenticator.hpp
@@ -0,0 +1,77 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_SECURITY_SASL_XOAUTH2SASLAUTHENTICATOR_HPP_INCLUDED
+#define VMIME_SECURITY_SASL_XOAUTH2SASLAUTHENTICATOR_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_SASL_SUPPORT
+
+
+#include "vmime/security/sasl/defaultSASLAuthenticator.hpp"
+
+
+namespace vmime {
+namespace security {
+namespace sasl {
+
+
+/** An authenticator that is capable of providing information
+ * for XOAuth2 authentication mechanisms (username and access token).
+ * This authenticator force using the XOAUTH2 mechanism.
+ */
+class VMIME_EXPORT XOAuth2SASLAuthenticator : public defaultSASLAuthenticator {
+
+public:
+
+ enum Mode {
+ MODE_SUGGEST, /**< Try XOAUTH2 before other mechanisms. */
+ MODE_EXCLUSIVE /**< Use XOAUTH2 and nothing else. */
+ };
+
+
+ XOAuth2SASLAuthenticator(const Mode mode);
+ ~XOAuth2SASLAuthenticator();
+
+ const std::vector <shared_ptr <SASLMechanism> > getAcceptableMechanisms(
+ const std::vector <shared_ptr <SASLMechanism> >& available,
+ const shared_ptr <SASLMechanism>& suggested
+ ) const;
+
+private:
+
+ Mode m_mode;
+};
+
+
+} // sasl
+} // security
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_SASL_SUPPORT
+
+#endif // VMIME_SECURITY_SASL_XOAUTH2SASLAUTHENTICATOR_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/security/sasl/XOAuth2SASLMechanism.cpp b/vmime-master/src/vmime/security/sasl/XOAuth2SASLMechanism.cpp
new file mode 100644
index 0000000..e5ecd4b
--- /dev/null
+++ b/vmime-master/src/vmime/security/sasl/XOAuth2SASLMechanism.cpp
@@ -0,0 +1,155 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_SASL_SUPPORT
+
+
+#include "vmime/security/sasl/XOAuth2SASLMechanism.hpp"
+
+#include "vmime/security/sasl/SASLContext.hpp"
+#include "vmime/security/sasl/SASLSession.hpp"
+
+#include "vmime/exception.hpp"
+
+#include <sstream>
+
+
+namespace vmime {
+namespace security {
+namespace sasl {
+
+
+XOAuth2SASLMechanism::XOAuth2SASLMechanism(
+ const shared_ptr <SASLContext>& ctx,
+ const string& /* name */
+)
+ : m_context(ctx),
+ m_complete(false) {
+
+}
+
+
+XOAuth2SASLMechanism::~XOAuth2SASLMechanism() {
+
+}
+
+
+const string XOAuth2SASLMechanism::getName() const {
+
+ return "XOAUTH2";
+}
+
+
+bool XOAuth2SASLMechanism::step(
+ const shared_ptr <SASLSession>& sess,
+ const byte_t* /* challenge */,
+ const size_t /* challengeLen */,
+ byte_t** response,
+ size_t* responseLen
+) {
+
+ // Build initial response
+ //
+ // The SASL XOAUTH2 initial client response has the following format:
+ // base64("user=" {User} "^Aauth=Bearer " {Access Token} "^A^A")
+
+ const std::string user(sess->getAuthenticator()->getUsername());
+ const std::string accessToken(sess->getAuthenticator()->getAccessToken());
+
+ std::ostringstream initRespBytes;
+ initRespBytes.write("user=", 5);
+ initRespBytes.write(user.c_str(), user.length());
+ initRespBytes.write("\x01", 1);
+ initRespBytes.write("auth=Bearer ", 12);
+ initRespBytes.write(accessToken.c_str(), accessToken.length());
+ initRespBytes.write("\x01\x01", 2);
+
+ const std::string initResp = initRespBytes.str();
+
+ // Set initial response
+ byte_t* res = new byte_t[initResp.length()];
+ std::copy(initResp.c_str(), initResp.c_str() + initResp.length(), res);
+
+ *response = res;
+ *responseLen = initResp.length();
+ m_complete = true;
+
+ return true;
+}
+
+
+bool XOAuth2SASLMechanism::isComplete() const {
+
+ return m_complete;
+}
+
+
+bool XOAuth2SASLMechanism::hasInitialResponse() const {
+
+ return true;
+}
+
+
+void XOAuth2SASLMechanism::encode(
+ const shared_ptr <SASLSession>& /* sess */,
+ const byte_t* input,
+ const size_t inputLen,
+ byte_t** output,
+ size_t* outputLen
+) {
+
+ // No encoding performed, just copy input bytes
+ byte_t* res = new byte_t[inputLen];
+ std::copy(input, input + inputLen, res);
+
+ *outputLen = inputLen;
+ *output = res;
+}
+
+
+void XOAuth2SASLMechanism::decode(
+ const shared_ptr <SASLSession>& /* sess */,
+ const byte_t* input,
+ const size_t inputLen,
+ byte_t** output,
+ size_t* outputLen
+) {
+
+ // No decoding performed, just copy input bytes
+ byte_t* res = new byte_t[inputLen];
+ std::copy(input, input + inputLen, res);
+
+ *outputLen = inputLen;
+ *output = res;
+}
+
+
+} // sasl
+} // security
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_SASL_SUPPORT
diff --git a/vmime-master/src/vmime/security/sasl/XOAuth2SASLMechanism.hpp b/vmime-master/src/vmime/security/sasl/XOAuth2SASLMechanism.hpp
new file mode 100644
index 0000000..eacbb0a
--- /dev/null
+++ b/vmime-master/src/vmime/security/sasl/XOAuth2SASLMechanism.hpp
@@ -0,0 +1,102 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_SECURITY_SASL_XOAUTH2SASLMECHANISM_HPP_INCLUDED
+#define VMIME_SECURITY_SASL_XOAUTH2SASLMECHANISM_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_SASL_SUPPORT
+
+
+#include "vmime/security/sasl/SASLMechanism.hpp"
+
+
+namespace vmime {
+namespace security {
+namespace sasl {
+
+
+class SASLContext;
+
+
+/** SASL XOAUTH2 mechanism, used by GMail.
+ */
+class VMIME_EXPORT XOAuth2SASLMechanism : public SASLMechanism {
+
+public:
+
+ XOAuth2SASLMechanism(const shared_ptr <SASLContext>& ctx, const string& name);
+ ~XOAuth2SASLMechanism();
+
+
+ const string getName() const;
+
+ bool step(
+ const shared_ptr <SASLSession>& sess,
+ const byte_t* challenge,
+ const size_t challengeLen,
+ byte_t** response,
+ size_t* responseLen
+ );
+
+ bool isComplete() const;
+
+ bool hasInitialResponse() const;
+
+ void encode(
+ const shared_ptr <SASLSession>& sess,
+ const byte_t* input,
+ const size_t inputLen,
+ byte_t** output,
+ size_t* outputLen
+ );
+
+ void decode(
+ const shared_ptr <SASLSession>& sess,
+ const byte_t* input,
+ const size_t inputLen,
+ byte_t** output,
+ size_t* outputLen
+ );
+
+private:
+
+ /** SASL context */
+ shared_ptr <SASLContext> m_context;
+
+ /** Authentication process status. */
+ bool m_complete;
+};
+
+
+} // sasl
+} // security
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_SASL_SUPPORT
+
+#endif // VMIME_SECURITY_SASL_XOAUTH2SASLMECHANISM_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/security/sasl/builtinSASLMechanism.cpp b/vmime-master/src/vmime/security/sasl/builtinSASLMechanism.cpp
new file mode 100644
index 0000000..846e2cc
--- /dev/null
+++ b/vmime-master/src/vmime/security/sasl/builtinSASLMechanism.cpp
@@ -0,0 +1,221 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_SASL_SUPPORT
+
+
+#include <gsasl.h>
+
+#include "vmime/security/sasl/builtinSASLMechanism.hpp"
+
+#include "vmime/security/sasl/SASLContext.hpp"
+#include "vmime/security/sasl/SASLSession.hpp"
+
+#include "vmime/exception.hpp"
+
+#include <stdexcept>
+#include <new>
+
+
+namespace vmime {
+namespace security {
+namespace sasl {
+
+
+builtinSASLMechanism::builtinSASLMechanism(
+ const shared_ptr <SASLContext>& ctx,
+ const string& name
+)
+ : m_context(ctx),
+ m_name(name),
+ m_complete(false) {
+
+}
+
+
+builtinSASLMechanism::~builtinSASLMechanism() {
+
+}
+
+
+const string builtinSASLMechanism::getName() const {
+
+ return m_name;
+}
+
+
+bool builtinSASLMechanism::step(
+ const shared_ptr <SASLSession>& sess,
+ const byte_t* challenge,
+ const size_t challengeLen,
+ byte_t** response,
+ size_t* responseLen
+) {
+
+ char* output = 0;
+ size_t outputLen = 0;
+
+ const int result = gsasl_step(
+ sess->m_gsaslSession,
+ reinterpret_cast <const char*>(challenge), challengeLen,
+ &output, &outputLen
+ );
+
+ if (result == GSASL_OK || result == GSASL_NEEDS_MORE) {
+
+ byte_t* res = new byte_t[outputLen];
+
+ for (size_t i = 0 ; i < outputLen ; ++i) {
+ res[i] = output[i];
+ }
+
+ *response = res;
+ *responseLen = outputLen;
+
+ gsasl_free(output);
+
+ } else {
+
+ *response = 0;
+ *responseLen = 0;
+ }
+
+ if (result == GSASL_OK) {
+
+ // Authentication process completed
+ m_complete = true;
+ return true;
+
+ } else if (result == GSASL_NEEDS_MORE) {
+
+ // Continue authentication process
+ return false;
+
+ } else if (result == GSASL_MALLOC_ERROR) {
+
+ throw std::bad_alloc();
+
+ } else {
+
+ throw exceptions::sasl_exception(
+ "Error when processing challenge: "
+ + SASLContext::getErrorMessage("gsasl_step", result)
+ );
+ }
+}
+
+
+bool builtinSASLMechanism::isComplete() const {
+
+ return m_complete;
+}
+
+
+bool builtinSASLMechanism::hasInitialResponse() const {
+
+ // It seems GNU SASL does not support initial response
+ return false;
+}
+
+
+void builtinSASLMechanism::encode(
+ const shared_ptr <SASLSession>& sess,
+ const byte_t* input,
+ const size_t inputLen,
+ byte_t** output,
+ size_t* outputLen
+) {
+
+ char* coutput = 0;
+ size_t coutputLen = 0;
+
+ if (gsasl_encode(sess->m_gsaslSession, reinterpret_cast <const char*>(input), inputLen,
+ &coutput, &coutputLen) != GSASL_OK) {
+
+ throw exceptions::sasl_exception("Encoding error.");
+ }
+
+ try {
+
+ byte_t* res = new byte_t[coutputLen];
+
+ std::copy(coutput, coutput + coutputLen, res);
+
+ *output = res;
+ *outputLen = static_cast <int>(coutputLen);
+
+ } catch (...) {
+
+ gsasl_free(coutput);
+ throw;
+ }
+
+ gsasl_free(coutput);
+}
+
+
+void builtinSASLMechanism::decode(
+ const shared_ptr <SASLSession>& sess,
+ const byte_t* input,
+ const size_t inputLen,
+ byte_t** output,
+ size_t* outputLen
+) {
+
+ char* coutput = 0;
+ size_t coutputLen = 0;
+
+ try {
+
+ if (gsasl_decode(sess->m_gsaslSession, reinterpret_cast <const char*>(input), inputLen,
+ &coutput, &coutputLen) != GSASL_OK) {
+
+ throw exceptions::sasl_exception("Decoding error.");
+ }
+
+ byte_t* res = new byte_t[coutputLen];
+
+ std::copy(coutput, coutput + coutputLen, res);
+
+ *output = res;
+ *outputLen = static_cast <int>(coutputLen);
+
+ } catch (...) {
+
+ gsasl_free(coutput);
+ throw;
+ }
+
+ gsasl_free(coutput);
+}
+
+
+} // sasl
+} // security
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_SASL_SUPPORT
diff --git a/vmime-master/src/vmime/security/sasl/builtinSASLMechanism.hpp b/vmime-master/src/vmime/security/sasl/builtinSASLMechanism.hpp
new file mode 100644
index 0000000..2e412d6
--- /dev/null
+++ b/vmime-master/src/vmime/security/sasl/builtinSASLMechanism.hpp
@@ -0,0 +1,105 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_SECURITY_SASL_BUILTINSASLMECHANISM_HPP_INCLUDED
+#define VMIME_SECURITY_SASL_BUILTINSASLMECHANISM_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_SASL_SUPPORT
+
+
+#include "vmime/security/sasl/SASLMechanism.hpp"
+
+
+namespace vmime {
+namespace security {
+namespace sasl {
+
+
+class SASLContext;
+
+
+/** A built-in authentication mechanism that relies on
+ * the GNU SASL library.
+ */
+class VMIME_EXPORT builtinSASLMechanism : public SASLMechanism {
+
+public:
+
+ builtinSASLMechanism(const shared_ptr <SASLContext>& ctx, const string& name);
+ ~builtinSASLMechanism();
+
+
+ const string getName() const;
+
+ bool step(
+ const shared_ptr <SASLSession>& sess,
+ const byte_t* challenge,
+ const size_t challengeLen,
+ byte_t** response, size_t* responseLen
+ );
+
+ bool isComplete() const;
+
+ bool hasInitialResponse() const;
+
+ void encode(
+ const shared_ptr <SASLSession>& sess,
+ const byte_t* input,
+ const size_t inputLen,
+ byte_t** output,
+ size_t* outputLen
+ );
+
+ void decode(
+ const shared_ptr <SASLSession>& sess,
+ const byte_t* input,
+ const size_t inputLen,
+ byte_t** output,
+ size_t* outputLen
+ );
+
+private:
+
+ /** SASL context */
+ shared_ptr <SASLContext> m_context;
+
+ /** Mechanism name */
+ const string m_name;
+
+ /** Authentication process status. */
+ bool m_complete;
+};
+
+
+} // sasl
+} // security
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_SASL_SUPPORT
+
+#endif // VMIME_SECURITY_SASL_BUILTINSASLMECHANISM_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/security/sasl/defaultSASLAuthenticator.cpp b/vmime-master/src/vmime/security/sasl/defaultSASLAuthenticator.cpp
new file mode 100644
index 0000000..ebd7e68
--- /dev/null
+++ b/vmime-master/src/vmime/security/sasl/defaultSASLAuthenticator.cpp
@@ -0,0 +1,159 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_SASL_SUPPORT
+
+
+#include "vmime/security/sasl/defaultSASLAuthenticator.hpp"
+
+#include "vmime/security/sasl/SASLMechanism.hpp"
+#include "vmime/security/sasl/SASLSession.hpp"
+#include "vmime/security/sasl/SASLContext.hpp"
+
+#include "vmime/net/service.hpp"
+
+
+namespace vmime {
+namespace security {
+namespace sasl {
+
+
+defaultSASLAuthenticator::defaultSASLAuthenticator() {
+
+}
+
+
+defaultSASLAuthenticator::~defaultSASLAuthenticator() {
+
+}
+
+
+const std::vector <shared_ptr <SASLMechanism> > defaultSASLAuthenticator::getAcceptableMechanisms(
+ const std::vector <shared_ptr <SASLMechanism> >& available,
+ const shared_ptr <SASLMechanism>& suggested
+) const {
+
+ if (suggested) {
+
+ std::vector <shared_ptr <SASLMechanism> > res;
+
+ res.push_back(suggested);
+
+ for (unsigned int i = 0 ; i < available.size() ; ++i) {
+
+ if (available[i]->getName() != suggested->getName()) {
+ res.push_back(available[i]);
+ }
+ }
+
+ return res;
+
+ } else {
+
+ return available;
+ }
+}
+
+
+const string defaultSASLAuthenticator::getUsername() const {
+
+ return m_default.getUsername();
+}
+
+
+const string defaultSASLAuthenticator::getPassword() const {
+
+ return m_default.getPassword();
+}
+
+
+const string defaultSASLAuthenticator::getAccessToken() const {
+
+ return m_default.getAccessToken();
+}
+
+
+const string defaultSASLAuthenticator::getHostname() const {
+
+ return m_default.getHostname();
+}
+
+
+const string defaultSASLAuthenticator::getAnonymousToken() const {
+
+ return m_default.getAnonymousToken();
+}
+
+
+const string defaultSASLAuthenticator::getServiceName() const {
+
+ return m_saslSession.lock()->getServiceName();
+}
+
+
+void defaultSASLAuthenticator::setService(const shared_ptr <net::service>& serv) {
+
+ m_service = serv;
+ m_default.setService(serv);
+}
+
+
+weak_ptr <net::service> defaultSASLAuthenticator::getService() const {
+
+ return m_service;
+}
+
+
+void defaultSASLAuthenticator::setSASLSession(const shared_ptr <SASLSession>& sess) {
+
+ m_saslSession = sess;
+}
+
+
+shared_ptr <SASLSession> defaultSASLAuthenticator::getSASLSession() const {
+
+ return m_saslSession.lock();
+}
+
+
+void defaultSASLAuthenticator::setSASLMechanism(const shared_ptr <SASLMechanism>& mech) {
+
+ m_saslMech = mech;
+}
+
+
+shared_ptr <SASLMechanism> defaultSASLAuthenticator::getSASLMechanism() const {
+
+ return m_saslMech;
+}
+
+
+} // sasl
+} // security
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_SASL_SUPPORT
diff --git a/vmime-master/src/vmime/security/sasl/defaultSASLAuthenticator.hpp b/vmime-master/src/vmime/security/sasl/defaultSASLAuthenticator.hpp
new file mode 100644
index 0000000..368e9ef
--- /dev/null
+++ b/vmime-master/src/vmime/security/sasl/defaultSASLAuthenticator.hpp
@@ -0,0 +1,91 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_SECURITY_SASL_DEFAULTSASLAUTHENTICATOR_HPP_INCLUDED
+#define VMIME_SECURITY_SASL_DEFAULTSASLAUTHENTICATOR_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_SASL_SUPPORT
+
+
+#include "vmime/security/sasl/SASLAuthenticator.hpp"
+#include "vmime/security/defaultAuthenticator.hpp"
+
+
+namespace vmime {
+namespace security {
+namespace sasl {
+
+
+/** An authenticator that is capable of providing information
+ * for simple authentication mechanisms (username and password).
+ */
+class VMIME_EXPORT defaultSASLAuthenticator : public SASLAuthenticator {
+
+public:
+
+ defaultSASLAuthenticator();
+ ~defaultSASLAuthenticator();
+
+ const std::vector <shared_ptr <SASLMechanism> > getAcceptableMechanisms(
+ const std::vector <shared_ptr <SASLMechanism> >& available,
+ const shared_ptr <SASLMechanism>& suggested
+ ) const;
+
+ const string getUsername() const;
+ const string getPassword() const;
+ const string getHostname() const;
+ const string getAnonymousToken() const;
+ const string getServiceName() const;
+ const string getAccessToken() const;
+
+ void setService(const shared_ptr <net::service>& serv);
+ weak_ptr <net::service> getService() const;
+
+ void setSASLSession(const shared_ptr <SASLSession>& sess);
+ shared_ptr <SASLSession> getSASLSession() const;
+
+ void setSASLMechanism(const shared_ptr <SASLMechanism>& mech);
+ shared_ptr <SASLMechanism> getSASLMechanism() const;
+
+private:
+
+ defaultAuthenticator m_default;
+
+ weak_ptr <net::service> m_service;
+ weak_ptr <SASLSession> m_saslSession;
+ shared_ptr <SASLMechanism> m_saslMech;
+};
+
+
+} // sasl
+} // security
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES && VMIME_HAVE_SASL_SUPPORT
+
+#endif // VMIME_SECURITY_SASL_DEFAULTSASLAUTHENTICATOR_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/streamContentHandler.cpp b/vmime-master/src/vmime/streamContentHandler.cpp
new file mode 100644
index 0000000..e35bcd7
--- /dev/null
+++ b/vmime-master/src/vmime/streamContentHandler.cpp
@@ -0,0 +1,257 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/streamContentHandler.hpp"
+
+#include "vmime/utility/outputStreamAdapter.hpp"
+#include "vmime/utility/inputStreamStringAdapter.hpp"
+#include "vmime/utility/seekableInputStream.hpp"
+#include "vmime/utility/streamUtils.hpp"
+
+
+namespace vmime {
+
+
+streamContentHandler::streamContentHandler()
+ : m_encoding(NO_ENCODING),
+ m_stream(null),
+ m_length(0) {
+
+}
+
+
+streamContentHandler::streamContentHandler(
+ const shared_ptr <utility::inputStream>& is,
+ const size_t length,
+ const vmime::encoding& enc
+) {
+
+ setData(is, length, enc);
+}
+
+
+streamContentHandler::~streamContentHandler() {
+
+}
+
+
+streamContentHandler::streamContentHandler(const streamContentHandler& cts)
+ : contentHandler(),
+ m_contentType(cts.m_contentType),
+ m_encoding(cts.m_encoding),
+ m_stream(cts.m_stream),
+ m_length(cts.m_length) {
+
+}
+
+
+shared_ptr <contentHandler> streamContentHandler::clone() const {
+
+ return make_shared <streamContentHandler>(*this);
+}
+
+
+streamContentHandler& streamContentHandler::operator=(const streamContentHandler& cts) {
+
+ m_contentType = cts.m_contentType;
+ m_encoding = cts.m_encoding;
+
+ m_stream = cts.m_stream;
+ m_length = cts.m_length;
+
+ return *this;
+}
+
+
+void streamContentHandler::setData(
+ const shared_ptr <utility::inputStream>& is,
+ const size_t length,
+ const vmime::encoding& enc
+) {
+
+ m_encoding = enc;
+ m_length = length;
+ m_stream = is;
+}
+
+
+void streamContentHandler::generate(
+ utility::outputStream& os,
+ const vmime::encoding& enc,
+ const size_t maxLineLength
+) const {
+
+ if (!m_stream) {
+ return;
+ }
+
+ // Managed data is already encoded
+ if (isEncoded()) {
+
+ // The data is already encoded but the encoding specified for
+ // the generation is different from the current one. We need
+ // to re-encode data: decode from input buffer to temporary
+ // buffer, and then re-encode to output stream...
+ if (m_encoding != enc) {
+
+ shared_ptr <utility::encoder::encoder> theDecoder = m_encoding.getEncoder();
+ shared_ptr <utility::encoder::encoder> theEncoder = enc.getEncoder();
+
+ theEncoder->getProperties()["maxlinelength"] = maxLineLength;
+ theEncoder->getProperties()["text"] = (m_contentType.getType() == mediaTypes::TEXT);
+
+ m_stream->reset(); // may not work...
+
+ std::ostringstream oss;
+ utility::outputStreamAdapter tempOut(oss);
+
+ theDecoder->decode(*m_stream, tempOut);
+
+ string str = oss.str();
+ utility::inputStreamStringAdapter tempIn(str);
+
+ theEncoder->encode(tempIn, os);
+
+ // No encoding to perform
+ } else {
+
+ m_stream->reset(); // may not work...
+
+ utility::bufferedStreamCopy(*m_stream, os);
+ }
+
+ // Need to encode data before
+ } else {
+
+ shared_ptr <utility::encoder::encoder> theEncoder = enc.getEncoder();
+ theEncoder->getProperties()["maxlinelength"] = maxLineLength;
+ theEncoder->getProperties()["text"] = (m_contentType.getType() == mediaTypes::TEXT);
+
+ m_stream->reset(); // may not work...
+
+ theEncoder->encode(*m_stream, os);
+ }
+}
+
+
+void streamContentHandler::extract(
+ utility::outputStream& os,
+ utility::progressListener* progress
+) const {
+
+ if (!m_stream) {
+ return;
+ }
+
+ // No decoding to perform
+ if (!isEncoded()) {
+
+ m_stream->reset(); // may not work...
+
+ if (progress) {
+ utility::bufferedStreamCopy(*m_stream, os, getLength(), progress);
+ } else {
+ utility::bufferedStreamCopy(*m_stream, os);
+ }
+
+ // Need to decode data
+ } else {
+
+ shared_ptr <utility::encoder::encoder> theDecoder = m_encoding.getEncoder();
+
+ m_stream->reset(); // may not work...
+
+ utility::progressListenerSizeAdapter plsa(progress, getLength());
+
+ theDecoder->decode(*m_stream, os, &plsa);
+ }
+}
+
+
+void streamContentHandler::extractRaw(
+ utility::outputStream& os,
+ utility::progressListener* progress
+) const {
+
+ if (!m_stream) {
+ return;
+ }
+
+ m_stream->reset(); // may not work...
+
+ if (progress) {
+ utility::bufferedStreamCopy(*m_stream, os, getLength(), progress);
+ } else {
+ utility::bufferedStreamCopy(*m_stream, os);
+ }
+}
+
+
+size_t streamContentHandler::getLength() const {
+
+ return m_length;
+}
+
+
+bool streamContentHandler::isEmpty() const {
+
+ return m_length == 0 || !m_stream;
+}
+
+
+bool streamContentHandler::isEncoded() const {
+
+ return m_encoding != NO_ENCODING;
+}
+
+
+const vmime::encoding& streamContentHandler::getEncoding() const {
+
+ return m_encoding;
+}
+
+
+bool streamContentHandler::isBuffered() const {
+
+ if (dynamicCast <utility::seekableInputStream>(m_stream)) {
+ return true;
+ }
+
+ // FIXME: some streams can be resetted
+ return false;
+}
+
+
+void streamContentHandler::setContentTypeHint(const mediaType& type) {
+
+ m_contentType = type;
+}
+
+
+const mediaType streamContentHandler::getContentTypeHint() const {
+
+ return m_contentType;
+}
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/streamContentHandler.hpp b/vmime-master/src/vmime/streamContentHandler.hpp
new file mode 100644
index 0000000..6964a1c
--- /dev/null
+++ b/vmime-master/src/vmime/streamContentHandler.hpp
@@ -0,0 +1,126 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_STREAMCONTENTHANDLER_HPP_INCLUDED
+#define VMIME_STREAMCONTENTHANDLER_HPP_INCLUDED
+
+
+#include "vmime/contentHandler.hpp"
+
+
+namespace vmime {
+
+
+/** A content handler which obtains its data from a stream.
+ */
+class VMIME_EXPORT streamContentHandler : public contentHandler {
+
+public:
+
+ /** Creates a new empty content handler. No data can be extracted until
+ * an input stream is set using setData() function.
+ *
+ * @return a reference to a new content handler
+ */
+ streamContentHandler();
+
+ /** Creates a new content handler using an input stream.
+ *
+ * @param is input stream from which data will be obtained
+ * @param length expected stream length. May be zero, but it is highly
+ * recommended to set this parameter to take part of some optimizations
+ * and features (eg. SMTP CHUNKING/SIZE extension).
+ * @param enc set to anything other than NO_ENCODING if the data obtained
+ * from the stream is already encoded with the specified encoding
+ *
+ * @return a reference to a new content handler
+ */
+ streamContentHandler(
+ const shared_ptr <utility::inputStream>& is,
+ const size_t length,
+ const vmime::encoding& enc = NO_ENCODING
+ );
+
+ ~streamContentHandler();
+
+ streamContentHandler(const streamContentHandler& cts);
+ streamContentHandler& operator=(const streamContentHandler& cts);
+
+ shared_ptr <contentHandler> clone() const;
+
+ /** Sets the data managed by this content handler.
+ *
+ * @param is input stream from which data will be obtained
+ * @param length expected stream length. May be zero, but it is highly
+ * recommended to set this parameter to take part of some optimizations
+ * and features (eg. SMTP CHUNKING/SIZE extension).
+ * @param enc set to anything other than NO_ENCODING if the data obtained
+ * from the stream is already encoded with the specified encoding
+ */
+ void setData(
+ const shared_ptr <utility::inputStream>& is,
+ const size_t length,
+ const vmime::encoding& enc = NO_ENCODING
+ );
+
+
+ void generate(
+ utility::outputStream& os,
+ const vmime::encoding& enc,
+ const size_t maxLineLength = lineLengthLimits::infinite
+ ) const;
+
+ void extract(utility::outputStream& os, utility::progressListener* progress = NULL) const;
+ void extractRaw(utility::outputStream& os, utility::progressListener* progress = NULL) const;
+
+ size_t getLength() const;
+
+ bool isEncoded() const;
+
+ const vmime::encoding& getEncoding() const;
+
+ bool isEmpty() const;
+
+ bool isBuffered() const;
+
+ void setContentTypeHint(const mediaType& type);
+ const mediaType getContentTypeHint() const;
+
+private:
+
+ mediaType m_contentType;
+
+ // Equals to NO_ENCODING if data is not encoded, otherwise this
+ // specifies the encoding that have been used to encode the data.
+ vmime::encoding m_encoding;
+
+ // Actual data
+ mutable shared_ptr <utility::inputStream> m_stream;
+ size_t m_length;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_STREAMCONTENTHANDLER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/stringContentHandler.cpp b/vmime-master/src/vmime/stringContentHandler.cpp
new file mode 100644
index 0000000..f7fadf7
--- /dev/null
+++ b/vmime-master/src/vmime/stringContentHandler.cpp
@@ -0,0 +1,228 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/stringContentHandler.hpp"
+
+#include "vmime/utility/inputStreamStringAdapter.hpp"
+#include "vmime/utility/outputStreamAdapter.hpp"
+#include "vmime/utility/streamUtils.hpp"
+
+
+namespace vmime {
+
+
+stringContentHandler::stringContentHandler() {
+
+}
+
+
+stringContentHandler::stringContentHandler(
+ const string& buffer,
+ const vmime::encoding& enc
+)
+ : m_encoding(enc),
+ m_string(buffer) {
+
+}
+
+
+stringContentHandler::stringContentHandler(
+ const stringContentHandler& cts
+)
+ : contentHandler(),
+ m_contentType(cts.m_contentType),
+ m_encoding(cts.m_encoding),
+ m_string(cts.m_string) {
+
+}
+
+
+stringContentHandler::~stringContentHandler() {
+
+}
+
+
+shared_ptr <contentHandler> stringContentHandler::clone() const {
+
+ return make_shared <stringContentHandler>(*this);
+}
+
+
+stringContentHandler& stringContentHandler::operator=(const stringContentHandler& cts) {
+
+ m_contentType = cts.m_contentType;
+ m_encoding = cts.m_encoding;
+ m_string = cts.m_string;
+
+ return *this;
+}
+
+
+void stringContentHandler::setData(const string& buffer, const vmime::encoding& enc) {
+
+ m_encoding = enc;
+ m_string = buffer;
+}
+
+
+stringContentHandler& stringContentHandler::operator=(const string& buffer) {
+
+ setData(buffer, NO_ENCODING);
+ return *this;
+}
+
+
+void stringContentHandler::generate(
+ utility::outputStream& os,
+ const vmime::encoding& enc,
+ const size_t maxLineLength
+) const {
+
+ // Managed data is already encoded
+ if (isEncoded()) {
+
+ // The data is already encoded but the encoding specified for
+ // the generation is different from the current one. We need
+ // to re-encode data: decode from input buffer to temporary
+ // buffer, and then re-encode to output stream...
+ if (m_encoding != enc) {
+
+ shared_ptr <utility::encoder::encoder> theDecoder = m_encoding.getEncoder();
+ shared_ptr <utility::encoder::encoder> theEncoder = enc.getEncoder();
+
+ theEncoder->getProperties()["maxlinelength"] = maxLineLength;
+ theEncoder->getProperties()["text"] = (m_contentType.getType() == mediaTypes::TEXT);
+
+ utility::inputStreamStringAdapter in(m_string);
+
+ std::ostringstream oss;
+ utility::outputStreamAdapter tempOut(oss);
+
+ theDecoder->decode(in, tempOut);
+
+ string str = oss.str();
+ utility::inputStreamStringAdapter tempIn(str);
+
+ theEncoder->encode(tempIn, os);
+
+ // No encoding to perform
+ } else {
+
+ os.write(m_string.data(), m_string.length());
+ }
+
+ // Need to encode data before
+ } else {
+
+ shared_ptr <utility::encoder::encoder> theEncoder = enc.getEncoder();
+ theEncoder->getProperties()["maxlinelength"] = maxLineLength;
+ theEncoder->getProperties()["text"] = (m_contentType.getType() == mediaTypes::TEXT);
+
+ utility::inputStreamStringAdapter in(m_string);
+
+ theEncoder->encode(in, os);
+ }
+}
+
+
+void stringContentHandler::extract(
+ utility::outputStream& os,
+ utility::progressListener* progress
+) const {
+
+ // No decoding to perform
+ if (!isEncoded()) {
+
+ utility::inputStreamStringAdapter in(m_string);
+ utility::progressListenerSizeAdapter plsa(progress, getLength());
+
+ utility::bufferedStreamCopy(in, os, m_string.length(), progress);
+
+ // Need to decode data
+ } else {
+
+ shared_ptr <utility::encoder::encoder> theDecoder = m_encoding.getEncoder();
+
+ utility::inputStreamStringAdapter in(m_string);
+ utility::progressListenerSizeAdapter plsa(progress, getLength());
+
+ theDecoder->decode(in, os, &plsa);
+ }
+}
+
+
+void stringContentHandler::extractRaw(
+ utility::outputStream& os,
+ utility::progressListener* progress
+) const {
+
+ utility::inputStreamStringAdapter in(m_string);
+ utility::progressListenerSizeAdapter plsa(progress, getLength());
+
+ utility::bufferedStreamCopy(in, os, m_string.length(), progress);
+}
+
+
+size_t stringContentHandler::getLength() const {
+
+ return m_string.length();
+}
+
+
+bool stringContentHandler::isEmpty() const {
+
+ return m_string.length() == 0;
+}
+
+
+bool stringContentHandler::isEncoded() const {
+
+ return m_encoding != NO_ENCODING;
+}
+
+
+const vmime::encoding& stringContentHandler::getEncoding() const {
+
+ return m_encoding;
+}
+
+
+bool stringContentHandler::isBuffered() const {
+
+ return true;
+}
+
+
+void stringContentHandler::setContentTypeHint(const mediaType& type) {
+
+ m_contentType = type;
+}
+
+
+const mediaType stringContentHandler::getContentTypeHint() const {
+
+ return m_contentType;
+}
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/stringContentHandler.hpp b/vmime-master/src/vmime/stringContentHandler.hpp
new file mode 100644
index 0000000..c9a7331
--- /dev/null
+++ b/vmime-master/src/vmime/stringContentHandler.hpp
@@ -0,0 +1,107 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_STRINGCONTENTHANDLER_HPP_INCLUDED
+#define VMIME_STRINGCONTENTHANDLER_HPP_INCLUDED
+
+
+#include "vmime/contentHandler.hpp"
+
+
+namespace vmime {
+
+
+class VMIME_EXPORT stringContentHandler : public contentHandler
+{
+public:
+
+ stringContentHandler();
+
+ stringContentHandler(
+ const string& buffer,
+ const vmime::encoding& enc = NO_ENCODING
+ );
+
+ ~stringContentHandler();
+
+ stringContentHandler(const stringContentHandler& cts);
+ stringContentHandler& operator=(const stringContentHandler& cts);
+
+ shared_ptr <contentHandler> clone() const;
+
+ /** Set data contained in this object.
+ *
+ * @param buffer buffer containing data
+ * @param enc set to anything other than NO_ENCODING if the data managed by
+ * this content handler is already encoded with the specified encoding (so, no
+ * encoding/decoding will be performed on generate()/extract()). Note that the
+ * data may be re-encoded (that is, decoded and encoded) if the encoding passed
+ * to generate() is different from this one.
+ */
+ void setData(
+ const string& buffer,
+ const vmime::encoding& enc = NO_ENCODING
+ );
+
+
+ stringContentHandler& operator=(const string& buffer);
+
+ void generate(
+ utility::outputStream& os,
+ const vmime::encoding& enc,
+ const size_t maxLineLength = lineLengthLimits::infinite
+ ) const;
+
+ void extract(utility::outputStream& os, utility::progressListener* progress = NULL) const;
+ void extractRaw(utility::outputStream& os, utility::progressListener* progress = NULL) const;
+
+ size_t getLength() const;
+
+ bool isEncoded() const;
+
+ const vmime::encoding& getEncoding() const;
+
+ bool isEmpty() const;
+
+ bool isBuffered() const;
+
+ void setContentTypeHint(const mediaType& type);
+ const mediaType getContentTypeHint() const;
+
+private:
+
+ mediaType m_contentType;
+
+ // Equals to NO_ENCODING if data is not encoded, otherwise this
+ // specifies the encoding that have been used to encode the data.
+ vmime::encoding m_encoding;
+
+ // The actual data
+ string m_string;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_STRINGCONTENTHANDLER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/text.cpp b/vmime-master/src/vmime/text.cpp
new file mode 100644
index 0000000..86ba44f
--- /dev/null
+++ b/vmime-master/src/vmime/text.cpp
@@ -0,0 +1,536 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/text.hpp"
+
+#include "vmime/parserHelpers.hpp"
+#include "vmime/encoding.hpp"
+
+
+namespace vmime {
+
+
+text::text() {
+
+}
+
+
+text::text(const text& t)
+ : headerFieldValue() {
+
+ copyFrom(t);
+}
+
+
+text::text(const string& t, const charset& ch) {
+
+ createFromString(t, ch);
+}
+
+
+text::text(const string& t) {
+
+ createFromString(t, charset::getLocalCharset());
+}
+
+
+text::text(const word& w) {
+
+ appendWord(make_shared <word>(w));
+}
+
+
+text::~text() {
+
+ removeAllWords();
+}
+
+
+void text::parseImpl(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition
+) {
+
+ removeAllWords();
+
+ size_t newPos;
+
+ const std::vector <shared_ptr <word> > words =
+ word::parseMultiple(ctx, buffer, position, end, &newPos);
+
+ copy_vector(words, m_words);
+
+ setParsedBounds(position, newPos);
+
+ if (newPosition) {
+ *newPosition = newPos;
+ }
+}
+
+
+void text::generateImpl(
+ const generationContext& ctx,
+ utility::outputStream& os,
+ const size_t curLinePos,
+ size_t* newLinePos
+) const {
+
+ encodeAndFold(ctx, os, curLinePos, newLinePos, 0);
+}
+
+
+void text::copyFrom(const component& other) {
+
+ const text& t = dynamic_cast <const text&>(other);
+
+ removeAllWords();
+
+ for (std::vector <shared_ptr <word> >::const_iterator i = t.m_words.begin() ;
+ i != t.m_words.end() ; ++i) {
+
+ m_words.push_back(make_shared <word>(**i));
+ }
+}
+
+
+text& text::operator=(const component& other) {
+
+ copyFrom(other);
+ return *this;
+}
+
+
+text& text::operator=(const text& other) {
+
+ copyFrom(other);
+ return *this;
+}
+
+
+bool text::operator==(const text& t) const {
+
+ if (getWordCount() == t.getWordCount()) {
+
+ bool equal = true;
+
+ std::vector <shared_ptr <word> >::const_iterator i = m_words.begin();
+ std::vector <shared_ptr <word> >::const_iterator j = t.m_words.begin();
+
+ for ( ; equal && i != m_words.end() ; ++i, ++j) {
+ equal = (**i == **j);
+ }
+
+ return equal;
+ }
+
+ return false;
+}
+
+
+bool text::operator!=(const text& t) const {
+
+ return !(*this == t);
+}
+
+
+const string text::getConvertedText(
+ const charset& dest,
+ const charsetConverterOptions& opts
+) const {
+
+ string out;
+
+ for (std::vector <shared_ptr <word> >::const_iterator i = m_words.begin() ;
+ i != m_words.end() ; ++i) {
+
+ out += (*i)->getConvertedText(dest, opts);
+ }
+
+ return out;
+}
+
+
+void text::appendWord(const shared_ptr <word>& w) {
+
+ m_words.push_back(w);
+}
+
+
+void text::insertWordBefore(const size_t pos, const shared_ptr <word>& w) {
+
+ m_words.insert(m_words.begin() + pos, w);
+}
+
+
+void text::insertWordAfter(const size_t pos, const shared_ptr <word>& w) {
+
+ m_words.insert(m_words.begin() + pos + 1, w);
+}
+
+
+void text::removeWord(const size_t pos) {
+
+ const std::vector <shared_ptr <word> >::iterator it = m_words.begin() + pos;
+
+ m_words.erase(it);
+}
+
+
+void text::removeAllWords() {
+
+ m_words.clear();
+}
+
+
+size_t text::getWordCount() const {
+
+ return m_words.size();
+}
+
+
+bool text::isEmpty() const {
+
+ return m_words.empty();
+}
+
+
+const shared_ptr <word> text::getWordAt(const size_t pos) {
+
+ return m_words[pos];
+}
+
+
+const shared_ptr <const word> text::getWordAt(const size_t pos) const {
+
+ return m_words[pos];
+}
+
+
+const std::vector <shared_ptr <const word> > text::getWordList() const {
+
+ std::vector <shared_ptr <const word> > list;
+
+ list.reserve(m_words.size());
+
+ for (std::vector <shared_ptr <word> >::const_iterator it = m_words.begin() ;
+ it != m_words.end() ; ++it) {
+
+ list.push_back(*it);
+ }
+
+ return list;
+}
+
+
+const std::vector <shared_ptr <word> > text::getWordList() {
+
+ return m_words;
+}
+
+
+shared_ptr <component> text::clone() const {
+
+ return make_shared <text>(*this);
+}
+
+
+shared_ptr <text> text::newFromString(const string& in, const charset& ch) {
+
+ shared_ptr <text> t = make_shared <text>();
+
+ t->createFromString(in, ch);
+
+ return t;
+}
+
+
+void text::createFromString(const string& in, const charset& ch) {
+
+ size_t asciiCount = 0;
+ size_t asciiPercent = 0;
+
+ removeAllWords();
+
+ // Check whether there is a recommended encoding for this charset.
+ // If so, the whole buffer will be encoded. Else, the number of
+ // 7-bit (ASCII) bytes in the input will be used to determine if
+ // we need to encode the whole buffer.
+ encoding recommendedEnc;
+ const bool alwaysEncode = ch.getRecommendedEncoding(recommendedEnc);
+
+ if (!alwaysEncode) {
+ asciiCount = utility::stringUtils::countASCIIchars(in.begin(), in.end());
+ asciiPercent = (in.length() == 0 ? 100 : (100 * asciiCount) / in.length());
+ }
+
+ // If there are "too much" non-ASCII chars, encode everything
+ if (alwaysEncode || asciiPercent < 60) { // less than 60% ASCII chars
+
+ appendWord(make_shared <word>(in, ch));
+
+ // Else, only encode words which need it
+ } else {
+
+ bool is8bit = false; // is the current word 8-bit?
+ bool prevIs8bit = false; // is previous word 8-bit?
+ unsigned int count = 0; // total number of words
+
+ for (size_t end = in.size(), pos = 0, start = 0 ; ; ) {
+
+ if (pos == end || parserHelpers::isSpace(in[pos])) {
+
+ const string chunk(in.begin() + start, in.begin() + pos);
+
+ if (pos != end) {
+ ++pos;
+ }
+
+ if (is8bit) {
+
+ if (count && prevIs8bit) {
+
+ // No need to create a new encoded word, just append
+ // the current word to the previous one.
+ shared_ptr <word> w = getWordAt(getWordCount() - 1);
+ w->getBuffer() += " " + chunk;
+
+ } else {
+
+ if (count) {
+ shared_ptr <word> w = getWordAt(getWordCount() - 1);
+ w->getBuffer() += ' ';
+ }
+
+ appendWord(make_shared <word>(chunk, ch));
+
+ prevIs8bit = true;
+ ++count;
+ }
+
+ } else {
+
+ if (count && !prevIs8bit) {
+
+ shared_ptr <word> w = getWordAt(getWordCount() - 1);
+ w->getBuffer() += " " + chunk;
+
+ } else {
+
+ appendWord(make_shared <word>(chunk, charset(charsets::US_ASCII)));
+
+ prevIs8bit = false;
+ ++count;
+ }
+ }
+
+ if (pos == end) {
+ break;
+ }
+
+ is8bit = false;
+ start = pos;
+
+ } else if (!parserHelpers::isAscii(in[pos])) {
+
+ is8bit = true;
+ ++pos;
+
+ } else {
+
+ ++pos;
+ }
+ }
+ }
+}
+
+
+void text::encodeAndFold(
+ const generationContext& ctx,
+ utility::outputStream& os,
+ const size_t firstLineOffset,
+ size_t* lastLineLength,
+ const int flags
+) const {
+
+ size_t curLineLength = firstLineOffset;
+ word::generatorState state;
+
+ for (size_t wi = 0 ; wi < getWordCount() ; ++wi) {
+
+ getWordAt(wi)->generate(
+ ctx, os, curLineLength,
+ &curLineLength, flags, &state
+ );
+ }
+
+ if (lastLineLength) {
+ *lastLineLength = curLineLength;
+ }
+}
+
+
+shared_ptr <text> text::decodeAndUnfold(const string& in) {
+
+ shared_ptr <text> t = make_shared <text>();
+
+ decodeAndUnfold(parsingContext::getDefaultContext(), in, t.get());
+
+ return t;
+}
+
+
+shared_ptr <text> text::decodeAndUnfold(const parsingContext& ctx, const string& in) {
+
+ shared_ptr <text> t = make_shared <text>();
+
+ decodeAndUnfold(ctx, in, t.get());
+
+ return t;
+}
+
+
+text* text::decodeAndUnfold(const string& in, text* generateInExisting) {
+
+ return decodeAndUnfold(parsingContext::getDefaultContext(), in, generateInExisting);
+}
+
+
+text* text::decodeAndUnfold(const parsingContext& ctx, const string& in, text* generateInExisting) {
+
+ text* out = generateInExisting ? generateInExisting : new text();
+
+ out->removeAllWords();
+
+ std::vector <shared_ptr <word> > words = word::parseMultiple(ctx, in, 0, in.length(), NULL);
+ fixBrokenWords(words);
+
+ copy_vector(words, out->m_words);
+
+ return out;
+}
+
+
+// static
+void text::fixBrokenWords(std::vector <shared_ptr <word> >& words) {
+
+ if (words.size() < 2) {
+ return;
+ }
+
+ // Fix words which encode a non-integral number of characters.
+ // This is not RFC-compliant, but we should be able to recover from it.
+ for (size_t i = 0, n = words.size() ; i < n - 1 ; ++i) {
+
+ shared_ptr <word> w1 = words[i];
+
+ // Check whether the word is valid
+ bool valid = false;
+
+ try {
+
+ valid = w1->getCharset().isValidText(w1->getBuffer(), NULL);
+
+ } catch (vmime::exceptions::charset_conv_error& e) {
+
+ // Unknown charset or unexpected conversion error: assume word is valid
+ valid = true;
+ }
+
+ // If the current word is not valid, try to grab some bytes
+ // from the next words, to see whether it becomes valid.
+ if (!valid) {
+
+ string buffer(w1->getBuffer());
+ size_t mergeWords = 1; // number of adjacent words to merge
+
+ for (size_t j = i + 1 ; j < n ; ++j) {
+
+ shared_ptr <word> nextWord = words[j];
+
+ if (nextWord->getCharset() != w1->getCharset()) {
+ break;
+ }
+
+ buffer += nextWord->getBuffer();
+ ++mergeWords;
+ }
+
+ if (mergeWords == 1) {
+ // No adjacent word with same charset found
+ continue;
+ }
+
+ string::size_type firstInvalidByte;
+ valid = w1->getCharset().isValidText(buffer, &firstInvalidByte);
+
+ // Current word with additional bytes from the next words
+ // is now valid: adjust buffers of words.
+ w1->setBuffer(string(buffer.begin(), buffer.begin() + firstInvalidByte));
+ words[i + 1]->setBuffer(string(buffer.begin() + firstInvalidByte, buffer.end()));
+
+ // Remove unused words
+ for (size_t j = 0 ; j < mergeWords - 2 ; ++j) {
+
+ words.erase(words.begin() + i + 2);
+ --n;
+ }
+
+ // If the next word is now empty, remove it
+ if (words[i + 1]->getBuffer().empty()) {
+
+ words.erase(words.begin() + i + 1);
+ --n;
+ }
+ }
+ }
+}
+
+
+const std::vector <shared_ptr <component> > text::getChildComponents() {
+
+ std::vector <shared_ptr <component> > list;
+
+ copy_vector(m_words, list);
+
+ return list;
+}
+
+
+const string text::getWholeBuffer() const {
+
+ string res;
+
+ for (std::vector <shared_ptr <word> >::const_iterator it = m_words.begin() ;
+ it != m_words.end() ; ++it) {
+
+ res += (*it)->getBuffer();
+ }
+
+ return res;
+}
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/text.hpp b/vmime-master/src/vmime/text.hpp
new file mode 100644
index 0000000..143f527
--- /dev/null
+++ b/vmime-master/src/vmime/text.hpp
@@ -0,0 +1,291 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_TEXT_HPP_INCLUDED
+#define VMIME_TEXT_HPP_INCLUDED
+
+
+#include "vmime/headerFieldValue.hpp"
+#include "vmime/base.hpp"
+#include "vmime/word.hpp"
+
+
+namespace vmime {
+
+
+/** List of encoded-words, as defined in RFC-2047 (basic type).
+ */
+class VMIME_EXPORT text : public headerFieldValue {
+
+public:
+
+ text();
+ text(const text& t);
+ text(const string& t, const charset& ch);
+ explicit text(const string& t);
+ explicit text(const word& w);
+ ~text();
+
+public:
+
+ bool operator==(const text& t) const;
+ bool operator!=(const text& t) const;
+
+ shared_ptr <component> clone() const;
+ void copyFrom(const component& other);
+ text& operator=(const component& other);
+ text& operator=(const text& other);
+
+ const std::vector <shared_ptr <component> > getChildComponents();
+
+ /** Add a word at the end of the list.
+ *
+ * @param w word to append
+ */
+ void appendWord(const shared_ptr <word>& w);
+
+ /** Insert a new word before the specified position.
+ *
+ * @param pos position at which to insert the new word (0 to insert at
+ * the beginning of the list)
+ * @param w word to insert
+ */
+ void insertWordBefore(const size_t pos, const shared_ptr <word>& w);
+
+ /** Insert a new word after the specified position.
+ *
+ * @param pos position of the word before the new word
+ * @param w word to insert
+ */
+ void insertWordAfter(const size_t pos, const shared_ptr <word>& w);
+
+ /** Remove the word at the specified position.
+ *
+ * @param pos position of the word to remove
+ */
+ void removeWord(const size_t pos);
+
+ /** Remove all words from the list.
+ */
+ void removeAllWords();
+
+ /** Return the number of words in the list.
+ *
+ * @return number of words
+ */
+ size_t getWordCount() const;
+
+ /** Tests whether the list of words is empty.
+ *
+ * @return true if there is no word, false otherwise
+ */
+ bool isEmpty() const;
+
+ /** Return the word at the specified position.
+ *
+ * @param pos position
+ * @return word at position 'pos'
+ */
+ const shared_ptr <word> getWordAt(const size_t pos);
+
+ /** Return the word at the specified position.
+ *
+ * @param pos position
+ * @return word at position 'pos'
+ */
+ const shared_ptr <const word> getWordAt(const size_t pos) const;
+
+ /** Return the word list.
+ *
+ * @return list of words
+ */
+ const std::vector <shared_ptr <const word> > getWordList() const;
+
+ /** Return the word list.
+ *
+ * @return list of words
+ */
+ const std::vector <shared_ptr <word> > getWordList();
+
+
+ /** Return the text converted into the specified charset.
+ * The encoded-words are decoded and then converted in the
+ * specified destination charset.
+ *
+ * @param dest output charset
+ * @param opts options for charset conversion
+ * @return text decoded in the specified charset
+ */
+ const string getConvertedText(
+ const charset& dest,
+ const charsetConverterOptions& opts = charsetConverterOptions()
+ ) const;
+
+ /** Return the unconverted (raw) data of all words. This is the
+ * concatenation of the results returned by getBuffer() on
+ * the contained words.
+ *
+ * @return raw data
+ */
+ const string getWholeBuffer() const;
+
+ /** This function can be used to make several encoded words from a text.
+ * All the characters in the text must be in the same specified charset.
+ *
+ * <p>Eg: giving:</p>
+ * <pre> &lt;iso-8859-1> "Linux dans un t'el'ephone mobile"
+ * ("=?iso-8859-1?Q?Linux_dans_un_t=E9l=E9phone_mobile?=")
+ * </pre><p>it will return:</p>
+ * <pre> &lt;us-ascii> "Linux dans un "
+ * &lt;iso-8859-1> "t'el'ephone "
+ * &lt;us-ascii> "mobile"
+ * ("Linux dans un =?iso-8859-1?Q?t=E9l=E9phone_?= mobile")
+ * </pre>
+ *
+ * @param in input string
+ * @param ch input charset
+ * @return new text object
+ */
+ static shared_ptr <text> newFromString(const string& in, const charset& ch);
+
+ /** This function can be used to make several encoded words from a text.
+ * All the characters in the text must be in the same specified charset.
+ *
+ * <p>Eg: giving:</p>
+ * <pre> &lt;iso-8859-1> "Linux dans un t'el'ephone mobile"
+ * ("=?iso-8859-1?Q?Linux_dans_un_t=E9l=E9phone_mobile?=")
+ * </pre><p>it will return:</p>
+ * <pre> &lt;us-ascii> "Linux dans un "
+ * &lt;iso-8859-1> "t'el'ephone "
+ * &lt;us-ascii> "mobile"
+ * ("Linux dans un =?iso-8859-1?Q?t=E9l=E9phone_?= mobile")
+ * </pre>
+ *
+ * @param in input string
+ * @param ch input charset
+ */
+ void createFromString(const string& in, const charset& ch);
+
+ /** Flags used by "encodeAndFold" function.
+ */
+ enum EncodeAndFoldFlags {
+
+ // NOTE: If both "FORCE_NO_ENCODING" and "FORCE_ENCODING" are
+ // specified, "FORCE_NO_ENCODING" is used by default.
+
+ FORCE_NO_ENCODING = (1 << 0), /**< Just fold lines, don't encode them. */
+ FORCE_ENCODING = (1 << 1), /**< Encode lines even if they are plain ASCII text. */
+ NO_NEW_LINE_SEQUENCE = (1 << 2), /**< Use CRLF instead of new-line sequence (CRLF + TAB). */
+ QUOTE_IF_POSSIBLE = (1 << 3), /**< Use quoting instead of encoding when possible (even if FORCE_ENCODING is specified). */
+ QUOTE_IF_NEEDED = (1 << 4) /**< Use quoting instead of encoding if needed (eg. whitespaces and/or special chars). */
+ };
+
+ /** Encode and fold text in respect to RFC-2047.
+ *
+ * @param ctx generation context
+ * @param os output stream
+ * @param firstLineOffset the first line length (may be useful if the current output line is not empty)
+ * @param lastLineLength will receive the length of the last line written
+ * @param flags encoding flags (see EncodeAndFoldFlags)
+ */
+ void encodeAndFold(
+ const generationContext& ctx,
+ utility::outputStream& os,
+ const size_t firstLineOffset,
+ size_t* lastLineLength,
+ const int flags
+ ) const;
+
+ /** Decode and unfold text (RFC-2047), using the default parsing context.
+ *
+ * @param in input string
+ * @return new text object
+ */
+ static shared_ptr <text> decodeAndUnfold(const string& in);
+
+ /** Decode and unfold text (RFC-2047).
+ *
+ * @param ctx parsingContext
+ * @param in input string
+ * @return new text object
+ */
+ static shared_ptr <text> decodeAndUnfold(const parsingContext& ctx, const string& in);
+
+ /** Decode and unfold text (RFC-2047), using the default parsing context.
+ *
+ * @param in input string
+ * @param generateInExisting if not NULL, the resulting text will be generated
+ * in the specified object instead of a new created object (in this case, the
+ * function returns the same pointer). Can be used to avoid copying the
+ * resulting object into an existing object.
+ * @return new text object or existing object if generateInExisting != NULL
+ */
+ static text* decodeAndUnfold(const string& in, text* generateInExisting);
+
+ /** Decode and unfold text (RFC-2047).
+ *
+ * @param ctx parsing context
+ * @param in input string
+ * @param generateInExisting if not NULL, the resulting text will be generated
+ * in the specified object instead of a new created object (in this case, the
+ * function returns the same pointer). Can be used to avoid copying the
+ * resulting object into an existing object.
+ * @return new text object or existing object if generateInExisting != NULL
+ */
+ static text* decodeAndUnfold(
+ const parsingContext& ctx,
+ const string& in,
+ text* generateInExisting
+ );
+
+protected:
+
+ static void fixBrokenWords(std::vector <shared_ptr <word> >& words);
+
+
+ // Component parsing & assembling
+ void parseImpl(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition = NULL
+ );
+
+ void generateImpl(
+ const generationContext& ctx,
+ utility::outputStream& os,
+ const size_t curLinePos = 0,
+ size_t* newLinePos = NULL
+ ) const;
+
+private:
+
+ std::vector <shared_ptr <word> > m_words;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_TEXT_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/textPart.hpp b/vmime-master/src/vmime/textPart.hpp
new file mode 100644
index 0000000..e34a169
--- /dev/null
+++ b/vmime-master/src/vmime/textPart.hpp
@@ -0,0 +1,117 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_TEXTPART_HPP_INCLUDED
+#define VMIME_TEXTPART_HPP_INCLUDED
+
+
+#include "vmime/bodyPart.hpp"
+
+#include "vmime/mediaType.hpp"
+#include "vmime/charset.hpp"
+#include "vmime/contentHandler.hpp"
+
+
+namespace vmime {
+
+
+/** Generic text part.
+ */
+class VMIME_EXPORT textPart : public object {
+
+ friend class textPartFactory;
+ friend class messageBuilder; // for generateIn, getPartCount
+ friend class messageParser; // for parse
+
+public:
+
+ virtual ~textPart() { }
+
+ /** Return the type of text part (eg: "text/html").
+ *
+ * @return type of text part
+ */
+ virtual const mediaType getType() const = 0;
+
+ /** Return the charset used to encode text in the
+ * text part.
+ *
+ * @return text charset
+ */
+ virtual const charset& getCharset() const = 0;
+
+ /** Set the charset used to encode text in the
+ * text part.
+ *
+ * @param ch text charset
+ */
+ virtual void setCharset(const charset& ch) = 0;
+
+ /** Return the text contained in the part.
+ *
+ * @return text of the part
+ */
+ virtual const shared_ptr <const contentHandler> getText() const = 0;
+
+ /** Set the text contained in the part.
+ *
+ * @param text text of the part
+ */
+ virtual void setText(const shared_ptr <contentHandler>& text) = 0;
+
+ /** Return the actual body parts this text part is composed of.
+ * For example, HTML parts are composed of two parts: one "text/html"
+ * part, and the plain text part "text/plain".
+ *
+ * @return number of body parts
+ */
+ virtual size_t getPartCount() const = 0;
+
+ /** Generate the text part(s) into the specified message.
+ *
+ * @param message the message
+ * @param parent body part into which generate this part
+ */
+ virtual void generateIn(
+ const shared_ptr <bodyPart>& message,
+ const shared_ptr <bodyPart>& parent
+ ) const = 0;
+
+ /** Parse the text part(s) from the specified message.
+ *
+ * @param message message containing the text part
+ * @param parent part containing the text part
+ * @param textPart actual text part
+ */
+ virtual void parse(
+ const shared_ptr <const bodyPart>& message,
+ const shared_ptr <const bodyPart>& parent,
+ const shared_ptr <const bodyPart>& textPart
+ ) = 0;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_TEXTPART_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/textPartFactory.cpp b/vmime-master/src/vmime/textPartFactory.cpp
new file mode 100644
index 0000000..2c58888
--- /dev/null
+++ b/vmime-master/src/vmime/textPartFactory.cpp
@@ -0,0 +1,68 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/textPartFactory.hpp"
+#include "vmime/exception.hpp"
+
+
+#include "vmime/plainTextPart.hpp"
+#include "vmime/htmlTextPart.hpp"
+
+
+namespace vmime {
+
+
+textPartFactory::textPartFactory() {
+
+ registerType <plainTextPart>(mediaType(mediaTypes::TEXT, mediaTypes::TEXT_PLAIN));
+ registerType <htmlTextPart>(mediaType(mediaTypes::TEXT, mediaTypes::TEXT_HTML));
+}
+
+
+textPartFactory::~textPartFactory() {
+
+}
+
+
+textPartFactory* textPartFactory::getInstance() {
+
+ static textPartFactory instance;
+ return &instance;
+}
+
+
+shared_ptr <textPart> textPartFactory::create(const mediaType& type)
+{
+ for (MapType::const_iterator it = m_map.begin() ;
+ it != m_map.end() ; ++it) {
+
+ if ((*it).first == type) {
+ return ((*it).second)();
+ }
+ }
+
+ throw exceptions::no_factory_available("No 'textPart' class registered for media type '" + type.generate() + "'.");
+}
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/textPartFactory.hpp b/vmime-master/src/vmime/textPartFactory.hpp
new file mode 100644
index 0000000..322c616
--- /dev/null
+++ b/vmime-master/src/vmime/textPartFactory.hpp
@@ -0,0 +1,77 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_TEXTPARTFACTORY_HPP_INCLUDED
+#define VMIME_TEXTPARTFACTORY_HPP_INCLUDED
+
+
+#include "vmime/textPart.hpp"
+#include "vmime/mediaType.hpp"
+
+
+namespace vmime {
+
+
+class VMIME_EXPORT textPartFactory {
+
+protected:
+
+ textPartFactory();
+ ~textPartFactory();
+
+ typedef shared_ptr <textPart> (*AllocFunc)(void);
+ typedef std::vector <std::pair <mediaType, AllocFunc> > MapType;
+
+ MapType m_map;
+
+#ifndef VMIME_BUILDING_DOC
+ template <class TYPE>
+ class registerer {
+ public:
+
+ static shared_ptr <textPart> creator() {
+
+ // Allocate a new object
+ return vmime::make_shared <TYPE>();
+ }
+ };
+#endif // VMIME_BUILDING_DOC
+
+public:
+
+ static textPartFactory* getInstance();
+
+ template <class T>
+ void registerType(const mediaType& type) {
+
+ m_map.push_back(MapType::value_type(type, &registerer<T>::creator));
+ }
+
+ shared_ptr <textPart> create(const mediaType& type);
+};
+
+
+} // vmime
+
+
+#endif // VMIME_TEXTPARTFACTORY_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/types.hpp b/vmime-master/src/vmime/types.hpp
new file mode 100644
index 0000000..3527883
--- /dev/null
+++ b/vmime-master/src/vmime/types.hpp
@@ -0,0 +1,87 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_TYPES_HPP_INCLUDED
+#define VMIME_TYPES_HPP_INCLUDED
+
+
+#include <limits>
+#include <string>
+#include <vector>
+#include <stdexcept>
+#include <cstddef>
+#include <utility>
+#include <memory>
+
+#include "vmime/config.hpp"
+
+
+#ifndef VMIME_BUILDING_DOC
+
+namespace vmime {
+
+ using std::shared_ptr;
+ using std::weak_ptr;
+ using std::make_shared;
+ using std::enable_shared_from_this;
+ using std::dynamic_pointer_cast;
+ using std::const_pointer_cast;
+
+ /** Custom deleter to be used with shared_ptr.
+ * This does not actually delete the pointer, and is used
+ * only for the singleton classes allocated on the stack.
+ */
+ template <typename T>
+ struct noop_shared_ptr_deleter {
+ void operator()(T*) const {}
+ };
+
+ template <typename T> using scoped_ptr = std::unique_ptr <T>;
+}
+
+#endif // VMIME_BUILDING_DOC
+
+
+namespace vmime {
+
+ typedef std::string string;
+
+ typedef unsigned short port_t;
+
+ typedef int char_t;
+
+ typedef vmime_uint8 byte_t;
+ typedef std::vector <byte_t> byteArray;
+
+ typedef std::size_t size_t;
+
+ // For compatibility with versions <= 0.7.1 (deprecated)
+ namespace net { }
+ namespace messaging = net;
+}
+
+
+#include "vmime/object.hpp"
+
+
+#endif // VMIME_TYPES_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/utility/childProcess.hpp b/vmime-master/src/vmime/utility/childProcess.hpp
new file mode 100644
index 0000000..b72ab85
--- /dev/null
+++ b/vmime-master/src/vmime/utility/childProcess.hpp
@@ -0,0 +1,103 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_UTILITY_CHILDPROCESS_HPP_INCLUDED
+#define VMIME_UTILITY_CHILDPROCESS_HPP_INCLUDED
+
+
+#include "vmime/utility/stream.hpp"
+#include "vmime/utility/file.hpp"
+
+#include <vector>
+
+
+namespace vmime {
+namespace utility {
+
+
+/** Spawn a process and redirect its standard input
+ * and/or standard output.
+ */
+class VMIME_EXPORT childProcess : public object {
+
+public:
+
+ virtual ~childProcess() { }
+
+ /** Flags used with start(). */
+ enum Flags {
+ FLAG_REDIRECT_STDIN = (1 << 0),
+ FLAG_REDIRECT_STDOUT = (1 << 1)
+ };
+
+ /** Start the child process.
+ *
+ * @param args list of arguments
+ * @param flags one or more childProcess::Flags
+ * @throws exceptions::system_error if the an error occurs
+ * before the process can be started
+ */
+ virtual void start(const std::vector <string>& args, const int flags = 0) = 0;
+
+ /** Return a wrapper to the child process standard input.
+ *
+ * @return output stream wrapper for child's stdin
+ */
+ virtual shared_ptr <utility::outputStream> getStdIn() = 0;
+
+ /** Return a wrapper to the child process standard output.
+ *
+ * @return input stream wrapper for child's stdout
+ */
+ virtual shared_ptr <utility::inputStream> getStdOut() = 0;
+
+ /** Wait for the process to finish.
+ *
+ * @throws exceptions::system_error if the process does
+ * not exit normally
+ */
+ virtual void waitForFinish() = 0;
+};
+
+
+/** Create 'childProcess' objects.
+ */
+class childProcessFactory : public object {
+
+public:
+
+ virtual ~childProcessFactory() { }
+
+ /** Create a new child process.
+ *
+ * @param path full path of the process executable file
+ */
+ virtual shared_ptr <childProcess> create(const utility::file::path& path) const = 0;
+};
+
+
+} // utility
+} // vmime
+
+
+#endif // VMIME_UTILITY_CHILDPROCESS_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/utility/datetimeUtils.cpp b/vmime-master/src/vmime/utility/datetimeUtils.cpp
new file mode 100644
index 0000000..b1a6c55
--- /dev/null
+++ b/vmime-master/src/vmime/utility/datetimeUtils.cpp
@@ -0,0 +1,317 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/utility/datetimeUtils.hpp"
+
+#include <stdexcept>
+
+
+namespace vmime {
+namespace utility {
+
+
+#ifndef VMIME_BUILDING_DOC
+
+static inline void nextMonth(datetime& d) {
+
+ if (d.getMonth() >= 12) {
+ d.setMonth(1);
+ d.setYear(d.getYear() + 1);
+ } else {
+ d.setMonth(d.getMonth() + 1);
+ }
+}
+
+
+static inline void prevMonth(datetime& d) {
+
+ if (d.getMonth() <= 1) {
+ d.setYear(d.getYear() - 1);
+ d.setMonth(12);
+ } else {
+ d.setMonth(d.getMonth() - 1);
+ }
+}
+
+
+static inline void nextDay(datetime& d) {
+
+ if (d.getDay() >= datetimeUtils::getDaysInMonth(d.getYear(), d.getMonth())) {
+ d.setDay(1);
+ nextMonth(d);
+ } else {
+ d.setDay(d.getDay() + 1);
+ }
+}
+
+
+static inline void prevDay(datetime& d) {
+
+ if (d.getDay() <= 1) {
+ prevMonth(d);
+ d.setDay(datetimeUtils::getDaysInMonth(d.getYear(), d.getMonth()));
+ } else {
+ d.setDay(d.getDay() - 1);
+ }
+}
+
+
+static inline void nextHour(datetime& d) {
+
+ if (d.getHour() >= 23) {
+ d.setHour(0);
+ nextDay(d);
+ } else {
+ d.setHour(d.getHour() + 1);
+ }
+}
+
+
+static inline void prevHour(datetime& d) {
+
+ if (d.getHour() <= 0) {
+ d.setHour(23);
+ prevDay(d);
+ } else {
+ d.setHour(d.getHour() - 1);
+ }
+}
+
+
+static inline void addHoursAndMinutes(datetime& d, const int h, const int m) {
+
+ d.setMinute(d.getMinute() + m);
+
+ if (d.getMinute() >= 60) {
+ d.setMinute(d.getMinute() - 60);
+ nextHour(d);
+ }
+
+ d.setHour(d.getHour() + h);
+
+ if (d.getHour() >= 24) {
+ d.setHour(d.getHour() - 24);
+ nextDay(d);
+ }
+}
+
+
+static inline void substractHoursAndMinutes(datetime& d, const int h, const int m) {
+
+ if (m > d.getMinute()) {
+ d.setMinute(60 - (m - d.getMinute()));
+ prevHour(d);
+ } else {
+ d.setMinute(d.getMinute() - m);
+ }
+
+ if (h > d.getHour()) {
+ d.setHour(24 - (h - d.getHour()));
+ prevDay(d);
+ } else {
+ d.setHour(d.getHour() - h);
+ }
+}
+
+#endif // VMIME_BUILDING_DOC
+
+
+const datetime datetimeUtils::toUniversalTime(const datetime& date) {
+
+ if (date.getZone() == datetime::GMT) {
+ return date; // no conversion needed
+ }
+
+ datetime nd(date);
+ nd.setZone(datetime::GMT);
+
+ const int z = date.getZone();
+ const int h = (z < 0) ? (-z / 60) : (z / 60);
+ const int m = (z < 0) ? (-z - h * 60) : (z - h * 60);
+
+ if (z < 0) { // GMT-hhmm: add hours and minutes to date
+ addHoursAndMinutes(nd, h, m);
+ } else { // GMT+hhmm: substract hours and minutes from date
+ substractHoursAndMinutes(nd, h, m);
+ }
+
+ return nd;
+}
+
+
+const datetime datetimeUtils::toLocalTime(const datetime& date, const int zone) {
+
+ datetime utcDate(date);
+
+ if (utcDate.getZone() != datetime::GMT) {
+ utcDate = toUniversalTime(date); // convert to UT before
+ }
+
+ datetime nd(utcDate);
+ nd.setZone(zone);
+
+ const int h = (zone < 0) ? (-zone / 60) : (zone / 60);
+ const int m = (zone < 0) ? (-zone - h * 60) : (zone - h * 60);
+
+ if (zone < 0) { // GMT+hhmm: substract hours and minutes from date
+ substractHoursAndMinutes(nd, h, m);
+ } else { // GMT-hhmm: add hours and minutes to date
+ addHoursAndMinutes(nd, h, m);
+ }
+
+ return nd;
+}
+
+
+bool datetimeUtils::isLeapYear(const int year) {
+
+ // From RFC 3339 - Appendix C. Leap Years:
+ return ((year % 4) == 0 && (year % 100 != 0 || year % 400 == 0));
+}
+
+
+int datetimeUtils::getDaysInMonth(const int year, const int month) {
+
+ static const int daysInMonth[12] = {
+ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+ };
+ static const int daysInMonthLeapYear[12] = {
+ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+ };
+
+ if (month < 1 || month > 12) {
+ throw std::out_of_range("Invalid month number");
+ }
+
+ return isLeapYear(year) ? daysInMonthLeapYear[month - 1] : daysInMonth[month - 1];
+}
+
+
+int datetimeUtils::getDayOfWeek(const int year, const int month, const int day) {
+
+ int y = year;
+ int m = month;
+
+ if (month < 1 || month > 12) {
+ throw std::out_of_range("Invalid month number");
+ } else if (day < 1 || day > getDaysInMonth(year, month)) {
+ throw std::out_of_range("Invalid day number");
+ }
+
+ // From RFC-3339 - Appendix B. Day of the Week
+
+ // Adjust months so February is the last one
+ m -= 2;
+
+ if (m < 1) {
+ m += 12;
+ --y;
+ }
+
+ // Split by century
+ const int cent = y / 100;
+ y %= 100;
+
+ return ((26 * m - 2) / 10 + day + y + (y >> 2) + (cent >> 2) + 5 * cent) % 7;
+}
+
+
+int datetimeUtils::getWeekOfYear(const int year, const int month, const int day, const bool iso) {
+
+ // Algorithm from http://personal.ecu.edu/mccartyr/ISOwdALG.txt
+
+ const bool leapYear = ((year % 4) == 0 && (year % 100) != 0) || (year % 400) == 0;
+ const bool leapYear_1 = (((year - 1) % 4) == 0 && ((year - 1) % 100) != 0) || ((year - 1) % 400) == 0;
+
+ // 4. Find the DayOfYearNumber for Y M D
+ static const int DAY_OF_YEAR_NUMBER_MAP[12] = {
+ 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334
+ };
+
+ int DayOfYearNumber = day + DAY_OF_YEAR_NUMBER_MAP[month - 1];
+
+ if (leapYear && month > 2) {
+ DayOfYearNumber += 1;
+ }
+
+ // 5. Find the Jan1Weekday for Y (Monday=1, Sunday=7)
+ const int YY = (year - 1) % 100;
+ const int C = (year - 1) - YY;
+ const int G = YY + YY / 4;
+ const int Jan1Weekday = 1 + (((((C / 100) % 4) * 5) + G) % 7);
+
+ // 6. Find the Weekday for Y M D
+ const int H = DayOfYearNumber + (Jan1Weekday - 1);
+ const int Weekday = 1 + ((H - 1) % 7);
+
+ // 7. Find if Y M D falls in YearNumber Y-1, WeekNumber 52 or 53
+ int YearNumber = 0, WeekNumber = 0;
+
+ if (DayOfYearNumber <= (8 - Jan1Weekday) && Jan1Weekday > 4) {
+
+ YearNumber = year - 1;
+
+ if (Jan1Weekday == 5 || (Jan1Weekday == 6 && leapYear_1)) {
+ WeekNumber = 53;
+ } else {
+ WeekNumber = 52;
+ }
+
+ } else {
+
+ YearNumber = year;
+ }
+
+ // 8. Find if Y M D falls in YearNumber Y+1, WeekNumber 1
+ if (YearNumber == year) {
+
+ const int I = (leapYear ? 366 : 365);
+
+ if ((I - DayOfYearNumber) < (4 - Weekday)) {
+ YearNumber = year + 1;
+ WeekNumber = 1;
+ }
+ }
+
+ // 9. Find if Y M D falls in YearNumber Y, WeekNumber 1 through 53
+ if (YearNumber == year) {
+
+ const int J = DayOfYearNumber + (7 - Weekday) + (Jan1Weekday - 1);
+
+ WeekNumber = J / 7;
+
+ if (Jan1Weekday > 4) {
+ WeekNumber -= 1;
+ }
+ }
+
+ if (!iso && (WeekNumber == 1 && month == 12)) {
+ WeekNumber = 53;
+ }
+
+ return WeekNumber;
+}
+
+
+} // utility
+} // vmime
diff --git a/vmime-master/src/vmime/utility/datetimeUtils.hpp b/vmime-master/src/vmime/utility/datetimeUtils.hpp
new file mode 100644
index 0000000..b762a6e
--- /dev/null
+++ b/vmime-master/src/vmime/utility/datetimeUtils.hpp
@@ -0,0 +1,98 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_DATETIMEUTILS_HPP_INCLUDED
+#define VMIME_DATETIMEUTILS_HPP_INCLUDED
+
+
+#include "vmime/dateTime.hpp"
+
+
+namespace vmime {
+namespace utility {
+
+
+/** Miscellaneous functions related to date/time.
+ */
+class VMIME_EXPORT datetimeUtils {
+
+public:
+
+ /** Test whether the specified year is a leap year.
+ *
+ * @param year year in 4-digit format
+ * @return true if year is a leap year, false otherwise
+ */
+ static bool isLeapYear(const int year);
+
+ /** Return the number of days in the specified month.
+ *
+ * @param year year in 4-digit format (this is needed to check
+ * for leap years)
+ * @param month month, January is 1, December is 12 (see datetime::Months enum)
+ * @return the number of days in the month
+ */
+ static int getDaysInMonth(const int year, const int month);
+
+ /** Convert the specified date/time to UT (GMT).
+ *
+ * @param date date/time to convert
+ * @return GMT date/time
+ */
+ static const datetime toUniversalTime(const datetime& date);
+
+ /** Convert the specified date/time to the specified time zone.
+ *
+ * @param date date/time to convert
+ * @param zone local zone to convert to (see datetime::TimeZones enum)
+ * @return local time and date
+ */
+ static const datetime toLocalTime(const datetime& date, const int zone);
+
+ /** Return the day of the week from the specified date.
+ *
+ * @param year year in 4-digit format
+ * @param month month (1-12), January is 1, December is 12 (see datetime::Months enum)
+ * @param day month day (1-31)
+ * @return the day of the week, Sunday is 0, Monday is 1 (see datetime::DaysOfWeek enum)
+ */
+ static int getDayOfWeek(const int year, const int month, const int day);
+
+ /** Return the week number in the year (ISO 8601).
+ *
+ * @param year year in 4-digit format
+ * @param month month (1-12), January is 1, December is 12 (see datetime::Months enum)
+ * @param day month day (1-31)
+ * @param iso if TRUE, use ISO week-numbering year (default is to use calendar year).
+ * For more information, read here: http://en.wikipedia.org/wiki/ISO_8601#Week_dates
+ * @return the week number (1 is the first week of the year)
+ */
+ static int getWeekOfYear(const int year, const int month, const int day, const bool iso = false);
+};
+
+
+} // utility
+} // vmime
+
+
+#endif // VMIME_DATETIMEUTILS_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/utility/encoder/b64Encoder.cpp b/vmime-master/src/vmime/utility/encoder/b64Encoder.cpp
new file mode 100644
index 0000000..ef4e581
--- /dev/null
+++ b/vmime-master/src/vmime/utility/encoder/b64Encoder.cpp
@@ -0,0 +1,350 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/utility/encoder/b64Encoder.hpp"
+#include "vmime/parserHelpers.hpp"
+
+
+namespace vmime {
+namespace utility {
+namespace encoder {
+
+
+b64Encoder::b64Encoder() {
+
+}
+
+
+const std::vector <string> b64Encoder::getAvailableProperties() const {
+
+ std::vector <string> list(encoder::getAvailableProperties());
+
+ list.push_back("maxlinelength");
+
+ return list;
+}
+
+
+// 7-bits alphabet used to encode binary data
+const unsigned char b64Encoder::sm_alphabet[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
+
+const unsigned char b64Encoder::sm_decodeMap[256] = {
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, // 0x00 - 0x0f
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, // 0x10 - 0x1f
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0x3e,0xff,0xff,0xff,0x3f, // 0x20 - 0x2f
+ 0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0xff,0xff,0xff,0x3d,0xff,0xff, // 0x30 - 0x3f
+ 0xff,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e, // 0x40 - 0x4f
+ 0x0f,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0xff,0xff,0xff,0xff,0xff, // 0x50 - 0x5f
+ 0xff,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28, // 0x60 - 0x6f
+ 0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,0x30,0x31,0x32,0x33,0xff,0xff,0xff,0xff,0xff, // 0x70 - 0x7f
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, // 0x80 - 0x8f
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, // 0x90 - 0x9f
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, // 0xa0 - 0xaf
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, // 0xb0 - 0xbf
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, // 0xc0 - 0xcf
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, // 0xd0 - 0xdf
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, // 0xe0 - 0xef
+ 0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, // 0xf0 - 0xff
+};
+
+#ifndef VMIME_BUILDING_DOC
+ #define B64_WRITE(s, x, l) s.write(reinterpret_cast <byte_t*>(x), l)
+#endif // VMIME_BUILDING_DOC
+
+
+
+size_t b64Encoder::encode(
+ utility::inputStream& in,
+ utility::outputStream& out,
+ utility::progressListener* progress
+) {
+
+ in.reset(); // may not work...
+
+ const size_t propMaxLineLength =
+ getProperties().getProperty <size_t>("maxlinelength", static_cast <size_t>(-1));
+
+ const bool cutLines = (propMaxLineLength != static_cast <size_t>(-1));
+ const size_t maxLineLength = std::min(propMaxLineLength, static_cast <size_t>(76));
+
+ // Process data
+ byte_t buffer[65536];
+ size_t bufferLength = 0;
+ size_t bufferPos = 0;
+
+ byte_t bytes[3];
+ byte_t output[4];
+
+ size_t total = 0;
+ size_t inTotal = 0;
+
+ size_t curCol = 0;
+
+ if (progress) {
+ progress->start(0);
+ }
+
+ while (bufferPos < bufferLength || !in.eof()) {
+
+ if (bufferPos >= bufferLength) {
+
+ bufferLength = in.read(buffer, sizeof(buffer));
+ bufferPos = 0;
+
+ if (bufferLength == 0) {
+ break;
+ }
+ }
+
+ // Get 3 bytes of data
+ int count = 0;
+
+ while (count < 3 && bufferPos < bufferLength) {
+ bytes[count++] = buffer[bufferPos++];
+ }
+
+ while (count < 3) {
+
+ // There may be more data in the next chunk...
+ if (bufferPos >= bufferLength) {
+
+ bufferLength = in.read(buffer, sizeof(buffer));
+ bufferPos = 0;
+
+ if (bufferLength == 0) {
+ break;
+ }
+ }
+
+ while (count < 3 && bufferPos < bufferLength) {
+ bytes[count++] = buffer[bufferPos++];
+ }
+ }
+
+ // Encode data
+ switch (count) {
+
+ case 1:
+
+ output[0] = sm_alphabet[(bytes[0] & 0xFC) >> 2];
+ output[1] = sm_alphabet[(bytes[0] & 0x03) << 4];
+ output[2] = sm_alphabet[64]; // padding
+ output[3] = sm_alphabet[64]; // padding
+
+ break;
+
+ case 2:
+
+ output[0] = sm_alphabet[(bytes[0] & 0xFC) >> 2];
+ output[1] = sm_alphabet[((bytes[0] & 0x03) << 4) | ((bytes[1] & 0xF0) >> 4)];
+ output[2] = sm_alphabet[(bytes[1] & 0x0F) << 2];
+ output[3] = sm_alphabet[64]; // padding
+
+ break;
+
+ default:
+ case 3:
+
+ output[0] = sm_alphabet[(bytes[0] & 0xFC) >> 2];
+ output[1] = sm_alphabet[((bytes[0] & 0x03) << 4) | ((bytes[1] & 0xF0) >> 4)];
+ output[2] = sm_alphabet[((bytes[1] & 0x0F) << 2) | ((bytes[2] & 0xC0) >> 6)];
+ output[3] = sm_alphabet[(bytes[2] & 0x3F)];
+
+ break;
+ }
+
+ // Write encoded data to output stream
+ B64_WRITE(out, output, 4);
+
+ inTotal += count;
+ total += 4;
+ curCol += 4;
+
+ if (cutLines && curCol + 2 /* \r\n */ + 4 /* next bytes */ >= maxLineLength) {
+ out.write("\r\n", 2);
+ curCol = 0;
+ }
+
+ if (progress) {
+ progress->progress(inTotal, inTotal);
+ }
+ }
+
+ if (progress) {
+ progress->stop(inTotal);
+ }
+
+ return total;
+}
+
+
+size_t b64Encoder::decode(
+ utility::inputStream& in,
+ utility::outputStream& out,
+ utility::progressListener* progress
+) {
+
+ in.reset(); // may not work...
+
+ // Process the data
+ byte_t buffer[16384];
+ size_t bufferLength = 0;
+ size_t bufferPos = 0;
+
+ size_t total = 0;
+ size_t inTotal = 0;
+
+ byte_t bytes[4];
+ byte_t output[3];
+
+ if (progress) {
+ progress->start(0);
+ }
+
+ while (bufferPos < bufferLength || !in.eof()) {
+
+ bytes[0] = '=';
+ bytes[1] = '=';
+ bytes[2] = '=';
+ bytes[3] = '=';
+
+ // Need to get more data?
+ if (bufferPos >= bufferLength) {
+
+ bufferLength = in.read(buffer, sizeof(buffer));
+ bufferPos = 0;
+
+ // No more data
+ if (bufferLength == 0) {
+ break;
+ }
+ }
+
+ // 4 bytes of input provide 3 bytes of output, so
+ // get the next 4 bytes from the input stream.
+ int count = 0;
+
+ while (count < 4 && bufferPos < bufferLength) {
+
+ const byte_t c = buffer[bufferPos++];
+
+ if (!parserHelpers::isSpace(c)) {
+ bytes[count++] = c;
+ }
+ }
+
+ if (count != 4) {
+
+ while (count < 4 && !in.eof()) {
+
+ // Data continues on the next chunk
+ bufferLength = in.read(buffer, sizeof(buffer));
+ bufferPos = 0;
+
+ while (count < 4 && bufferPos < bufferLength) {
+
+ const byte_t c = buffer[bufferPos++];
+
+ if (!parserHelpers::isSpace(c)) {
+ bytes[count++] = c;
+ }
+ }
+ }
+ }
+
+ if (count != 4) { // input length is not a multiple of 4 bytes
+ break;
+ }
+
+ // Decode the bytes
+ byte_t c1 = bytes[0];
+ byte_t c2 = bytes[1];
+
+ if (c1 == '=' || c2 == '=') { // end
+ break;
+ }
+
+ output[0] = static_cast <byte_t>((sm_decodeMap[c1] << 2) | ((sm_decodeMap[c2] & 0x30) >> 4));
+
+ c1 = bytes[2];
+
+ if (c1 == '=') { // end
+ B64_WRITE(out, output, 1);
+ total += 1;
+ break;
+ }
+
+ output[1] = static_cast <byte_t>(((sm_decodeMap[c2] & 0xf) << 4) | ((sm_decodeMap[c1] & 0x3c) >> 2));
+
+ c2 = bytes[3];
+
+ if (c2 == '=') { // end
+ B64_WRITE(out, output, 2);
+ total += 2;
+ break;
+ }
+
+ output[2] = static_cast <byte_t>(((sm_decodeMap[c1] & 0x03) << 6) | sm_decodeMap[c2]);
+
+ B64_WRITE(out, output, 3);
+ total += 3;
+ inTotal += count;
+
+ if (progress) {
+ progress->progress(inTotal, inTotal);
+ }
+ }
+
+ if (progress) {
+ progress->stop(inTotal);
+ }
+
+ return total;
+}
+
+
+size_t b64Encoder::getEncodedSize(const size_t n) const {
+
+ const size_t propMaxLineLength =
+ getProperties().getProperty <size_t>("maxlinelength", static_cast <size_t>(-1));
+
+ const bool cutLines = (propMaxLineLength != static_cast <size_t>(-1));
+ const size_t maxLineLength = std::min(propMaxLineLength, static_cast <size_t>(76));
+
+ return (n * 4) / 3 // 3 bytes of input provide 4 bytes of output
+ + (cutLines ? (n / maxLineLength) * 2 : 0) // CRLF (2 bytes) for each line.
+ + 4; // padding
+}
+
+
+size_t b64Encoder::getDecodedSize(const size_t n) const {
+
+ // 4 bytes of input provide 3 bytes of output
+ return (n * 3) / 4;
+}
+
+
+} // encoder
+} // utility
+} // vmime
diff --git a/vmime-master/src/vmime/utility/encoder/b64Encoder.hpp b/vmime-master/src/vmime/utility/encoder/b64Encoder.hpp
new file mode 100644
index 0000000..c5be2c3
--- /dev/null
+++ b/vmime-master/src/vmime/utility/encoder/b64Encoder.hpp
@@ -0,0 +1,73 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_UTILITY_ENCODER_B64ENCODER_HPP_INCLUDED
+#define VMIME_UTILITY_ENCODER_B64ENCODER_HPP_INCLUDED
+
+
+#include "vmime/utility/encoder/encoder.hpp"
+
+
+namespace vmime {
+namespace utility {
+namespace encoder {
+
+
+/** Base64 encoder.
+ */
+class VMIME_EXPORT b64Encoder : public encoder {
+
+public:
+
+ b64Encoder();
+
+ size_t encode(
+ utility::inputStream& in,
+ utility::outputStream& out,
+ utility::progressListener* progress = NULL
+ );
+
+ size_t decode(
+ utility::inputStream& in,
+ utility::outputStream& out,
+ utility::progressListener* progress = NULL
+ );
+
+ const std::vector <string> getAvailableProperties() const;
+
+ size_t getEncodedSize(const size_t n) const;
+ size_t getDecodedSize(const size_t n) const;
+
+protected:
+
+ static const unsigned char sm_alphabet[];
+ static const unsigned char sm_decodeMap[256];
+};
+
+
+} // encoder
+} // utility
+} // vmime
+
+
+#endif // VMIME_UTILITY_ENCODER_B64ENCODER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/utility/encoder/binaryEncoder.cpp b/vmime-master/src/vmime/utility/encoder/binaryEncoder.cpp
new file mode 100644
index 0000000..b30bb7b
--- /dev/null
+++ b/vmime-master/src/vmime/utility/encoder/binaryEncoder.cpp
@@ -0,0 +1,39 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/utility/encoder/binaryEncoder.hpp"
+
+
+namespace vmime {
+namespace utility {
+namespace encoder {
+
+
+binaryEncoder::binaryEncoder() {
+
+}
+
+
+} // encoder
+} // utility
+} // vmime
diff --git a/vmime-master/src/vmime/utility/encoder/binaryEncoder.hpp b/vmime-master/src/vmime/utility/encoder/binaryEncoder.hpp
new file mode 100644
index 0000000..331014e
--- /dev/null
+++ b/vmime-master/src/vmime/utility/encoder/binaryEncoder.hpp
@@ -0,0 +1,51 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_UTILITY_ENCODER_BINARYENCODER_HPP_INCLUDED
+#define VMIME_UTILITY_ENCODER_BINARYENCODER_HPP_INCLUDED
+
+
+#include "vmime/utility/encoder/noopEncoder.hpp"
+
+
+namespace vmime {
+namespace utility {
+namespace encoder {
+
+
+/** Binary encoder.
+ */
+class VMIME_EXPORT binaryEncoder : public noopEncoder {
+
+public:
+
+ binaryEncoder();
+};
+
+
+} // encoder
+} // utility
+} // vmime
+
+
+#endif // VMIME_UTILITY_ENCODER_BINARYENCODER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/utility/encoder/eightBitEncoder.cpp b/vmime-master/src/vmime/utility/encoder/eightBitEncoder.cpp
new file mode 100644
index 0000000..a966931
--- /dev/null
+++ b/vmime-master/src/vmime/utility/encoder/eightBitEncoder.cpp
@@ -0,0 +1,39 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/utility/encoder/eightBitEncoder.hpp"
+
+
+namespace vmime {
+namespace utility {
+namespace encoder {
+
+
+eightBitEncoder::eightBitEncoder() {
+
+}
+
+
+} // encoder
+} // utility
+} // vmime
diff --git a/vmime-master/src/vmime/utility/encoder/eightBitEncoder.hpp b/vmime-master/src/vmime/utility/encoder/eightBitEncoder.hpp
new file mode 100644
index 0000000..c400f51
--- /dev/null
+++ b/vmime-master/src/vmime/utility/encoder/eightBitEncoder.hpp
@@ -0,0 +1,51 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_UTILITY_ENCODER_EIGHTBITENCODER_HPP_INCLUDED
+#define VMIME_UTILITY_ENCODER_EIGHTBITENCODER_HPP_INCLUDED
+
+
+#include "vmime/utility/encoder/noopEncoder.hpp"
+
+
+namespace vmime {
+namespace utility {
+namespace encoder {
+
+
+/** 8-bit encoder.
+ */
+class VMIME_EXPORT eightBitEncoder : public noopEncoder {
+
+public:
+
+ eightBitEncoder();
+};
+
+
+} // encoder
+} // utility
+} // vmime
+
+
+#endif // VMIME_UTILITY_ENCODER_EIGHTBITENCODER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/utility/encoder/encoder.cpp b/vmime-master/src/vmime/utility/encoder/encoder.cpp
new file mode 100644
index 0000000..634adf0
--- /dev/null
+++ b/vmime-master/src/vmime/utility/encoder/encoder.cpp
@@ -0,0 +1,76 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/utility/encoder/encoder.hpp"
+#include "vmime/exception.hpp"
+
+
+namespace vmime {
+namespace utility {
+namespace encoder {
+
+
+encoder::encoder() {
+
+}
+
+
+encoder::~encoder() {
+
+}
+
+
+const propertySet& encoder::getProperties() const {
+
+ return m_props;
+}
+
+
+propertySet& encoder::getProperties() {
+
+ return m_props;
+}
+
+
+const propertySet& encoder::getResults() const {
+
+ return m_results;
+}
+
+
+propertySet& encoder::getResults() {
+
+ return m_results;
+}
+
+
+const std::vector <string> encoder::getAvailableProperties() const {
+
+ std::vector <string> list;
+ return list;
+}
+
+
+} // encoder
+} // utility
+} // vmime
diff --git a/vmime-master/src/vmime/utility/encoder/encoder.hpp b/vmime-master/src/vmime/utility/encoder/encoder.hpp
new file mode 100644
index 0000000..134e813
--- /dev/null
+++ b/vmime-master/src/vmime/utility/encoder/encoder.hpp
@@ -0,0 +1,135 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_UTILITY_ENCODER_ENCODER_HPP_INCLUDED
+#define VMIME_UTILITY_ENCODER_ENCODER_HPP_INCLUDED
+
+
+#include "vmime/base.hpp"
+#include "vmime/propertySet.hpp"
+#include "vmime/exception.hpp"
+#include "vmime/utility/progressListener.hpp"
+
+
+namespace vmime {
+namespace utility {
+namespace encoder {
+
+
+/** Encode/decode data in different encodings.
+ */
+class VMIME_EXPORT encoder : public object {
+
+public:
+
+ encoder();
+ virtual ~encoder();
+
+ /** Encode data.
+ *
+ * @param in input data (decoded)
+ * @param out output stream for encoded data
+ * @param progress progress listener, or NULL if you do not
+ * want to receive progress notifications
+ * @return number of bytes written into output stream
+ */
+ virtual size_t encode(
+ utility::inputStream& in,
+ utility::outputStream& out,
+ utility::progressListener* progress = NULL
+ ) = 0;
+
+ /** Decode data.
+ *
+ * @param in input data (encoded)
+ * @param out output stream for decoded data
+ * @param progress progress listener, or NULL if you do not
+ * want to receive progress notifications
+ * @return number of bytes written into output stream
+ */
+ virtual size_t decode(
+ utility::inputStream& in,
+ utility::outputStream& out,
+ utility::progressListener* progress = NULL
+ ) = 0;
+
+ /** Return the properties of the encoder.
+ *
+ * @return properties of the encoder
+ */
+ const propertySet& getProperties() const;
+
+ /** Return the properties of the encoder.
+ *
+ * @return properties of the encoder
+ */
+ propertySet& getProperties();
+
+ /** Return a list of property names that can be set for
+ * this encoder.
+ *
+ * @return list of property names
+ */
+ virtual const std::vector <string> getAvailableProperties() const;
+
+ /** Return the results returned by this encoder.
+ *
+ * @return results returned by the encoder
+ */
+ const propertySet& getResults() const;
+
+ /** Return the encoded size for the specified input (decoded) size.
+ * If the size is not exact, it may be an estimate which should always
+ * be larger than the actual encoded size.
+ *
+ * @param n count of input (decoded) bytes
+ * @return count of output (encoded) bytes
+ */
+ virtual size_t getEncodedSize(const size_t n) const = 0;
+
+ /** Return the encoded size for the specified input (encoded) size.
+ * If the size is not exact, it may be an estimate which should always
+ * be larger than the actual decoded size.
+ *
+ * @param n count of input (encoded) bytes
+ * @return count of output (decoded) bytes
+ */
+ virtual size_t getDecodedSize(const size_t n) const = 0;
+
+protected:
+
+ propertySet& getResults();
+
+private:
+
+ propertySet m_props;
+ propertySet m_results;
+};
+
+
+} // encoder
+} // utility
+} // vmime
+
+
+#endif // VMIME_UTILITY_ENCODER_ENCODER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/utility/encoder/encoderFactory.cpp b/vmime-master/src/vmime/utility/encoder/encoderFactory.cpp
new file mode 100644
index 0000000..df655ae
--- /dev/null
+++ b/vmime-master/src/vmime/utility/encoder/encoderFactory.cpp
@@ -0,0 +1,149 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/utility/encoder/encoderFactory.hpp"
+#include "vmime/exception.hpp"
+
+#include "vmime/utility/encoder/b64Encoder.hpp"
+#include "vmime/utility/encoder/qpEncoder.hpp"
+#include "vmime/utility/encoder/uuEncoder.hpp"
+#include "vmime/utility/encoder/binaryEncoder.hpp"
+#include "vmime/utility/encoder/sevenBitEncoder.hpp"
+#include "vmime/utility/encoder/eightBitEncoder.hpp"
+
+
+namespace vmime {
+namespace utility {
+namespace encoder {
+
+
+encoderFactory::encoderFactory() {
+
+ // Register some default encoders
+ registerName <b64Encoder>("base64");
+ registerName <qpEncoder>("quoted-printable");
+ registerName <uuEncoder>("uuencode");
+ registerName <uuEncoder>("x-uuencode");
+ registerName <sevenBitEncoder>("7bit");
+ registerName <eightBitEncoder>("8bit");
+ registerName <binaryEncoder>("binary");
+
+ // Also register some non-standard encoding names
+ registerName <sevenBitEncoder>("7-bit");
+ registerName <eightBitEncoder>("8-bit");
+ registerName <eightBitEncoder>("8bits");
+
+ // Finally, register some bogus encoding names, for compatibility
+ registerName <qpEncoder>("bmoted-printable");
+}
+
+
+encoderFactory::~encoderFactory() {
+
+}
+
+
+shared_ptr <encoderFactory> encoderFactory::getInstance() {
+
+ static encoderFactory instance;
+ return shared_ptr <encoderFactory>(&instance, noop_shared_ptr_deleter <encoderFactory>());
+}
+
+
+shared_ptr <encoder> encoderFactory::create(const string& name) {
+
+ try {
+
+ return (getEncoderByName(name)->create());
+
+ } catch (exceptions::no_encoder_available &) {
+
+ if (m_defaultEncoder) {
+ return m_defaultEncoder;
+ }
+
+ throw;
+ }
+}
+
+
+const shared_ptr <const encoderFactory::registeredEncoder>
+ encoderFactory::getEncoderByName(const string& name) const {
+
+ const string lcName(utility::stringUtils::toLower(name));
+
+ for (std::vector <shared_ptr <registeredEncoder> >::const_iterator it = m_encoders.begin() ;
+ it != m_encoders.end() ; ++it) {
+
+ if ((*it)->getName() == lcName) {
+ return (*it);
+ }
+ }
+
+ throw exceptions::no_encoder_available(name);
+}
+
+
+size_t encoderFactory::getEncoderCount() const {
+
+ return m_encoders.size();
+}
+
+
+const shared_ptr <const encoderFactory::registeredEncoder>
+ encoderFactory::getEncoderAt(const size_t pos) const {
+
+ return m_encoders[pos];
+}
+
+
+const std::vector <shared_ptr <const encoderFactory::registeredEncoder> >
+ encoderFactory::getEncoderList() const {
+
+ std::vector <shared_ptr <const registeredEncoder> > res;
+
+ for (std::vector <shared_ptr <registeredEncoder> >::const_iterator it = m_encoders.begin() ;
+ it != m_encoders.end() ; ++it) {
+
+ res.push_back(*it);
+ }
+
+ return res;
+}
+
+
+void encoderFactory::setDefaultEncoder(const shared_ptr <encoder>& enc) {
+
+ m_defaultEncoder = enc;
+}
+
+
+shared_ptr <encoder> encoderFactory::getDefaultEncoder() const {
+
+ return m_defaultEncoder;
+}
+
+
+} // encoder
+} // utility
+} // vmime
diff --git a/vmime-master/src/vmime/utility/encoder/encoderFactory.hpp b/vmime-master/src/vmime/utility/encoder/encoderFactory.hpp
new file mode 100644
index 0000000..e475f8e
--- /dev/null
+++ b/vmime-master/src/vmime/utility/encoder/encoderFactory.hpp
@@ -0,0 +1,164 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_UTILITY_ENCODER_ENCODERFACTORY_HPP_INCLUDED
+#define VMIME_UTILITY_ENCODER_ENCODERFACTORY_HPP_INCLUDED
+
+
+#include "vmime/utility/encoder/encoder.hpp"
+#include "vmime/utility/stringUtils.hpp"
+
+
+namespace vmime {
+namespace utility {
+namespace encoder {
+
+
+/** A factory to create 'encoder' objects for the specified encoding.
+ */
+class VMIME_EXPORT encoderFactory
+{
+private:
+
+ encoderFactory();
+ ~encoderFactory();
+
+public:
+
+ static shared_ptr <encoderFactory> getInstance();
+
+ /** Information about a registered encoder. */
+ class VMIME_EXPORT registeredEncoder : public object {
+
+ protected:
+
+ virtual ~registeredEncoder() { }
+
+ public:
+
+ virtual shared_ptr <encoder> create() const = 0;
+
+ virtual const string& getName() const = 0;
+ };
+
+private:
+
+ template <class E>
+ class registeredEncoderImpl : public registeredEncoder {
+
+ public:
+
+ registeredEncoderImpl(const string& name) : m_name(name) { }
+
+ shared_ptr <encoder> create() const {
+
+ return vmime::make_shared <E>();
+ }
+
+ const string& getName() const {
+
+ return m_name;
+ }
+
+ private:
+
+ const string m_name;
+ };
+
+
+ std::vector <shared_ptr <registeredEncoder> > m_encoders;
+ shared_ptr <encoder> m_defaultEncoder;
+
+public:
+
+ /** Register a new encoder by its encoding name.
+ *
+ * @param name encoding name
+ */
+ template <class E>
+ void registerName(const string& name) {
+
+ m_encoders.push_back(
+ vmime::make_shared <registeredEncoderImpl <E> >(utility::stringUtils::toLower(name))
+ );
+ }
+
+ /** Create a new encoder instance from an encoding name.
+ *
+ * @param name encoding name (eg. "base64")
+ * @return a new encoder instance for the specified encoding
+ * @throw exceptions::no_encoder_available if no encoder is registered
+ * for this encoding
+ */
+ shared_ptr <encoder> create(const string& name);
+
+ /** Return information about a registered encoder.
+ *
+ * @param name encoding name
+ * @return information about this encoder
+ * @throw exceptions::no_encoder_available if no encoder is registered
+ * for this encoding
+ */
+ const shared_ptr <const registeredEncoder> getEncoderByName(const string& name) const;
+
+ /** Return the number of registered encoders.
+ *
+ * @return number of registered encoders
+ */
+ size_t getEncoderCount() const;
+
+ /** Return the registered encoder at the specified position.
+ *
+ * @param pos position of the registered encoder to return
+ * @return registered encoder at the specified position
+ */
+ const shared_ptr <const registeredEncoder> getEncoderAt(const size_t pos) const;
+
+ /** Return a list of all registered encoders.
+ *
+ * @return list of registered encoders
+ */
+ const std::vector <shared_ptr <const registeredEncoder> > getEncoderList() const;
+
+ /** Set the default encoder to use when no other encoder
+ * is registered for an encoding (fallback).
+ *
+ * @param enc default encoder
+ */
+ void setDefaultEncoder(const shared_ptr <encoder>& enc);
+
+ /** Return the default encoder to use when no other encoder
+ * is registered for an encoding (fallback).
+ *
+ * @return default encoder
+ */
+ shared_ptr <encoder> getDefaultEncoder() const;
+};
+
+
+} // encoder
+} // utility
+} // vmime
+
+
+#endif // VMIME_UTILITY_ENCODER_ENCODERFACTORY_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/utility/encoder/noopEncoder.cpp b/vmime-master/src/vmime/utility/encoder/noopEncoder.cpp
new file mode 100644
index 0000000..30cc6c1
--- /dev/null
+++ b/vmime-master/src/vmime/utility/encoder/noopEncoder.cpp
@@ -0,0 +1,94 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/utility/encoder/noopEncoder.hpp"
+
+#include "vmime/utility/streamUtils.hpp"
+
+
+namespace vmime {
+namespace utility {
+namespace encoder {
+
+
+noopEncoder::noopEncoder() {
+
+}
+
+
+size_t noopEncoder::encode(
+ utility::inputStream& in,
+ utility::outputStream& out,
+ utility::progressListener* progress
+) {
+
+ in.reset(); // may not work...
+
+ // No encoding performed
+ size_t res = 0;
+
+ if (progress)
+ res = utility::bufferedStreamCopy(in, out, 0, progress);
+ else
+ res = utility::bufferedStreamCopy(in, out);
+
+ return res;
+}
+
+
+size_t noopEncoder::decode(
+ utility::inputStream& in,
+ utility::outputStream& out,
+ utility::progressListener* progress
+) {
+
+ in.reset(); // may not work...
+
+ // No decoding performed
+ size_t res = 0;
+
+ if (progress) {
+ res = utility::bufferedStreamCopy(in, out, 0, progress);
+ } else {
+ res = utility::bufferedStreamCopy(in, out);
+ }
+
+ return res;
+}
+
+
+size_t noopEncoder::getEncodedSize(const size_t n) const {
+
+ return n;
+}
+
+
+size_t noopEncoder::getDecodedSize(const size_t n) const {
+
+ return n;
+}
+
+
+} // encoder
+} // utility
+} // vmime
diff --git a/vmime-master/src/vmime/utility/encoder/noopEncoder.hpp b/vmime-master/src/vmime/utility/encoder/noopEncoder.hpp
new file mode 100644
index 0000000..91944de
--- /dev/null
+++ b/vmime-master/src/vmime/utility/encoder/noopEncoder.hpp
@@ -0,0 +1,66 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_UTILITY_ENCODER_NOOPENCODER_HPP_INCLUDED
+#define VMIME_UTILITY_ENCODER_NOOPENCODER_HPP_INCLUDED
+
+
+#include "vmime/utility/encoder/encoder.hpp"
+
+
+namespace vmime {
+namespace utility {
+namespace encoder {
+
+
+/** Default, no-op encoder (simple copy, no encoding/decoding is performed).
+ */
+class VMIME_EXPORT noopEncoder : public encoder {
+
+public:
+
+ noopEncoder();
+
+ size_t encode(
+ utility::inputStream& in,
+ utility::outputStream& out,
+ utility::progressListener* progress = NULL
+ );
+
+ size_t decode(
+ utility::inputStream& in,
+ utility::outputStream& out,
+ utility::progressListener* progress = NULL
+ );
+
+ size_t getEncodedSize(const size_t n) const;
+ size_t getDecodedSize(const size_t n) const;
+};
+
+
+} // encoder
+} // utility
+} // vmime
+
+
+#endif // VMIME_UTILITY_ENCODER_NOOPENCODER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/utility/encoder/qpEncoder.cpp b/vmime-master/src/vmime/utility/encoder/qpEncoder.cpp
new file mode 100644
index 0000000..4aeb640
--- /dev/null
+++ b/vmime-master/src/vmime/utility/encoder/qpEncoder.cpp
@@ -0,0 +1,568 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/utility/encoder/qpEncoder.hpp"
+#include "vmime/parserHelpers.hpp"
+
+
+namespace vmime {
+namespace utility {
+namespace encoder {
+
+
+qpEncoder::qpEncoder() {
+
+}
+
+
+const std::vector <string> qpEncoder::getAvailableProperties() const {
+
+ std::vector <string> list(encoder::getAvailableProperties());
+
+ list.push_back("maxlinelength");
+
+ list.push_back("text"); // if set, '\r' and '\n' are not hex-encoded.
+ // WARNING! You should not use this for binary data!
+
+ list.push_back("rfc2047"); // for header fields encoding (RFC #2047)
+
+ return list;
+}
+
+
+
+// Hex-encoding table
+const unsigned char qpEncoder::sm_hexDigits[] = "0123456789ABCDEF";
+
+
+// RFC-2047 encoding table: we always encode RFC-2047 using the restricted
+// charset, that is the one used for 'phrase' in From/To/Cc/... headers.
+//
+// " The set of characters that may be used in a "Q"-encoded 'encoded-word'
+// is restricted to: <upper and lower case ASCII letters, decimal digits,
+// "!", "*", "+", "-", "/", "=", and "_" (underscore, ASCII 95.)>. "
+//
+// Two special cases:
+// - encode space (32) as underscore (95)
+// - encode underscore as hex (=5F)
+//
+// This is a quick lookup table:
+// '1' means "encode", '0' means "no encoding"
+//
+const vmime_uint8 qpEncoder::sm_RFC2047EncodeTable[] = {
+ /* 0 NUL */ 1, /* 1 SOH */ 1, /* 2 STX */ 1, /* 3 ETX */ 1, /* 4 EOT */ 1, /* 5 ENQ */ 1,
+ /* 6 ACK */ 1, /* 7 BEL */ 1, /* 8 BS */ 1, /* 9 TAB */ 1, /* 10 LF */ 1, /* 11 VT */ 1,
+ /* 12 FF */ 1, /* 13 CR */ 1, /* 14 SO */ 1, /* 15 SI */ 1, /* 16 DLE */ 1, /* 17 DC1 */ 1,
+ /* 18 DC2 */ 1, /* 19 DC3 */ 1, /* 20 DC4 */ 1, /* 21 NAK */ 1, /* 22 SYN */ 1, /* 23 ETB */ 1,
+ /* 24 CAN */ 1, /* 25 EM */ 1, /* 26 SUB */ 1, /* 27 ESC */ 1, /* 28 FS */ 1, /* 29 GS */ 1,
+ /* 30 RS */ 1, /* 31 US */ 1, /* 32 SPACE*/ 1, /* 33 ! */ 0, /* 34 " */ 1, /* 35 # */ 1,
+ /* 36 $ */ 1, /* 37 % */ 1, /* 38 & */ 1, /* 39 ' */ 1, /* 40 ( */ 1, /* 41 ) */ 1,
+ /* 42 * */ 0, /* 43 + */ 0, /* 44 , */ 1, /* 45 - */ 0, /* 46 . */ 1, /* 47 / */ 0,
+ /* 48 0 */ 0, /* 49 1 */ 0, /* 50 2 */ 0, /* 51 3 */ 0, /* 52 4 */ 0, /* 53 5 */ 0,
+ /* 54 6 */ 0, /* 55 7 */ 0, /* 56 8 */ 0, /* 57 9 */ 0, /* 58 : */ 1, /* 59 ; */ 1,
+ /* 60 < */ 1, /* 61 = */ 1, /* 62 > */ 1, /* 63 ? */ 1, /* 64 @ */ 1, /* 65 A */ 0,
+ /* 66 B */ 0, /* 67 C */ 0, /* 68 D */ 0, /* 69 E */ 0, /* 70 F */ 0, /* 71 G */ 0,
+ /* 72 H */ 0, /* 73 I */ 0, /* 74 J */ 0, /* 75 K */ 0, /* 76 L */ 0, /* 77 M */ 0,
+ /* 78 N */ 0, /* 79 O */ 0, /* 80 P */ 0, /* 81 Q */ 0, /* 82 R */ 0, /* 83 S */ 0,
+ /* 84 T */ 0, /* 85 U */ 0, /* 86 V */ 0, /* 87 W */ 0, /* 88 X */ 0, /* 89 Y */ 0,
+ /* 90 Z */ 0, /* 91 [ */ 1, /* 92 " */ 1, /* 93 ] */ 1, /* 94 ^ */ 1, /* 95 _ */ 1,
+ /* 96 ` */ 1, /* 97 a */ 0, /* 98 b */ 0, /* 99 c */ 0, /* 100 d */ 0, /* 101 e */ 0,
+ /* 102 f */ 0, /* 103 g */ 0, /* 104 h */ 0, /* 105 i */ 0, /* 106 j */ 0, /* 107 k */ 0,
+ /* 108 l */ 0, /* 109 m */ 0, /* 110 n */ 0, /* 111 o */ 0, /* 112 p */ 0, /* 113 q */ 0,
+ /* 114 r */ 0, /* 115 s */ 0, /* 116 t */ 0, /* 117 u */ 0, /* 118 v */ 0, /* 119 w */ 0,
+ /* 120 x */ 0, /* 121 y */ 0, /* 122 z */ 0, /* 123 { */ 1, /* 124 | */ 1, /* 125 } */ 1,
+ /* 126 ~ */ 1, /* 127 DEL */ 1
+};
+
+
+// Hex-decoding table
+const vmime_uint8 qpEncoder::sm_hexDecodeTable[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0,
+ 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+
+// static
+bool qpEncoder::RFC2047_isEncodingNeededForChar(const byte_t c) {
+
+ return c >= 128 || sm_RFC2047EncodeTable[c] != 0;
+}
+
+
+// static
+int qpEncoder::RFC2047_getEncodedLength(const byte_t c) {
+
+ if (c >= 128 || sm_RFC2047EncodeTable[c] != 0) {
+
+ if (c == 32) { // space
+
+ // Encoded as "_"
+ return 1;
+
+ } else {
+
+ // Hex encoding
+ return 3;
+ }
+
+ } else {
+
+ return 1; // no encoding
+ }
+}
+
+
+#ifndef VMIME_BUILDING_DOC
+
+#define QP_ENCODE_HEX(x) \
+ outBuffer[outBufferPos] = '='; \
+ outBuffer[outBufferPos + 1] = sm_hexDigits[x >> 4]; \
+ outBuffer[outBufferPos + 2] = sm_hexDigits[x & 0xF]; \
+ outBufferPos += 3; \
+ curCol += 3
+
+#define QP_WRITE(s, x, l) s.write(reinterpret_cast <byte_t*>(x), l)
+
+#endif // VMIME_BUILDING_DOC
+
+
+size_t qpEncoder::encode(
+ utility::inputStream& in,
+ utility::outputStream& out,
+ utility::progressListener* progress
+) {
+
+ in.reset(); // may not work...
+
+ const size_t propMaxLineLength =
+ getProperties().getProperty <size_t>("maxlinelength", static_cast <size_t>(-1));
+
+ const bool rfc2047 = getProperties().getProperty <bool>("rfc2047", false);
+ const bool text = getProperties().getProperty <bool>("text", false); // binary mode by default
+
+ const bool cutLines = (propMaxLineLength != static_cast <size_t>(-1));
+ const size_t maxLineLength = std::min(propMaxLineLength, static_cast <size_t>(74));
+
+ // Process the data
+ byte_t buffer[16384];
+ size_t bufferLength = 0;
+ size_t bufferPos = 0;
+
+ size_t curCol = 0;
+
+ byte_t outBuffer[16384];
+ size_t outBufferPos = 0;
+
+ size_t total = 0;
+ size_t inTotal = 0;
+
+ if (progress) {
+ progress->start(0);
+ }
+
+ while (bufferPos < bufferLength || !in.eof()) {
+
+ // Flush current output buffer
+ if (outBufferPos + 6 >= static_cast <int>(sizeof(outBuffer))) {
+
+ QP_WRITE(out, outBuffer, outBufferPos);
+
+ total += outBufferPos;
+ outBufferPos = 0;
+ }
+
+ // Need to get more data?
+ if (bufferPos >= bufferLength) {
+
+ bufferLength = in.read(buffer, sizeof(buffer));
+ bufferPos = 0;
+
+ // No more data
+ if (bufferLength == 0) {
+ break;
+ }
+ }
+
+ // Get the next char and encode it
+ const byte_t c = buffer[bufferPos++];
+
+ if (rfc2047) {
+
+ if (c >= 128 || sm_RFC2047EncodeTable[c] != 0) {
+
+ if (c == 32) { // space
+
+ // RFC-2047, Page 5, 4.2. The "Q" encoding:
+ // << The 8-bit hexadecimal value 20 (e.g., ISO-8859-1 SPACE) may be
+ // represented as "_" (underscore, ASCII 95.). >>
+ outBuffer[outBufferPos++] = '_';
+ ++curCol;
+
+ } else {
+
+ // Other characters: '=' + hexadecimal encoding
+ QP_ENCODE_HEX(c);
+ }
+
+ } else {
+
+ // No encoding
+ outBuffer[outBufferPos++] = c;
+ ++curCol;
+ }
+
+ } else {
+
+ switch (c) {
+
+ case 46: { // .
+
+ if (curCol == 0) {
+ // If a '.' appears at the beginning of a line, we encode it to
+ // to avoid problems with SMTP servers... ("\r\n.\r\n" means the
+ // end of data transmission).
+ QP_ENCODE_HEX('.');
+ continue;
+ }
+
+ outBuffer[outBufferPos++] = '.';
+ ++curCol;
+ break;
+ }
+ case 32: { // space
+
+ // Need to get more data?
+ if (bufferPos >= bufferLength) {
+ bufferLength = in.read(buffer, sizeof(buffer));
+ bufferPos = 0;
+ }
+
+ // Spaces cannot appear at the end of a line. So, encode the space.
+ if (bufferPos >= bufferLength ||
+ (buffer[bufferPos] == '\r' || buffer[bufferPos] == '\n')) {
+
+ QP_ENCODE_HEX(' ');
+
+ } else {
+
+ outBuffer[outBufferPos++] = ' ';
+ ++curCol;
+ }
+
+ break;
+ }
+ case 9: { // TAB
+
+ QP_ENCODE_HEX(c);
+ break;
+ }
+ case 13: // CR
+ case 10: { // LF
+
+ // RFC-2045/6.7(4)
+
+ // Text data
+ if (text && !rfc2047) {
+
+ outBuffer[outBufferPos++] = c;
+ ++curCol;
+
+ if (c == 10) {
+ curCol = 0; // reset current line length
+ }
+
+ // Binary data
+ } else {
+
+ QP_ENCODE_HEX(c);
+ }
+
+ break;
+ }
+ case 61: { // =
+
+ QP_ENCODE_HEX('=');
+ break;
+ }
+ /*
+ Rule #2: (Literal representation) Octets with decimal values of 33
+ through 60 inclusive, and 62 through 126, inclusive, MAY be
+ represented as the ASCII characters which correspond to those
+ octets (EXCLAMATION POINT through LESS THAN, and GREATER THAN
+ through TILDE, respectively).
+ */
+ default:
+
+ //if ((c >= 33 && c <= 60) || (c >= 62 && c <= 126))
+ if (c >= 33 && c <= 126 && c != 61 && c != 63) {
+
+ outBuffer[outBufferPos++] = c;
+ ++curCol;
+
+ // Other characters: '=' + hexadecimal encoding
+ } else {
+
+ QP_ENCODE_HEX(c);
+ }
+
+ break;
+
+ } // switch (c)
+
+ // Soft line break : "=\r\n"
+ if (cutLines && curCol >= maxLineLength - 1) {
+
+ outBuffer[outBufferPos] = '=';
+ outBuffer[outBufferPos + 1] = '\r';
+ outBuffer[outBufferPos + 2] = '\n';
+
+ outBufferPos += 3;
+ curCol = 0;
+ }
+
+ } // !rfc2047
+
+ ++inTotal;
+
+ if (progress) {
+ progress->progress(inTotal, inTotal);
+ }
+ }
+
+ // Flush remaining output buffer
+ if (outBufferPos != 0) {
+ QP_WRITE(out, outBuffer, outBufferPos);
+ total += outBufferPos;
+ }
+
+ if (progress) {
+ progress->stop(inTotal);
+ }
+
+ return total;
+}
+
+
+size_t qpEncoder::decode(
+ utility::inputStream& in,
+ utility::outputStream& out,
+ utility::progressListener* progress
+) {
+
+ in.reset(); // may not work...
+
+ // Process the data
+ const bool rfc2047 = getProperties().getProperty <bool>("rfc2047", false);
+
+ byte_t buffer[16384];
+ size_t bufferLength = 0;
+ size_t bufferPos = 0;
+
+ byte_t outBuffer[16384];
+ size_t outBufferPos = 0;
+
+ size_t total = 0;
+ size_t inTotal = 0;
+
+ while (bufferPos < bufferLength || !in.eof()) {
+
+ // Flush current output buffer
+ if (outBufferPos >= sizeof(outBuffer)) {
+
+ QP_WRITE(out, outBuffer, outBufferPos);
+
+ total += outBufferPos;
+ outBufferPos = 0;
+ }
+
+ // Need to get more data?
+ if (bufferPos >= bufferLength) {
+
+ bufferLength = in.read(buffer, sizeof(buffer));
+ bufferPos = 0;
+
+ // No more data
+ if (bufferLength == 0) {
+ break;
+ }
+ }
+
+ // Decode the next sequence (hex-encoded byte or printable character)
+ byte_t c = buffer[bufferPos++];
+
+ ++inTotal;
+
+ switch (c) {
+
+ case '=': {
+
+ if (bufferPos >= bufferLength) {
+ bufferLength = in.read(buffer, sizeof(buffer));
+ bufferPos = 0;
+ }
+
+ if (bufferPos < bufferLength) {
+
+ c = buffer[bufferPos++];
+
+ ++inTotal;
+
+ switch (c) {
+
+ // Ignore soft line break ("=\r\n" or "=\n")
+ case '\r':
+
+ // Read one byte more
+ if (bufferPos >= bufferLength) {
+ bufferLength = in.read(buffer, sizeof(buffer));
+ bufferPos = 0;
+ }
+
+ if (bufferPos < bufferLength) {
+ ++bufferPos;
+ ++inTotal;
+ }
+
+ break;
+
+ case '\n':
+
+ break;
+
+ // Hex-encoded char
+ default:
+ {
+ // We need another byte...
+ if (bufferPos >= bufferLength) {
+ bufferLength = in.read(buffer, sizeof(buffer));
+ bufferPos = 0;
+ }
+
+ if (bufferPos < bufferLength) {
+
+ const byte_t next = buffer[bufferPos++];
+
+ ++inTotal;
+
+ const byte_t value = static_cast <byte_t>(
+ sm_hexDecodeTable[c] * 16 + sm_hexDecodeTable[next]
+ );
+
+ outBuffer[outBufferPos++] = value;
+
+ } else {
+
+ // Premature end-of-data
+ }
+
+ break;
+ }
+
+ }
+
+ } else {
+
+ // Premature end-of-data
+ }
+
+ break;
+ }
+ case '_': {
+
+ if (rfc2047) {
+
+ // RFC-2047, Page 5, 4.2. The "Q" encoding:
+ // << Note that the "_" always represents hexadecimal 20, even if the SPACE
+ // character occupies a different code position in the character set in use. >>
+ outBuffer[outBufferPos++] = 0x20;
+ break;
+ }
+
+ outBuffer[outBufferPos++] = c;
+ break;
+ }
+ default: {
+
+ outBuffer[outBufferPos++] = c;
+ break;
+ }
+
+ }
+
+ if (progress) {
+ progress->progress(inTotal, inTotal);
+ }
+ }
+
+ // Flush remaining output buffer
+ if (outBufferPos != 0) {
+ QP_WRITE(out, outBuffer, outBufferPos);
+ total += outBufferPos;
+ }
+
+ if (progress) {
+ progress->stop(inTotal);
+ }
+
+ return total;
+}
+
+
+size_t qpEncoder::getEncodedSize(const size_t n) const {
+
+ const size_t propMaxLineLength =
+ getProperties().getProperty <size_t>("maxlinelength", static_cast <size_t>(-1));
+
+ const bool cutLines = (propMaxLineLength != static_cast <size_t>(-1));
+ const size_t maxLineLength = std::min(propMaxLineLength, static_cast <size_t>(74));
+
+ // Worst cast: 1 byte of input provide 3 bytes of output
+ // Count CRLF (2 bytes) for each line.
+ return n * 3 + (cutLines ? (n / maxLineLength) * 2 : 0);
+}
+
+
+size_t qpEncoder::getDecodedSize(const size_t n) const {
+
+ // Worst case: 1 byte of input equals 1 byte of output
+ return n;
+}
+
+
+} // encoder
+} // utility
+} // vmime
diff --git a/vmime-master/src/vmime/utility/encoder/qpEncoder.hpp b/vmime-master/src/vmime/utility/encoder/qpEncoder.hpp
new file mode 100644
index 0000000..21263a6
--- /dev/null
+++ b/vmime-master/src/vmime/utility/encoder/qpEncoder.hpp
@@ -0,0 +1,77 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_UTILITY_ENCODER_QPENCODER_HPP_INCLUDED
+#define VMIME_UTILITY_ENCODER_QPENCODER_HPP_INCLUDED
+
+
+#include "vmime/utility/encoder/encoder.hpp"
+
+
+namespace vmime {
+namespace utility {
+namespace encoder {
+
+
+/** Quoted-printable encoder.
+ */
+class VMIME_EXPORT qpEncoder : public encoder {
+
+public:
+
+ qpEncoder();
+
+ size_t encode(
+ utility::inputStream& in,
+ utility::outputStream& out,
+ utility::progressListener* progress = NULL
+ );
+
+ size_t decode(
+ utility::inputStream& in,
+ utility::outputStream& out,
+ utility::progressListener* progress = NULL
+ );
+
+ const std::vector <string> getAvailableProperties() const;
+
+ static bool RFC2047_isEncodingNeededForChar(const unsigned char c);
+ static int RFC2047_getEncodedLength(const unsigned char c);
+
+ size_t getEncodedSize(const size_t n) const;
+ size_t getDecodedSize(const size_t n) const;
+
+protected:
+
+ static const unsigned char sm_hexDigits[17];
+ static const unsigned char sm_hexDecodeTable[256];
+ static const unsigned char sm_RFC2047EncodeTable[128];
+};
+
+
+} // encoder
+} // utility
+} // vmime
+
+
+#endif // VMIME_UTILITY_ENCODER_QPENCODER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/utility/encoder/sevenBitEncoder.cpp b/vmime-master/src/vmime/utility/encoder/sevenBitEncoder.cpp
new file mode 100644
index 0000000..999b11e
--- /dev/null
+++ b/vmime-master/src/vmime/utility/encoder/sevenBitEncoder.cpp
@@ -0,0 +1,39 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/utility/encoder/sevenBitEncoder.hpp"
+
+
+namespace vmime {
+namespace utility {
+namespace encoder {
+
+
+sevenBitEncoder::sevenBitEncoder() {
+
+}
+
+
+} // encoder
+} // utility
+} // vmime
diff --git a/vmime-master/src/vmime/utility/encoder/sevenBitEncoder.hpp b/vmime-master/src/vmime/utility/encoder/sevenBitEncoder.hpp
new file mode 100644
index 0000000..37f84a6
--- /dev/null
+++ b/vmime-master/src/vmime/utility/encoder/sevenBitEncoder.hpp
@@ -0,0 +1,51 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_UTILITY_ENCODER_SEVENBITENCODER_HPP_INCLUDED
+#define VMIME_UTILITY_ENCODER_SEVENBITENCODER_HPP_INCLUDED
+
+
+#include "vmime/utility/encoder/noopEncoder.hpp"
+
+
+namespace vmime {
+namespace utility {
+namespace encoder {
+
+
+/** 7-bit encoder.
+ */
+class VMIME_EXPORT sevenBitEncoder : public noopEncoder
+{
+public:
+
+ sevenBitEncoder();
+};
+
+
+} // encoder
+} // utility
+} // vmime
+
+
+#endif // VMIME_UTILITY_ENCODER_SEVENBITENCODER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/utility/encoder/uuEncoder.cpp b/vmime-master/src/vmime/utility/encoder/uuEncoder.cpp
new file mode 100644
index 0000000..24dcdc8
--- /dev/null
+++ b/vmime-master/src/vmime/utility/encoder/uuEncoder.cpp
@@ -0,0 +1,358 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/utility/encoder/uuEncoder.hpp"
+#include "vmime/parserHelpers.hpp"
+
+
+namespace vmime {
+namespace utility {
+namespace encoder {
+
+
+uuEncoder::uuEncoder() {
+
+ getProperties()["mode"] = 644;
+ getProperties()["filename"] = "no_name";
+ getProperties()["maxlinelength"] = 46;
+}
+
+
+const std::vector <string> uuEncoder::getAvailableProperties() const {
+
+ std::vector <string> list(encoder::getAvailableProperties());
+
+ list.push_back("maxlinelength");
+
+ list.push_back("mode");
+ list.push_back("filename");
+
+ return list;
+}
+
+
+// This is the character encoding function to make a character printable
+static inline byte_t UUENCODE(const unsigned int c) {
+
+ return static_cast <byte_t>((c & 077) + ' ');
+}
+
+// Single character decoding
+static inline unsigned int UUDECODE(const unsigned int c) {
+
+ return (c - ' ') & 077;
+}
+
+
+size_t uuEncoder::encode(
+ utility::inputStream& in,
+ utility::outputStream& out,
+ utility::progressListener* progress
+) {
+
+ in.reset(); // may not work...
+
+ const string propFilename = getProperties().getProperty <string>("filename", "");
+ const string propMode = getProperties().getProperty <string>("mode", "644");
+
+ const size_t maxLineLength =
+ std::min(getProperties().getProperty <size_t>("maxlinelength", 46), static_cast <size_t>(46));
+
+ size_t total = 0;
+ size_t inTotal = 0;
+
+ // Output the prelude text ("begin [mode] [filename]")
+ out << "begin";
+
+ if (!propFilename.empty()) {
+ out << " " << propMode << " " << propFilename;
+ total += 2 + propMode.length() + propFilename.length();
+ }
+
+ out << "\r\n";
+ total += 7;
+
+ // Process the data
+ byte_t inBuffer[64];
+ byte_t outBuffer[64];
+
+ if (progress) {
+ progress->start(0);
+ }
+
+ while (!in.eof()) {
+
+ // Process up to 45 characters per line
+ std::fill(inBuffer, inBuffer + sizeof(inBuffer), 0);
+
+ const size_t inLength = in.read(inBuffer, maxLineLength - 1);
+
+ outBuffer[0] = UUENCODE(static_cast <unsigned int>(inLength)); // Line length
+
+ size_t j = 1;
+
+ for (size_t i = 0 ; i < inLength ; i += 3, j += 4) {
+
+ const byte_t c1 = inBuffer[i];
+ const byte_t c2 = inBuffer[i + 1];
+ const byte_t c3 = inBuffer[i + 2];
+
+ outBuffer[j] = UUENCODE(c1 >> 2);
+ outBuffer[j + 1] = UUENCODE(((c1 << 4) & 060) | ((c2 >> 4) & 017));
+ outBuffer[j + 2] = UUENCODE(((c2 << 2) & 074) | ((c3 >> 6) & 03));
+ outBuffer[j + 3] = UUENCODE(c3 & 077);
+ }
+
+ outBuffer[j] = '\r';
+ outBuffer[j + 1] = '\n';
+
+ out.write(outBuffer, j + 2);
+
+ total += j + 2;
+ inTotal += inLength;
+
+ if (progress) {
+ progress->progress(inTotal, inTotal);
+ }
+ }
+
+ out << "end\r\n";
+ total += 5;
+
+ if (progress) {
+ progress->stop(inTotal);
+ }
+
+ return total;
+}
+
+
+size_t uuEncoder::decode(
+ utility::inputStream& in,
+ utility::outputStream& out,
+ utility::progressListener* progress
+) {
+
+ in.reset(); // may not work...
+
+ // Process the data
+ byte_t inBuffer[64];
+ byte_t outBuffer[64];
+
+ size_t total = 0;
+ size_t inTotal = 0;
+
+ bool stop = false;
+
+ std::fill(inBuffer, inBuffer + sizeof(inBuffer), 0);
+
+ if (progress) {
+ progress->start(0);
+ }
+
+ while (!stop && !in.eof()) {
+
+ // Get the line length
+ byte_t lengthChar;
+
+ if (in.read(&lengthChar, 1) == 0) {
+ break;
+ }
+
+ const size_t outLength = UUDECODE(lengthChar);
+ const size_t inLength = std::min((outLength * 4) / 3, static_cast <size_t>(64));
+ size_t inPos = 0;
+
+ switch (lengthChar) {
+
+ case ' ':
+ case '\t':
+ case '\r':
+ case '\n': {
+
+ // Ignore
+ continue;
+ }
+ case 'b': {
+
+ // Read 5 characters more to check for begin ("begin ...\r\n" or "begin ...\n")
+ inPos = in.read(inBuffer, 5);
+
+ if (inPos == 5 &&
+ inBuffer[0] == 'e' &&
+ inBuffer[1] == 'g' &&
+ inBuffer[2] == 'i' &&
+ inBuffer[3] == 'n' &&
+ parserHelpers::isSpace(inBuffer[4])) {
+
+ inTotal += 5;
+
+ byte_t c = 0;
+
+ size_t count = 0;
+ byte_t buffer[512];
+
+ while (count < sizeof(buffer) - 1 && in.read(&c, 1) == 1) {
+
+ if (c == '\n') {
+ break;
+ }
+
+ buffer[count++] = c;
+ }
+
+ inTotal += count;
+
+ if (c != '\n') {
+
+ // OOPS! Weird line. Don't try to decode more...
+
+ if (progress) {
+ progress->stop(inTotal);
+ }
+
+ return total;
+ }
+
+ // Parse filename and mode
+ if (count > 0) {
+
+ buffer[count] = '\0';
+
+ byte_t* p = buffer;
+
+ while (*p && parserHelpers::isSpace(*p)) ++p;
+
+ byte_t* modeStart = buffer;
+
+ while (*p && !parserHelpers::isSpace(*p)) ++p;
+
+ getResults()["mode"] = string(modeStart, p);
+
+ while (*p && parserHelpers::isSpace(*p)) ++p;
+
+ byte_t* filenameStart = buffer;
+
+ while (*p && !(*p == '\r' || *p == '\n')) ++p;
+
+ getResults()["filename"] = string(filenameStart, p);
+
+ // No filename or mode specified
+ } else {
+
+ getResults()["filename"] = "untitled";
+ getResults()["mode"] = 644;
+ }
+
+ continue;
+ }
+
+ break;
+ }
+ case 'e': {
+
+ // Read 3 characters more to check for end ("end\r\n" or "end\n")
+ inPos = in.read(inBuffer, 3);
+
+ if (inPos == 3 &&
+ inBuffer[0] == 'n' &&
+ inBuffer[1] == 'd' &&
+ (inBuffer[2] == '\r' || inBuffer[2] == '\n')) {
+
+ stop = true;
+ inTotal += 3;
+ continue;
+ }
+
+ break;
+ }
+
+ }
+
+ // Read encoded data
+ if (in.read(inBuffer + inPos, inLength - inPos) != inLength - inPos) {
+ // Premature end of data
+ break;
+ }
+
+ inTotal += (inLength - inPos);
+
+ // Decode data
+ for (size_t i = 0, j = 0 ; i < inLength ; i += 4, j += 3) {
+
+ const byte_t c1 = inBuffer[i];
+ const byte_t c2 = inBuffer[i + 1];
+ const byte_t c3 = inBuffer[i + 2];
+ const byte_t c4 = inBuffer[i + 3];
+
+ const size_t n = std::min(inLength - i, static_cast <size_t>(3));
+
+ if (n >= 3) {
+ outBuffer[j + 2] = static_cast <byte_t>(UUDECODE(c3) << 6 | UUDECODE(c4));
+ }
+ if (n >= 2) {
+ outBuffer[j + 1] = static_cast <byte_t>(UUDECODE(c2) << 4 | UUDECODE(c3) >> 2);
+ }
+ if (n >= 1) {
+ outBuffer[j] = static_cast <byte_t>(UUDECODE(c1) << 2 | UUDECODE(c2) >> 4);
+ }
+
+ total += n;
+ }
+
+ out.write(outBuffer, outLength);
+
+ std::fill(inBuffer, inBuffer + sizeof(inBuffer), 0);
+
+ if (progress) {
+ progress->progress(inTotal, inTotal);
+ }
+ }
+
+ if (progress) {
+ progress->stop(inTotal);
+ }
+
+ return total;
+}
+
+
+size_t uuEncoder::getEncodedSize(const size_t n) const {
+
+ // 3 bytes of input provide 4 bytes of output.
+ // Count CRLF (2 bytes) for each line of 45 characters.
+ // Also reserve some space for header and footer.
+ return 200 + n * 3 + (n / 45) * 2;
+}
+
+
+size_t uuEncoder::getDecodedSize(const size_t n) const {
+
+ // 4 bytes of input provide 3 bytes of output
+ return (n * 3) / 4;
+}
+
+
+} // encoder
+} // utility
+} // vmime
diff --git a/vmime-master/src/vmime/utility/encoder/uuEncoder.hpp b/vmime-master/src/vmime/utility/encoder/uuEncoder.hpp
new file mode 100644
index 0000000..841cf66
--- /dev/null
+++ b/vmime-master/src/vmime/utility/encoder/uuEncoder.hpp
@@ -0,0 +1,68 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_UTILITY_ENCODER_UUENCODER_HPP_INCLUDED
+#define VMIME_UTILITY_ENCODER_UUENCODER_HPP_INCLUDED
+
+
+#include "vmime/utility/encoder/encoder.hpp"
+
+
+namespace vmime {
+namespace utility {
+namespace encoder {
+
+
+/** UUEncode encoder.
+ */
+class VMIME_EXPORT uuEncoder : public encoder {
+
+public:
+
+ uuEncoder();
+
+ size_t encode(
+ utility::inputStream& in,
+ utility::outputStream& out,
+ utility::progressListener* progress = NULL
+ );
+
+ size_t decode(
+ utility::inputStream& in,
+ utility::outputStream& out,
+ utility::progressListener* progress = NULL
+ );
+
+ const std::vector <string> getAvailableProperties() const;
+
+ size_t getEncodedSize(const size_t n) const;
+ size_t getDecodedSize(const size_t n) const;
+};
+
+
+} // encoder
+} // utility
+} // vmime
+
+
+#endif // VMIME_UTILITY_ENCODER_UUENCODER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/utility/file.hpp b/vmime-master/src/vmime/utility/file.hpp
new file mode 100644
index 0000000..6e0605e
--- /dev/null
+++ b/vmime-master/src/vmime/utility/file.hpp
@@ -0,0 +1,264 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_UTILITY_FILE_HPP_INCLUDED
+#define VMIME_UTILITY_FILE_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+
+#include "vmime/utility/path.hpp"
+#include "vmime/utility/stream.hpp"
+
+
+#if VMIME_HAVE_FILESYSTEM_FEATURES
+
+
+namespace vmime {
+namespace utility {
+
+
+class file;
+
+
+/** File list iterator (see file::getFiles).
+ */
+class VMIME_EXPORT fileIterator : public object {
+
+public:
+
+ virtual ~fileIterator() { }
+
+ /** Check whether the cursor has reach the end of the list.
+ *
+ * @return true if you can call nextElement(), or false
+ * if no more file is available
+ */
+ virtual bool hasMoreElements() const = 0;
+
+ /** Return the next file in the list.
+ *
+ * @return next file or NULL
+ */
+ virtual shared_ptr <file> nextElement() = 0;
+};
+
+
+/** Write to a file.
+ */
+class VMIME_EXPORT fileWriter : public object {
+
+public:
+
+ virtual ~fileWriter() { }
+
+ virtual shared_ptr <utility::outputStream> getOutputStream() = 0;
+};
+
+
+/** Read from a file.
+ */
+class VMIME_EXPORT fileReader : public object {
+
+public:
+
+ virtual ~fileReader() { }
+
+ virtual shared_ptr <utility::inputStream> getInputStream() = 0;
+};
+
+
+/** Abstract representation of a file or directory.
+ */
+class VMIME_EXPORT file : public object {
+
+public:
+
+ typedef utility::path path;
+ typedef unsigned long length_type;
+
+
+ virtual ~file() { }
+
+
+ /** Create the file pointed by this file object.
+ *
+ * @throw exceptions::filesystem_exception if an error occurs
+ */
+ virtual void createFile() = 0;
+
+ /** Create the directory pointed by this file object.
+ *
+ * @param createAll if set to true, recursively create all
+ * parent directories if they do not exist
+ * @throw exceptions::filesystem_exception if an error occurs
+ */
+ virtual void createDirectory(const bool createAll = false) = 0;
+
+ /** Test whether this is a file.
+ *
+ * @return true if this is a file, false otherwise
+ */
+ virtual bool isFile() const = 0;
+
+ /** Test whether this is a directory.
+ *
+ * @return true if this is a directory, false otherwise
+ */
+ virtual bool isDirectory() const = 0;
+
+ /** Test whether this file is readible.
+ *
+ * @return true if we can read this file, false otherwise
+ */
+ virtual bool canRead() const = 0;
+
+ /** Test whether this file is writeable.
+ *
+ * @return true if we can write to this file, false otherwise
+ */
+ virtual bool canWrite() const = 0;
+
+ /** Return the length of this file.
+ *
+ * @return file size (in bytes)
+ */
+ virtual length_type getLength() = 0;
+
+ /** Return the full path of this file/directory.
+ *
+ * @return full path of the file
+ */
+ virtual const path& getFullPath() const = 0;
+
+ /** Test whether this file/directory exists.
+ *
+ * @return true if the file exists, false otherwise
+ */
+ virtual bool exists() const = 0;
+
+ /** Return the parent directory of this file/directory.
+ *
+ * @return parent directory (or NULL if root)
+ */
+ virtual shared_ptr <file> getParent() const = 0;
+
+ /** Rename the file/directory.
+ *
+ * @param newName full path of the new file
+ * @throw exceptions::filesystem_exception if an error occurs
+ */
+ virtual void rename(const path& newName) = 0;
+
+ /** Deletes this file/directory.
+ * If this is a directory, it must be empty.
+ *
+ * @throw exceptions::filesystem_exception if an error occurs
+ */
+ virtual void remove() = 0;
+
+ /** Return an object capable of writing to this file.
+ *
+ * @return file writer object
+ */
+ virtual shared_ptr <fileWriter> getFileWriter() = 0;
+
+ /** Return an object capable of reading from this file.
+ *
+ * @return file reader object
+ */
+ virtual shared_ptr <fileReader> getFileReader() = 0;
+
+ /** Enumerate files contained in this directory.
+ *
+ * @return file iterator to enumerate files
+ * @throw exceptions::not_a_directory if this is not a directory,
+ * exceptions::filesystem_exception if another error occurs
+ */
+ virtual shared_ptr <fileIterator> getFiles() const = 0;
+
+protected:
+
+ file() { }
+
+private:
+
+ file(const file&) : object() { }
+};
+
+
+/** Constructs 'file' objects.
+ */
+class VMIME_EXPORT fileSystemFactory : public object {
+
+public:
+
+ virtual ~fileSystemFactory() { }
+
+ /** Create a new file object from the specified path.
+ *
+ * @param path full path (absolute) of the file
+ * @return new file object for the path
+ */
+ virtual shared_ptr <file> create(const file::path& path) const = 0;
+
+ /** Parse a path contained in a string.
+ *
+ * @param str string containing a path in a system-dependent representation
+ * @return path object (abstract representation)
+ */
+ virtual const file::path stringToPath(const string& str) const = 0;
+
+ /** Return the system-dependent string representation for the specified path.
+ *
+ * @param path abstract representation of the path
+ * @return string representation of the path
+ */
+ virtual const string pathToString(const file::path& path) const = 0;
+
+ /** Test whether the specified path component is syntactically
+ * valid (ie: does not contain any 'special' character).
+ *
+ * @param comp path component to test
+ * @return true if the component is valid, false otherwise
+ */
+ virtual bool isValidPathComponent(const file::path::component& comp) const = 0;
+
+ /** Test whether the specified path is syntactically valid
+ * (ie: components do not contain any 'special' character).
+ *
+ * @param path path to test
+ * @return true if the path is valid, false otherwise
+ */
+ virtual bool isValidPath(const file::path& path) const = 0;
+};
+
+
+} // utility
+} // vmime
+
+
+#endif // VMIME_HAVE_FILESYSTEM_FEATURES
+
+
+#endif // VMIME_UTILITY_FILE_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/utility/filteredStream.cpp b/vmime-master/src/vmime/utility/filteredStream.cpp
new file mode 100644
index 0000000..d5ec17b
--- /dev/null
+++ b/vmime-master/src/vmime/utility/filteredStream.cpp
@@ -0,0 +1,402 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/utility/filteredStream.hpp"
+
+#include <algorithm>
+
+
+namespace vmime {
+namespace utility {
+
+
+// filteredInputStream
+
+size_t filteredInputStream::getBlockSize() {
+
+ return std::min(inputStream::getBlockSize(), getPreviousInputStream().getBlockSize());
+}
+
+
+// filteredOutputStream
+
+size_t filteredOutputStream::getBlockSize() {
+
+ return std::min(outputStream::getBlockSize(), getNextOutputStream().getBlockSize());
+}
+
+
+// dotFilteredInputStream
+
+dotFilteredInputStream::dotFilteredInputStream(inputStream& is)
+ : m_stream(is),
+ m_previousChar2('\0'),
+ m_previousChar1('\0') {
+
+}
+
+
+inputStream& dotFilteredInputStream::getPreviousInputStream() {
+
+ return m_stream;
+}
+
+
+bool dotFilteredInputStream::eof() const {
+
+ return m_stream.eof();
+}
+
+
+void dotFilteredInputStream::reset() {
+
+ m_previousChar2 = '\0';
+ m_previousChar1 = '\0';
+
+ m_stream.reset();
+}
+
+
+size_t dotFilteredInputStream::read(byte_t* const data, const size_t count) {
+
+ const size_t read = m_stream.read(data, count);
+
+ const byte_t* readPtr = data;
+ byte_t* writePtr = data;
+
+ const byte_t* end = data + read;
+
+ size_t written = 0;
+
+ byte_t prevChar2 = m_previousChar2;
+ byte_t prevChar1 = m_previousChar1;
+
+ // Replace "\n.." with "\n."
+ while (readPtr < end) {
+
+ if (*readPtr == '.' && prevChar2 == '\n' && prevChar1 == '.') {
+
+ // Ignore last dot
+ prevChar2 = '\0';
+ prevChar1 = '.';
+
+ } else {
+
+ *writePtr = *readPtr;
+
+ ++writePtr;
+ ++written;
+
+ prevChar2 = prevChar1;
+ prevChar1 = *readPtr;
+ }
+
+ ++readPtr;
+ }
+
+ m_previousChar2 = prevChar2;
+ m_previousChar1 = prevChar1;
+
+ return written;
+}
+
+
+size_t dotFilteredInputStream::skip(const size_t /* count */) {
+
+ // Skipping bytes is not supported
+ return 0;
+}
+
+
+// dotFilteredOutputStream
+
+dotFilteredOutputStream::dotFilteredOutputStream(outputStream& os)
+ : m_stream(os),
+ m_previousChar('\0'),
+ m_start(true) {
+
+}
+
+
+outputStream& dotFilteredOutputStream::getNextOutputStream() {
+
+ return m_stream;
+}
+
+
+void dotFilteredOutputStream::writeImpl(const byte_t* const data, const size_t count) {
+
+ if (count == 0) {
+ return;
+ }
+
+ const byte_t* pos = data;
+ const byte_t* end = data + count;
+ const byte_t* start = data;
+
+ if (m_previousChar == '.') {
+
+ if (data[0] == '\n' || data[0] == '\r') {
+
+ m_stream.write(".", 1); // extra <DOT>
+ m_stream.write(data, 1);
+
+ pos = data + 1;
+ }
+ }
+
+ // Replace "\n." with "\n.."
+ while ((pos = std::find(pos, end, '.')) != end) {
+
+ const byte_t previousChar = (pos == data ? m_previousChar : *(pos - 1));
+
+ if (previousChar == '\n') {
+
+ m_stream.write(start, pos - start);
+ m_stream.write("..", 2);
+
+ start = pos + 1;
+
+ } else if (pos == data && m_start) { // <DOT><CR><LF> at the beginning of content
+
+ m_stream.write(start, pos - start);
+
+ if (pos + 1 < end && (*(pos + 1) == '\n' || *(pos + 1) == '\r')) {
+ m_stream.write("..", 2);
+ } else {
+ m_stream.write(".", 1);
+ }
+
+ start = pos + 1;
+ }
+
+ ++pos;
+ }
+
+ m_stream.write(start, end - start);
+ m_previousChar = data[count - 1];
+ m_start = false;
+}
+
+
+void dotFilteredOutputStream::flush() {
+
+ // Do nothing
+ m_stream.flush();
+}
+
+
+size_t dotFilteredOutputStream::getBlockSize() {
+
+ return m_stream.getBlockSize();
+}
+
+
+// CRLFToLFFilteredOutputStream
+
+CRLFToLFFilteredOutputStream::CRLFToLFFilteredOutputStream(outputStream& os)
+ : m_stream(os),
+ m_previousChar('\0') {
+
+}
+
+
+outputStream& CRLFToLFFilteredOutputStream::getNextOutputStream() {
+
+ return m_stream;
+}
+
+
+void CRLFToLFFilteredOutputStream::writeImpl(const byte_t* const data, const size_t count) {
+
+ if (count == 0) {
+ return;
+ }
+
+ const byte_t* pos = data;
+ const byte_t* end = data + count;
+ const byte_t* start = data;
+
+ // Warning: if the whole buffer finishes with '\r', this
+ // last character will not be written back if flush() is
+ // not called
+ if (m_previousChar == '\r') {
+
+ if (*pos != '\n') {
+ m_stream.write("\r", 1); // write back \r
+ m_previousChar = *pos;
+ }
+ }
+
+ // Replace "\r\n" (CRLF) with "\n" (LF)
+ while ((pos = std::find(pos, end, '\n')) != end) {
+
+ const byte_t previousChar = (pos == data ? m_previousChar : *(pos - 1));
+
+ if (previousChar == '\r') {
+
+ if (pos != start) {
+ m_stream.write(start, pos - 1 - start); // do not write \r
+ }
+
+ m_stream.write("\n", 1);
+
+ start = pos + 1;
+ }
+
+ ++pos;
+ }
+
+ if (data[count - 1] == '\r') {
+
+ m_stream.write(start, end - start - 1);
+ m_previousChar = '\r';
+
+ } else {
+
+ m_stream.write(start, end - start);
+ m_previousChar = data[count - 1];
+ }
+}
+
+
+void CRLFToLFFilteredOutputStream::flush() {
+
+ m_stream.flush();
+
+ // TODO
+}
+
+
+size_t CRLFToLFFilteredOutputStream::getBlockSize() {
+
+ return m_stream.getBlockSize();
+}
+
+
+// LFToCRLFFilteredOutputStream
+
+LFToCRLFFilteredOutputStream::LFToCRLFFilteredOutputStream(outputStream& os)
+ : m_stream(os),
+ m_previousChar('\0') {
+
+}
+
+
+outputStream& LFToCRLFFilteredOutputStream::getNextOutputStream() {
+
+ return m_stream;
+}
+
+
+void LFToCRLFFilteredOutputStream::writeImpl(const byte_t* const data, const size_t count)
+{
+ if (count == 0) {
+ return;
+ }
+
+ string buffer;
+ buffer.reserve(count);
+
+ const byte_t* pos = data;
+ const byte_t* end = data + count;
+
+ byte_t previousChar = m_previousChar;
+
+ while (pos < end) {
+
+ switch (*pos) {
+
+ case '\r':
+
+ buffer.append(1, '\r');
+ buffer.append(1, '\n');
+
+ break;
+
+ case '\n':
+
+ if (previousChar != '\r') {
+ buffer.append(1, '\r');
+ buffer.append(1, '\n');
+ }
+
+ break;
+
+ default:
+
+ buffer.append(1, *pos);
+ break;
+ }
+
+ previousChar = *pos;
+ ++pos;
+ }
+
+ m_stream.write(&buffer[0], buffer.length());
+
+ m_previousChar = previousChar;
+}
+
+
+void LFToCRLFFilteredOutputStream::flush() {
+
+ m_stream.flush();
+}
+
+
+size_t LFToCRLFFilteredOutputStream::getBlockSize() {
+
+ return m_stream.getBlockSize();
+}
+
+
+// stopSequenceFilteredInputStream <1>
+
+template <>
+size_t stopSequenceFilteredInputStream <1>::read(byte_t* const data, const size_t count) {
+
+ if (eof() || m_stream.eof()) {
+ m_eof = true;
+ return 0;
+ }
+
+ const size_t read = m_stream.read(data, count);
+ byte_t* end = data + read;
+
+ byte_t* pos = std::find(data, end, m_sequence[0]);
+
+ if (pos == end) {
+
+ return read;
+
+ } else {
+
+ m_found = 1;
+ return pos - data;
+ }
+}
+
+
+} // utility
+} // vmime
diff --git a/vmime-master/src/vmime/utility/filteredStream.hpp b/vmime-master/src/vmime/utility/filteredStream.hpp
new file mode 100644
index 0000000..2414c54
--- /dev/null
+++ b/vmime-master/src/vmime/utility/filteredStream.hpp
@@ -0,0 +1,405 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_UTILITY_FILTEREDSTREAM_HPP_INCLUDED
+#define VMIME_UTILITY_FILTEREDSTREAM_HPP_INCLUDED
+
+
+#include <algorithm>
+
+#include "vmime/utility/inputStream.hpp"
+#include "vmime/utility/outputStream.hpp"
+
+
+namespace vmime {
+namespace utility {
+
+
+/** A stream whose input is filtered.
+ */
+class VMIME_EXPORT filteredInputStream : public inputStream {
+public:
+
+ virtual size_t getBlockSize();
+
+ /** Return a reference to the stream being filtered.
+ *
+ * @return stream being filtered
+ */
+ virtual inputStream& getPreviousInputStream() = 0;
+};
+
+
+/** A stream whose output is filtered.
+ */
+class VMIME_EXPORT filteredOutputStream : public outputStream {
+
+public:
+
+ virtual size_t getBlockSize();
+
+ /** Return a reference to the stream being filtered.
+ *
+ * @return destination stream for filtered data
+ */
+ virtual outputStream& getNextOutputStream() = 0;
+};
+
+
+/** A filtered input stream which replaces "\n.."
+ * sequences with "\n." sequences.
+ */
+class VMIME_EXPORT dotFilteredInputStream : public filteredInputStream {
+
+public:
+
+ /** Construct a new filter for the specified input stream.
+ *
+ * @param is stream from which to read data to be filtered
+ */
+ dotFilteredInputStream(inputStream& is);
+
+ inputStream& getPreviousInputStream();
+
+ bool eof() const;
+
+ void reset();
+
+ size_t read(byte_t* const data, const size_t count);
+
+ size_t skip(const size_t count);
+
+private:
+
+ inputStream& m_stream;
+
+ byte_t m_previousChar2; // (N - 1)th character of previous buffer
+ byte_t m_previousChar1; // (N)th (last) character of previous buffer
+};
+
+
+/** A filtered output stream which replaces "\n."
+ * sequences with "\n.." sequences.
+ */
+class VMIME_EXPORT dotFilteredOutputStream : public filteredOutputStream {
+
+public:
+
+ /** Construct a new filter for the specified output stream.
+ *
+ * @param os stream into which write filtered data
+ */
+ dotFilteredOutputStream(outputStream& os);
+
+ outputStream& getNextOutputStream();
+
+ void flush();
+
+ size_t getBlockSize();
+
+protected:
+
+ void writeImpl(const byte_t* const data, const size_t count);
+
+private:
+
+ outputStream& m_stream;
+ byte_t m_previousChar;
+ bool m_start;
+};
+
+
+/** A filtered output stream which replaces CRLF sequences
+ * with single LF characters.
+ */
+class VMIME_EXPORT CRLFToLFFilteredOutputStream : public filteredOutputStream {
+
+public:
+
+ /** Construct a new filter for the specified output stream.
+ *
+ * @param os stream into which write filtered data
+ */
+ CRLFToLFFilteredOutputStream(outputStream& os);
+
+ outputStream& getNextOutputStream();
+
+ void flush();
+
+ size_t getBlockSize();
+
+protected:
+
+ void writeImpl(const byte_t* const data, const size_t count);
+
+private:
+
+ outputStream& m_stream;
+ byte_t m_previousChar;
+};
+
+
+/** A filtered output stream which replaces CR or LF characters
+ * with CRLF sequences.
+ */
+class VMIME_EXPORT LFToCRLFFilteredOutputStream : public filteredOutputStream {
+
+public:
+
+ /** Construct a new filter for the specified output stream.
+ *
+ * @param os stream into which write filtered data
+ */
+ LFToCRLFFilteredOutputStream(outputStream& os);
+
+ outputStream& getNextOutputStream();
+
+ void flush();
+
+ size_t getBlockSize();
+
+protected:
+
+ void writeImpl(const byte_t* const data, const size_t count);
+
+private:
+
+ outputStream& m_stream;
+ byte_t m_previousChar;
+};
+
+
+/** A filtered input stream which stops when a specified sequence
+ * is found (eof() method will return 'true').
+ */
+template <int COUNT>
+class VMIME_EXPORT stopSequenceFilteredInputStream : public filteredInputStream {
+
+public:
+
+ /** Construct a new filter for the specified input stream.
+ *
+ * @param is stream from which to read data to be filtered
+ * @param sequence sequence on which to stop
+ */
+ stopSequenceFilteredInputStream(inputStream& is, const byte_t* sequence)
+ : m_stream(is),
+ m_sequence(sequence),
+ m_found(0),
+ m_eof(false) {
+
+ }
+
+ /** Construct a new filter for the specified input stream.
+ *
+ * @param is stream from which to read data to be filtered
+ * @param sequence sequence on which to stop
+ */
+ stopSequenceFilteredInputStream(inputStream& is, const char* sequence)
+ : m_stream(is),
+ m_sequence(reinterpret_cast <const byte_t*>(sequence)),
+ m_found(0),
+ m_eof(false) {
+
+ }
+
+ inputStream& getPreviousInputStream() {
+
+ return m_stream;
+ }
+
+ bool eof() const {
+
+ return m_found == COUNT || m_eof;
+ }
+
+ void reset() {
+
+ m_found = 0;
+ m_stream.reset();
+ }
+
+ size_t read(byte_t* const data, const size_t count) {
+
+ // Read buffer must be at least 'COUNT' size + 1 byte
+ if (eof() || count <= COUNT) {
+ return 0;
+ }
+
+ if (m_stream.eof()) {
+
+ if (m_found != 0) {
+
+ const size_t found = m_found;
+
+ for (size_t f = 0 ; f < found ; ++f) {
+ data[f] = m_sequence[f];
+ }
+
+ m_found = 0;
+ m_eof = true;
+
+ return found;
+
+ } else {
+
+ m_eof = true;
+ return 0;
+ }
+ }
+
+ size_t read = m_stream.read(data, count - COUNT);
+
+ byte_t* end = data + read;
+ byte_t* pos = data;
+
+ while (pos < end) {
+
+ // Very simple case, search for the whole sequence
+ if (m_found == 0) {
+
+ while (pos < end) {
+
+ pos = std::find(pos, end, m_sequence[0]);
+
+ if (pos == end) {
+ return read;
+ }
+
+ m_found = 1;
+ ++pos;
+
+ while (pos < end && m_found < COUNT && m_sequence[m_found] == *pos) {
+ ++m_found;
+ ++pos;
+ }
+
+ // Didn't found whole sequence
+ if (m_found != COUNT) {
+
+ // We reached the end of the buffer
+ if (pos == end) {
+
+ return read - m_found;
+
+ // Common prefix but not whole sequence
+ } else {
+
+ m_found = 0;
+ }
+
+ // Whole sequence found
+ } else {
+
+ // End of stream
+ return pos - data - m_found;
+ }
+ }
+
+ // More complex case: search for a sequence which has begun
+ // in a previous buffer
+ } else {
+
+ // Search for the end of the previously started sequence
+ while (pos < end && m_found < COUNT && m_sequence[m_found] == *pos) {
+ ++m_found;
+ ++pos;
+ }
+
+ if (m_found != COUNT) {
+
+ // End of buffer
+ if (pos == end) {
+
+ // No data: this buffer is a sub-sequence of the
+ // searched sequence
+ return 0;
+
+ // Common prefix
+ } else {
+
+ // We have to reinject the incomplete sequence into
+ // the stream data
+
+ // -- shift right data
+ const size_t n = pos - data;
+
+ byte_t* newEnd = data + read + m_found - n;
+ byte_t* oldEnd = data + read;
+
+ for (size_t i = 0 ; i < read - n ; ++i) {
+
+ --newEnd;
+ --oldEnd;
+
+ *newEnd = *oldEnd;
+ }
+
+ // -- copy the prefix just before data
+ for (size_t f = 0 ; f < m_found ; ++f) {
+ data[f] = m_sequence[f];
+ }
+
+ read += m_found - n;
+ end += m_found - n;
+
+ m_found = 0;
+ }
+
+ } else {
+
+ return 0; // no more data
+ }
+ }
+ }
+
+ return read;
+ }
+
+ size_t skip(const size_t /* count */) {
+
+ // Not supported
+ return 0;
+ }
+
+private:
+
+ inputStream& m_stream;
+
+ const byte_t* m_sequence;
+ size_t m_found;
+
+ bool m_eof;
+};
+
+
+template <>
+size_t stopSequenceFilteredInputStream <1>::read(byte_t* const data, const size_t count);
+
+
+} // utility
+} // vmime
+
+
+#endif // VMIME_UTILITY_FILTEREDSTREAM_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/utility/inputStream.cpp b/vmime-master/src/vmime/utility/inputStream.cpp
new file mode 100644
index 0000000..916d8ba
--- /dev/null
+++ b/vmime-master/src/vmime/utility/inputStream.cpp
@@ -0,0 +1,33 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/utility/inputStream.hpp"
+
+
+namespace vmime {
+namespace utility {
+
+
+} // utility
+} // vmime
+
diff --git a/vmime-master/src/vmime/utility/inputStream.hpp b/vmime-master/src/vmime/utility/inputStream.hpp
new file mode 100644
index 0000000..0e1c2df
--- /dev/null
+++ b/vmime-master/src/vmime/utility/inputStream.hpp
@@ -0,0 +1,75 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_UTILITY_INPUTSTREAM_HPP_INCLUDED
+#define VMIME_UTILITY_INPUTSTREAM_HPP_INCLUDED
+
+
+#include "vmime/utility/stream.hpp"
+
+
+namespace vmime {
+namespace utility {
+
+
+/** Simple input stream.
+ */
+class VMIME_EXPORT inputStream : public stream {
+
+public:
+
+ /** Test for end of stream (no more data to read).
+ *
+ * @return true if we have reached the end of stream, false otherwise
+ */
+ virtual bool eof() const = 0;
+
+ /** Set the read pointer to the beginning of the stream.
+ *
+ * @warning WARNING: this may not work for all stream types.
+ */
+ virtual void reset() = 0;
+
+ /** Read data from the stream.
+ *
+ * @param data will receive the data read
+ * @param count maximum number of bytes to read
+ * @return number of bytes read
+ */
+ virtual size_t read(byte_t* const data, const size_t count) = 0;
+
+ /** Skip a number of bytes.
+ *
+ * @param count maximum number of bytes to ignore
+ * @return number of bytes skipped
+ */
+ virtual size_t skip(const size_t count) = 0;
+};
+
+
+} // utility
+} // vmime
+
+
+#endif // VMIME_UTILITY_INPUTSTREAM_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/utility/inputStreamAdapter.cpp b/vmime-master/src/vmime/utility/inputStreamAdapter.cpp
new file mode 100644
index 0000000..28be103
--- /dev/null
+++ b/vmime-master/src/vmime/utility/inputStreamAdapter.cpp
@@ -0,0 +1,84 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/utility/inputStreamAdapter.hpp"
+
+
+namespace vmime {
+namespace utility {
+
+
+inputStreamAdapter::inputStreamAdapter(std::istream& is)
+ : m_stream(is) {
+
+}
+
+
+bool inputStreamAdapter::eof() const {
+
+ return m_stream.eof();
+}
+
+
+void inputStreamAdapter::reset() {
+
+ m_stream.exceptions(std::ios_base::badbit);
+ m_stream.seekg(0, std::ios::beg);
+ m_stream.clear();
+}
+
+
+size_t inputStreamAdapter::read(byte_t* const data, const size_t count) {
+
+ m_stream.exceptions(std::ios_base::badbit);
+ m_stream.read(reinterpret_cast <char*>(data), count);
+
+ return m_stream.gcount();
+}
+
+
+size_t inputStreamAdapter::skip(const size_t count) {
+
+ m_stream.exceptions(std::ios_base::badbit);
+ m_stream.ignore(count);
+
+ return m_stream.gcount();
+}
+
+
+size_t inputStreamAdapter::getPosition() const {
+
+ return m_stream.tellg();
+}
+
+
+void inputStreamAdapter::seek(const size_t pos) {
+
+ m_stream.clear();
+ m_stream.seekg(pos, std::ios_base::beg);
+}
+
+
+} // utility
+} // vmime
+
diff --git a/vmime-master/src/vmime/utility/inputStreamAdapter.hpp b/vmime-master/src/vmime/utility/inputStreamAdapter.hpp
new file mode 100644
index 0000000..340765c
--- /dev/null
+++ b/vmime-master/src/vmime/utility/inputStreamAdapter.hpp
@@ -0,0 +1,65 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_UTILITY_INPUTSTREAMADAPTER_HPP_INCLUDED
+#define VMIME_UTILITY_INPUTSTREAMADAPTER_HPP_INCLUDED
+
+
+#include "vmime/utility/seekableInputStream.hpp"
+
+#include <istream>
+
+
+namespace vmime {
+namespace utility {
+
+
+/** An adapter class for C++ standard input streams.
+ */
+class VMIME_EXPORT inputStreamAdapter : public seekableInputStream {
+
+public:
+
+ /** @param is input stream to wrap
+ */
+ inputStreamAdapter(std::istream& is);
+
+ bool eof() const;
+ void reset();
+ size_t read(byte_t* const data, const size_t count);
+ size_t skip(const size_t count);
+ size_t getPosition() const;
+ void seek(const size_t pos);
+
+private:
+
+ std::istream& m_stream;
+};
+
+
+} // utility
+} // vmime
+
+
+#endif // VMIME_UTILITY_INPUTSTREAMADAPTER_HPP_INCLUDED
+
diff --git a/vmime-master/src/vmime/utility/inputStreamByteBufferAdapter.cpp b/vmime-master/src/vmime/utility/inputStreamByteBufferAdapter.cpp
new file mode 100644
index 0000000..927215c
--- /dev/null
+++ b/vmime-master/src/vmime/utility/inputStreamByteBufferAdapter.cpp
@@ -0,0 +1,104 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/utility/inputStreamByteBufferAdapter.hpp"
+
+
+namespace vmime {
+namespace utility {
+
+
+inputStreamByteBufferAdapter::inputStreamByteBufferAdapter(const byte_t* buffer, const size_t length)
+ : m_buffer(buffer),
+ m_length(length),
+ m_pos(0) {
+
+}
+
+
+bool inputStreamByteBufferAdapter::eof() const {
+
+ return m_pos >= m_length;
+}
+
+
+void inputStreamByteBufferAdapter::reset() {
+
+ m_pos = 0;
+}
+
+
+size_t inputStreamByteBufferAdapter::read(byte_t* const data, const size_t count) {
+
+ const size_t remaining = m_length - m_pos;
+
+ if (remaining < count) {
+
+ std::copy(m_buffer + m_pos, m_buffer + m_pos + remaining, data);
+ m_pos += remaining;
+
+ return remaining;
+
+ } else {
+
+ std::copy(m_buffer + m_pos, m_buffer + m_pos + count, data);
+ m_pos += count;
+
+ return count;
+ }
+}
+
+
+size_t inputStreamByteBufferAdapter::skip(const size_t count) {
+
+ const size_t remaining = m_length - m_pos;
+
+ if (remaining < count) {
+
+ m_pos += remaining;
+ return remaining;
+
+ } else {
+
+ m_pos += count;
+ return count;
+ }
+}
+
+
+size_t inputStreamByteBufferAdapter::getPosition() const {
+
+ return m_pos;
+}
+
+
+void inputStreamByteBufferAdapter::seek(const size_t pos) {
+
+ if (pos <= m_length) {
+ m_pos = pos;
+ }
+}
+
+
+} // utility
+} // vmime
diff --git a/vmime-master/src/vmime/utility/inputStreamByteBufferAdapter.hpp b/vmime-master/src/vmime/utility/inputStreamByteBufferAdapter.hpp
new file mode 100644
index 0000000..c9094c7
--- /dev/null
+++ b/vmime-master/src/vmime/utility/inputStreamByteBufferAdapter.hpp
@@ -0,0 +1,63 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_UTILITY_INPUTSTREAMBYTEBUFFERADAPTER_HPP_INCLUDED
+#define VMIME_UTILITY_INPUTSTREAMBYTEBUFFERADAPTER_HPP_INCLUDED
+
+
+#include "vmime/utility/seekableInputStream.hpp"
+
+
+namespace vmime {
+namespace utility {
+
+
+/** An adapter class for reading from an array of bytes.
+ */
+class VMIME_EXPORT inputStreamByteBufferAdapter : public seekableInputStream {
+
+public:
+
+ inputStreamByteBufferAdapter(const byte_t* buffer, size_t length);
+
+ bool eof() const;
+ void reset();
+ size_t read(byte_t* const data, const size_t count);
+ size_t skip(const size_t count);
+ size_t getPosition() const;
+ void seek(const size_t pos);
+
+private:
+
+ const byte_t* m_buffer;
+ const size_t m_length;
+
+ size_t m_pos;
+};
+
+
+} // utility
+} // vmime
+
+
+#endif // VMIME_UTILITY_INPUTSTREAMBYTEBUFFERADAPTER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/utility/inputStreamPointerAdapter.cpp b/vmime-master/src/vmime/utility/inputStreamPointerAdapter.cpp
new file mode 100644
index 0000000..3f468d4
--- /dev/null
+++ b/vmime-master/src/vmime/utility/inputStreamPointerAdapter.cpp
@@ -0,0 +1,48 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/utility/inputStreamPointerAdapter.hpp"
+
+
+namespace vmime {
+namespace utility {
+
+
+inputStreamPointerAdapter::inputStreamPointerAdapter(std::istream* is, const bool own)
+ : inputStreamAdapter(*is),
+ m_stream(is),
+ m_own(own) {
+
+}
+
+
+inputStreamPointerAdapter::~inputStreamPointerAdapter() {
+
+ if (m_own) {
+ delete m_stream;
+ }
+}
+
+
+} // utility
+} // vmime
diff --git a/vmime-master/src/vmime/utility/inputStreamPointerAdapter.hpp b/vmime-master/src/vmime/utility/inputStreamPointerAdapter.hpp
new file mode 100644
index 0000000..e48f9ce
--- /dev/null
+++ b/vmime-master/src/vmime/utility/inputStreamPointerAdapter.hpp
@@ -0,0 +1,61 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_UTILITY_INPUTSTREAMPOINTERADAPTER_HPP_INCLUDED
+#define VMIME_UTILITY_INPUTSTREAMPOINTERADAPTER_HPP_INCLUDED
+
+
+#include "vmime/utility/inputStreamAdapter.hpp"
+
+#include <istream>
+
+
+namespace vmime {
+namespace utility {
+
+
+/** An adapter class for pointer to C++ standard input stream.
+ */
+class VMIME_EXPORT inputStreamPointerAdapter : public inputStreamAdapter {
+
+public:
+
+ /** @param is input stream to wrap
+ * @param own if set to 'true', the pointer will be deleted when
+ * this object is destroyed
+ */
+ inputStreamPointerAdapter(std::istream* is, const bool own = true);
+ ~inputStreamPointerAdapter();
+
+private:
+
+ std::istream* m_stream;
+ const bool m_own;
+};
+
+
+} // utility
+} // vmime
+
+
+#endif // VMIME_UTILITY_INPUTSTREAMPOINTERADAPTER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/utility/inputStreamSocketAdapter.cpp b/vmime-master/src/vmime/utility/inputStreamSocketAdapter.cpp
new file mode 100644
index 0000000..515906b
--- /dev/null
+++ b/vmime-master/src/vmime/utility/inputStreamSocketAdapter.cpp
@@ -0,0 +1,79 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/utility/inputStreamSocketAdapter.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/net/socket.hpp"
+
+
+namespace vmime {
+namespace utility {
+
+
+inputStreamSocketAdapter::inputStreamSocketAdapter(net::socket& sok)
+ : m_socket(sok) {
+
+}
+
+
+bool inputStreamSocketAdapter::eof() const {
+
+ // Can't know...
+ return false;
+}
+
+
+void inputStreamSocketAdapter::reset() {
+
+ // Not supported
+}
+
+
+size_t inputStreamSocketAdapter::read(byte_t* const data, const size_t count) {
+
+ return m_socket.receiveRaw(data, count);
+}
+
+
+size_t inputStreamSocketAdapter::skip(const size_t /* count */) {
+
+ // Not supported
+ return 0;
+}
+
+
+size_t inputStreamSocketAdapter::getBlockSize() {
+
+ return m_socket.getBlockSize();
+}
+
+
+} // utility
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
diff --git a/vmime-master/src/vmime/utility/inputStreamSocketAdapter.hpp b/vmime-master/src/vmime/utility/inputStreamSocketAdapter.hpp
new file mode 100644
index 0000000..1650037
--- /dev/null
+++ b/vmime-master/src/vmime/utility/inputStreamSocketAdapter.hpp
@@ -0,0 +1,75 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_UTILITY_INPUTSTREAMSOCKETADAPTER_HPP_INCLUDED
+#define VMIME_UTILITY_INPUTSTREAMSOCKETADAPTER_HPP_INCLUDED
+
+
+#include "vmime/utility/inputStream.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+namespace vmime {
+namespace net {
+ class socket; // forward reference
+} // net
+} // vmime
+
+
+namespace vmime {
+namespace utility {
+
+
+/** An input stream that is connected to a socket.
+ */
+class VMIME_EXPORT inputStreamSocketAdapter : public inputStream {
+
+public:
+
+ inputStreamSocketAdapter(net::socket& sok);
+
+ bool eof() const;
+ void reset();
+ size_t read(byte_t* const data, const size_t count);
+ size_t skip(const size_t count);
+
+ size_t getBlockSize();
+
+private:
+
+ inputStreamSocketAdapter(const inputStreamSocketAdapter&);
+
+ net::socket& m_socket;
+};
+
+
+} // utility
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+
+#endif // VMIME_UTILITY_INPUTSTREAMSOCKETADAPTER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/utility/inputStreamStringAdapter.cpp b/vmime-master/src/vmime/utility/inputStreamStringAdapter.cpp
new file mode 100644
index 0000000..bf09a9b
--- /dev/null
+++ b/vmime-master/src/vmime/utility/inputStreamStringAdapter.cpp
@@ -0,0 +1,119 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/utility/inputStreamStringAdapter.hpp"
+
+
+namespace vmime {
+namespace utility {
+
+
+inputStreamStringAdapter::inputStreamStringAdapter(const string& buffer)
+ : m_buffer(buffer),
+ m_begin(0),
+ m_end(buffer.length()),
+ m_pos(0) {
+
+}
+
+
+inputStreamStringAdapter::inputStreamStringAdapter(
+ const string& buffer,
+ const size_t begin,
+ const size_t end
+)
+ : m_buffer(buffer),
+ m_begin(begin),
+ m_end(end),
+ m_pos(begin) {
+
+}
+
+
+bool inputStreamStringAdapter::eof() const {
+
+ return m_pos >= m_end;
+}
+
+
+void inputStreamStringAdapter::reset() {
+
+ m_pos = m_begin;
+}
+
+
+size_t inputStreamStringAdapter::read(byte_t* const data, const size_t count) {
+
+ if (m_pos + count >= m_end) {
+
+ const size_t remaining = m_end - m_pos;
+
+ std::copy(m_buffer.begin() + m_pos, m_buffer.end(), data);
+ m_pos = m_end;
+
+ return remaining;
+
+ } else {
+
+ std::copy(m_buffer.begin() + m_pos, m_buffer.begin() + m_pos + count, data);
+ m_pos += count;
+
+ return count;
+ }
+}
+
+
+size_t inputStreamStringAdapter::skip(const size_t count) {
+
+ if (m_pos + count >= m_end) {
+
+ const size_t remaining = m_end - m_pos;
+ m_pos = m_end;
+
+ return remaining;
+
+ } else {
+
+ m_pos += count;
+
+ return count;
+ }
+}
+
+
+size_t inputStreamStringAdapter::getPosition() const {
+
+ return m_pos - m_begin;
+}
+
+
+void inputStreamStringAdapter::seek(const size_t pos) {
+
+ if (m_begin + pos <= m_end) {
+ m_pos = m_begin + pos;
+ }
+}
+
+
+} // utility
+} // vmime
diff --git a/vmime-master/src/vmime/utility/inputStreamStringAdapter.hpp b/vmime-master/src/vmime/utility/inputStreamStringAdapter.hpp
new file mode 100644
index 0000000..2c2cbb8
--- /dev/null
+++ b/vmime-master/src/vmime/utility/inputStreamStringAdapter.hpp
@@ -0,0 +1,66 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_UTILITY_INPUTSTREAMSTRINGADAPTER_HPP_INCLUDED
+#define VMIME_UTILITY_INPUTSTREAMSTRINGADAPTER_HPP_INCLUDED
+
+
+#include "vmime/utility/seekableInputStream.hpp"
+
+
+namespace vmime {
+namespace utility {
+
+
+/** An adapter class for string input.
+ */
+class VMIME_EXPORT inputStreamStringAdapter : public seekableInputStream {
+
+public:
+
+ inputStreamStringAdapter(const string& buffer);
+ inputStreamStringAdapter(const string& buffer, const size_t begin, const size_t end);
+
+ bool eof() const;
+ void reset();
+ size_t read(byte_t* const data, const size_t count);
+ size_t skip(const size_t count);
+ size_t getPosition() const;
+ void seek(const size_t pos);
+
+private:
+
+ inputStreamStringAdapter(const inputStreamStringAdapter&);
+
+ const string m_buffer; // do _NOT_ keep a reference...
+ const size_t m_begin;
+ const size_t m_end;
+ size_t m_pos;
+};
+
+
+} // utility
+} // vmime
+
+
+#endif // VMIME_UTILITY_INPUTSTREAMSTRINGADAPTER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/utility/outputStream.cpp b/vmime-master/src/vmime/utility/outputStream.cpp
new file mode 100644
index 0000000..b07fb07
--- /dev/null
+++ b/vmime-master/src/vmime/utility/outputStream.cpp
@@ -0,0 +1,44 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/utility/outputStream.hpp"
+
+
+namespace vmime {
+namespace utility {
+
+
+void outputStream::write(const byte_t* const data, const size_t count) {
+
+ writeImpl(data, count);
+}
+
+
+void outputStream::write(const char* const data, const size_t count) {
+
+ writeImpl(reinterpret_cast <const byte_t*>(data), count);
+}
+
+
+} // utility
+} // vmime
diff --git a/vmime-master/src/vmime/utility/outputStream.hpp b/vmime-master/src/vmime/utility/outputStream.hpp
new file mode 100644
index 0000000..318c1dd
--- /dev/null
+++ b/vmime-master/src/vmime/utility/outputStream.hpp
@@ -0,0 +1,133 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_UTILITY_OUTPUTSTREAM_HPP_INCLUDED
+#define VMIME_UTILITY_OUTPUTSTREAM_HPP_INCLUDED
+
+
+#include "vmime/utility/stream.hpp"
+
+
+#if defined(_MSC_VER) && (_MSC_VER <= 1200) // VC++6
+# include <cstring>
+#endif
+
+
+namespace vmime {
+namespace utility {
+
+
+/** Simple output stream.
+ */
+class VMIME_EXPORT outputStream : public stream {
+
+public:
+
+ /** Write data to the stream.
+ *
+ * @param data buffer containing data to write
+ * @param count number of bytes to write
+ */
+ void write(const byte_t* const data, const size_t count);
+
+ /** Write data to the stream.
+ *
+ * @param data buffer containing data to write
+ * @param count number of bytes to write
+ */
+ void write(const char* const data, const size_t count);
+
+ /** Write data to the stream.
+ *
+ * @param data buffer containing data to write
+ * @param N number of bytes to write, including terminating
+ * null (value is induced by compiler)
+ */
+ template <int N>
+ void write(const char (&data)[N]) {
+
+ write(data, N - 1);
+ }
+
+ /** Flush this output stream and forces any buffered output
+ * bytes to be written out to the stream.
+ */
+ virtual void flush() = 0;
+
+protected:
+
+ /** Write data to the stream.
+ * This is the method to be implemented is subclasses.
+ *
+ * @param data buffer containing data to write
+ * @param count number of bytes to write
+ */
+ virtual void writeImpl(const byte_t* const data, const size_t count) = 0;
+};
+
+
+// Helpers functions
+
+VMIME_EXPORT outputStream& operator<<(outputStream& os, const string& str);
+VMIME_EXPORT outputStream& operator<<(outputStream& os, const byte_t c);
+
+
+#if defined(_MSC_VER) && (_MSC_VER <= 1200) // Internal compiler error with VC++6
+
+inline outputStream& operator<<(outputStream& os, const char* str) {
+
+ os.write(reinterpret_cast <const byte_t*>(str), ::strlen(str));
+ return os;
+}
+
+#else
+
+template <int N>
+outputStream& operator<<(outputStream& os, const char (&str)[N]) {
+
+ os.write(reinterpret_cast <const byte_t*>(str), N - 1);
+ return os;
+}
+
+#endif // defined(_MSC_VER) && (_MSC_VER <= 1200)
+
+
+template <typename T>
+outputStream& operator<<(outputStream& os, const T& t) {
+
+ std::ostringstream oss;
+ oss.imbue(std::locale::classic()); // no formatting
+
+ oss << t;
+
+ os << oss.str();
+
+ return os;
+}
+
+
+} // utility
+} // vmime
+
+
+#endif // VMIME_UTILITY_OUTPUTSTREAM_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/utility/outputStreamAdapter.cpp b/vmime-master/src/vmime/utility/outputStreamAdapter.cpp
new file mode 100644
index 0000000..7455691
--- /dev/null
+++ b/vmime-master/src/vmime/utility/outputStreamAdapter.cpp
@@ -0,0 +1,52 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/utility/outputStreamAdapter.hpp"
+
+
+namespace vmime {
+namespace utility {
+
+
+outputStreamAdapter::outputStreamAdapter(std::ostream& os)
+ : m_stream(os) {
+
+}
+
+
+void outputStreamAdapter::writeImpl(const byte_t* const data, const size_t count) {
+
+ m_stream.exceptions(std::ios_base::badbit);
+ m_stream.write(reinterpret_cast <const char*>(data), count);
+}
+
+
+void outputStreamAdapter::flush() {
+
+ m_stream.exceptions(std::ios_base::badbit);
+ m_stream.flush();
+}
+
+
+} // utility
+} // vmime
diff --git a/vmime-master/src/vmime/utility/outputStreamAdapter.hpp b/vmime-master/src/vmime/utility/outputStreamAdapter.hpp
new file mode 100644
index 0000000..35c5cde
--- /dev/null
+++ b/vmime-master/src/vmime/utility/outputStreamAdapter.hpp
@@ -0,0 +1,63 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_UTILITY_OUTPUTSTREAMADAPTER_HPP_INCLUDED
+#define VMIME_UTILITY_OUTPUTSTREAMADAPTER_HPP_INCLUDED
+
+
+#include "vmime/utility/outputStream.hpp"
+
+#include <ostream>
+
+
+namespace vmime {
+namespace utility {
+
+
+/** An adapter class for C++ standard output streams.
+ */
+class VMIME_EXPORT outputStreamAdapter : public outputStream {
+
+public:
+
+ /** @param os output stream to wrap
+ */
+ outputStreamAdapter(std::ostream& os);
+
+ void flush();
+
+protected:
+
+ void writeImpl(const byte_t* const data, const size_t count);
+
+private:
+
+ std::ostream& m_stream;
+};
+
+
+} // utility
+} // vmime
+
+
+#endif // VMIME_UTILITY_OUTPUTSTREAMADAPTER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/utility/outputStreamByteArrayAdapter.cpp b/vmime-master/src/vmime/utility/outputStreamByteArrayAdapter.cpp
new file mode 100644
index 0000000..a38bd79
--- /dev/null
+++ b/vmime-master/src/vmime/utility/outputStreamByteArrayAdapter.cpp
@@ -0,0 +1,50 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/utility/outputStreamByteArrayAdapter.hpp"
+
+
+namespace vmime {
+namespace utility {
+
+
+outputStreamByteArrayAdapter::outputStreamByteArrayAdapter(byteArray& array)
+ : m_array(array) {
+
+}
+
+
+void outputStreamByteArrayAdapter::writeImpl(const byte_t* const data, const size_t count) {
+
+ m_array.insert(m_array.end(), data, data + count);
+}
+
+
+void outputStreamByteArrayAdapter::flush() {
+
+ // Do nothing
+}
+
+
+} // utility
+} // vmime
diff --git a/vmime-master/src/vmime/utility/outputStreamByteArrayAdapter.hpp b/vmime-master/src/vmime/utility/outputStreamByteArrayAdapter.hpp
new file mode 100644
index 0000000..f36ff9c
--- /dev/null
+++ b/vmime-master/src/vmime/utility/outputStreamByteArrayAdapter.hpp
@@ -0,0 +1,59 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_UTILITY_OUTPUTSTREAMBYTEARRAYADAPTER_HPP_INCLUDED
+#define VMIME_UTILITY_OUTPUTSTREAMBYTEARRAYADAPTER_HPP_INCLUDED
+
+
+#include "vmime/utility/outputStream.hpp"
+
+
+namespace vmime {
+namespace utility {
+
+
+/** An adapter class for byte array output.
+ */
+class VMIME_EXPORT outputStreamByteArrayAdapter : public outputStream {
+
+public:
+
+ outputStreamByteArrayAdapter(byteArray& array);
+
+ void flush();
+
+protected:
+
+ void writeImpl(const byte_t* const data, const size_t count);
+
+private:
+
+ byteArray& m_array;
+};
+
+
+} // utility
+} // vmime
+
+
+#endif // VMIME_UTILITY_OUTPUTSTREAMBYTEARRAYADAPTER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/utility/outputStreamSocketAdapter.cpp b/vmime-master/src/vmime/utility/outputStreamSocketAdapter.cpp
new file mode 100644
index 0000000..cd82c44
--- /dev/null
+++ b/vmime-master/src/vmime/utility/outputStreamSocketAdapter.cpp
@@ -0,0 +1,65 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/utility/outputStreamSocketAdapter.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+#include "vmime/net/socket.hpp"
+
+
+namespace vmime {
+namespace utility {
+
+
+outputStreamSocketAdapter::outputStreamSocketAdapter(net::socket& sok)
+ : m_socket(sok) {
+
+}
+
+
+void outputStreamSocketAdapter::writeImpl(const byte_t* const data, const size_t count) {
+
+ m_socket.sendRaw(data, count);
+}
+
+
+void outputStreamSocketAdapter::flush() {
+
+ // Do nothing
+}
+
+
+size_t outputStreamSocketAdapter::getBlockSize() {
+
+ return m_socket.getBlockSize();
+}
+
+
+} // utility
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
diff --git a/vmime-master/src/vmime/utility/outputStreamSocketAdapter.hpp b/vmime-master/src/vmime/utility/outputStreamSocketAdapter.hpp
new file mode 100644
index 0000000..4fb199b
--- /dev/null
+++ b/vmime-master/src/vmime/utility/outputStreamSocketAdapter.hpp
@@ -0,0 +1,76 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_UTILITY_OUTPUTSTREAMSOCKETADAPTER_HPP_INCLUDED
+#define VMIME_UTILITY_OUTPUTSTREAMSOCKETADAPTER_HPP_INCLUDED
+
+
+#include "vmime/utility/outputStream.hpp"
+
+
+#if VMIME_HAVE_MESSAGING_FEATURES
+
+
+namespace vmime {
+namespace net {
+ class socket; // forward reference
+} // net
+} // vmime
+
+
+namespace vmime {
+namespace utility {
+
+
+/** An output stream that is connected to a socket.
+ */
+class VMIME_EXPORT outputStreamSocketAdapter : public outputStream {
+
+public:
+
+ outputStreamSocketAdapter(net::socket& sok);
+
+ void flush();
+
+ size_t getBlockSize();
+
+protected:
+
+ void writeImpl(const byte_t* const data, const size_t count);
+
+private:
+
+ outputStreamSocketAdapter(const outputStreamSocketAdapter&);
+
+ net::socket& m_socket;
+};
+
+
+} // utility
+} // vmime
+
+
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+
+#endif // VMIME_UTILITY_OUTPUTSTREAMSOCKETADAPTER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/utility/outputStreamStringAdapter.cpp b/vmime-master/src/vmime/utility/outputStreamStringAdapter.cpp
new file mode 100644
index 0000000..12c809c
--- /dev/null
+++ b/vmime-master/src/vmime/utility/outputStreamStringAdapter.cpp
@@ -0,0 +1,52 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/utility/outputStreamStringAdapter.hpp"
+
+#include "vmime/utility/stringUtils.hpp"
+
+
+namespace vmime {
+namespace utility {
+
+
+outputStreamStringAdapter::outputStreamStringAdapter(string& buffer)
+ : m_buffer(buffer) {
+
+}
+
+
+void outputStreamStringAdapter::writeImpl(const byte_t* const data, const size_t count) {
+
+ vmime::utility::stringUtils::appendBytesToString(m_buffer, data, count);
+}
+
+
+void outputStreamStringAdapter::flush() {
+
+ // Do nothing
+}
+
+
+} // utility
+} // vmime
diff --git a/vmime-master/src/vmime/utility/outputStreamStringAdapter.hpp b/vmime-master/src/vmime/utility/outputStreamStringAdapter.hpp
new file mode 100644
index 0000000..a29e2cb
--- /dev/null
+++ b/vmime-master/src/vmime/utility/outputStreamStringAdapter.hpp
@@ -0,0 +1,59 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_UTILITY_OUTPUTSTREAMSTRINGADAPTER_HPP_INCLUDED
+#define VMIME_UTILITY_OUTPUTSTREAMSTRINGADAPTER_HPP_INCLUDED
+
+
+#include "vmime/utility/outputStream.hpp"
+
+
+namespace vmime {
+namespace utility {
+
+
+/** An adapter class for string output.
+ */
+class VMIME_EXPORT outputStreamStringAdapter : public outputStream {
+
+public:
+
+ outputStreamStringAdapter(string& buffer);
+
+ void flush();
+
+protected:
+
+ void writeImpl(const byte_t* const data, const size_t count);
+
+private:
+
+ string& m_buffer;
+};
+
+
+} // utility
+} // vmime
+
+
+#endif // VMIME_UTILITY_OUTPUTSTREAMSTRINGADAPTER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/utility/parserInputStreamAdapter.cpp b/vmime-master/src/vmime/utility/parserInputStreamAdapter.cpp
new file mode 100644
index 0000000..98bbe60
--- /dev/null
+++ b/vmime-master/src/vmime/utility/parserInputStreamAdapter.cpp
@@ -0,0 +1,175 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/utility/parserInputStreamAdapter.hpp"
+
+
+namespace vmime {
+namespace utility {
+
+
+parserInputStreamAdapter::parserInputStreamAdapter(const shared_ptr <seekableInputStream>& stream)
+ : m_stream(stream) {
+
+}
+
+
+bool parserInputStreamAdapter::eof() const {
+
+ return m_stream->eof();
+}
+
+
+void parserInputStreamAdapter::reset() {
+
+ m_stream->reset();
+}
+
+
+size_t parserInputStreamAdapter::read(byte_t* const data, const size_t count) {
+
+ return m_stream->read(data, count);
+}
+
+
+shared_ptr <seekableInputStream> parserInputStreamAdapter::getUnderlyingStream() {
+
+ return m_stream;
+}
+
+
+const string parserInputStreamAdapter::extract(const size_t begin, const size_t end) const {
+
+ const size_t initialPos = m_stream->getPosition();
+
+ byte_t *buffer = NULL;
+
+ try {
+
+ buffer = new byte_t[end - begin + 1];
+
+ m_stream->seek(begin);
+
+ const size_t readBytes = m_stream->read(buffer, end - begin);
+ buffer[readBytes] = '\0';
+
+ m_stream->seek(initialPos);
+
+ string str(buffer, buffer + readBytes);
+ delete [] buffer;
+
+ return str;
+
+ } catch (...) {
+
+ delete [] buffer;
+
+ m_stream->seek(initialPos);
+ throw;
+ }
+}
+
+
+size_t parserInputStreamAdapter::findNext(
+ const string& token,
+ const size_t startPosition
+) {
+
+ static const unsigned int BUFFER_SIZE = 4096;
+
+ // Token must not be longer than BUFFER_SIZE/2
+ if (token.empty() || token.length() > BUFFER_SIZE / 2) {
+ return npos;
+ }
+
+ const size_t initialPos = getPosition();
+
+ seek(startPosition);
+
+ try {
+
+ byte_t findBuffer[BUFFER_SIZE];
+ byte_t* findBuffer1 = findBuffer;
+ byte_t* findBuffer2 = findBuffer + (BUFFER_SIZE / 2);
+
+ size_t findBufferLen = 0;
+ size_t findBufferOffset = 0;
+
+ bool isEOF = false;
+
+ // Fill in initial buffer
+ findBufferLen = read(findBuffer, BUFFER_SIZE);
+
+ while (findBufferLen != 0) {
+
+ // Find token
+ for (byte_t *begin = findBuffer, *end = findBuffer + findBufferLen - token.length() ;
+ begin <= end ; ++begin) {
+
+ if (begin[0] == token[0] &&
+ (token.length() == 1 ||
+ memcmp(static_cast <const void *>(&begin[1]),
+ static_cast <const void *>(token.data() + 1),
+ token.length() - 1) == 0)) {
+
+ seek(initialPos);
+
+ return startPosition + findBufferOffset + (begin - findBuffer);
+ }
+ }
+
+ // Rotate buffer
+ memcpy(findBuffer1, findBuffer2, (BUFFER_SIZE / 2));
+
+ // Read more bytes
+ if (findBufferLen < BUFFER_SIZE && (eof() || isEOF)) {
+
+ break;
+
+ } else {
+
+ const size_t bytesRead = read(findBuffer2, BUFFER_SIZE / 2);
+
+ if (bytesRead == 0) {
+ isEOF = true;
+ }
+
+ findBufferLen = (BUFFER_SIZE / 2) + bytesRead;
+ findBufferOffset += (BUFFER_SIZE / 2);
+ }
+ }
+
+ seek(initialPos);
+
+ } catch (...) {
+
+ seek(initialPos);
+ throw;
+ }
+
+ return npos;
+}
+
+
+} // utility
+} // vmime
diff --git a/vmime-master/src/vmime/utility/parserInputStreamAdapter.hpp b/vmime-master/src/vmime/utility/parserInputStreamAdapter.hpp
new file mode 100644
index 0000000..e448d29
--- /dev/null
+++ b/vmime-master/src/vmime/utility/parserInputStreamAdapter.hpp
@@ -0,0 +1,172 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_UTILITY_PARSERINPUTSTREAMADAPTER_HPP_INCLUDED
+#define VMIME_UTILITY_PARSERINPUTSTREAMADAPTER_HPP_INCLUDED
+
+
+#include "vmime/utility/seekableInputStream.hpp"
+
+#include <cstring>
+
+
+namespace vmime {
+namespace utility {
+
+
+/** An adapter class used for parsing from an input stream.
+ */
+class VMIME_EXPORT parserInputStreamAdapter : public seekableInputStream {
+
+public:
+
+ /** @param stream input stream to wrap
+ */
+ parserInputStreamAdapter(const shared_ptr <seekableInputStream>& stream);
+
+ shared_ptr <seekableInputStream> getUnderlyingStream();
+
+ bool eof() const;
+ void reset();
+ size_t read(byte_t* const data, const size_t count);
+
+ void seek(const size_t pos) {
+
+ m_stream->seek(pos);
+ }
+
+ size_t skip(const size_t count) {
+
+ return m_stream->skip(count);
+ }
+
+ size_t getPosition() const {
+
+ return m_stream->getPosition();
+ }
+
+ /** Get the byte at the current position without updating the
+ * current position.
+ *
+ * @return byte at the current position
+ */
+ byte_t peekByte() const {
+
+ const size_t initialPos = m_stream->getPosition();
+
+ try {
+
+ byte_t buffer[1];
+ const size_t readBytes = m_stream->read(buffer, 1);
+
+ m_stream->seek(initialPos);
+
+ return (readBytes == 1 ? buffer[0] : static_cast <byte_t>(0));
+
+ } catch (...) {
+
+ m_stream->seek(initialPos);
+ throw;
+ }
+ }
+
+ /** Get the byte at the current position and advance current
+ * position by one byte.
+ *
+ * @return byte at the current position
+ */
+ byte_t getByte() {
+
+ byte_t buffer[1];
+ const size_t readBytes = m_stream->read(buffer, 1);
+
+ return readBytes == 1 ? buffer[0] : static_cast <byte_t>(0);
+ }
+
+ /** Check whether the bytes following the current position match
+ * the specified bytes. Position is not updated.
+ *
+ * @param bytes bytes to compare
+ * @param length number of bytes
+ * @return true if the next bytes match the pattern, false otherwise
+ */
+ template <typename T>
+ bool matchBytes(const T* bytes, const size_t length) const {
+
+ const size_t initialPos = m_stream->getPosition();
+
+ try {
+
+ byte_t buffer[32];
+ const size_t readBytes = m_stream->read(buffer, length);
+
+ m_stream->seek(initialPos);
+
+ return readBytes == length && ::memcmp(bytes, buffer, length) == 0;
+
+ } catch (...) {
+
+ m_stream->seek(initialPos);
+ throw;
+ }
+ }
+
+ const string extract(const size_t begin, const size_t end) const;
+
+ /** Skips bytes matching a predicate from the current position.
+ * The current position is updated to the next following byte
+ * which does not match the predicate.
+ *
+ * @param pred predicate
+ * @param endPosition stop at this position (or at end of the stream,
+ * whichever comes first)
+ * @return number of bytes skipped
+ */
+ template <typename PREDICATE>
+ size_t skipIf(PREDICATE pred, const size_t endPosition) {
+
+ const size_t initialPos = getPosition();
+ size_t pos = initialPos;
+
+ while (!m_stream->eof() && pos < endPosition && pred(getByte())) {
+ ++pos;
+ }
+
+ m_stream->seek(pos);
+
+ return pos - initialPos;
+ }
+
+ size_t findNext(const string& token, const size_t startPosition = 0);
+
+private:
+
+ mutable shared_ptr <seekableInputStream> m_stream;
+};
+
+
+} // utility
+} // vmime
+
+
+#endif // VMIME_UTILITY_PARSERINPUTSTREAMADAPTER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/utility/path.cpp b/vmime-master/src/vmime/utility/path.cpp
new file mode 100644
index 0000000..0c70f11
--- /dev/null
+++ b/vmime-master/src/vmime/utility/path.cpp
@@ -0,0 +1,324 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/utility/path.hpp"
+
+#include <algorithm>
+
+
+namespace vmime {
+namespace utility {
+
+
+path::path() {
+
+}
+
+
+path::path(const component& c) {
+
+ m_list.push_back(c);
+}
+
+
+path::path(const path& p)
+ : object() {
+
+ m_list.resize(p.m_list.size());
+ std::copy(p.m_list.begin(), p.m_list.end(), m_list.begin());
+}
+
+
+path::path(const string& s) {
+
+ m_list.push_back(component(s));
+}
+
+
+path path::operator/(const path& p) const {
+
+ path pr(*this);
+ pr /= p;
+
+ return pr;
+}
+
+
+path path::operator/(const component& c) const {
+
+ path pr(*this);
+ pr /= c;
+
+ return pr;
+}
+
+
+path& path::operator/=(const path& p) {
+
+ const list::size_type size = m_list.size();
+
+ m_list.resize(size + p.m_list.size());
+ std::copy(p.m_list.begin(), p.m_list.end(), m_list.begin() + size);
+
+ return *this;
+}
+
+
+path& path::operator/=(const component& c) {
+
+ m_list.push_back(c);
+ return *this;
+}
+
+
+path path::getParent() const {
+
+ path p;
+
+ if (!isEmpty()) {
+ p.m_list.resize(m_list.size() - 1);
+ std::copy(m_list.begin(), m_list.end() - 1, p.m_list.begin());
+ }
+
+ return p;
+}
+
+
+path& path::operator=(const path& p) {
+
+ m_list.resize(p.m_list.size());
+ std::copy(p.m_list.begin(), p.m_list.end(), m_list.begin());
+
+ return *this;
+}
+
+
+path& path::operator=(const component& c) {
+
+ m_list.resize(1);
+ m_list[0] = c;
+
+ return *this;
+}
+
+
+bool path::operator==(const path& p) const {
+
+ if (m_list.size() != p.m_list.size()) {
+ return (false);
+ }
+
+ list::const_iterator i = m_list.begin();
+ list::const_iterator j = p.m_list.begin();
+
+ bool equal = true;
+
+ for ( ; equal && i != m_list.end() ; ++i, ++j) {
+ equal = ((*i).isEquivalent(*j));
+ }
+
+ return equal;
+}
+
+
+bool path::operator!=(const path& p) const {
+
+ return !(*this == p);
+}
+
+
+bool path::isEmpty() const {
+
+ return m_list.empty();
+}
+
+
+bool path::isRoot() const {
+
+ return m_list.empty();
+}
+
+
+const path::component path::getLastComponent() const {
+
+ return m_list[m_list.size() - 1];
+}
+
+
+path::component& path::getLastComponent() {
+
+ return m_list[m_list.size() - 1];
+}
+
+
+size_t path::getSize() const {
+
+ return m_list.size();
+}
+
+
+const path::component& path::operator[](const size_t x) const {
+
+ return m_list[x];
+}
+
+
+path::component& path::operator[](const size_t x) {
+
+ return m_list[x];
+}
+
+
+bool path::isDirectParentOf(const path& p) const {
+
+ if (p.getSize() != getSize() + 1) {
+ return false;
+ }
+
+ bool equal = true;
+
+ for (list::size_type i = 0 ; equal && i < m_list.size() ; ++i) {
+ equal = (m_list[i].isEquivalent(p.m_list[i]));
+ }
+
+ return equal;
+}
+
+
+bool path::isParentOf(const path& p) const {
+
+ if (p.getSize() < getSize() + 1) {
+ return false;
+ }
+
+ bool equal = true;
+
+ for (list::size_type i = 0 ; equal && i < m_list.size() ; ++i) {
+ equal = (m_list[i].isEquivalent(p.m_list[i]));
+ }
+
+ return equal;
+}
+
+
+void path::renameParent(const path& oldPath, const path& newPath) {
+
+ if (isEmpty() || oldPath.getSize() > getSize()) {
+ return;
+ }
+
+ bool equal = true;
+ list::size_type i;
+
+ for (i = 0 ; equal && i < oldPath.m_list.size() ; ++i) {
+ equal = (m_list[i].isEquivalent(oldPath.m_list[i]));
+ }
+
+ if (i != oldPath.m_list.size())
+ return;
+
+ list newList;
+
+ for (list::size_type j = 0 ; j < newPath.m_list.size() ; ++j) {
+ newList.push_back(newPath.m_list[j]);
+ }
+
+ for (list::size_type j = i ; j < m_list.size() ; ++j) {
+ newList.push_back(m_list[j]);
+ }
+
+ m_list.resize(newList.size());
+ std::copy(newList.begin(), newList.end(), m_list.begin());
+}
+
+
+void path::appendComponent(const path::component& c) {
+
+ m_list.push_back(c);
+}
+
+
+const path::component& path::getComponentAt(const size_t pos) const {
+
+ return m_list[pos];
+}
+
+
+path::component& path::getComponentAt(const size_t pos) {
+
+ return m_list[pos];
+}
+
+
+// static
+path path::fromString(const string& str, const string& sep, const charset& cset) {
+
+ path p;
+
+ size_t start = 0;
+ size_t end = 0;
+
+ do {
+
+ end = str.find(sep, start);
+
+ string comp;
+
+ if (end == string::npos) {
+ comp = str.substr(start);
+ } else {
+ comp = str.substr(start, end - start);
+ }
+
+ // Skip leading or trailing separators
+ if (comp.length()) {
+ p.appendComponent(component(comp, cset));
+ }
+
+ start = end + 1;
+
+ } while (end != string::npos);
+
+ return p;
+}
+
+
+const string path::toString(const string& sep, const charset& cset) const {
+
+ string str;
+
+ for (size_t i = 0 ; i < m_list.size() ; ++i) {
+
+ if (i != 0) {
+ str += sep;
+ }
+
+ str += m_list[i].getConvertedText(cset);
+ }
+
+ return str;
+}
+
+
+} // utility
+} // vmime
diff --git a/vmime-master/src/vmime/utility/path.hpp b/vmime-master/src/vmime/utility/path.hpp
new file mode 100644
index 0000000..f1f1514
--- /dev/null
+++ b/vmime-master/src/vmime/utility/path.hpp
@@ -0,0 +1,189 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_UTILITY_PATH_HPP_INCLUDED
+#define VMIME_UTILITY_PATH_HPP_INCLUDED
+
+
+#include <vector>
+
+#include "vmime/types.hpp"
+#include "vmime/word.hpp"
+
+
+namespace vmime {
+namespace utility {
+
+
+/** Abstract representation of a path (filesystem, mailbox, etc).
+ */
+class VMIME_EXPORT path : public object {
+
+public:
+
+ typedef vmime::word component;
+ typedef std::vector <component> list;
+
+ // Construct a path
+ path();
+ path(const component& c);
+ path(const path& p);
+ explicit path(const string& s);
+
+ // Append a component to a path
+ path operator/(const path& p) const;
+ path operator/(const component& c) const;
+
+ path& operator/=(const path& p);
+ path& operator/=(const component& c);
+
+ // Return the parent path
+ path getParent() const;
+
+ // Assignment
+ path& operator=(const path& p);
+ path& operator=(const component& c);
+
+ // Path comparison
+ bool operator==(const path& p) const;
+ bool operator!=(const path& p) const;
+
+ /** Append a component to the path.
+ *
+ * @param c component to add
+ */
+ void appendComponent(const component& c);
+
+ /** Return the component at the specified position.
+ *
+ * @param pos position
+ * @return component at position 'pos'
+ */
+ const component& getComponentAt(const size_t pos) const;
+
+ /** Return the component at the specified position.
+ *
+ * @param pos position
+ * @return component at position 'pos'
+ */
+ component& getComponentAt(const size_t pos);
+
+ /** Test whether this path is empty (root).
+ *
+ * @return true if the path is empty (no components = root)
+ */
+ bool isEmpty() const;
+
+ /** Test whether this path is the root (alias for isEmpty()).
+ *
+ * @return true if the path is the root
+ */
+ bool isRoot() const;
+
+ /** Return the last component of this path (const version).
+ *
+ * @return last component
+ */
+ const component getLastComponent() const;
+
+ /** Return the last component of this path (non-const version).
+ *
+ * @return last component
+ */
+ component& getLastComponent();
+
+ /** Return the number of components in this path.
+ *
+ * @return number of components
+ */
+ size_t getSize() const;
+
+ /** Return the specified component of the path (const version).
+ *
+ * @param x index of the component
+ * @return component at the specified index
+ */
+ const component& operator[](const size_t x) const;
+
+ /** Return the specified component of the path (non-const version).
+ *
+ * @param x index of the component
+ * @return component at the specified index
+ */
+ component& operator[](const size_t x);
+
+ /** Test whether this path is a direct parent of another one.
+ *
+ * @param p other path
+ * @return true if the specified path is a child
+ * of this path, false otherwise
+ */
+ bool isDirectParentOf(const path& p) const;
+
+ /** Test whether this path is a parent of another one.
+ *
+ * @param p other path
+ * @return true if the specified path is a child (direct or
+ * indirect) of this path, false otherwise
+ */
+ bool isParentOf(const path& p) const;
+
+ /** Rename a parent component in the path.
+ * Example: path("a/b/c/d").renameParent("a/b", "x/y/z")
+ * will return path("x/y/z/c/d").
+ *
+ * @param oldPath old parent path
+ * @param newPath new parent path
+ */
+ void renameParent(const path& oldPath, const path& newPath);
+
+ /** Construct a new path from a string.
+ *
+ * @param str string representation of the path
+ * @param sep separator string (eg: "/")
+ * @param cset charset in which the path is encoded (use the value returned by
+ * vmime::charset::getLocalCharset() to use the default charset of your system)
+ * @return a new path corresponding to the specified string
+ */
+ static path fromString(const string& str, const string& sep, const charset& cset);
+
+ /** Returns a string representation of this path.
+ *
+ * @param sep separator string (eg: "/")
+ * @param cset charset in which to encode the components (use the value returned by
+ * vmime::charset::getLocalCharset() to use the default charset of your system)
+ * @return a string representing this path
+ */
+ const string toString(const string& sep, const charset& cset) const;
+
+private:
+
+ list m_list;
+};
+
+
+} // utility
+} // vmime
+
+
+#endif // VMIME_UTILITY_PATH_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/utility/progressListener.cpp b/vmime-master/src/vmime/utility/progressListener.cpp
new file mode 100644
index 0000000..cc4969c
--- /dev/null
+++ b/vmime-master/src/vmime/utility/progressListener.cpp
@@ -0,0 +1,78 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/utility/progressListener.hpp"
+
+
+namespace vmime {
+namespace utility {
+
+
+// progressListenerSizeAdapter
+
+progressListenerSizeAdapter::progressListenerSizeAdapter(
+ progressListener* list,
+ const size_t total
+)
+ : m_wrapped(list),
+ m_total(total) {
+
+}
+
+
+void progressListenerSizeAdapter::start(const size_t predictedTotal) {
+
+ if (m_wrapped) {
+ m_wrapped->start(predictedTotal);
+ }
+}
+
+
+void progressListenerSizeAdapter::progress(const size_t current, const size_t currentTotal) {
+
+ if (m_wrapped) {
+
+ if (currentTotal > m_total) {
+ m_total = currentTotal;
+ }
+
+ m_wrapped->progress(current, m_total);
+ }
+}
+
+
+void progressListenerSizeAdapter::stop(const size_t total) {
+
+ if (m_wrapped) {
+
+ if (total > m_total) {
+ m_total = total;
+ }
+
+ m_wrapped->stop(m_total);
+ }
+}
+
+
+} // utility
+} // vmime
diff --git a/vmime-master/src/vmime/utility/progressListener.hpp b/vmime-master/src/vmime/utility/progressListener.hpp
new file mode 100644
index 0000000..18b4e4d
--- /dev/null
+++ b/vmime-master/src/vmime/utility/progressListener.hpp
@@ -0,0 +1,99 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_UTILITY_PROGRESSLISTENER_HPP_INCLUDED
+#define VMIME_UTILITY_PROGRESSLISTENER_HPP_INCLUDED
+
+
+#include "vmime/config.hpp"
+#include "vmime/types.hpp"
+
+
+namespace vmime {
+namespace utility {
+
+
+/** An interface to implement if you want to be notified
+ * of a state of progress by some objects.
+ */
+class VMIME_EXPORT progressListener {
+
+protected:
+
+ virtual ~progressListener() { }
+
+public:
+
+ /** Called at the beginning of the operation.
+ *
+ * @param predictedTotal predicted amount of units (this has
+ * no concrete meaning: these are not bytes, nor percentage...)
+ */
+ virtual void start(const size_t predictedTotal) = 0;
+
+ /** Called during the operation (can be called several times).
+ *
+ * @param current current position
+ * @param currentTotal adjusted total amount of units
+ */
+ virtual void progress(const size_t current, const size_t currentTotal) = 0;
+
+ /** Called at the end of the operation.
+ *
+ * @param total final total amount of units
+ */
+ virtual void stop(const size_t total) = 0;
+};
+
+
+
+/** A progress listener used when total size is known by the
+ * receiver, but not by the notifier.
+ */
+class VMIME_EXPORT progressListenerSizeAdapter : public progressListener {
+
+public:
+
+ /** Construct a new progressListenerSizeAdapter object.
+ *
+ * @param list wrapped progress listener (can be NULL)
+ * @param total predicted total
+ */
+ progressListenerSizeAdapter(progressListener* list, const size_t total);
+
+ void start(const size_t predictedTotal);
+ void progress(const size_t current, const size_t currentTotal);
+ void stop(const size_t total);
+
+private:
+
+ progressListener* m_wrapped;
+ size_t m_total;
+};
+
+
+} // utility
+} // vmime
+
+
+#endif // VMIME_UTILITY_PROGRESSLISTENER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/utility/random.cpp b/vmime-master/src/vmime/utility/random.cpp
new file mode 100644
index 0000000..055122b
--- /dev/null
+++ b/vmime-master/src/vmime/utility/random.cpp
@@ -0,0 +1,90 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/utility/random.hpp"
+#include "vmime/platform.hpp"
+
+#include <ctime>
+
+
+namespace vmime {
+namespace utility {
+
+
+static unsigned int getRandomSeed() {
+
+ unsigned int seed;
+
+ platform::getHandler()->generateRandomBytes(
+ reinterpret_cast <unsigned char*>(&seed), sizeof(seed)
+ );
+
+ return seed;
+}
+
+
+unsigned int random::getNext() {
+
+ static unsigned int next = getRandomSeed();
+
+ // Park and Miller's minimal standard generator:
+ // xn+1 = (a * xn + b) mod c
+ // xn+1 = (16807 * xn) mod (2^31 - 1)
+ next = static_cast<unsigned int>((16807 * next) % 2147483647ul);
+ return next;
+}
+
+
+unsigned int random::getTime() {
+
+ return static_cast <unsigned int>((platform::getHandler()->getUnixTime()));
+}
+
+
+unsigned int random::getProcess() {
+
+ return platform::getHandler()->getProcessId();
+}
+
+
+const string random::getString(const size_t length, const string& randomChars) {
+
+ string res;
+ res.resize(length);
+
+ const unsigned int x = static_cast <unsigned int>(randomChars.length());
+ size_t c = 0;
+
+ while (c < length) {
+
+ for (unsigned int n = random::getNext() ; n != 0 && c < length ; n /= x) {
+ res[c++] = randomChars[n % x];
+ }
+ }
+
+ return res;
+}
+
+
+} // utility
+} // vmime
diff --git a/vmime-master/src/vmime/utility/random.hpp b/vmime-master/src/vmime/utility/random.hpp
new file mode 100644
index 0000000..21f4949
--- /dev/null
+++ b/vmime-master/src/vmime/utility/random.hpp
@@ -0,0 +1,78 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_UTILITY_RANDOM_HPP_INCLUDED
+#define VMIME_UTILITY_RANDOM_HPP_INCLUDED
+
+
+#include "vmime/types.hpp"
+
+
+namespace vmime {
+namespace utility {
+
+
+/** Pseudo-random number generator.
+ */
+class random {
+
+public:
+
+ /** Return a new random number.
+ *
+ * @return random number
+ */
+ static unsigned int getNext();
+
+ /** Return the current time as a number (may be used to
+ * build "random" strings).
+ *
+ * @return time as a number
+ */
+ static unsigned int getTime();
+
+ /** Return the current process number (may be user to
+ * build "random" strings).
+ *
+ * @return process number
+ */
+ static unsigned int getProcess();
+
+ /** Return a random character string with the specified length.
+ *
+ * @param length length of the string to generate
+ * @param randomChars list of characters to use
+ * @return random string
+ */
+ static const string getString(
+ const size_t length,
+ const string& randomChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
+ );
+};
+
+
+} // utility
+} // vmime
+
+
+#endif // VMIME_UTILITY_RANDOM_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/utility/seekableInputStream.hpp b/vmime-master/src/vmime/utility/seekableInputStream.hpp
new file mode 100644
index 0000000..181e904
--- /dev/null
+++ b/vmime-master/src/vmime/utility/seekableInputStream.hpp
@@ -0,0 +1,62 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_UTILITY_SEEKABLEINPUTSTREAM_HPP_INCLUDED
+#define VMIME_UTILITY_SEEKABLEINPUTSTREAM_HPP_INCLUDED
+
+
+#include "vmime/utility/inputStream.hpp"
+
+
+namespace vmime {
+namespace utility {
+
+
+/** An input stream that allows seeking within the input.
+ */
+class VMIME_EXPORT seekableInputStream : public inputStream {
+
+public:
+
+ /** Returns the current position in this stream.
+ *
+ * @return the offset from the beginning of the stream, in bytes,
+ * at which the next read occurs
+ */
+ virtual size_t getPosition() const = 0;
+
+ /** Sets the position, measured from the beginning of this stream,
+ * at which the next read occurs.
+ *
+ * @param pos the offset position, measured in bytes from the
+ * beginning of the stream, at which to set the stream pointer.
+ */
+ virtual void seek(const size_t pos) = 0;
+};
+
+
+} // utility
+} // vmime
+
+
+#endif // VMIME_UTILITY_SEEKABLEINPUTSTREAM_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/utility/seekableInputStreamRegionAdapter.cpp b/vmime-master/src/vmime/utility/seekableInputStreamRegionAdapter.cpp
new file mode 100644
index 0000000..3272366
--- /dev/null
+++ b/vmime-master/src/vmime/utility/seekableInputStreamRegionAdapter.cpp
@@ -0,0 +1,111 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/utility/seekableInputStreamRegionAdapter.hpp"
+
+
+namespace vmime {
+namespace utility {
+
+
+seekableInputStreamRegionAdapter::seekableInputStreamRegionAdapter(
+ const shared_ptr <seekableInputStream>& stream,
+ const size_t begin,
+ const size_t length
+)
+ : m_stream(stream),
+ m_begin(begin),
+ m_length(length),
+ m_position(0) {
+
+}
+
+
+bool seekableInputStreamRegionAdapter::eof() const {
+
+ return m_position >= m_length;
+}
+
+
+void seekableInputStreamRegionAdapter::reset() {
+
+ m_position = 0;
+}
+
+
+size_t seekableInputStreamRegionAdapter::read(byte_t* const data, const size_t count) {
+
+ m_stream->seek(m_begin + m_position);
+
+ size_t readBytes = 0;
+
+ if (m_position + count >= m_length) {
+
+ const size_t remaining = m_length - m_position;
+ readBytes = m_stream->read(data, remaining);
+
+ } else {
+
+ readBytes = m_stream->read(data, count);
+ }
+
+ m_position += readBytes;
+
+ return readBytes;
+}
+
+
+size_t seekableInputStreamRegionAdapter::skip(const size_t count) {
+
+ if (m_position + count >= m_length) {
+
+ const size_t remaining = m_length - m_position;
+ m_position += remaining;
+ return remaining;
+
+ } else {
+
+ m_position += count;
+ return count;
+ }
+}
+
+
+size_t seekableInputStreamRegionAdapter::getPosition() const {
+
+ return m_position;
+}
+
+
+void seekableInputStreamRegionAdapter::seek(const size_t pos) {
+
+ if (pos > m_length) {
+ m_position = m_length;
+ } else {
+ m_position = pos;
+ }
+}
+
+
+} // utility
+} // vmime
diff --git a/vmime-master/src/vmime/utility/seekableInputStreamRegionAdapter.hpp b/vmime-master/src/vmime/utility/seekableInputStreamRegionAdapter.hpp
new file mode 100644
index 0000000..8406b29
--- /dev/null
+++ b/vmime-master/src/vmime/utility/seekableInputStreamRegionAdapter.hpp
@@ -0,0 +1,73 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_UTILITY_SEEKABLEINPUTSTREAMREGIONADAPTER_HPP_INCLUDED
+#define VMIME_UTILITY_SEEKABLEINPUTSTREAMREGIONADAPTER_HPP_INCLUDED
+
+
+#include "vmime/utility/seekableInputStream.hpp"
+
+
+namespace vmime {
+namespace utility {
+
+
+/** An adapter for reading a limited region of a seekable input stream.
+ */
+class VMIME_EXPORT seekableInputStreamRegionAdapter : public seekableInputStream {
+
+public:
+
+ /** Creates a new adapter for a seekableInputStream.
+ *
+ * @param stream source stream
+ * @param begin start position in source stream
+ * @param length region length in source stream
+ */
+ seekableInputStreamRegionAdapter(
+ const shared_ptr <seekableInputStream>& stream,
+ const size_t begin,
+ const size_t length
+ );
+
+ bool eof() const;
+ void reset();
+ size_t read(byte_t* const data, const size_t count);
+ size_t skip(const size_t count);
+ size_t getPosition() const;
+ void seek(const size_t pos);
+
+private:
+
+ shared_ptr <seekableInputStream> m_stream;
+ size_t m_begin;
+ size_t m_length;
+ size_t m_position;
+};
+
+
+} // utility
+} // vmime
+
+
+#endif // VMIME_UTILITY_SEEKABLEINPUTSTREAMREGIONADAPTER_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/utility/stream.cpp b/vmime-master/src/vmime/utility/stream.cpp
new file mode 100644
index 0000000..96f99cb
--- /dev/null
+++ b/vmime-master/src/vmime/utility/stream.cpp
@@ -0,0 +1,39 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/utility/stream.hpp"
+
+
+
+namespace vmime {
+namespace utility {
+
+
+size_t stream::getBlockSize() {
+
+ return 32768; // 32 KB
+}
+
+
+} // utility
+} // vmime
diff --git a/vmime-master/src/vmime/utility/stream.hpp b/vmime-master/src/vmime/utility/stream.hpp
new file mode 100644
index 0000000..9aa1392
--- /dev/null
+++ b/vmime-master/src/vmime/utility/stream.hpp
@@ -0,0 +1,60 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_UTILITY_STREAM_HPP_INCLUDED
+#define VMIME_UTILITY_STREAM_HPP_INCLUDED
+
+
+#include <sstream>
+
+#include "vmime/config.hpp"
+#include "vmime/types.hpp"
+#include "vmime/base.hpp"
+
+
+namespace vmime {
+namespace utility {
+
+
+/** Base class for input/output stream.
+ */
+class VMIME_EXPORT stream : public object, private noncopyable {
+
+public:
+
+ virtual ~stream() { }
+
+ /** Return the preferred maximum block size when reading
+ * from or writing to this stream.
+ *
+ * @return block size, in bytes
+ */
+ virtual size_t getBlockSize();
+};
+
+
+} // utility
+} // vmime
+
+
+#endif // VMIME_UTILITY_STREAM_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/utility/streamUtils.cpp b/vmime-master/src/vmime/utility/streamUtils.cpp
new file mode 100644
index 0000000..793973c
--- /dev/null
+++ b/vmime-master/src/vmime/utility/streamUtils.cpp
@@ -0,0 +1,130 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/utility/streamUtils.hpp"
+
+#include <algorithm> // for std::copy
+#include <iterator> // for std::back_inserter
+
+
+
+namespace vmime {
+namespace utility {
+
+
+outputStream& operator<<(outputStream& os, const byte_t c) {
+
+ os.write(&c, 1);
+ return os;
+}
+
+
+outputStream& operator<<(outputStream& os, const string& str) {
+
+ os.write(str.data(), str.length());
+ return os;
+}
+
+
+size_t bufferedStreamCopy(inputStream& is, outputStream& os) {
+
+ return bufferedStreamCopy(is, os, 0, NULL);
+}
+
+
+size_t bufferedStreamCopyRange(
+ inputStream& is,
+ outputStream& os,
+ const size_t start,
+ const size_t length
+) {
+
+ const size_t blockSize =
+ std::min(is.getBlockSize(), os.getBlockSize());
+
+ is.skip(start);
+
+ std::vector <byte_t> vbuffer(blockSize);
+
+ byte_t* buffer = &vbuffer.front();
+ size_t total = 0;
+
+ while (!is.eof() && total < length) {
+
+ const size_t remaining = std::min(length - total, blockSize);
+ const size_t read = is.read(buffer, remaining);
+
+ if (read != 0) {
+ os.write(buffer, read);
+ total += read;
+ }
+ }
+
+ return total;
+}
+
+
+size_t bufferedStreamCopy(
+ inputStream& is,
+ outputStream& os,
+ const size_t length,
+ progressListener* progress
+) {
+
+ const size_t blockSize =
+ std::min(is.getBlockSize(), os.getBlockSize());
+
+ std::vector <byte_t> vbuffer(blockSize);
+
+ byte_t* buffer = &vbuffer.front();
+ size_t total = 0;
+
+ if (progress != NULL) {
+ progress->start(length);
+ }
+
+ while (!is.eof()) {
+
+ const size_t read = is.read(buffer, blockSize);
+
+ if (read != 0) {
+
+ os.write(buffer, read);
+ total += read;
+
+ if (progress != NULL) {
+ progress->progress(total, std::max(total, length));
+ }
+ }
+ }
+
+ if (progress != NULL) {
+ progress->stop(total);
+ }
+
+ return total;
+}
+
+
+} // utility
+} // vmime
diff --git a/vmime-master/src/vmime/utility/streamUtils.hpp b/vmime-master/src/vmime/utility/streamUtils.hpp
new file mode 100644
index 0000000..5d81fbe
--- /dev/null
+++ b/vmime-master/src/vmime/utility/streamUtils.hpp
@@ -0,0 +1,83 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_UTILITY_STREAMUTILS_HPP_INCLUDED
+#define VMIME_UTILITY_STREAMUTILS_HPP_INCLUDED
+
+
+#include "vmime/utility/inputStream.hpp"
+#include "vmime/utility/outputStream.hpp"
+
+#include "vmime/utility/progressListener.hpp"
+
+
+namespace vmime {
+namespace utility {
+
+
+/** Copy data from one stream into another stream using a buffered method.
+ *
+ * @param is input stream (source data)
+ * @param os output stream (destination for data)
+ * @return number of bytes copied
+ */
+VMIME_EXPORT size_t bufferedStreamCopy(inputStream& is, outputStream& os);
+
+/** Copy data from one stream into another stream using a buffered method
+ * and copying only a specified range of data.
+ *
+ * @param is input stream (source data)
+ * @param os output stream (destination for data)
+ * @param start number of bytes to ignore before starting copying
+ * @param length maximum number of bytes to copy
+ * @return number of bytes copied
+ */
+VMIME_EXPORT size_t bufferedStreamCopyRange(
+ inputStream& is,
+ outputStream& os,
+ const size_t start,
+ const size_t length
+);
+
+/** Copy data from one stream into another stream using a buffered method
+ * and notify progress state of the operation.
+ *
+ * @param is input stream (source data)
+ * @param os output stream (destination for data)
+ * @param length predicted number of bytes to copy
+ * @param progress listener to notify
+ * @return number of bytes copied
+ */
+VMIME_EXPORT size_t bufferedStreamCopy(
+ inputStream& is,
+ outputStream& os,
+ const size_t length,
+ progressListener* progress
+);
+
+
+} // utility
+} // vmime
+
+
+#endif // VMIME_UTILITY_STREAMUTILS_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/utility/stringUtils.cpp b/vmime-master/src/vmime/utility/stringUtils.cpp
new file mode 100644
index 0000000..823a3ea
--- /dev/null
+++ b/vmime-master/src/vmime/utility/stringUtils.cpp
@@ -0,0 +1,337 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/utility/stringUtils.hpp"
+#include "vmime/parserHelpers.hpp"
+
+
+namespace vmime {
+namespace utility {
+
+
+bool stringUtils::isStringEqualNoCase(const string& s1, const char* s2, const size_t n) {
+
+ // 'n' is the number of characters to compare
+ // 's2' must be in lowercase letters only
+ if (s1.length() < n) {
+ return (false);
+ }
+
+ const std::ctype <char>& fac =
+ std::use_facet <std::ctype <char> >(std::locale::classic());
+
+ bool equal = true;
+
+ for (size_t i = 0 ; equal && i < n ; ++i) {
+ equal = (fac.tolower(static_cast <unsigned char>(s1[i])) == s2[i]);
+ }
+
+ return equal;
+}
+
+
+bool stringUtils::isStringEqualNoCase(const string& s1, const string& s2) {
+
+ if (s1.length() != s2.length()) {
+ return false;
+ }
+
+ const std::ctype <char>& fac =
+ std::use_facet <std::ctype <char> >(std::locale::classic());
+
+ bool equal = true;
+ const string::const_iterator end = s1.end();
+
+ for (string::const_iterator i = s1.begin(), j = s2.begin() ; equal && i != end ; ++i, ++j) {
+ equal = (fac.tolower(static_cast <unsigned char>(*i)) == fac.tolower(static_cast <unsigned char>(*j)));
+ }
+
+ return equal;
+}
+
+
+bool stringUtils::isStringEqualNoCase(
+ const string::const_iterator begin,
+ const string::const_iterator end,
+ const char* s,
+ const size_t n
+) {
+
+ if (static_cast <size_t>(end - begin) < n) {
+ return false;
+ }
+
+ const std::ctype <char>& fac =
+ std::use_facet <std::ctype <char> >(std::locale::classic());
+
+ bool equal = true;
+ char* c = const_cast<char*>(s);
+ size_t r = n;
+
+ for (string::const_iterator i = begin ; equal && r && *c ; ++i, ++c, --r) {
+ equal = (fac.tolower(static_cast <unsigned char>(*i)) == static_cast <unsigned char>(*c));
+ }
+
+ return r == 0 && equal;
+}
+
+
+const string stringUtils::toLower(const string& str) {
+
+ const std::ctype <char>& fac =
+ std::use_facet <std::ctype <char> >(std::locale::classic());
+
+ string out;
+ out.resize(str.size());
+
+ for (size_t i = 0, len = str.length() ; i < len ; ++i) {
+ out[i] = fac.tolower(static_cast <unsigned char>(str[i]));
+ }
+
+ return out;
+}
+
+
+const string stringUtils::toUpper(const string& str) {
+
+ const std::ctype <char>& fac =
+ std::use_facet <std::ctype <char> >(std::locale::classic());
+
+ string out;
+ out.resize(str.size());
+
+ for (size_t i = 0, len = str.length() ; i < len ; ++i) {
+ out[i] = fac.toupper(static_cast <unsigned char>(str[i]));
+ }
+
+ return out;
+}
+
+
+const string stringUtils::trim(const string& str) {
+
+ string::const_iterator b = str.begin();
+ string::const_iterator e = str.end();
+
+ if (b != e) {
+
+ for ( ; b != e && parserHelpers::isSpace(*b) ; ++b) {}
+ for ( ; e != b && parserHelpers::isSpace(*(e - 1)) ; --e) {}
+ }
+
+ return string(b, e);
+}
+
+
+size_t stringUtils::countASCIIchars(
+ const string::const_iterator begin,
+ const string::const_iterator end
+) {
+
+ size_t count = 0;
+
+ for (string::const_iterator i = begin ; i != end ; ++i) {
+
+ if (parserHelpers::isAscii(*i)) {
+
+ if (*i != '=' || ((i + 1) != end && *(i + 1) != '?')) { // To avoid bad behaviour...
+ ++count;
+ }
+ }
+ }
+
+ return count;
+}
+
+
+bool stringUtils::is7bit(const string& str) {
+
+ return countASCIIchars(str.begin(), str.end()) == str.length();
+}
+
+
+size_t stringUtils::findFirstNonASCIIchar(
+ const string::const_iterator begin,
+ const string::const_iterator end
+) {
+
+ size_t pos = string::npos;
+
+ for (string::const_iterator i = begin ; i != end ; ++i) {
+
+ if (!parserHelpers::isAscii(*i)) {
+ pos = i - begin;
+ break;
+ }
+ }
+
+ return pos;
+}
+
+
+const string stringUtils::unquote(const string& str) {
+
+ if (str.length() < 2) {
+ return str;
+ }
+
+ if (str[0] != '"' || str[str.length() - 1] != '"') {
+ return str;
+ }
+
+ string res;
+ res.reserve(str.length());
+
+ bool escaped = false;
+
+ for (string::const_iterator it = str.begin() + 1, end = str.end() - 1 ; it != end ; ++it) {
+
+ const char c = *it;
+
+ if (escaped) {
+
+ res += c;
+ escaped = false;
+
+ } else if (!escaped && c == '\\') {
+
+ escaped = true;
+
+ } else {
+
+ res += c;
+ }
+ }
+
+ return res;
+}
+
+
+bool stringUtils::needQuoting(const string& str, const string& specialChars) {
+
+ return str.find_first_of(specialChars.c_str()) != string::npos;
+}
+
+
+string stringUtils::quote(
+ const string& str,
+ const string& escapeSpecialChars,
+ const string& escapeChar
+) {
+
+ std::ostringstream oss;
+ size_t lastPos = 0, pos = 0;
+
+ while ((pos = str.find_first_of(escapeSpecialChars, lastPos)) != string::npos) {
+
+ oss << str.substr(lastPos, pos - lastPos)
+ << escapeChar
+ << str[pos];
+
+ lastPos = pos + 1;
+ }
+
+ oss << str.substr(lastPos);
+
+ return oss.str();
+}
+
+
+bool stringUtils::isValidHostname(const vmime::string& hostname) {
+
+ short numberOfDots = 0;
+ return isValidFQDNImpl(hostname, &numberOfDots);
+}
+
+
+bool stringUtils::isValidFQDN(const vmime::string& fqdn) {
+
+ short numberOfDots = 0;
+ return isValidFQDNImpl(fqdn, &numberOfDots) && numberOfDots >= 2;
+}
+
+
+bool stringUtils::isValidFQDNImpl(const vmime::string& fqdn, short* numberOfDots) {
+
+ bool alphanumOnly = true;
+ bool invalid = false;
+ bool previousIsDot = true; // dot is not allowed as the first char
+ bool previousIsDash = true; // dash is not allowed as the first char
+
+ *numberOfDots = 0;
+
+ for (size_t i = 0, n = fqdn.length() ; alphanumOnly && !invalid && i < n ; ++i) {
+
+ const char c = fqdn[i];
+
+ alphanumOnly = (
+ (c >= '0' && c <= '9') // DIGIT
+ || (c >= 'a' && c <= 'z') // ALPHA
+ || (c >= 'A' && c <= 'Z') // ALPHA
+ || (c == '.')
+ || (c == '-')
+ );
+
+ if (c == '-') {
+
+ if (previousIsDot) {
+ invalid = true; // dash is not allowed as the first char
+ }
+
+ previousIsDot = false;
+ previousIsDash = true;
+
+ } else if (c == '.') {
+
+ if (previousIsDash) {
+
+ invalid = true; // dash is not allowed as the first char
+
+ } else if (previousIsDot) {
+
+ invalid = true; // consecutive dots are not allowed
+
+ } else {
+
+ ++*numberOfDots;
+ previousIsDot = true;
+ }
+
+ previousIsDash = false;
+
+ } else {
+
+ previousIsDot = false;
+ previousIsDash = false;
+ }
+ }
+
+ return alphanumOnly &&
+ !previousIsDot &&
+ !previousIsDash &&
+ !invalid;
+}
+
+
+} // utility
+} // vmime
diff --git a/vmime-master/src/vmime/utility/stringUtils.hpp b/vmime-master/src/vmime/utility/stringUtils.hpp
new file mode 100644
index 0000000..4678940
--- /dev/null
+++ b/vmime-master/src/vmime/utility/stringUtils.hpp
@@ -0,0 +1,271 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_UTILITY_STRINGUTILS_HPP_INCLUDED
+#define VMIME_UTILITY_STRINGUTILS_HPP_INCLUDED
+
+
+#include "vmime/types.hpp"
+#include "vmime/base.hpp"
+
+#include <sstream>
+
+
+namespace vmime {
+namespace utility {
+
+
+/** Miscellaneous functions related to strings.
+ */
+class VMIME_EXPORT stringUtils {
+
+public:
+
+ /** Makes a string from bytes.
+ *
+ * @param data pointer to buffer containing data
+ * @param count number of bytes to use from buffer
+ * @return a string object containing a copy of the specified data
+ */
+ static const string makeStringFromBytes(const byte_t* data, const size_t count) {
+
+ return string(reinterpret_cast <const char*>(data), count);
+ }
+
+ /** Casts a string to bytes.
+ *
+ * @param str string
+ * @return pointer to the first byte of the string
+ */
+ static const byte_t* bytesFromString(const string& str) {
+
+ return reinterpret_cast <const byte_t*>(str.data());
+ }
+
+ /** Casts a NULL-terminated string to bytes.
+ *
+ * @param str string
+ * @return pointer to the first byte of the string
+ */
+ static const byte_t* bytesFromString(const char* str) {
+
+ return reinterpret_cast <const byte_t*>(str);
+ }
+
+ /** Appends bytes to a string.
+ *
+ * @param str string to which append data
+ * @param data pointer to buffer containing data
+ * @param count number of bytes to use from buffer
+ * @return a reference to modified string
+ */
+ static string& appendBytesToString(string& str, const byte_t* data, const size_t count) {
+
+ str.append(reinterpret_cast <const char*>(data), count);
+ return str;
+ }
+
+ /** Test two strings for equality (case insensitive).
+ * \warning Use this with ASCII-only strings.
+ *
+ * @param s1 first string
+ * @param s2 second string (must be in lower-case!)
+ * @param n length of the second string
+ * @return true if the two strings compare equally, false otherwise
+ */
+ static bool isStringEqualNoCase(const string& s1, const char* s2, const size_t n);
+
+ /** Test two strings for equality (case insensitive).
+ * \warning Use this with ASCII-only strings.
+ *
+ * @param s1 first string
+ * @param s2 second string
+ * @return true if the two strings compare equally, false otherwise
+ */
+ static bool isStringEqualNoCase(const string& s1, const string& s2);
+
+ /** Test two strings for equality (case insensitive).
+ * \warning Use this with ASCII-only strings.
+ *
+ * @param begin start position of the first string
+ * @param end end position of the first string
+ * @param s second string (must be in lower-case!)
+ * @param n length of the second string
+ * @return true if the two strings compare equally, false otherwise
+ */
+ static bool isStringEqualNoCase(
+ const string::const_iterator begin,
+ const string::const_iterator end,
+ const char* s,
+ const size_t n
+ );
+
+ /** Transform all the characters in a string to lower-case.
+ * \warning Use this with ASCII-only strings.
+ *
+ * @param str the string to transform
+ * @return a new string in lower-case
+ */
+ static const string toLower(const string& str);
+
+ /** Transform all the characters in a string to upper-case.
+ * \warning Use this with ASCII-only strings.
+ *
+ * @param str the string to transform
+ * @return a new string in upper-case
+ */
+ static const string toUpper(const string& str);
+
+ /** Strip the space characters (SPC, TAB, CR, LF) at the beginning
+ * and at the end of the specified string.
+ *
+ * @param str string in which to strip spaces
+ * @return a new string with space characters removed
+ */
+ static const string trim(const string& str);
+
+ /** Return the number of 7-bit US-ASCII characters in a string.
+ *
+ * @param begin start position
+ * @param end end position
+ * @return number of ASCII characters
+ */
+ static size_t countASCIIchars(
+ const string::const_iterator begin,
+ const string::const_iterator end
+ );
+
+ /** Returns whether the specified string is composed exclusively
+ * of 7-bit ASCII characters.
+ *
+ * @param str string to test
+ * @return true if the string is ASCII-only, false otherwise
+ */
+ static bool is7bit(const string& str);
+
+ /** Returns the position of the first non 7-bit US-ASCII character in a string.
+ *
+ * @param begin start position
+ * @param end end position
+ * @return position since begin, or string::npos
+ */
+ static size_t findFirstNonASCIIchar(
+ const string::const_iterator begin,
+ const string::const_iterator end
+ );
+
+ /** Convert the specified value to a string value.
+ *
+ * @param value to convert
+ * @return value converted from type 'TYPE'
+ */
+ template <class TYPE>
+ static const string toString(const TYPE& value) {
+
+ std::ostringstream oss;
+ oss.imbue(std::locale::classic());
+
+ oss << value;
+
+ return oss.str();
+ }
+
+ /** Convert the specified string value to a value of
+ * the specified type.
+ *
+ * @param value value to convert
+ * @return value converted into type 'TYPE'
+ */
+ template <class TYPE>
+ static const TYPE fromString(const string& value) {
+
+ TYPE ret;
+
+ std::istringstream iss(value);
+ iss.imbue(std::locale::classic());
+
+ iss >> ret;
+
+ return ret;
+ }
+
+ /** Unquote the specified string and transform escaped characters.
+ *
+ * @param str string from which to remove quotes
+ * @return unquoted string
+ */
+ static const string unquote(const string& str);
+
+ /** Determines whether the specified string needs to be quoted.
+ *
+ * @param str string to test
+ * @param specialChars list of characters that will cause the
+ * string to be quoted
+ * @return true if the string needs to be quoted, false otherwise
+ */
+ static bool needQuoting(
+ const string& str,
+ const string& specialChars = " \t\"(),:;<>@[\\]"
+ );
+
+ /** Quotes the specified string.
+ *
+ * @param str string to quote
+ * @param escapeSpecialChars list of characters that will be escaped
+ * @param escapeChar character that will be used for escaping (eg. '\')
+ * @return quoted string
+ */
+ static string quote(
+ const string& str,
+ const string& escapeSpecialChars,
+ const string& escapeChar
+ );
+
+ /** Return whether the specified string is a valid host name
+ * or domain name.
+ *
+ * @param hostname string to test
+ * @return true if the string is a valid host name or domain
+ * name, or false otherwise
+ */
+ static bool isValidHostname(const vmime::string& hostname);
+
+ /** Return whether the specified string is a valid fully
+ * qualified domain name (FQDN).
+ *
+ * @param fqdn string to test
+ * @return true if the string seems to be a FQDN, false otherwise
+ */
+ static bool isValidFQDN(const vmime::string& fqdn);
+
+private:
+
+ static bool isValidFQDNImpl(const vmime::string& fqdn, short* minNumberOfDots);
+};
+
+
+} // utility
+} // vmime
+
+
+#endif // VMIME_UTILITY_STRINGUTILS_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/utility/sync/autoLock.hpp b/vmime-master/src/vmime/utility/sync/autoLock.hpp
new file mode 100644
index 0000000..a3d3a7c
--- /dev/null
+++ b/vmime-master/src/vmime/utility/sync/autoLock.hpp
@@ -0,0 +1,65 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_UTILITY_SYNC_AUTOLOCK_HPP_INCLUDED
+#define VMIME_UTILITY_SYNC_AUTOLOCK_HPP_INCLUDED
+
+
+#include "vmime/base.hpp"
+
+
+namespace vmime {
+namespace utility {
+namespace sync {
+
+
+/** Critical section wrapper class
+ */
+template <class M>
+class VMIME_EXPORT autoLock : public object {
+
+public:
+
+ autoLock(const shared_ptr <M>& mutex)
+ : m_mutex(mutex) {
+
+ m_mutex->lock();
+ }
+
+ ~autoLock() {
+
+ m_mutex->unlock();
+ }
+
+private:
+
+ shared_ptr <M> m_mutex;
+};
+
+
+} // sync
+} // utility
+} // vmime
+
+
+#endif // VMIME_UTILITY_SYNC_AUTOLOCK_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/utility/sync/criticalSection.cpp b/vmime-master/src/vmime/utility/sync/criticalSection.cpp
new file mode 100644
index 0000000..a1013cd
--- /dev/null
+++ b/vmime-master/src/vmime/utility/sync/criticalSection.cpp
@@ -0,0 +1,44 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/utility/sync/criticalSection.hpp"
+
+
+namespace vmime {
+namespace utility {
+namespace sync {
+
+
+criticalSection::criticalSection() {
+
+}
+
+
+criticalSection::~criticalSection() {
+
+}
+
+
+} // sync
+} // utility
+} // vmime
diff --git a/vmime-master/src/vmime/utility/sync/criticalSection.hpp b/vmime-master/src/vmime/utility/sync/criticalSection.hpp
new file mode 100644
index 0000000..1e7008c
--- /dev/null
+++ b/vmime-master/src/vmime/utility/sync/criticalSection.hpp
@@ -0,0 +1,64 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_UTILITY_SYNC_CRITICALSECTION_HPP_INCLUDED
+#define VMIME_UTILITY_SYNC_CRITICALSECTION_HPP_INCLUDED
+
+
+#include "vmime/base.hpp"
+
+
+namespace vmime {
+namespace utility {
+namespace sync {
+
+
+/** Critical section class.
+ */
+class VMIME_EXPORT criticalSection : public object {
+
+public:
+
+ virtual ~criticalSection();
+
+ /** Enters the critical section.
+ */
+ virtual void lock() = 0;
+
+ /** Leaves the critical section.
+ */
+ virtual void unlock() = 0;
+
+protected:
+
+ criticalSection();
+ criticalSection(criticalSection&);
+};
+
+
+} // sync
+} // utility
+} // vmime
+
+
+#endif // VMIME_UTILITY_SYNC_CRITICALSECTION_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/utility/url.cpp b/vmime-master/src/vmime/utility/url.cpp
new file mode 100644
index 0000000..59cb1f5
--- /dev/null
+++ b/vmime-master/src/vmime/utility/url.cpp
@@ -0,0 +1,431 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/utility/url.hpp"
+
+#include "vmime/parserHelpers.hpp"
+#include "vmime/utility/urlUtils.hpp"
+#include "vmime/exception.hpp"
+
+#include <sstream>
+
+
+namespace vmime {
+namespace utility {
+
+
+// Unspecified port
+const port_t url::UNSPECIFIED_PORT = static_cast <port_t>(-1);
+
+// Known protocols
+const string url::PROTOCOL_FILE = "file";
+const string url::PROTOCOL_HTTP = "http";
+const string url::PROTOCOL_FTP = "ftp";
+
+
+
+url::url(const string& s) {
+
+ parse(s);
+}
+
+
+url::url(const url& u) {
+
+ operator=(u);
+}
+
+
+url::url(
+ const string& protocol,
+ const string& host,
+ const port_t port,
+ const string& path,
+ const string& username,
+ const string& password
+)
+ : m_protocol(protocol),
+ m_username(username),
+ m_password(password),
+ m_host(host),
+ m_port(port),
+ m_path(path) {
+
+}
+
+
+url& url::operator=(const url& u) {
+
+ m_protocol = u.m_protocol;
+
+ m_username = u.m_username;
+ m_password = u.m_password;
+
+ m_host = u.m_host;
+ m_port = u.m_port;
+
+ m_path = u.m_path;
+
+ m_params = u.m_params;
+
+ return *this;
+}
+
+
+url& url::operator=(const string& s) {
+
+ parse(s);
+
+ return *this;
+}
+
+
+url::operator string() const {
+
+ return build();
+}
+
+
+const string url::build() const {
+
+ std::ostringstream oss;
+ oss.imbue(std::locale::classic());
+
+ oss << m_protocol << "://";
+
+ if (!m_username.empty()) {
+
+ oss << urlUtils::encode(m_username);
+
+ if (!m_password.empty()) {
+
+ oss << ":";
+ oss << urlUtils::encode(m_password);
+ }
+
+ oss << "@";
+ }
+
+ oss << urlUtils::encode(m_host);
+
+ if (m_port != UNSPECIFIED_PORT) {
+
+ oss << ":";
+ oss << m_port;
+ }
+
+ if (!m_path.empty()) {
+
+ oss << "/";
+ oss << urlUtils::encode(m_path);
+ }
+
+
+ if (!m_params.empty()) {
+
+ if (m_path.empty()) {
+ oss << "/";
+ }
+
+ oss << "?";
+
+ for (std::map <string, string>::const_iterator it = m_params.begin() ;
+ it != m_params.end() ; ++it) {
+
+ if (it != m_params.begin()) {
+ oss << "&";
+ }
+
+ oss << urlUtils::encode((*it).first);
+ oss << "=";
+ oss << urlUtils::encode((*it).second);
+ }
+ }
+
+ return oss.str();
+}
+
+
+void url::parse(const string& str) {
+
+ // Protocol
+ const size_t protoEnd = str.find("://");
+
+ if (protoEnd == string::npos) {
+ throw exceptions::malformed_url("No protocol separator");
+ }
+
+ const string proto =
+ utility::stringUtils::toLower(string(str.begin(), str.begin() + protoEnd));
+
+ // Username/password
+ size_t slashPos = str.find('/', protoEnd + 3);
+
+ if (slashPos == string::npos) {
+ slashPos = str.length();
+ }
+
+ size_t atPos = str.rfind('@', slashPos);
+ string hostPart;
+
+ string username;
+ string password;
+
+ if (proto == PROTOCOL_FILE) {
+
+ // No user name, password and host part.
+ slashPos = protoEnd + 3;
+
+ } else {
+
+ if (atPos != string::npos && atPos < slashPos) {
+
+ const string userPart(str.begin() + protoEnd + 3, str.begin() + atPos);
+ const size_t colonPos = userPart.find(':');
+
+ if (colonPos == string::npos) {
+
+ username = userPart;
+
+ } else {
+
+ username = string(userPart.begin(), userPart.begin() + colonPos);
+ password = string(userPart.begin() + colonPos + 1, userPart.end());
+ }
+
+ hostPart = string(str.begin() + atPos + 1, str.begin() + slashPos);
+
+ } else {
+
+ hostPart = string(str.begin() + protoEnd + 3, str.begin() + slashPos);
+ }
+ }
+
+ // Host/port
+ const size_t colonPos = hostPart.find(':');
+
+ string host;
+ string port;
+
+ if (colonPos == string::npos) {
+
+ host = utility::stringUtils::trim(hostPart);
+
+ } else {
+
+ host = utility::stringUtils::trim(string(hostPart.begin(), hostPart.begin() + colonPos));
+ port = utility::stringUtils::trim(string(hostPart.begin() + colonPos + 1, hostPart.end()));
+ }
+
+ // Path
+ string path = utility::stringUtils::trim(string(str.begin() + slashPos, str.end()));
+ string params;
+
+ size_t paramSep = path.find_first_of('?');
+
+ if (paramSep != string::npos) {
+
+ params = string(path.begin() + paramSep + 1, path.end());
+ path.erase(path.begin() + paramSep, path.end());
+ }
+
+ if (path == "/") {
+ path.clear();
+ }
+
+ // Some sanity check
+ if (proto.empty()) {
+
+ throw exceptions::malformed_url("No protocol specified");
+
+ } else if (host.empty()) {
+
+ // Accept empty host (eg. "file:///home/vincent/mydoc")
+ if (proto != PROTOCOL_FILE) {
+ throw exceptions::malformed_url("No host specified");
+ }
+ }
+
+ bool onlyDigit = true;
+
+ for (string::const_iterator it = port.begin() ;
+ onlyDigit && it != port.end() ; ++it) {
+
+ onlyDigit = parserHelpers::isDigit(*it);
+ }
+
+ if (!onlyDigit) {
+ throw exceptions::malformed_url("Port can only contain digits");
+ }
+
+ std::istringstream iss(port);
+ iss.imbue(std::locale::classic());
+
+ port_t portNum = 0;
+ iss >> portNum;
+
+ if (portNum == 0) {
+ portNum = UNSPECIFIED_PORT;
+ }
+
+ // Extract parameters
+ m_params.clear();
+
+ if (!params.empty()) {
+
+ size_t pos = 0;
+
+ do {
+
+ const size_t start = pos;
+
+ pos = params.find_first_of('&', pos);
+
+ const size_t equal = params.find_first_of('=', start);
+ const size_t end = (pos == string::npos ? params.length() : pos);
+
+ string name;
+ string value;
+
+ if (equal == string::npos || equal > pos) { // no value
+
+ name = string(params.begin() + start, params.begin() + end);
+ value = name;
+
+ } else {
+
+ name = string(params.begin() + start, params.begin() + equal);
+ value = string(params.begin() + equal + 1, params.begin() + end);
+ }
+
+ name = urlUtils::decode(name);
+ value = urlUtils::decode(value);
+
+ m_params[name] = value;
+
+ if (pos != string::npos) {
+ ++pos;
+ }
+
+ } while (pos != string::npos);
+ }
+
+ // Now, save URL parts
+ m_protocol = proto;
+
+ m_username = urlUtils::decode(username);
+ m_password = urlUtils::decode(password);
+
+ m_host = urlUtils::decode(host);
+ m_port = portNum;
+
+ m_path = urlUtils::decode(path);
+}
+
+
+const string& url::getProtocol() const {
+
+ return m_protocol;
+}
+
+
+void url::setProtocol(const string& protocol) {
+
+ m_protocol = protocol;
+}
+
+
+const string& url::getUsername() const {
+
+ return m_username;
+}
+
+
+void url::setUsername(const string& username) {
+
+ m_username = username;
+}
+
+
+const string& url::getPassword() const {
+
+ return m_password;
+}
+
+
+void url::setPassword(const string& password) {
+
+ m_password = password;
+}
+
+
+const string& url::getHost() const {
+
+ return m_host;
+}
+
+
+void url::setHost(const string& host) {
+
+ m_host = host;
+}
+
+
+port_t url::getPort() const {
+
+ return m_port;
+}
+
+
+void url::setPort(const port_t port) {
+
+ m_port = port;
+}
+
+
+const string& url::getPath() const {
+
+ return m_path;
+}
+
+
+void url::setPath(const string& path) {
+
+ m_path = path;
+}
+
+
+const std::map <string, string>& url::getParams() const {
+
+ return m_params;
+}
+
+
+std::map <string, string>& url::getParams() {
+
+ return m_params;
+}
+
+
+} // utility
+} // vmime
diff --git a/vmime-master/src/vmime/utility/url.hpp b/vmime-master/src/vmime/utility/url.hpp
new file mode 100644
index 0000000..8dfa3c4
--- /dev/null
+++ b/vmime-master/src/vmime/utility/url.hpp
@@ -0,0 +1,213 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_UTILITY_URL_HPP_INCLUDED
+#define VMIME_UTILITY_URL_HPP_INCLUDED
+
+
+#include "vmime/types.hpp"
+#include "vmime/base.hpp"
+#include "vmime/propertySet.hpp"
+
+
+namespace vmime {
+namespace utility {
+
+
+/** This class represents a Uniform Resource Locator (a pointer
+ * to a "resource" on the World Wide Web).
+ *
+ * Format:
+ * "protocol://[username[:password]@]host[:port][/path]"
+ */
+class VMIME_EXPORT url {
+
+public:
+
+ /** Means "port not specified" (use default port). */
+ static const port_t UNSPECIFIED_PORT;
+
+ /** Standard name for FILE protocol (local file-system). */
+ static const string PROTOCOL_FILE;
+
+ /** Standard name for HTTP protocol. */
+ static const string PROTOCOL_HTTP;
+
+ /** Standard name for FTP protocol. */
+ static const string PROTOCOL_FTP;
+
+
+ /** Construct an URL from a string (parse the URL components).
+ *
+ * @param s full URL string (eg. http://www.vmime.org:80/download.html)
+ * @throw exceptions::malformed_url if URL is malformed
+ */
+ url(const string& s);
+
+ /** Construct an URL from another URL object.
+ *
+ * @param u other URL object
+ */
+ url(const url& u);
+
+ /** Construct an URL from the components.
+ *
+ * @param protocol protocol (eg. "http", "ftp"...)
+ * @param host host name (eg. "www.vmime.org", "123.45.67.89")
+ * @param port optional port number (eg. 80, 110 or UNSPECIFIED_PORT to mean "default")
+ * @param path optional full path (eg. "download.html")
+ * @param username optional user name
+ * @param password optional user password
+ */
+ url(
+ const string& protocol,
+ const string& host,
+ const port_t port = UNSPECIFIED_PORT,
+ const string& path = "",
+ const string& username = "",
+ const string& password = ""
+ );
+
+
+ /** Return the protocol of the URL (eg: "http").
+ *
+ * @return protocol of the URL
+ */
+ const string& getProtocol() const;
+
+ /** Set the protocol of the URL.
+ *
+ * @param protocol new protocol (eg: "http")
+ */
+ void setProtocol(const string& protocol);
+
+ /** Return the username specified in the URL
+ * or empty if not specified.
+ *
+ * @return user name
+ */
+ const string& getUsername() const;
+
+ /** Set the username of the URL.
+ *
+ * @param username user name
+ */
+ void setUsername(const string& username);
+
+ /** Return the password specified in the URL
+ * or empty if not specified.
+ *
+ * @return user password
+ */
+ const string& getPassword() const;
+
+ /** Set the password of the URL.
+ *
+ * @param password user password
+ */
+ void setPassword(const string& password);
+
+ /** Return the host name of the URL (server name or IP address).
+ *
+ * @return host name
+ */
+ const string& getHost() const;
+
+ /** Set the host name of the URL.
+ *
+ * @param host server name or IP address
+ */
+ void setHost(const string& host);
+
+ /** Return the port of the URL, or url::UNSPECIFIED_PORT if
+ * the default port if used.
+ *
+ * @return server port
+ */
+ port_t getPort() const;
+
+ /** Set the port of the URL.
+ *
+ * @param port server port or url::UNSPECIFIED_PORT to
+ * use the default port of the protocol
+ */
+ void setPort(const port_t port);
+
+ /** Return the path portion of the URL,
+ * or empty if not specified.
+ *
+ * @return path
+ */
+ const string& getPath() const;
+
+ /** Set the part portion of the URL.
+ *
+ * @param path path
+ */
+ void setPath(const string& path);
+
+ /** Return the parameters of the URL (read-only).
+ *
+ * @return parameters
+ */
+ const std::map <string, string>& getParams() const;
+
+ /** Return the parameters of the URL.
+ *
+ * @return parameters
+ */
+ std::map <string, string>& getParams();
+
+ /** Build a string URL from this object.
+ */
+ operator string() const;
+
+ url& operator=(const url& u);
+ url& operator=(const string& s);
+
+private:
+
+ const string build() const;
+ void parse(const string& str);
+
+
+ string m_protocol;
+
+ string m_username;
+ string m_password;
+
+ string m_host;
+
+ port_t m_port;
+
+ string m_path;
+
+ std::map <string, string> m_params;
+};
+
+
+} // utility
+} // vmime
+
+
+#endif // VMIME_UTILITY_URL_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/utility/urlUtils.cpp b/vmime-master/src/vmime/utility/urlUtils.cpp
new file mode 100644
index 0000000..cf51a50
--- /dev/null
+++ b/vmime-master/src/vmime/utility/urlUtils.cpp
@@ -0,0 +1,133 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/utility/urlUtils.hpp"
+#include "vmime/parserHelpers.hpp"
+
+
+namespace vmime {
+namespace utility {
+
+
+const string urlUtils::encode(const string& s) {
+
+ static const string RESERVED_CHARS =
+ /* reserved */ "$&+,/:;=?@"
+ /* unsafe */ "<>#%{}[]|\\^\"~`";
+
+ string result;
+ result.reserve(s.length());
+
+ for (string::const_iterator it = s.begin() ; it != s.end() ; ++it) {
+
+ const char c = *it;
+
+ if (parserHelpers::isPrint(c) && !parserHelpers::isSpace(c) &&
+ static_cast <unsigned char>(c) <= 127 &&
+ RESERVED_CHARS.find(c) == string::npos) {
+
+ result += c;
+
+ } else {
+
+ char hex[4];
+ const unsigned char k = static_cast <unsigned char>(c);
+
+ hex[0] = '%';
+ hex[1] = "0123456789ABCDEF"[k / 16];
+ hex[2] = "0123456789ABCDEF"[k % 16];
+ hex[3] = 0;
+
+ result += hex;
+ }
+ }
+
+ return result;
+}
+
+
+const string urlUtils::decode(const string& s) {
+
+ string result;
+ result.reserve(s.length());
+
+ for (string::const_iterator it = s.begin() ; it != s.end() ; ) {
+
+ const char c = *it;
+
+ switch (c) {
+
+ case '%': {
+
+ ++it; // skip '%'
+
+ const char_t p = (it != s.end() ? *(it++) : 0);
+ const char_t q = (it != s.end() ? *(it++) : 0);
+
+ unsigned int r = 0;
+
+ switch (p) {
+
+ case 0: r = '%'; break;
+ case 'a': case 'A': r = 10; break;
+ case 'b': case 'B': r = 11; break;
+ case 'c': case 'C': r = 12; break;
+ case 'd': case 'D': r = 13; break;
+ case 'e': case 'E': r = 14; break;
+ case 'f': case 'F': r = 15; break;
+ default: r = p - '0'; break;
+ }
+
+ if (q != 0) {
+
+ r *= 16;
+
+ switch (q) {
+
+ case 'a': case 'A': r += 10; break;
+ case 'b': case 'B': r += 11; break;
+ case 'c': case 'C': r += 12; break;
+ case 'd': case 'D': r += 13; break;
+ case 'e': case 'E': r += 14; break;
+ case 'f': case 'F': r += 15; break;
+ default: r += q - '0'; break;
+ }
+ }
+
+ result += static_cast <char>(r);
+ break;
+ }
+ default:
+
+ result += c;
+ ++it;
+ break;
+ }
+ }
+
+ return result;
+}
+
+
+} // utility
+} // vmime
diff --git a/vmime-master/src/vmime/utility/urlUtils.hpp b/vmime-master/src/vmime/utility/urlUtils.hpp
new file mode 100644
index 0000000..54ffa2a
--- /dev/null
+++ b/vmime-master/src/vmime/utility/urlUtils.hpp
@@ -0,0 +1,57 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_UTILITY_URLUTILS_HPP_INCLUDED
+#define VMIME_UTILITY_URLUTILS_HPP_INCLUDED
+
+
+#include "vmime/types.hpp"
+#include "vmime/base.hpp"
+
+
+namespace vmime {
+namespace utility {
+
+
+/** Miscellaneous functions related to URLs.
+ */
+class VMIME_EXPORT urlUtils {
+
+public:
+
+ /** Encode extended characters in a URL string (ASCII characters
+ * are unmodified, other are encoded as '%' followed by hex code).
+ */
+ static const string encode(const string& s);
+
+ /** Decode an hex-encoded URL (see encode()).
+ */
+ static const string decode(const string& s);
+};
+
+
+} // utility
+} // vmime
+
+
+#endif // VMIME_UTILITY_URLUTILS_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/vmime.hpp b/vmime-master/src/vmime/vmime.hpp
new file mode 100644
index 0000000..e92b7e5
--- /dev/null
+++ b/vmime-master/src/vmime/vmime.hpp
@@ -0,0 +1,160 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should.have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_INCLUDED
+#define VMIME_INCLUDED
+
+
+// Configuration
+#include "config.hpp"
+
+// Base definitions
+#include "base.hpp"
+#include "exception.hpp"
+#include "platform.hpp"
+
+// Base components
+#include "dateTime.hpp"
+#include "message.hpp"
+#include "bodyPart.hpp"
+#include "charset.hpp"
+#include "text.hpp"
+#include "encoding.hpp"
+#include "contentDisposition.hpp"
+#include "emailAddress.hpp"
+#include "mailbox.hpp"
+#include "mailboxGroup.hpp"
+#include "mailboxList.hpp"
+#include "addressList.hpp"
+#include "mediaType.hpp"
+#include "messageId.hpp"
+#include "messageIdSequence.hpp"
+#include "relay.hpp"
+#include "disposition.hpp"
+#include "path.hpp"
+
+#include "emptyContentHandler.hpp"
+#include "fileContentHandler.hpp"
+#include "stringContentHandler.hpp"
+#include "streamContentHandler.hpp"
+
+#include "generationContext.hpp"
+#include "parsingContext.hpp"
+
+// Message components
+#include "message.hpp"
+
+// Header fields
+#include "headerFieldFactory.hpp"
+#include "mailboxField.hpp"
+#include "parameterizedHeaderField.hpp"
+
+// Encoders
+#include "utility/encoder/encoderFactory.hpp"
+
+// Streams
+#include "utility/filteredStream.hpp"
+#include "utility/inputStream.hpp"
+#include "utility/inputStreamAdapter.hpp"
+#include "utility/inputStreamByteBufferAdapter.hpp"
+#include "utility/inputStreamPointerAdapter.hpp"
+#include "utility/inputStreamSocketAdapter.hpp"
+#include "utility/inputStreamStringAdapter.hpp"
+#include "utility/outputStream.hpp"
+#include "utility/outputStreamAdapter.hpp"
+#include "utility/outputStreamByteArrayAdapter.hpp"
+#include "utility/outputStreamSocketAdapter.hpp"
+#include "utility/outputStreamStringAdapter.hpp"
+#include "utility/streamUtils.hpp"
+
+// Message builder/parser
+#include "messageBuilder.hpp"
+#include "messageParser.hpp"
+
+#include "fileAttachment.hpp"
+#include "defaultAttachment.hpp"
+#include "messageAttachment.hpp"
+
+#include "plainTextPart.hpp"
+#include "htmlTextPart.hpp"
+
+#include "attachmentHelper.hpp"
+
+// MDN
+#include "mdn/MDNHelper.hpp"
+
+// Misc
+#include "misc/importanceHelper.hpp"
+
+// Property set
+#include "propertySet.hpp"
+
+// Utilities
+#include "utility/datetimeUtils.hpp"
+#include "utility/filteredStream.hpp"
+#include "charsetConverter.hpp"
+
+// Security
+#include "security/authenticator.hpp"
+#include "security/defaultAuthenticator.hpp"
+
+// Security/digest
+#include "security/digest/messageDigestFactory.hpp"
+
+// Security/SASL
+#if VMIME_HAVE_SASL_SUPPORT
+ #include "security/sasl/SASLAuthenticator.hpp"
+ #include "security/sasl/defaultSASLAuthenticator.hpp"
+ #include "security/sasl/SASLContext.hpp"
+ #include "security/sasl/SASLSession.hpp"
+#endif // VMIME_HAVE_SASL_SUPPORT
+
+// Messaging features
+#if VMIME_HAVE_MESSAGING_FEATURES
+ #include "net/socket.hpp"
+
+ #include "net/serviceFactory.hpp"
+ #include "net/store.hpp"
+ #include "net/transport.hpp"
+
+ #include "net/session.hpp"
+
+ #include "net/folder.hpp"
+ #include "net/message.hpp"
+#endif // VMIME_HAVE_MESSAGING_FEATURES
+
+// Net/TLS
+#if VMIME_HAVE_TLS_SUPPORT
+ #include "security/cert/certificate.hpp"
+ #include "security/cert/certificateChain.hpp"
+ #include "security/cert/certificateVerifier.hpp"
+
+ #include "security/cert/X509Certificate.hpp"
+
+ #include "security/cert/defaultCertificateVerifier.hpp"
+
+ #include "net/tls/TLSSession.hpp"
+#endif // VMIME_HAVE_TLS_SUPPORT
+
+
+#endif // VMIME_INCLUDED
diff --git a/vmime-master/src/vmime/word.cpp b/vmime-master/src/vmime/word.cpp
new file mode 100644
index 0000000..2607e90
--- /dev/null
+++ b/vmime-master/src/vmime/word.cpp
@@ -0,0 +1,939 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/word.hpp"
+#include "vmime/text.hpp"
+
+#include "vmime/utility/stringUtils.hpp"
+#include "vmime/parserHelpers.hpp"
+
+#include "vmime/utility/outputStreamStringAdapter.hpp"
+#include "vmime/utility/inputStreamStringAdapter.hpp"
+
+#include "vmime/utility/encoder/encoder.hpp"
+#include "vmime/utility/encoder/b64Encoder.hpp"
+#include "vmime/utility/encoder/qpEncoder.hpp"
+
+#include "vmime/wordEncoder.hpp"
+
+
+namespace vmime {
+
+
+word::word()
+ : m_charset(charset::getLocalCharset()) {
+
+}
+
+
+word::word(const word& w)
+ : headerFieldValue(),
+ m_buffer(w.m_buffer),
+ m_charset(w.m_charset),
+ m_lang(w.m_lang) {
+
+}
+
+
+word::word(const string& buffer) // Defaults to local charset
+ : m_buffer(buffer),
+ m_charset(charset::getLocalCharset()) {
+
+}
+
+
+word::word(const string& buffer, const charset& charset)
+ : m_buffer(buffer),
+ m_charset(charset) {
+
+}
+
+
+word::word(const string& buffer, const charset& charset, const string& lang)
+ : m_buffer(buffer),
+ m_charset(charset),
+ m_lang(lang) {
+
+}
+
+
+shared_ptr <word> word::parseNext(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition,
+ parserState* state
+) {
+
+ size_t pos = position;
+
+ // Ignore white-spaces:
+ // - before the first word
+ // - between two encoded words
+ // - after the last word
+ // Always ignore newlines
+ string whiteSpaces;
+
+ while (pos < end && parserHelpers::isSpace(buffer[pos])) {
+
+ if (buffer[pos] != '\r' && buffer[pos] != '\n') { // do not include newlines
+ whiteSpaces += buffer[pos];
+ }
+
+ ++pos;
+ }
+
+ size_t startPos = pos;
+ string unencoded;
+
+ const charset defaultCharset = ctx.getInternationalizedEmailSupport()
+ ? charset(charsets::UTF_8) : charset(charsets::US_ASCII);
+
+ while (pos < end) {
+
+ // End of line: does not occur in the middle of an encoded word. This is
+ // used to remove folding white-spaces from unencoded text.
+ if (buffer[pos] == '\n') {
+
+ size_t endPos = pos;
+
+ if (pos > position && buffer[pos - 1] == '\r') {
+ ++pos;
+ --endPos;
+ }
+
+ while (pos != end && parserHelpers::isSpace(buffer[pos])) {
+ ++pos;
+ }
+
+ unencoded += buffer.substr(startPos, endPos - startPos);
+
+ if (pos != end) { // ignore white-spaces at end
+ unencoded += ' ';
+ }
+
+ startPos = pos;
+ continue;
+
+ // Start of an encoded word
+ } else if (pos + 8 < end && // 8 = "=?(.+)?(.+)?(.*)?="
+ buffer[pos] == '=' && buffer[pos + 1] == '?') {
+
+ // Check whether there is some unencoded text before
+ unencoded += buffer.substr(startPos, pos - startPos);
+
+ if (!unencoded.empty()) {
+
+ if (state->prevIsEncoded && !state->isFirst) {
+ unencoded = whiteSpaces + unencoded;
+ }
+
+ shared_ptr <word> w = make_shared <word>(unencoded, defaultCharset);
+ w->setParsedBounds(position, pos);
+
+ if (newPosition) {
+ *newPosition = pos;
+ }
+
+ state->prevIsEncoded = false;
+ state->isFirst = false;
+
+ return w;
+ }
+
+ // ...else find the finish sequence '?=' and return an encoded word
+ const size_t wordStart = pos;
+
+ pos += 2;
+
+ while (pos < end && buffer[pos] != '?') {
+ ++pos;
+ }
+
+ if (pos < end) {
+
+ ++pos; // skip '?' between charset and encoding
+
+ while (pos < end && buffer[pos] != '?') {
+ ++pos;
+ }
+
+ if (pos < end) {
+ ++pos; // skip '?' between encoding and encoded data
+ }
+ }
+
+ while (pos < end) {
+
+ if (buffer[pos] == '\n') {
+
+ // End of line not allowed in the middle of an encoded word:
+ // treat this text as unencoded text (see *).
+ break;
+
+ } else if (buffer[pos] == '?' && pos + 1 < end && buffer[pos + 1] == '=') {
+
+ // Found the finish sequence
+ break;
+ }
+
+ ++pos;
+ }
+
+ if (pos == end) { // not a valid word (no finish sequence)
+ continue;
+ } else if (buffer[pos] == '\n') { // (*)
+ continue;
+ }
+
+ pos += 2; // ?=
+
+ shared_ptr <word> w = make_shared <word>();
+ w->parseWithState(ctx, buffer, wordStart, pos, NULL, state);
+
+ if (newPosition) {
+ *newPosition = pos;
+ }
+
+ state->prevIsEncoded = true;
+ state->isFirst = false;
+
+ return w;
+ }
+
+ ++pos;
+ }
+
+ if (startPos != end) {
+
+ if (state->prevIsEncoded && !state->isFirst) {
+ unencoded = whiteSpaces + unencoded;
+ }
+
+ unencoded += buffer.substr(startPos, end - startPos);
+ }
+
+ // Treat unencoded text at the end of the buffer
+ if (!unencoded.empty()) {
+
+ shared_ptr <word> w = make_shared <word>(unencoded, defaultCharset);
+ w->setParsedBounds(position, end);
+
+ if (newPosition) {
+ *newPosition = end;
+ }
+
+ state->prevIsEncoded = false;
+ state->isFirst = false;
+
+ return w;
+ }
+
+ return null;
+}
+
+
+const std::vector <shared_ptr <word> > word::parseMultiple(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition
+) {
+
+ std::vector <shared_ptr <word> > res;
+ shared_ptr <word> w;
+
+ size_t pos = position;
+
+ parserState state;
+
+ while ((w = word::parseNext(ctx, buffer, pos, end, &pos, &state))) {
+ res.push_back(w);
+ }
+
+ if (newPosition) {
+ *newPosition = pos;
+ }
+
+ return res;
+}
+
+
+void word::parseImpl(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition
+) {
+
+ parseWithState(ctx, buffer, position, end, newPosition, NULL);
+}
+
+
+void word::parseWithState(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition,
+ parserState* state
+) {
+
+ if (position + 6 < end && // 6 = "=?(.+)?(.*)?="
+ buffer[position] == '=' && buffer[position + 1] == '?') {
+
+ string::const_iterator p = buffer.begin() + position + 2;
+ const string::const_iterator pend = buffer.begin() + end;
+
+ const string::const_iterator charsetPos = p;
+
+ for ( ; p != pend && *p != '?' ; ++p) {}
+
+ if (p != pend) { // a charset is specified
+
+ const string::const_iterator charsetEnd = p;
+ const string::const_iterator encPos = ++p; // skip '?'
+
+ for ( ; p != pend && *p != '?' ; ++p) {}
+
+ if (p != pend) { // an encoding is specified
+
+ //const string::const_iterator encEnd = p;
+ const string::const_iterator dataPos = ++p; // skip '?'
+
+ for ( ; p != pend && !(*p == '?' && *(p + 1) == '=') ; ++p) {}
+
+ if (p != pend) { // some data is specified
+
+ const string::const_iterator dataEnd = p;
+ p += 2; // skip '?='
+
+ scoped_ptr <utility::encoder::encoder> theEncoder;
+
+ // Base-64 encoding
+ if (*encPos == 'B' || *encPos == 'b') {
+
+ theEncoder.reset(new utility::encoder::b64Encoder());
+
+ // Quoted-Printable encoding
+ } else if (*encPos == 'Q' || *encPos == 'q') {
+
+ theEncoder.reset(new utility::encoder::qpEncoder());
+ theEncoder->getProperties()["rfc2047"] = true;
+ }
+
+ if (theEncoder) {
+
+ // Extract charset and language
+ const string charsetAndLang(charsetPos, charsetEnd);
+ const string::size_type asteriskPos = charsetAndLang.find('*');
+
+ if (asteriskPos != string::npos) {
+
+ m_charset = charset(string(charsetAndLang.begin(), charsetAndLang.begin() + asteriskPos));
+ m_lang = string(charsetAndLang.begin() + asteriskPos + 1, charsetAndLang.end());
+
+ } else {
+
+ m_charset = charset(charsetAndLang);
+ m_lang.clear();
+ }
+
+ // Decode text
+ string encodedBuffer(dataPos, dataEnd);
+ string decodedBuffer;
+
+ if (state && !state->undecodedBytes.empty()) {
+
+ encodedBuffer = state->undecodedBytes + encodedBuffer;
+ state->undecodedBytes.clear();
+ }
+
+ utility::inputStreamStringAdapter ein(encodedBuffer);
+ utility::outputStreamStringAdapter eout(decodedBuffer);
+
+ const size_t decodedLen = theEncoder->decode(ein, eout);
+
+ m_buffer = decodedBuffer;
+
+ setParsedBounds(position, p - buffer.begin());
+
+ if (newPosition) {
+ *newPosition = (p - buffer.begin());
+ }
+
+ // For Base64 encoding, ensure all bytes have been decoded.
+ // If there are remaining bytes, keep them for the next run.
+ //
+ // This allows decoding some insanities like:
+ // =?utf-8?B?5Lit5?= =?utf-8?B?paH?=
+ if (*encPos == 'B' || *encPos == 'b') {
+
+ const size_t actualEncodedLen = encodedBuffer.length();
+ const size_t theoricalEncodedLen =
+ ((decodedLen + ((decodedLen % 3) ? (3 - (decodedLen % 3)) : 0) ) / 3) * 4;
+
+ if (state && actualEncodedLen != theoricalEncodedLen) {
+ state->undecodedBytes.assign(dataPos + theoricalEncodedLen, dataEnd);
+ }
+ }
+
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ // Unknown encoding or malformed encoded word: treat the buffer as ordinary text (RFC-2047, Page 9).
+ m_buffer = string(buffer.begin() + position, buffer.begin() + end);
+ m_charset = ctx.getInternationalizedEmailSupport()
+ ? charset(charsets::UTF_8) : charset(charsets::US_ASCII);
+
+ setParsedBounds(position, end);
+
+ if (newPosition) {
+ *newPosition = end;
+ }
+}
+
+
+void word::generateImpl(
+ const generationContext& ctx,
+ utility::outputStream& os,
+ const size_t curLinePos,
+ size_t* newLinePos
+) const {
+
+ generate(ctx, os, curLinePos, newLinePos, 0, NULL);
+}
+
+
+void word::generate(
+ const generationContext& ctx,
+ utility::outputStream& os,
+ const size_t curLinePos,
+ size_t* newLinePos,
+ const int flags,
+ generatorState* state
+) const {
+
+ size_t curLineLength = curLinePos;
+
+ generatorState defaultGeneratorState;
+
+ if (!state) {
+ state = &defaultGeneratorState;
+ }
+
+ // Find out if encoding is forced or required by contents + charset
+ bool encodingNeeded = false;
+
+ if ((flags & text::FORCE_NO_ENCODING) != 0) {
+ encodingNeeded = false;
+ } else if ((flags & text::FORCE_ENCODING) != 0) {
+ encodingNeeded = true;
+ } else { // auto-detect
+ encodingNeeded = wordEncoder::isEncodingNeeded(ctx, m_buffer, m_charset, m_lang);
+ }
+
+ // If text does not need to be encoded, quote the buffer (no folding is performed).
+ if (!encodingNeeded &&
+ (flags & text::QUOTE_IF_NEEDED) &&
+ utility::stringUtils::needQuoting(m_buffer)) {
+
+ const string quoted = utility::stringUtils::quote(m_buffer, "\\\"", "\\");
+
+ os << '"' << quoted << '"';
+ curLineLength += 1 + quoted.length() + 1;
+
+ // If possible and requested (with flag), quote the buffer (no folding is performed).
+ // Quoting is possible if and only if:
+ // - the buffer does not need to be encoded
+ // - the buffer does not contain quoting character (")
+ // - there is enough remaining space on the current line to hold the whole buffer
+ } else if (!encodingNeeded &&
+ (flags & text::QUOTE_IF_POSSIBLE) &&
+ m_buffer.find('"') == string::npos &&
+ (curLineLength + 2 /* 2 x " */ + m_buffer.length()) < ctx.getMaxLineLength()) {
+
+ os << '"' << m_buffer << '"';
+ curLineLength += 2 + m_buffer.length();
+
+ // We will fold lines without encoding them.
+ } else if (!encodingNeeded) {
+
+ string buffer;
+
+ if (ctx.getInternationalizedEmailSupport()) {
+
+ // Convert the buffer to UTF-8
+ charset::convert(m_buffer, buffer, m_charset, charsets::UTF_8);
+
+ } else {
+
+ // Leave the buffer as-is
+ buffer = m_buffer;
+ }
+
+ // Here, we could have the following conditions:
+ //
+ // * a maximum line length of N bytes
+ // * a buffer containing N+1 bytes, with no whitespace
+ //
+ // Look in the buffer for any run (ie. whitespace-separated sequence) which
+ // is longer than the maximum line length. If there is one, then force encoding,
+ // so that no generated line is longer than the maximum line length.
+ size_t maxRunLength = 0;
+ size_t curRunLength = 0;
+
+ for (string::const_iterator p = buffer.begin(), end = buffer.end() ; p != end ; ++p) {
+
+ if (parserHelpers::isSpace(*p)) {
+
+ maxRunLength = std::max(maxRunLength, curRunLength);
+ curRunLength = 0;
+
+ } else {
+
+ curRunLength++;
+ }
+ }
+
+ maxRunLength = std::max(maxRunLength, curRunLength);
+
+ if (((flags & text::FORCE_NO_ENCODING) == 0) && maxRunLength >= ctx.getMaxLineLength() - 3) {
+
+ // Generate with encoding forced
+ generate(ctx, os, curLinePos, newLinePos, flags | text::FORCE_ENCODING, state);
+ return;
+ }
+
+ // Output runs, and fold line when a whitespace is encountered
+ string::const_iterator lastWSpos = buffer.end(); // last white-space position
+ string::const_iterator curLineStart = buffer.begin(); // current line start
+
+ string::const_iterator p = buffer.begin();
+ const string::const_iterator end = buffer.end();
+
+ bool finished = false;
+ bool newLine = false;
+
+ while (!finished) {
+
+ for ( ; p != end ; ++p, ++curLineLength) {
+
+ // Exceeded maximum line length, but we have found a white-space
+ // where we can cut the line...
+ if (curLineLength >= ctx.getMaxLineLength() && lastWSpos != end) {
+ break;
+ }
+
+ if (*p == ' ' || *p == '\t') {
+ // Remember the position of this white-space character
+ lastWSpos = p;
+ }
+ }
+
+ if (p != end) {
+ ++curLineLength;
+ }
+
+ if (p == end || lastWSpos == end) {
+
+ // If we are here, it means that we have found no whitespace
+ // before the first "maxLineLength" characters. In this case,
+ // we write the full line no matter of the max line length...
+
+ if (!newLine && p != end && lastWSpos == end &&
+ !state->isFirstWord && curLineStart == buffer.begin()) {
+
+ // Here, we are continuing on the line of previous encoded
+ // word, but there is not even enough space to put the
+ // first word of this line, so we start a new line.
+ if (flags & text::NO_NEW_LINE_SEQUENCE) {
+
+ os << CRLF;
+ curLineLength = 0;
+
+ state->lastCharIsSpace = true;
+
+ } else {
+
+ os << NEW_LINE_SEQUENCE;
+ curLineLength = NEW_LINE_SEQUENCE_LENGTH;
+
+ state->lastCharIsSpace = true;
+ }
+
+ p = curLineStart;
+ lastWSpos = end;
+ newLine = true;
+
+ } else {
+
+ if (!state->isFirstWord &&
+ (state->prevWordIsEncoded || ctx.getInternationalizedEmailSupport()) &&
+ !state->lastCharIsSpace &&
+ !parserHelpers::isSpace(*curLineStart)) {
+
+ os << " "; // Separate from previous word
+ }
+
+ os << string(curLineStart, p);
+
+ if (p != buffer.begin() && parserHelpers::isSpace(*(p - 1))) {
+ state->lastCharIsSpace = true;
+ } else {
+ state->lastCharIsSpace = false;
+ }
+
+ if (p == end) {
+
+ finished = true;
+
+ } else {
+
+ if (flags & text::NO_NEW_LINE_SEQUENCE) {
+
+ os << CRLF;
+ curLineLength = 0;
+
+ } else {
+
+ os << NEW_LINE_SEQUENCE;
+ curLineLength = NEW_LINE_SEQUENCE_LENGTH;
+ }
+
+ curLineStart = p;
+ lastWSpos = end;
+ newLine = true;
+ }
+ }
+
+ } else {
+
+ // In this case, there will not be enough space on the line for all the
+ // characters _after_ the last white-space; so we cut the line at this
+ // last white-space.
+
+ if (curLineLength != NEW_LINE_SEQUENCE_LENGTH &&
+ !state->isFirstWord &&
+ state->prevWordIsEncoded) {
+
+ os << " "; // Separate from previous word
+ }
+
+ os << string(curLineStart, lastWSpos);
+
+ if (lastWSpos > curLineStart && parserHelpers::isSpace(*(lastWSpos - 1))) {
+ state->lastCharIsSpace = true;
+ } else {
+ state->lastCharIsSpace = false;
+ }
+
+ if (flags & text::NO_NEW_LINE_SEQUENCE) {
+
+ os << CRLF;
+ curLineLength = 0;
+
+ state->lastCharIsSpace = true;
+
+ } else {
+
+ os << NEW_LINE_SEQUENCE;
+ curLineLength = NEW_LINE_SEQUENCE_LENGTH;
+
+ state->lastCharIsSpace = true;
+ }
+
+ curLineStart = lastWSpos + 1;
+
+ p = lastWSpos + 1;
+ lastWSpos = end;
+ newLine = true;
+ }
+ }
+
+ /*
+ RFC #2047:
+ 4. Encodings
+
+ Initially, the legal values for "encoding" are "Q" and "B". These
+ encodings are described below. The "Q" encoding is recommended for
+ use when most of the characters to be encoded are in the ASCII
+ character set; otherwise, the "B" encoding should be used.
+ Nevertheless, a mail reader which claims to recognize 'encoded-word's
+ MUST be able to accept either encoding for any character set which it
+ supports.
+ */
+ } else {
+
+ // We will encode _AND_ fold lines
+
+ /*
+ RFC #2047:
+ 2. Syntax of encoded-words
+
+ " While there is no limit to the length of a multiple-line header
+ field, each line of a header field that contains one or more
+ 'encoded-word's is limited to 76 characters. "
+ */
+
+ const size_t maxLineLength3 =
+ (ctx.getMaxLineLength() == lineLengthLimits::infinite)
+ ? ctx.getMaxLineLength()
+ : std::min(ctx.getMaxLineLength(), static_cast <size_t>(76));
+
+ wordEncoder wordEnc(m_buffer, m_charset);
+
+ const string wordStart("=?"
+ + m_charset.getName()
+ + (m_lang.empty() ? "" : string("*") + m_lang)
+ + "?"
+ + (wordEnc.getEncoding() == wordEncoder::ENCODING_B64 ? 'B' : 'Q')
+ + "?");
+ const string wordEnd("?=");
+
+ const size_t minWordLength = wordStart.length() + wordEnd.length();
+ const size_t maxLineLength2 = (maxLineLength3 < minWordLength + 1)
+ ? maxLineLength3 + minWordLength + 1 : maxLineLength3;
+
+ // Checks whether remaining space on this line is usable. If too few
+ // characters can be encoded, start a new line.
+ bool startNewLine = true;
+
+ if (curLineLength + 2 < maxLineLength2) {
+
+ const size_t remainingSpaceOnLine = maxLineLength2 - curLineLength - 2;
+
+ if (remainingSpaceOnLine < minWordLength + 10) {
+
+ // Space for no more than 10 encoded chars!
+ // It is not worth while to continue on this line...
+ startNewLine = true;
+
+ } else {
+
+ // OK, there is enough usable space on the current line.
+ startNewLine = false;
+ }
+ }
+
+ if (startNewLine) {
+
+ os << NEW_LINE_SEQUENCE;
+ curLineLength = NEW_LINE_SEQUENCE_LENGTH;
+
+ state->lastCharIsSpace = true;
+ }
+
+ // Encode and fold input buffer
+ if (!startNewLine && !state->isFirstWord && !state->lastCharIsSpace) {
+
+ os << " "; // Separate from previous word
+ ++curLineLength;
+
+ state->lastCharIsSpace = true;
+ }
+
+ for (unsigned int i = 0 ; ; ++i) {
+
+ // Compute the number of encoded chars that will fit on this line
+ const size_t fit = maxLineLength2 - minWordLength
+ - (i == 0 ? curLineLength : NEW_LINE_SEQUENCE_LENGTH);
+
+ // Get the next encoded chunk
+ const string chunk = wordEnc.getNextChunk(fit);
+
+ if (chunk.empty()) {
+ break;
+ }
+
+ // Start a new encoded word
+ if (i != 0) {
+
+ os << NEW_LINE_SEQUENCE;
+ curLineLength = NEW_LINE_SEQUENCE_LENGTH;
+ }
+
+ os << wordStart;
+ curLineLength += minWordLength;
+
+ os << chunk;
+ curLineLength += chunk.length();
+
+ // End of the encoded word
+ os << wordEnd;
+
+ state->prevWordIsEncoded = true;
+ state->lastCharIsSpace = false;
+ }
+ }
+
+ if (newLinePos) {
+ *newLinePos = curLineLength;
+ }
+
+ state->isFirstWord = false;
+}
+
+
+word& word::operator=(const word& w) {
+
+ m_buffer = w.m_buffer;
+ m_charset = w.m_charset;
+ m_lang = w.m_lang;
+
+ return *this;
+}
+
+
+word& word::operator=(const string& s) {
+
+ m_buffer = s;
+ m_charset = charset::getLocalCharset();
+ m_lang.clear();
+
+ return *this;
+}
+
+
+void word::copyFrom(const component& other) {
+
+ const word& w = dynamic_cast <const word&>(other);
+
+ m_buffer = w.m_buffer;
+ m_charset = w.m_charset;
+ m_lang = w.m_lang;
+}
+
+
+bool word::operator==(const word& w) const {
+
+ return m_charset == w.m_charset && m_buffer == w.m_buffer && m_lang == w.m_lang;
+}
+
+
+bool word::operator!=(const word& w) const {
+
+ return m_charset != w.m_charset || m_buffer != w.m_buffer || m_lang != w.m_lang;
+}
+
+
+bool word::isEquivalent(const word& other) const {
+
+ return getConvertedText(charset(charsets::UTF_8)) == other.getConvertedText(charset(charsets::UTF_8));
+}
+
+
+const string word::getConvertedText(
+ const charset& dest,
+ const charsetConverterOptions& opts
+) const {
+
+ if (dest == m_charset) {
+ return m_buffer; // no conversion needed
+ }
+
+ string out;
+
+ try {
+
+ charset::convert(m_buffer, out, m_charset, dest, opts);
+
+ } catch (vmime::exceptions::charset_conv_error& e) {
+
+ // Do not fail if charset is not recognized:
+ // copy 'word' as raw text
+ out = m_buffer;
+ }
+
+ return out;
+}
+
+
+shared_ptr <component> word::clone() const {
+
+ return make_shared <word>(m_buffer, m_charset);
+}
+
+
+const charset& word::getCharset() const {
+
+ return m_charset;
+}
+
+
+void word::setCharset(const charset& ch) {
+
+ m_charset = ch;
+}
+
+
+const string word::getLanguage() const {
+
+ return m_lang;
+}
+
+
+void word::setLanguage(const string& lang) {
+
+ m_lang = lang;
+}
+
+
+const string& word::getBuffer() const {
+
+ return m_buffer;
+}
+
+
+string& word::getBuffer() {
+
+ return m_buffer;
+}
+
+
+bool word::isEmpty() const {
+
+ return m_buffer.empty();
+}
+
+
+void word::setBuffer(const string& buffer) {
+
+ m_buffer = buffer;
+}
+
+
+const std::vector <shared_ptr <component> > word::getChildComponents() {
+
+ return std::vector <shared_ptr <component> >();
+}
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/word.hpp b/vmime-master/src/vmime/word.hpp
new file mode 100644
index 0000000..1565a0b
--- /dev/null
+++ b/vmime-master/src/vmime/word.hpp
@@ -0,0 +1,272 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_WORD_HPP_INCLUDED
+#define VMIME_WORD_HPP_INCLUDED
+
+
+#include "vmime/headerFieldValue.hpp"
+#include "vmime/charset.hpp"
+#include "vmime/charsetConverterOptions.hpp"
+
+
+namespace vmime {
+
+
+/** A class that encapsulates an encoded-word (RFC-2047):
+ * some text encoded into one specified charset.
+ */
+class VMIME_EXPORT word : public headerFieldValue {
+
+ friend class text;
+
+public:
+
+ /** Construct an empty word.
+ * Charset is set to the current locale charset.
+ */
+ word();
+
+ /** Construct a word by copying another word.
+ */
+ word(const word& w);
+
+ /** Construct a word using a string buffer.
+ * Charset is set to the current locale charset.
+ */
+ explicit word(const string& buffer);
+
+ /** Construct a word using a string buffer and a specified charset.
+ *
+ * @param buffer string buffer
+ * @param charset charset in which the string is encoded
+ */
+ word(const string& buffer, const charset& charset);
+
+ /** Construct a word using a string buffer and a specified charset
+ * and language tag (RFC-1766).
+ *
+ * @param buffer string buffer
+ * @param charset charset in which the string is encoded
+ * @param lang language tag, in the format specified by RFC-1766
+ */
+ word(const string& buffer, const charset& charset, const string& lang);
+
+ /** Return the raw data for this encoded word.
+ *
+ * @return raw data buffer
+ */
+ const string& getBuffer() const;
+
+ /** Return the raw data for this encoded word.
+ *
+ * @return raw data buffer
+ */
+ string& getBuffer();
+
+ /** Tests whether this word is empty.
+ *
+ * @return true if the buffer is empty, false otherwise
+ */
+ bool isEmpty() const;
+
+ /** Set the raw data for this encoded word.
+ *
+ * @param buffer raw data buffer
+ */
+ void setBuffer(const string& buffer);
+
+ /** Return the charset of this word.
+ *
+ * @return charset for this word
+ */
+ const charset& getCharset() const;
+
+ /** Set the charset of this word.
+ *
+ * @param ch charset of this word
+ */
+ void setCharset(const charset& ch);
+
+ /** Return the language used in this word (optional).
+ * If not specified, the value is empty.
+ *
+ * @return language tag for this word, in the format specified
+ * by RFC-1766
+ */
+ const string getLanguage() const;
+
+ /** Set the language used in this word (optional).
+ *
+ * @param lang language tag, in the format specified by RFC-1766
+ */
+ void setLanguage(const string& lang);
+
+ /** Returns whether two words actually represent the same text,
+ * regardless of their charset.
+ *
+ * @param other word to compare to
+ * @return true if the two words represent the same text, or false otherwise
+ */
+ bool isEquivalent(const word& other) const;
+
+
+ word& operator=(const word& w);
+ word& operator=(const string& s);
+
+ bool operator==(const word& w) const;
+ bool operator!=(const word& w) const;
+
+ /** Return the contained text converted to the specified charset.
+ *
+ * @param dest output charset
+ * @param opts options for charset conversion
+ * @return word converted to the specified charset
+ */
+ const string getConvertedText(
+ const charset& dest,
+ const charsetConverterOptions& opts = charsetConverterOptions()
+ ) const;
+
+ /** Replace data in this word by data in other word.
+ *
+ * @param other other word to copy data from
+ */
+ void copyFrom(const component& other);
+
+ /** Clone this word.
+ *
+ * @return a copy of this word
+ */
+ shared_ptr <component> clone() const;
+
+
+#ifndef VMIME_BUILDING_DOC
+ class generatorState {
+
+ public:
+
+ generatorState()
+ : isFirstWord(true),
+ prevWordIsEncoded(false),
+ lastCharIsSpace(false) {
+
+ }
+
+ bool isFirstWord;
+ bool prevWordIsEncoded;
+ bool lastCharIsSpace;
+ };
+
+ class parserState {
+
+ public:
+
+ parserState()
+ : prevIsEncoded(false),
+ isFirst(true) {
+
+ }
+
+ bool prevIsEncoded;
+ bool isFirst;
+ std::string undecodedBytes;
+ };
+#endif
+
+
+protected:
+
+ void parseImpl(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition = NULL
+ );
+
+ void generateImpl(
+ const generationContext& ctx,
+ utility::outputStream& os,
+ const size_t curLinePos = 0,
+ size_t* newLinePos = NULL
+ ) const;
+
+ void parseWithState(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition,
+ parserState* state
+ );
+
+public:
+
+ using component::generate;
+
+#ifndef VMIME_BUILDING_DOC
+ void generate(
+ const generationContext& ctx,
+ utility::outputStream& os,
+ const size_t curLinePos,
+ size_t* newLinePos,
+ const int flags,
+ generatorState* state
+ ) const;
+#endif
+
+ const std::vector <shared_ptr <component> > getChildComponents();
+
+private:
+
+ static shared_ptr <word> parseNext(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition,
+ parserState* state
+ );
+
+ static const std::vector <shared_ptr <word> > parseMultiple(
+ const parsingContext& ctx,
+ const string& buffer,
+ const size_t position,
+ const size_t end,
+ size_t* newPosition
+ );
+
+
+ // The "m_buffer" of this word holds the data, and this data is encoded
+ // in the specified "m_charset".
+ string m_buffer;
+ charset m_charset;
+ string m_lang;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_WORD_HPP_INCLUDED
diff --git a/vmime-master/src/vmime/wordEncoder.cpp b/vmime-master/src/vmime/wordEncoder.cpp
new file mode 100644
index 0000000..4f47d04
--- /dev/null
+++ b/vmime-master/src/vmime/wordEncoder.cpp
@@ -0,0 +1,320 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/wordEncoder.hpp"
+
+#include "vmime/exception.hpp"
+#include "vmime/charsetConverter.hpp"
+
+#include "vmime/encoding.hpp"
+
+#include "vmime/utility/encoder/b64Encoder.hpp"
+#include "vmime/utility/encoder/qpEncoder.hpp"
+
+#include "vmime/utility/stringUtils.hpp"
+
+#include "vmime/utility/outputStreamStringAdapter.hpp"
+#include "vmime/utility/inputStreamStringAdapter.hpp"
+
+
+namespace vmime {
+
+
+wordEncoder::wordEncoder(
+ const string& buffer,
+ const charset& charset,
+ const Encoding encoding
+)
+ : m_buffer(buffer),
+ m_pos(0),
+ m_length(buffer.length()),
+ m_charset(charset),
+ m_encoding(encoding) {
+
+ try {
+
+ string utf8Buffer;
+
+ vmime::charset::convert(
+ buffer, utf8Buffer, charset, vmime::charset(charsets::UTF_8)
+ );
+
+ m_buffer = utf8Buffer;
+ m_length = utf8Buffer.length();
+
+ m_simple = false;
+
+ } catch (exceptions::charset_conv_error&) {
+
+ // Ignore exception.
+ // We will fall back on simple encoding.
+ m_simple = true;
+ }
+
+ if (m_encoding == ENCODING_AUTO) {
+ m_encoding = guessBestEncoding(buffer, charset);
+ }
+
+ if (m_encoding == ENCODING_B64) {
+
+ m_encoder = make_shared <utility::encoder::b64Encoder>();
+
+ } else { // ENCODING_QP
+
+ m_encoder = make_shared <utility::encoder::qpEncoder>();
+ m_encoder->getProperties()["rfc2047"] = true;
+ }
+}
+
+
+static size_t getUTF8CharLength(
+ const string& buffer,
+ const size_t pos,
+ const size_t length
+) {
+
+ // Gives the number of extra bytes in a UTF8 char, given the leading char
+ static const unsigned char UTF8_EXTRA_BYTES[256] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5
+ };
+
+ const unsigned char c = buffer[pos];
+ const unsigned char n = UTF8_EXTRA_BYTES[c];
+
+ if (n < length - pos) {
+ return n + 1;
+ } else {
+ return 1;
+ }
+}
+
+
+const string wordEncoder::getNextChunk(const size_t maxLength) {
+
+ const size_t remaining = m_length - m_pos;
+
+ if (remaining == 0) {
+ return string();
+ }
+
+ vmime::string chunk;
+ vmime::utility::outputStreamStringAdapter chunkStream(chunk);
+
+ // Simple encoding
+ if (m_simple) {
+
+ // WARNING! Simple encoding can encode a non-integral number of
+ // characters and then may generate incorrectly-formed words!
+
+ if (m_encoding == ENCODING_B64) {
+
+ // Here, we have a formula to compute the maximum number of source
+ // bytes to encode knowing the maximum number of encoded chars. In
+ // Base64 encoding, 3 bytes of input provide 4 bytes of output.
+ const size_t inputCount =
+ std::min(remaining, (maxLength > 1) ? ((maxLength - 1) * 3) / 4 : 1);
+
+ // Encode chunk
+ utility::inputStreamStringAdapter in(m_buffer, m_pos, m_pos + inputCount);
+
+ m_encoder->encode(in, chunkStream);
+ m_pos += inputCount;
+
+ } else { // ENCODING_QP
+
+ // Compute exactly how much input bytes are needed to have an output
+ // string length of less than 'maxLength' bytes. In Quoted-Printable
+ // encoding, encoded bytes take 3 bytes.
+ size_t inputCount = 0;
+ size_t outputCount = 0;
+
+ while ((inputCount == 0 || outputCount < maxLength) && (inputCount < remaining)) {
+
+ const unsigned char c = m_buffer[m_pos + inputCount];
+
+ inputCount++;
+ outputCount += utility::encoder::qpEncoder::RFC2047_getEncodedLength(c);
+ }
+
+ // Encode chunk
+ utility::inputStreamStringAdapter in(m_buffer, m_pos, m_pos + inputCount);
+
+ m_encoder->encode(in, chunkStream);
+ m_pos += inputCount;
+ }
+
+ // Fully RFC-compliant encoding
+ } else {
+
+ shared_ptr <charsetConverter> conv = charsetConverter::create(charsets::UTF_8, m_charset);
+
+ size_t inputCount = 0;
+ size_t outputCount = 0;
+ string encodeBuffer;
+
+ while ((inputCount == 0 || outputCount < maxLength) && (inputCount < remaining)) {
+
+ // Get the next UTF8 character
+ const size_t inputCharLength =
+ getUTF8CharLength(m_buffer, m_pos + inputCount, m_length);
+
+ const string inputChar(
+ m_buffer.begin() + m_pos + inputCount,
+ m_buffer.begin() + m_pos + inputCount + inputCharLength
+ );
+
+ // Convert back to original encoding
+ string encodeBytes;
+ conv->convert(inputChar, encodeBytes);
+
+ encodeBuffer += encodeBytes;
+
+ // Compute number of output bytes
+ if (m_encoding == ENCODING_B64) {
+
+ outputCount = std::max(
+ static_cast <size_t>(4),
+ (encodeBuffer.length() * 4) / 3
+ );
+
+ } else { // ENCODING_QP
+
+ for (size_t i = 0, n = encodeBytes.length() ; i < n ; ++i) {
+
+ const unsigned char c = encodeBytes[i];
+ outputCount += utility::encoder::qpEncoder::RFC2047_getEncodedLength(c);
+ }
+ }
+
+ inputCount += inputCharLength;
+ }
+
+ // Encode chunk
+ utility::inputStreamStringAdapter in(encodeBuffer);
+
+ m_encoder->encode(in, chunkStream);
+ m_pos += inputCount;
+ }
+
+ return chunk;
+}
+
+
+wordEncoder::Encoding wordEncoder::getEncoding() const {
+
+ return m_encoding;
+}
+
+
+// static
+bool wordEncoder::isEncodingNeeded(
+ const generationContext& ctx,
+ const string& buffer,
+ const charset& charset,
+ const string& lang
+) {
+
+ if (!ctx.getInternationalizedEmailSupport()) {
+
+ // Charset-specific encoding
+ encoding recEncoding;
+
+ if (charset.getRecommendedEncoding(recEncoding)) {
+ return true;
+ }
+
+ // No encoding is needed if the buffer only contains ASCII chars
+ if (utility::stringUtils::findFirstNonASCIIchar(buffer.begin(), buffer.end()) != string::npos) {
+ return true;
+ }
+ }
+
+ // Force encoding when there are only ASCII chars, but there is
+ // also at least one of '\n' or '\r' (header fields)
+ if (buffer.find_first_of("\n\r") != string::npos) {
+ return true;
+ }
+
+ // If any RFC-2047 sequence is found in the buffer, encode it
+ if (buffer.find("=?") != string::npos || buffer.find("?=") != string::npos) {
+ return true;
+ }
+
+ // If a language is specified, force encoding
+ if (!lang.empty()) {
+ return true;
+ }
+
+ return false;
+}
+
+
+// static
+wordEncoder::Encoding wordEncoder::guessBestEncoding(
+ const string& buffer,
+ const charset& charset
+) {
+
+ // Charset-specific encoding
+ encoding recEncoding;
+
+ if (charset.getRecommendedEncoding(recEncoding)) {
+
+ if (recEncoding == encoding(encodingTypes::QUOTED_PRINTABLE)) {
+ return ENCODING_QP;
+ } else {
+ return ENCODING_B64;
+ }
+ }
+
+ // Use Base64 if more than 40% non-ASCII, or Quoted-Printable else (default)
+ const size_t asciiCount =
+ utility::stringUtils::countASCIIchars(buffer.begin(), buffer.end());
+
+ const size_t asciiPercent =
+ buffer.length() == 0 ? 100 : (100 * asciiCount) / buffer.length();
+
+ if (asciiPercent < 60) {
+ return ENCODING_B64;
+ } else {
+ return ENCODING_QP;
+ }
+}
+
+
+} // vmime
diff --git a/vmime-master/src/vmime/wordEncoder.hpp b/vmime-master/src/vmime/wordEncoder.hpp
new file mode 100644
index 0000000..e37bbe7
--- /dev/null
+++ b/vmime-master/src/vmime/wordEncoder.hpp
@@ -0,0 +1,118 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#ifndef VMIME_WORDENCODER_HPP_INCLUDED
+#define VMIME_WORDENCODER_HPP_INCLUDED
+
+
+#include "vmime/charset.hpp"
+
+
+namespace vmime {
+
+
+namespace utility {
+namespace encoder {
+
+class encoder;
+
+} // encoder
+} // utility
+
+
+/** Encodes words according to RFC-2047.
+ */
+class VMIME_EXPORT wordEncoder {
+
+public:
+
+ /** Available encodings for RFC-2047. */
+ enum Encoding {
+ ENCODING_AUTO,
+ ENCODING_QP,
+ ENCODING_B64
+ };
+
+
+ wordEncoder(
+ const string& buffer,
+ const charset& charset,
+ const Encoding encoding = ENCODING_AUTO
+ );
+
+
+ /** Return the next chunk in the word.
+ *
+ * @param maxLength maximal length of the chunk
+ * @return next chunk, of maximal length 'maxLength' if possible
+ */
+ const string getNextChunk(const size_t maxLength);
+
+ /** Return the encoding used.
+ *
+ * @return encoding
+ */
+ Encoding getEncoding() const;
+
+ /** Test whether RFC-2047 encoding is needed.
+ *
+ * @param ctx generation context
+ * @param buffer buffer to analyze
+ * @param charset charset of the buffer
+ * @param lang language code, in the format specified by RFC-1766
+ * @return true if encoding is needed, false otherwise.
+ */
+ static bool isEncodingNeeded(
+ const generationContext& ctx,
+ const string& buffer,
+ const charset& charset,
+ const string& lang
+ );
+
+ /** Guess the best RFC-2047 encoding to use for the specified buffer.
+ *
+ * @param buffer buffer to analyze
+ * @param charset charset of the buffer
+ * @return RFC-2047 encoding
+ */
+ static Encoding guessBestEncoding(const string& buffer, const charset& charset);
+
+private:
+
+ string m_buffer;
+ size_t m_pos;
+ size_t m_length;
+
+ bool m_simple;
+
+ charset m_charset;
+ Encoding m_encoding;
+
+ shared_ptr <utility::encoder::encoder> m_encoder;
+};
+
+
+} // vmime
+
+
+#endif // VMIME_WORDENCODER_HPP_INCLUDED
diff --git a/vmime-master/test-outsourced-build.sh b/vmime-master/test-outsourced-build.sh
new file mode 100755
index 0000000..ac07288
--- /dev/null
+++ b/vmime-master/test-outsourced-build.sh
@@ -0,0 +1,12 @@
+#!/bin/bash
+rm -rf _build _install
+mkdir _build _install
+cd _build
+rm -f ../CMakeCache.txt ../src/vmime/config.hpp ../src/vmime/export-static.hpp ../src/vmime/export-shared.hpp
+#cmake .. -DCMAKE_INSTALL_PREFIX=../_install -DVMIME_BUILD_SHARED_LIBRARY=NO
+#cmake .. -DCMAKE_INSTALL_PREFIX=../_install -DVMIME_BUILD_TESTS=YES
+cmake .. -DCMAKE_INSTALL_PREFIX=../_install -DVMIME_BUILD_TESTS=YES -DVMIME_BUILD_SAMPLES=YES -DVMIME_TLS_SUPPORT_LIB=openssl -DCMAKE_BUILD_TYPE=Debug
+cmake .. -L
+make
+make install
+
diff --git a/vmime-master/tests/misc/importanceHelperTest.cpp b/vmime-master/tests/misc/importanceHelperTest.cpp
new file mode 100644
index 0000000..d04d730
--- /dev/null
+++ b/vmime-master/tests/misc/importanceHelperTest.cpp
@@ -0,0 +1,191 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/misc/importanceHelper.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(importanceHelperTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testResetImportance)
+
+ VMIME_TEST(testSetImportance1)
+ VMIME_TEST(testSetImportance2)
+ VMIME_TEST(testSetImportance3)
+ VMIME_TEST(testSetImportance4)
+ VMIME_TEST(testSetImportance5)
+
+ VMIME_TEST(testGetImportance1)
+ VMIME_TEST(testGetImportance2)
+ VMIME_TEST(testGetImportance3)
+ VMIME_TEST(testGetImportance4)
+ VMIME_TEST(testGetImportance5)
+ VMIME_TEST_LIST_END
+
+
+ // resetImportance
+
+ void testResetImportance() {
+
+ vmime::shared_ptr <vmime::header> hdr = vmime::make_shared <vmime::header>();
+
+ hdr->getField("Importance")->setValue("xxx");
+ hdr->getField("X-Priority")->setValue("yyy");
+
+ VASSERT_NO_THROW("1", hdr->findField("Importance"));
+ VASSERT_NO_THROW("2", hdr->findField("X-Priority"));
+
+ vmime::misc::importanceHelper::resetImportanceHeader(hdr);
+
+ VASSERT_NULL("3", hdr->findField("Importance"));
+ VASSERT_NULL("4", hdr->findField("X-Priority"));
+ }
+
+
+ // setImportance
+
+ void testSetImportanceImpl(
+ const vmime::misc::importanceHelper::Importance i,
+ const std::string& ImportanceValue,
+ const std::string& XPriorityValue
+ ) {
+
+ vmime::shared_ptr <vmime::header> hdr = vmime::make_shared <vmime::header>();
+
+ vmime::misc::importanceHelper::setImportanceHeader(hdr, i);
+
+ VASSERT_NO_THROW("1", hdr->findField("Importance"));
+ VASSERT_EQ("2", ImportanceValue, hdr->findField("Importance")->getValue()->generate());
+
+ VASSERT_NO_THROW("3", hdr->findField("X-Priority"));
+ VASSERT_EQ("4", XPriorityValue, hdr->findField("X-Priority")->getValue()->generate());
+ }
+
+ void testSetImportance1() {
+
+ testSetImportanceImpl(
+ vmime::misc::importanceHelper::IMPORTANCE_HIGHEST,
+ "high", "1 (Highest)"
+ );
+ }
+
+ void testSetImportance2() {
+
+ testSetImportanceImpl(
+ vmime::misc::importanceHelper::IMPORTANCE_HIGH,
+ "high", "2 (High)"
+ );
+ }
+
+ void testSetImportance3() {
+
+ testSetImportanceImpl(
+ vmime::misc::importanceHelper::IMPORTANCE_NORMAL,
+ "normal", "3 (Normal)"
+ );
+ }
+
+ void testSetImportance4() {
+
+ testSetImportanceImpl(
+ vmime::misc::importanceHelper::IMPORTANCE_LOW,
+ "low", "4 (Low)"
+ );
+ }
+
+ void testSetImportance5() {
+
+ testSetImportanceImpl(
+ vmime::misc::importanceHelper::IMPORTANCE_LOWEST,
+ "low", "5 (Lowest)"
+ );
+ }
+
+
+ // getImportance
+
+ void testGetImportanceImpl(
+ const vmime::misc::importanceHelper::Importance i1,
+ const vmime::misc::importanceHelper::Importance i2,
+ const std::string& ImportanceValue,
+ const std::string& XPriorityValue
+ ) {
+
+ vmime::shared_ptr <vmime::header> hdr1 = vmime::make_shared <vmime::header>();
+
+ hdr1->getField("Importance")->setValue(ImportanceValue);
+ VASSERT_EQ("1", i1, vmime::misc::importanceHelper::getImportanceHeader(hdr1));
+
+ vmime::shared_ptr <vmime::header> hdr2 = vmime::make_shared <vmime::header>();
+
+ hdr2->getField("X-Priority")->setValue(XPriorityValue);
+ VASSERT_EQ("2", i2, vmime::misc::importanceHelper::getImportanceHeader(hdr2));
+ }
+
+ void testGetImportance1() {
+
+ testGetImportanceImpl(
+ vmime::misc::importanceHelper::IMPORTANCE_HIGHEST,
+ vmime::misc::importanceHelper::IMPORTANCE_HIGHEST,
+ "high", "1 (Highest)");
+ }
+
+ void testGetImportance2() {
+
+ testGetImportanceImpl(
+ vmime::misc::importanceHelper::IMPORTANCE_HIGHEST,
+ vmime::misc::importanceHelper::IMPORTANCE_HIGH,
+ "high", "2 (High)"
+ );
+ }
+
+ void testGetImportance3() {
+
+ testGetImportanceImpl(
+ vmime::misc::importanceHelper::IMPORTANCE_NORMAL,
+ vmime::misc::importanceHelper::IMPORTANCE_NORMAL,
+ "normal", "3 (Normal)"
+ );
+ }
+
+ void testGetImportance4() {
+
+ testGetImportanceImpl(
+ vmime::misc::importanceHelper::IMPORTANCE_LOWEST,
+ vmime::misc::importanceHelper::IMPORTANCE_LOW,
+ "low", "4 (Low)"
+ );
+ }
+
+ void testGetImportance5() {
+
+ testGetImportanceImpl(
+ vmime::misc::importanceHelper::IMPORTANCE_LOWEST,
+ vmime::misc::importanceHelper::IMPORTANCE_LOWEST,
+ "low", "5 (Lowest)"
+ );
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/net/folderAttributesTest.cpp b/vmime-master/tests/net/folderAttributesTest.cpp
new file mode 100644
index 0000000..da0e025
--- /dev/null
+++ b/vmime-master/tests/net/folderAttributesTest.cpp
@@ -0,0 +1,137 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/net/folderAttributes.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(folderAttributesTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testConstruct)
+ VMIME_TEST(testConstructCopy)
+ VMIME_TEST(testSetType)
+ VMIME_TEST(testSetFlags)
+ VMIME_TEST(testHasFlag)
+ VMIME_TEST(testSetUserFlags)
+ VMIME_TEST(testHasUserFlag)
+ VMIME_TEST(testSetSpecialUse)
+ VMIME_TEST_LIST_END
+
+
+ void testConstruct() {
+
+ vmime::net::folderAttributes attr;
+
+ // Default values
+ VASSERT_EQ("type", vmime::net::folderAttributes::TYPE_CONTAINS_FOLDERS
+ | vmime::net::folderAttributes::TYPE_CONTAINS_MESSAGES, attr.getType());
+ VASSERT_EQ("flags", 0, attr.getFlags());
+ VASSERT_EQ("user-flags", 0, attr.getUserFlags().size());
+ VASSERT_EQ("special-use", vmime::net::folderAttributes::SPECIALUSE_NONE, attr.getSpecialUse());
+ }
+
+ void testConstructCopy() {
+
+ std::vector <vmime::string> userFlags;
+ userFlags.push_back("\\XMyFlag1");
+ userFlags.push_back("\\XMyFlag2");
+ userFlags.push_back("\\XMyFlag3");
+
+ vmime::net::folderAttributes attr;
+
+ attr.setFlags(vmime::net::folderAttributes::FLAG_HAS_CHILDREN);
+ attr.setUserFlags(userFlags);
+
+ vmime::net::folderAttributes attr2(attr);
+
+ VASSERT("flags", attr2.getFlags() == attr.getFlags());
+ VASSERT("user-flags", attr2.getUserFlags() == attr.getUserFlags());
+ }
+
+ void testSetType() {
+
+ vmime::net::folderAttributes attr;
+ attr.setType(vmime::net::folderAttributes::TYPE_CONTAINS_FOLDERS);
+
+ VASSERT_EQ("eq", vmime::net::folderAttributes::TYPE_CONTAINS_FOLDERS, attr.getType());
+ }
+
+ void testSetFlags() {
+
+ vmime::net::folderAttributes attr;
+ attr.setFlags(vmime::net::folderAttributes::FLAG_HAS_CHILDREN);
+
+ VASSERT_EQ("eq", vmime::net::folderAttributes::FLAG_HAS_CHILDREN, attr.getFlags());
+ }
+
+ void testHasFlag() {
+
+ vmime::net::folderAttributes attr;
+ attr.setFlags(vmime::net::folderAttributes::FLAG_HAS_CHILDREN);
+
+ VASSERT("has", attr.hasFlag(vmime::net::folderAttributes::FLAG_HAS_CHILDREN));
+ VASSERT("has-not", !attr.hasFlag(vmime::net::folderAttributes::FLAG_NO_OPEN));
+ }
+
+ void testSetUserFlags() {
+
+ std::vector <vmime::string> userFlags;
+ userFlags.push_back("\\XMyFlag1");
+ userFlags.push_back("\\XMyFlag2");
+ userFlags.push_back("\\XMyFlag3");
+
+ vmime::net::folderAttributes attr;
+ attr.setUserFlags(userFlags);
+
+ VASSERT("eq", attr.getUserFlags() == userFlags);
+ }
+
+ void testHasUserFlag() {
+
+ std::vector <vmime::string> userFlags;
+ userFlags.push_back("\\XMyFlag1");
+ userFlags.push_back("\\XMyFlag2");
+ userFlags.push_back("\\XMyFlag3");
+
+ vmime::net::folderAttributes attr;
+ attr.setUserFlags(userFlags);
+
+ VASSERT("has", attr.hasUserFlag("\\XMyFlag1"));
+ VASSERT("has-casesensitive", !attr.hasUserFlag("\\xmyflag1"));
+ VASSERT("has-not", !attr.hasUserFlag("\\XMyFlag4"));
+ }
+
+ void testSetSpecialUse() {
+
+ const int use = vmime::net::folderAttributes::SPECIALUSE_JUNK
+ | vmime::net::folderAttributes::SPECIALUSE_TRASH;
+
+ vmime::net::folderAttributes attr;
+ attr.setSpecialUse(use);
+
+ VASSERT_EQ("eq", use, attr.getSpecialUse());
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/net/imap/IMAPCommandTest.cpp b/vmime-master/tests/net/imap/IMAPCommandTest.cpp
new file mode 100644
index 0000000..cf3446d
--- /dev/null
+++ b/vmime-master/tests/net/imap/IMAPCommandTest.cpp
@@ -0,0 +1,495 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/net/imap/IMAPCommand.hpp"
+#include "vmime/net/imap/IMAPStore.hpp"
+#include "vmime/net/imap/IMAPConnection.hpp"
+
+
+using namespace vmime::net::imap;
+
+
+VMIME_TEST_SUITE_BEGIN(IMAPCommandTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testCreateCommand)
+ VMIME_TEST(testCreateCommandParams)
+ VMIME_TEST(testLOGIN)
+ VMIME_TEST(testAUTHENTICATE)
+ VMIME_TEST(testAUTHENTICATE_InitialResponse)
+ VMIME_TEST(testLIST)
+ VMIME_TEST(testSELECT)
+ VMIME_TEST(testSTATUS)
+ VMIME_TEST(testCREATE)
+ VMIME_TEST(testDELETE)
+ VMIME_TEST(testRENAME)
+ VMIME_TEST(testFETCH)
+ VMIME_TEST(testSTORE)
+ VMIME_TEST(testAPPEND)
+ VMIME_TEST(testCOPY)
+ VMIME_TEST(testSEARCH)
+ VMIME_TEST(testSTARTTLS)
+ VMIME_TEST(testCAPABILITY)
+ VMIME_TEST(testNOOP)
+ VMIME_TEST(testEXPUNGE)
+ VMIME_TEST(testCLOSE)
+ VMIME_TEST(testLOGOUT)
+ VMIME_TEST(testSend)
+ VMIME_TEST_LIST_END
+
+
+ void testCreateCommand() {
+
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPCommand::createCommand("MY_COMMAND");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "MY_COMMAND", cmd->getText());
+ }
+
+ void testCreateCommandParams() {
+
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPCommand::createCommand("MY_COMMAND param1 param2");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "MY_COMMAND param1 param2", cmd->getText());
+ }
+
+ void testLOGIN() {
+
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPCommand::LOGIN("username", "password");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "LOGIN username password", cmd->getText());
+ VASSERT_EQ("Trace Text", "LOGIN {username} {password}", cmd->getTraceText());
+ }
+
+ void testAUTHENTICATE() {
+
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPCommand::AUTHENTICATE("saslmechanism");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "AUTHENTICATE saslmechanism", cmd->getText());
+ }
+
+ void testAUTHENTICATE_InitialResponse() {
+
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPCommand::AUTHENTICATE("saslmechanism", "initial-response");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "AUTHENTICATE saslmechanism initial-response", cmd->getText());
+ }
+
+ void testLIST() {
+
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPCommand::LIST("ref-name", "mailbox-name");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "LIST ref-name mailbox-name", cmd->getText());
+
+ vmime::shared_ptr <IMAPCommand> cmdQuote = IMAPCommand::LIST("ref name", "mailbox-name");
+
+ VASSERT_NOT_NULL("Not null", cmdQuote);
+ VASSERT_EQ("Text", "LIST \"ref name\" mailbox-name", cmdQuote->getText());
+ }
+
+ void testSELECT() {
+
+ std::vector <vmime::string> params;
+ params.push_back("param-1");
+ params.push_back("param-2");
+
+
+ vmime::shared_ptr <IMAPCommand> cmdRO = IMAPCommand::SELECT(
+ /* readOnly */ true, "mailbox-name", std::vector <vmime::string>()
+ );
+
+ VASSERT_NOT_NULL("Not null", cmdRO);
+ VASSERT_EQ("Text", "EXAMINE mailbox-name", cmdRO->getText());
+
+ vmime::shared_ptr <IMAPCommand> cmdROQuote = IMAPCommand::SELECT(
+ /* readOnly */ true, "mailbox name", std::vector <vmime::string>()
+ );
+
+ VASSERT_NOT_NULL("Not null", cmdROQuote);
+ VASSERT_EQ("Text", "EXAMINE \"mailbox name\"", cmdROQuote->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdRW = IMAPCommand::SELECT(
+ /* readOnly */ false, "mailbox-name", std::vector <vmime::string>()
+ );
+
+ VASSERT_NOT_NULL("Not null", cmdRW);
+ VASSERT_EQ("Text", "SELECT mailbox-name", cmdRW->getText());
+
+ vmime::shared_ptr <IMAPCommand> cmdRWParams = IMAPCommand::SELECT(
+ /* readOnly */ false, "mailbox-name", params
+ );
+
+ VASSERT_NOT_NULL("Not null", cmdRWParams);
+ VASSERT_EQ("Text", "SELECT mailbox-name (param-1 param-2)", cmdRWParams->getText());
+
+ vmime::shared_ptr <IMAPCommand> cmdRWQuote = IMAPCommand::SELECT(
+ /* readOnly */ false, "mailbox name", std::vector <vmime::string>()
+ );
+
+ VASSERT_NOT_NULL("Not null", cmdRWQuote);
+ VASSERT_EQ("Text", "SELECT \"mailbox name\"", cmdRWQuote->getText());
+ }
+
+ void testSTATUS() {
+
+ std::vector <vmime::string> attribs;
+ attribs.push_back("attrib-1");
+ attribs.push_back("attrib-2");
+
+
+ vmime::shared_ptr <IMAPCommand> cmd =
+ IMAPCommand::STATUS("mailbox-name", attribs);
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "STATUS mailbox-name (attrib-1 attrib-2)", cmd->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdQuote =
+ IMAPCommand::STATUS("mailbox name", attribs);
+
+ VASSERT_NOT_NULL("Not null", cmdQuote);
+ VASSERT_EQ("Text", "STATUS \"mailbox name\" (attrib-1 attrib-2)", cmdQuote->getText());
+ }
+
+ void testCREATE() {
+
+ std::vector <vmime::string> params;
+ params.push_back("param-1");
+ params.push_back("param-2");
+
+
+ vmime::shared_ptr <IMAPCommand> cmd =
+ IMAPCommand::CREATE("mailbox-name", params);
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "CREATE mailbox-name (param-1 param-2)", cmd->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdQuote =
+ IMAPCommand::CREATE("mailbox name", params);
+
+ VASSERT_NOT_NULL("Not null", cmdQuote);
+ VASSERT_EQ("Text", "CREATE \"mailbox name\" (param-1 param-2)", cmdQuote->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdNoParam =
+ IMAPCommand::CREATE("mailbox-name", std::vector <vmime::string>());
+
+ VASSERT_NOT_NULL("Not null", cmdNoParam);
+ VASSERT_EQ("Text", "CREATE mailbox-name", cmdNoParam->getText());
+ }
+
+ void testDELETE() {
+
+ vmime::shared_ptr <IMAPCommand> cmd =
+ IMAPCommand::DELETE("mailbox-name");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "DELETE mailbox-name", cmd->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdQuote =
+ IMAPCommand::DELETE("mailbox name");
+
+ VASSERT_NOT_NULL("Not null", cmdQuote);
+ VASSERT_EQ("Text", "DELETE \"mailbox name\"", cmdQuote->getText());
+ }
+
+ void testRENAME() {
+
+ vmime::shared_ptr <IMAPCommand> cmd =
+ IMAPCommand::RENAME("mailbox-name", "new-mailbox-name");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "RENAME mailbox-name new-mailbox-name", cmd->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdQuote =
+ IMAPCommand::RENAME("mailbox name", "new mailbox name");
+
+ VASSERT_NOT_NULL("Not null", cmdQuote);
+ VASSERT_EQ("Text", "RENAME \"mailbox name\" \"new mailbox name\"", cmdQuote->getText());
+ }
+
+ void testFETCH() {
+
+ std::vector <vmime::string> params;
+ params.push_back("param-1");
+ params.push_back("param-2");
+
+
+ vmime::shared_ptr <IMAPCommand> cmdNum =
+ IMAPCommand::FETCH(vmime::net::messageSet::byNumber(42), params);
+
+ VASSERT_NOT_NULL("Not null", cmdNum);
+ VASSERT_EQ("Text", "FETCH 42 (param-1 param-2)", cmdNum->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdNums =
+ IMAPCommand::FETCH(vmime::net::messageSet::byNumber(42, 47), params);
+
+ VASSERT_NOT_NULL("Not null", cmdNums);
+ VASSERT_EQ("Text", "FETCH 42:47 (param-1 param-2)", cmdNums->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdUID =
+ IMAPCommand::FETCH(vmime::net::messageSet::byUID(42), params);
+
+ VASSERT_NOT_NULL("Not null", cmdUID);
+ VASSERT_EQ("Text", "UID FETCH 42 (param-1 param-2)", cmdUID->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdUIDs =
+ IMAPCommand::FETCH(vmime::net::messageSet::byUID(42, 47), params);
+
+ VASSERT_NOT_NULL("Not null", cmdUIDs);
+ VASSERT_EQ("Text", "UID FETCH 42:47 (param-1 param-2)", cmdUIDs->getText());
+ }
+
+ void testSTORE() {
+
+ std::vector <vmime::string> flags;
+ flags.push_back("flag-1");
+ flags.push_back("flag-2");
+
+
+ vmime::shared_ptr <IMAPCommand> cmdNum = IMAPCommand::STORE(
+ vmime::net::messageSet::byNumber(42), vmime::net::message::FLAG_MODE_SET, flags
+ );
+
+ VASSERT_NOT_NULL("Not null", cmdNum);
+ VASSERT_EQ("Text", "STORE 42 FLAGS (flag-1 flag-2)", cmdNum->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdNums = IMAPCommand::STORE(
+ vmime::net::messageSet::byNumber(42, 47), vmime::net::message::FLAG_MODE_SET, flags
+ );
+
+ VASSERT_NOT_NULL("Not null", cmdNums);
+ VASSERT_EQ("Text", "STORE 42:47 FLAGS (flag-1 flag-2)", cmdNums->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdUID = IMAPCommand::STORE(
+ vmime::net::messageSet::byUID(42), vmime::net::message::FLAG_MODE_SET, flags
+ );
+
+ VASSERT_NOT_NULL("Not null", cmdUID);
+ VASSERT_EQ("Text", "UID STORE 42 FLAGS (flag-1 flag-2)", cmdUID->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdUIDs = IMAPCommand::STORE(
+ vmime::net::messageSet::byUID(42, 47), vmime::net::message::FLAG_MODE_SET, flags
+ );
+
+ VASSERT_NOT_NULL("Not null", cmdUIDs);
+ VASSERT_EQ("Text", "UID STORE 42:47 FLAGS (flag-1 flag-2)", cmdUIDs->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdAdd = IMAPCommand::STORE(
+ vmime::net::messageSet::byUID(42, 47), vmime::net::message::FLAG_MODE_ADD, flags
+ );
+
+ VASSERT_NOT_NULL("Not null", cmdAdd);
+ VASSERT_EQ("Text", "UID STORE 42:47 +FLAGS (flag-1 flag-2)", cmdAdd->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdRem = IMAPCommand::STORE(
+ vmime::net::messageSet::byUID(42, 47), vmime::net::message::FLAG_MODE_REMOVE, flags
+ );
+
+ VASSERT_NOT_NULL("Not null", cmdRem);
+ VASSERT_EQ("Text", "UID STORE 42:47 -FLAGS (flag-1 flag-2)", cmdRem->getText());
+ }
+
+ void testAPPEND() {
+
+ std::vector <vmime::string> flags;
+ flags.push_back("flag-1");
+ flags.push_back("flag-2");
+
+
+ vmime::shared_ptr <IMAPCommand> cmd =
+ IMAPCommand::APPEND("mailbox-name", flags, /* date */ NULL, 1234);
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "APPEND mailbox-name (flag-1 flag-2) {1234}", cmd->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdQuote =
+ IMAPCommand::APPEND("mailbox name", flags, /* date */ NULL, 1234);
+
+ VASSERT_NOT_NULL("Not null", cmdQuote);
+ VASSERT_EQ("Text", "APPEND \"mailbox name\" (flag-1 flag-2) {1234}", cmdQuote->getText());
+
+
+ vmime::datetime date(2014, 3, 15, 23, 11, 47, vmime::datetime::GMT2);
+ vmime::shared_ptr <IMAPCommand> cmdDate =
+ IMAPCommand::APPEND("mailbox name", flags, &date, 1234);
+
+ VASSERT_NOT_NULL("Not null", cmdDate);
+ VASSERT_EQ("Text", "APPEND \"mailbox name\" (flag-1 flag-2) \"15-Mar-2014 23:11:47 +0200\" {1234}", cmdDate->getText());
+ }
+
+ void testCOPY() {
+
+ vmime::shared_ptr <IMAPCommand> cmdNum =
+ IMAPCommand::COPY(vmime::net::messageSet::byNumber(42), "mailbox-name");
+
+ VASSERT_NOT_NULL("Not null", cmdNum);
+ VASSERT_EQ("Text", "COPY 42 mailbox-name", cmdNum->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdNums =
+ IMAPCommand::COPY(vmime::net::messageSet::byNumber(42, 47), "mailbox-name");
+
+ VASSERT_NOT_NULL("Not null", cmdNums);
+ VASSERT_EQ("Text", "COPY 42:47 mailbox-name", cmdNums->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdUID =
+ IMAPCommand::COPY(vmime::net::messageSet::byUID(42), "mailbox-name");
+
+ VASSERT_NOT_NULL("Not null", cmdUID);
+ VASSERT_EQ("Text", "UID COPY 42 mailbox-name", cmdUID->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdUIDs =
+ IMAPCommand::COPY(vmime::net::messageSet::byUID(42, 47), "mailbox-name");
+
+ VASSERT_NOT_NULL("Not null", cmdUIDs);
+ VASSERT_EQ("Text", "UID COPY 42:47 mailbox-name", cmdUIDs->getText());
+
+
+ vmime::shared_ptr <IMAPCommand> cmdQuote =
+ IMAPCommand::COPY(vmime::net::messageSet::byNumber(42, 47), "mailbox name");
+
+ VASSERT_NOT_NULL("Not null", cmdQuote);
+ VASSERT_EQ("Text", "COPY 42:47 \"mailbox name\"", cmdQuote->getText());
+ }
+
+ void testSEARCH() {
+
+ std::vector <vmime::string> searchKeys;
+ searchKeys.push_back("search-key-1");
+ searchKeys.push_back("search-key-2");
+
+ vmime::shared_ptr <IMAPCommand> cmd =
+ IMAPCommand::SEARCH(searchKeys, /* charset */ NULL);
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "SEARCH search-key-1 search-key-2", cmd->getText());
+
+
+ vmime::charset cset("test-charset");
+
+ vmime::shared_ptr <IMAPCommand> cmdCset =
+ IMAPCommand::SEARCH(searchKeys, &cset);
+
+ VASSERT_NOT_NULL("Not null", cmdCset);
+ VASSERT_EQ("Text", "SEARCH CHARSET test-charset search-key-1 search-key-2", cmdCset->getText());
+ }
+
+ void testSTARTTLS() {
+
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPCommand::STARTTLS();
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "STARTTLS", cmd->getText());
+ }
+
+ void testCAPABILITY() {
+
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPCommand::CAPABILITY();
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "CAPABILITY", cmd->getText());
+ }
+
+ void testNOOP() {
+
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPCommand::NOOP();
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "NOOP", cmd->getText());
+ }
+
+ void testEXPUNGE() {
+
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPCommand::EXPUNGE();
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "EXPUNGE", cmd->getText());
+ }
+
+ void testCLOSE() {
+
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPCommand::CLOSE();
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "CLOSE", cmd->getText());
+ }
+
+ void testLOGOUT() {
+
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPCommand::LOGOUT();
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "LOGOUT", cmd->getText());
+ }
+
+ void testSend() {
+
+ vmime::shared_ptr <IMAPCommand> cmd =
+ IMAPCommand::createCommand("MY_COMMAND param1 param2");
+
+ vmime::shared_ptr <vmime::net::session> sess = vmime::net::session::create();
+
+ vmime::shared_ptr <vmime::security::authenticator> auth =
+ vmime::make_shared <vmime::security::defaultAuthenticator>();
+
+ vmime::shared_ptr <IMAPStore> store =
+ vmime::make_shared <IMAPStore>(sess, auth, /* secured */ false);
+
+ vmime::shared_ptr <IMAPConnection> conn =
+ vmime::make_shared <IMAPConnection>(store, auth);
+
+ vmime::shared_ptr <testSocket> sok = vmime::make_shared <testSocket>();
+ conn->setSocket(sok);
+
+ cmd->send(conn);
+
+ vmime::string response;
+ sok->localReceive(response);
+
+ VASSERT_EQ("Sent buffer", vmime::string(*conn->getTag()) + " MY_COMMAND param1 param2\r\n", response);
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/net/imap/IMAPParserTest.cpp b/vmime-master/tests/net/imap/IMAPParserTest.cpp
new file mode 100644
index 0000000..60ce16d
--- /dev/null
+++ b/vmime-master/tests/net/imap/IMAPParserTest.cpp
@@ -0,0 +1,374 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/net/imap/IMAPTag.hpp"
+#include "vmime/net/imap/IMAPParser.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(IMAPParserTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testExtraSpaceInCapaResponse)
+ VMIME_TEST(testContinueReqWithoutSpace)
+ VMIME_TEST(testNILValueInBodyFldEnc)
+ VMIME_TEST(testFETCHResponse_optional_body_fld_lang)
+ VMIME_TEST(testFETCHBodyStructure_NIL_body_fld_param_value)
+ VMIME_TEST(testFETCHBodyStructure_empty_body_fld_param_instead_of_NIL)
+ VMIME_TEST(testPipelining)
+ VMIME_TEST(testStarFlagWithoutBackslash)
+ VMIME_TEST_LIST_END
+
+
+ // For Apple iCloud IMAP server
+ void testExtraSpaceInCapaResponse() {
+
+ const char* resp =
+ "* CAPABILITY IMAP4rev1 AUTH=ATOKEN AUTH=PLAIN \r\n" // extra space at end
+ "a001 OK Capability completed.\r\n";
+
+ // Strict mode
+ {
+ auto socket = vmime::make_shared <testSocket>();
+ socket->localSend(resp);
+
+ auto parser = vmime::make_shared <vmime::net::imap::IMAPParser>();
+ auto tag = vmime::make_shared <vmime::net::imap::IMAPTag>();
+
+ parser->setSocket(socket);
+ parser->setTimeoutHandler(vmime::make_shared <testTimeoutHandler>());
+ parser->setStrict(true);
+
+ VASSERT_THROW("strict mode", parser->readResponse(*tag), vmime::exceptions::invalid_response);
+ }
+
+ // Non-strict mode
+ {
+ auto socket = vmime::make_shared <testSocket>();
+ socket->localSend(resp);
+
+ auto parser = vmime::make_shared <vmime::net::imap::IMAPParser>();
+ auto tag = vmime::make_shared <vmime::net::imap::IMAPTag>();
+
+ parser->setSocket(socket);
+ parser->setTimeoutHandler(vmime::make_shared <testTimeoutHandler>());
+ parser->setStrict(false);
+
+ VASSERT_NO_THROW("non-strict mode", parser->readResponse(*tag));
+ }
+ }
+
+ // For Apple iCloud/Exchange IMAP server
+ void testContinueReqWithoutSpace() {
+
+ // continue_req ::= "+" SPACE (resp_text / base64)
+ //
+ // Some servers do not send SPACE when response text is empty.
+ // IMAP parser should allow this in non-strict mode.
+ //
+ // Eg:
+ //
+ // C: a002 AUTHENTICATE xxx[CR][LF]
+ // S: +[CR][LF]
+
+ vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
+ vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>();
+
+ vmime::shared_ptr <vmime::net::imap::IMAPTag> tag =
+ vmime::make_shared <vmime::net::imap::IMAPTag>();
+
+ socket->localSend("+\r\n");
+
+ vmime::shared_ptr <vmime::net::imap::IMAPParser> parser =
+ vmime::make_shared <vmime::net::imap::IMAPParser>();
+
+ parser->setSocket(socket);
+ parser->setTimeoutHandler(toh);
+
+ parser->setStrict(false);
+ VASSERT_NO_THROW("non-strict mode", parser->readResponse(*tag));
+
+ ++(*tag);
+
+ socket->localSend("+\r\n");
+
+ parser->setStrict(true);
+ VASSERT_THROW("strict mode", parser->readResponse(*tag), vmime::exceptions::invalid_response);
+ }
+
+ // When an IMAP4 client sends a FETCH (bodystructure) request to a server
+ // that is running the Exchange Server 2007 IMAP4 service, a corrupted
+ // response is sent as a reply
+ // --> http://support.microsoft.com/kb/975918/en-us
+ void testNILValueInBodyFldEnc() {
+
+ const char* resp = "* 7970 FETCH (UID 8036 FLAGS () BODYSTRUCTURE (\"text\" \"html\" (\"charset\" \"utf-8\") NIL NIL NIL 175501 1651 NIL NIL NIL NIL) RFC822.HEADER {3}\r\nx\r\n)\r\na001 OK FETCH complete\r\n";
+
+ // Strict mode
+ {
+ auto socket = vmime::make_shared <testSocket>();
+ socket->localSend(resp);
+
+ auto parser = vmime::make_shared <vmime::net::imap::IMAPParser>();
+ auto tag = vmime::make_shared <vmime::net::imap::IMAPTag>();
+
+ parser->setSocket(socket);
+ parser->setTimeoutHandler(vmime::make_shared <testTimeoutHandler>());
+ parser->setStrict(true);
+
+ VASSERT_THROW("strict mode", parser->readResponse(*tag), vmime::exceptions::invalid_response);
+ }
+
+ // Non-strict mode
+ {
+ auto socket = vmime::make_shared <testSocket>();
+ socket->localSend(resp);
+
+ auto parser = vmime::make_shared <vmime::net::imap::IMAPParser>();
+ auto tag = vmime::make_shared <vmime::net::imap::IMAPTag>();
+
+ parser->setSocket(socket);
+ parser->setTimeoutHandler(vmime::make_shared <testTimeoutHandler>());
+ parser->setStrict(false);
+
+ VASSERT_NO_THROW("non-strict mode", parser->readResponse(*tag));
+ }
+ }
+
+ // "body_fld_lang" is optional after "body_fld_dsp" in "body_ext_mpart" (Yahoo)
+ void testFETCHResponse_optional_body_fld_lang() {
+
+ vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
+ vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>();
+
+ vmime::shared_ptr <vmime::net::imap::IMAPTag> tag =
+ vmime::make_shared <vmime::net::imap::IMAPTag>();
+
+ const char* resp = "* 1 FETCH (UID 7 RFC822.SIZE 694142 BODYSTRUCTURE (((\"text\" \"plain\" (\"charset\" \"utf-8\") NIL NIL \"7bit\" 0 0 NIL NIL NIL NIL)(\"text\" \"html\" (\"charset\" \"utf-8\") NIL NIL \"7bit\" 193 0 NIL NIL NIL NIL) \"alternative\" (\"boundary\" \"----=_Part_536_109505883.1410847112666\") NIL)(\"image\" \"jpeg\" NIL \"<4db20d0e-e9f8-729b-aaf7-688b5956d0bc@yahoo.com>\" NIL \"base64\" 351784 NIL (\"attachment\" (\"name\" \"att2\" \"filename\" \"9.jpg\")) NIL NIL)(\"image\" \"jpeg\" NIL \"<542417d7-c0ed-db72-f9fc-d9ab2c7e0a6f@yahoo.com>\" NIL \"base64\" 337676 NIL (\"attachment\" (\"name\" \"att3\" \"filename\" \"10.jpg\")) NIL NIL) \"mixed\" (\"boundary\" \"----=_Part_537_1371134700.1410847112668\") NIL) RFC822.HEADER {3}\r\nx\r\n)\r\na001 OK FETCH complete\r\n";
+
+ socket->localSend(resp);
+
+ vmime::shared_ptr <vmime::net::imap::IMAPParser> parser =
+ vmime::make_shared <vmime::net::imap::IMAPParser>();
+
+ parser->setSocket(socket);
+ parser->setTimeoutHandler(toh);
+
+ VASSERT_NO_THROW("parse", parser->readResponse(*tag));
+ }
+
+ // Support for NIL boundary, for mail.ru IMAP server:
+ // https://www.ietf.org/mail-archive/web/imapext/current/msg05442.html
+ void testFETCHBodyStructure_NIL_body_fld_param_value() {
+
+ // ...("boundary" NIL)))... is an invalid syntax for a "body_fld_param_item"
+ const char* resp = "* 1 FETCH (BODYSTRUCTURE ((\"text\" \"plain\" (\"charset\" \"utf-8\") NIL NIL \"8bit\" 536 0 NIL NIL NIL NIL)(\"text\" \"html\" (\"charset\" \"utf-8\") NIL NIL \"8bit\" 7130 0 NIL NIL NIL NIL) \"alternative\" (\"boundary\" NIL)))\r\na001 OK FETCH complete\r\n";
+
+ // Strict mode
+ {
+ auto socket = vmime::make_shared <testSocket>();
+ socket->localSend(resp);
+
+ auto parser = vmime::make_shared <vmime::net::imap::IMAPParser>();
+ auto tag = vmime::make_shared <vmime::net::imap::IMAPTag>();
+
+ parser->setSocket(socket);
+ parser->setTimeoutHandler(vmime::make_shared <testTimeoutHandler>());
+ parser->setStrict(true);
+
+ VASSERT_THROW("strict mode", parser->readResponse(*tag), vmime::exceptions::invalid_response);
+ }
+
+ // Non-strict mode
+ {
+ auto socket = vmime::make_shared <testSocket>();
+ socket->localSend(resp);
+
+ auto parser = vmime::make_shared <vmime::net::imap::IMAPParser>();
+ auto tag = vmime::make_shared <vmime::net::imap::IMAPTag>();
+
+ parser->setSocket(socket);
+ parser->setTimeoutHandler(vmime::make_shared <testTimeoutHandler>());
+ parser->setStrict(false);
+
+ VASSERT_NO_THROW("non-strict mode", parser->readResponse(*tag));
+ }
+ }
+
+ void testFETCHBodyStructure_empty_body_fld_param_instead_of_NIL() {
+
+ const char* resp = "* 1 FETCH (BODYSTRUCTURE ((\"text\" \"html\" (\"charset\" \"cp1251\") NIL NIL \"base64\" 84056 0 NIL (\"inline\" NIL) NIL NIL)(\"image\" \"gif\" () \"25b2b55b5d97f04e9ea939fe32a46a65.gif\" NIL \"base64\" 20776 NIL (\"inline\" NIL) NIL NIL) \"related\" (\"boundary\" NIL)))\r\na001 OK FETCH complete\r\n";
+
+ // Strict mode
+ {
+ auto socket = vmime::make_shared <testSocket>();
+ socket->localSend(resp);
+
+ auto parser = vmime::make_shared <vmime::net::imap::IMAPParser>();
+ auto tag = vmime::make_shared <vmime::net::imap::IMAPTag>();
+
+ parser->setSocket(socket);
+ parser->setTimeoutHandler(vmime::make_shared <testTimeoutHandler>());
+ parser->setStrict(true);
+
+ VASSERT_THROW("strict mode", parser->readResponse(*tag), vmime::exceptions::invalid_response);
+ }
+
+ // Non-strict mode
+ {
+ auto socket = vmime::make_shared <testSocket>();
+ socket->localSend(resp);
+
+ auto parser = vmime::make_shared <vmime::net::imap::IMAPParser>();
+ auto tag = vmime::make_shared <vmime::net::imap::IMAPTag>();
+
+ parser->setSocket(socket);
+ parser->setTimeoutHandler(vmime::make_shared <testTimeoutHandler>());
+ parser->setStrict(false);
+
+ VASSERT_NO_THROW("non-strict mode", parser->readResponse(*tag));
+ }
+ }
+
+ // Test pipelined and out-of-order replies
+ void testPipelining() {
+
+ /*
+ [C] a001 SELECT "INBOX"
+ [C] a002 UID FETCH 42 (INTERNALDATE)
+ [C] a003 UID FETCH 43 (INTERNALDATE)
+ [S] * NO Error for a001
+ [S] a001 NO Access denied
+ [S] * NO Error for a003
+ [S] a003 BAD No mailbox selected
+ [S] * NO Error for a002
+ [S] a002 BAD No mailbox selected
+ */
+
+ vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
+ vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>();
+
+ vmime::net::imap::IMAPTag tag1; // a001
+ vmime::net::imap::IMAPTag tag2(tag1); // a002
+ ++tag2;
+ vmime::net::imap::IMAPTag tag3(tag2); // a003
+ ++tag3;
+
+ socket->localSend(
+ "* NO Error for a001\r\n"
+ "a001 NO Access denied\r\n"
+ "* NO Error for a003\r\n"
+ "a003 BAD No mailbox selected a003\r\n"
+ "* NO Error for a002\r\n"
+ "a002 BAD No mailbox selected a002\r\n"
+ );
+
+ vmime::shared_ptr <vmime::net::imap::IMAPParser> parser =
+ vmime::make_shared <vmime::net::imap::IMAPParser>();
+
+ parser->setSocket(socket);
+ parser->setTimeoutHandler(toh);
+
+ // Test response a001
+ vmime::scoped_ptr <vmime::net::imap::IMAPParser::response> resp1(parser->readResponse(tag1, /* literalHandler */ NULL));
+ VASSERT("a001 response", resp1);
+ VASSERT("a001 response_done", resp1->response_done);
+ VASSERT_EQ("a001 response tag", "a001", resp1->response_done->response_tagged->tag->tagString);
+ VASSERT_EQ("a001 response text", "Access denied", resp1->response_done->response_tagged->resp_cond_state->resp_text->text);
+ VASSERT_EQ("a001 resp_data.size()", 1, resp1->continue_req_or_response_data.size());
+ VASSERT("a001 resp_data[0]", resp1->continue_req_or_response_data[0]->response_data);
+ VASSERT("a001 resp_cond_state", resp1->continue_req_or_response_data[0]->response_data->resp_cond_state);
+ VASSERT_EQ("a001 resp_cond_state.text", "Error for a001", resp1->continue_req_or_response_data[0]->response_data->resp_cond_state->resp_text->text);
+ VASSERT_EQ("a001 resp_cond_state.status", vmime::net::imap::IMAPParser::resp_cond_state::NO, resp1->continue_req_or_response_data[0]->response_data->resp_cond_state->status);
+
+ // Test response a002
+ vmime::scoped_ptr <vmime::net::imap::IMAPParser::response> resp2(parser->readResponse(tag2, /* literalHandler */ NULL));
+ VASSERT("a002 response", resp2);
+ VASSERT("a002 response_done", resp2->response_done);
+ VASSERT_EQ("a002 response tag", "a002", resp2->response_done->response_tagged->tag->tagString);
+ VASSERT_EQ("a002 response text", "No mailbox selected a002", resp2->response_done->response_tagged->resp_cond_state->resp_text->text);
+ VASSERT_EQ("a002 resp_data.size()", 1, resp2->continue_req_or_response_data.size());
+ VASSERT("a002 resp_data[0]", resp2->continue_req_or_response_data[0]->response_data);
+ VASSERT("a002 resp_cond_state", resp2->continue_req_or_response_data[0]->response_data->resp_cond_state);
+ VASSERT_EQ("a002 resp_cond_state.text", "Error for a002", resp2->continue_req_or_response_data[0]->response_data->resp_cond_state->resp_text->text);
+ VASSERT_EQ("a002 resp_cond_state.status", vmime::net::imap::IMAPParser::resp_cond_state::NO, resp2->continue_req_or_response_data[0]->response_data->resp_cond_state->status);
+
+ // Test response a003
+ vmime::scoped_ptr <vmime::net::imap::IMAPParser::response> resp3(parser->readResponse(tag3, /* literalHandler */ NULL));
+ VASSERT("a003 response", resp3);
+ VASSERT("a003 response_done", resp3->response_done);
+ VASSERT_EQ("a003 response tag", "a003", resp3->response_done->response_tagged->tag->tagString);
+ VASSERT_EQ("a003 response text", "No mailbox selected a003", resp3->response_done->response_tagged->resp_cond_state->resp_text->text);
+ VASSERT_EQ("a003 resp_data.size()", 1, resp3->continue_req_or_response_data.size());
+ VASSERT("a003 resp_data[0]", resp3->continue_req_or_response_data[0]->response_data);
+ VASSERT("a003 resp_cond_state", resp3->continue_req_or_response_data[0]->response_data->resp_cond_state);
+ VASSERT_EQ("a003 resp_cond_state.text", "Error for a003", resp3->continue_req_or_response_data[0]->response_data->resp_cond_state->resp_text->text);
+ VASSERT_EQ("a003 resp_cond_state.status", vmime::net::imap::IMAPParser::resp_cond_state::NO, resp3->continue_req_or_response_data[0]->response_data->resp_cond_state->status);
+ }
+
+ // Some IMAP servers return "*" instead of "\*" in PERMANENTFLAGS
+ void testStarFlagWithoutBackslash() {
+
+ const char* resp =
+ "* OK [PERMANENTFLAGS (Answered Flagged Deleted Seen Draft *)] Flags permitted.\r\n"
+ "a001 OK Completed.\r\n";
+
+ // Strict mode
+ {
+ auto socket = vmime::make_shared <testSocket>();
+ auto toh = vmime::make_shared <testTimeoutHandler>();
+
+ auto tag = vmime::make_shared <vmime::net::imap::IMAPTag>();
+
+ socket->localSend(resp);
+
+ auto parser = vmime::make_shared <vmime::net::imap::IMAPParser>();
+
+ parser->setSocket(socket);
+ parser->setTimeoutHandler(toh);
+ parser->setStrict(true);
+
+ VASSERT_THROW("strict mode", parser->readResponse(*tag), vmime::exceptions::invalid_response);
+ }
+
+ // Non-strict mode
+ {
+ auto socket = vmime::make_shared <testSocket>();
+ auto toh = vmime::make_shared <testTimeoutHandler>();
+
+ auto tag = vmime::make_shared <vmime::net::imap::IMAPTag>();
+
+ socket->localSend(resp);
+
+ auto parser = vmime::make_shared <vmime::net::imap::IMAPParser>();
+
+ parser->setSocket(socket);
+ parser->setTimeoutHandler(toh);
+ parser->setStrict(false);
+
+ VASSERT_NO_THROW("non-strict mode", parser->readResponse(*tag));
+ }
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/net/imap/IMAPTagTest.cpp b/vmime-master/tests/net/imap/IMAPTagTest.cpp
new file mode 100644
index 0000000..c8e09b6
--- /dev/null
+++ b/vmime-master/tests/net/imap/IMAPTagTest.cpp
@@ -0,0 +1,90 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/net/imap/IMAPTag.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(imapTagTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testConstruct)
+ VMIME_TEST(testIncrement)
+ VMIME_TEST(testReset)
+ VMIME_TEST(testNumber)
+ VMIME_TEST_LIST_END
+
+
+ void testConstruct() {
+
+ vmime::shared_ptr <vmime::net::imap::IMAPTag> tag =
+ vmime::make_shared <vmime::net::imap::IMAPTag>();
+
+ VASSERT_EQ("init", "a001", static_cast <vmime::string>(*tag));
+ }
+
+ void testIncrement() {
+
+ vmime::shared_ptr <vmime::net::imap::IMAPTag> tag =
+ vmime::make_shared <vmime::net::imap::IMAPTag>();
+
+ (*tag)++;
+ VASSERT_EQ("init", "a002", static_cast <vmime::string>(*tag));
+
+ (*tag)++;
+ VASSERT_EQ("init", "a003", static_cast <vmime::string>(*tag));
+
+ (*tag)++;
+ VASSERT_EQ("init", "a004", static_cast <vmime::string>(*tag));
+ }
+
+ void testReset() {
+
+ vmime::shared_ptr <vmime::net::imap::IMAPTag> tag =
+ vmime::make_shared <vmime::net::imap::IMAPTag>();
+
+ for (int i = tag->number() ; i < tag->maximumNumber() ; ++i) {
+ (*tag)++;
+ }
+
+ VASSERT_EQ("last", "Z999", static_cast <vmime::string>(*tag));
+
+ (*tag)++;
+
+ VASSERT_EQ("reset", "a001", static_cast <vmime::string>(*tag));
+ }
+
+ void testNumber() {
+
+ vmime::shared_ptr <vmime::net::imap::IMAPTag> tag =
+ vmime::make_shared <vmime::net::imap::IMAPTag>();
+
+ for (int i = 0 ; i < 41 ; ++i) {
+ (*tag)++;
+ }
+
+ VASSERT_EQ("number", 42, tag->number());
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/net/imap/IMAPUtilsTest.cpp b/vmime-master/tests/net/imap/IMAPUtilsTest.cpp
new file mode 100644
index 0000000..b707fd0
--- /dev/null
+++ b/vmime-master/tests/net/imap/IMAPUtilsTest.cpp
@@ -0,0 +1,283 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/net/imap/IMAPUtils.hpp"
+#include "vmime/net/imap/IMAPParser.hpp"
+
+
+using namespace vmime::net::imap;
+
+
+
+VMIME_TEST_SUITE_BEGIN(IMAPUtilsTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testQuoteString)
+ VMIME_TEST(testToModifiedUTF7)
+ VMIME_TEST(testFromModifiedUTF7)
+ VMIME_TEST(testConvertAddressList)
+ VMIME_TEST(testMessageFlagList)
+ VMIME_TEST(testDateTime)
+ VMIME_TEST(testPathToString)
+ VMIME_TEST(testStringToPath)
+ VMIME_TEST(testBuildFetchCommand)
+ VMIME_TEST_LIST_END
+
+
+ void testQuoteString() {
+
+ VASSERT_EQ("unquoted", "ascii", IMAPUtils::quoteString("ascii"));
+ VASSERT_EQ("space", "\"ascii with space\"", IMAPUtils::quoteString("ascii with space"));
+
+ VASSERT_EQ("special1", "\"(\"", IMAPUtils::quoteString("("));
+ VASSERT_EQ("special2", "\")\"", IMAPUtils::quoteString(")"));
+ VASSERT_EQ("special3", "\"{\"", IMAPUtils::quoteString("{"));
+ VASSERT_EQ("special4", "\" \"", IMAPUtils::quoteString(" "));
+ VASSERT_EQ("special5", "\"%\"", IMAPUtils::quoteString("%"));
+ VASSERT_EQ("special6", "\"*\"", IMAPUtils::quoteString("*"));
+ VASSERT_EQ("special7", "\"\\\"\"", IMAPUtils::quoteString("\""));
+ VASSERT_EQ("special8", "\"\\\\\"", IMAPUtils::quoteString("\\"));
+ VASSERT_EQ("special9", "\"\x7f\"", IMAPUtils::quoteString("\x7f"));
+
+ }
+
+ void testToModifiedUTF7() {
+
+ #define FC(x) vmime::net::folder::path::component(x, vmime::charsets::UTF_8)
+
+ // Example strings from RFC-1642 (modified for IMAP UTF-7)
+ VASSERT_EQ("1", "A&ImIDkQ-.", IMAPUtils::toModifiedUTF7('/', FC("A\xe2\x89\xa2\xce\x91.")));
+ VASSERT_EQ("2", "Hi Mum &Jjo-!", IMAPUtils::toModifiedUTF7('/', FC("Hi Mum \xe2\x98\xba!")));
+ VASSERT_EQ("3", "&ZeVnLIqe-", IMAPUtils::toModifiedUTF7('/', FC("\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e")));
+ VASSERT_EQ("4", "Item 3 is &AKM- 1.", IMAPUtils::toModifiedUTF7('/', FC("Item 3 is \xc2\xa3 1.")));
+
+ VASSERT_EQ("escape char", "&-", IMAPUtils::toModifiedUTF7('/', FC("&")));
+ VASSERT_EQ("ascii", "plain ascii text", IMAPUtils::toModifiedUTF7('/', FC("plain ascii text")));
+ VASSERT_EQ("special", "!\"#$%*+-;<=>@[]^_`{|}", IMAPUtils::toModifiedUTF7('/', FC("!\"#$%*+-;<=>@[]^_`{|}")));
+
+ #undef FC
+ }
+
+ void testFromModifiedUTF7() {
+
+ #define FC(x) vmime::net::folder::path::component(x, vmime::charsets::UTF_8)
+
+ // Example strings from RFC-1642 (modified for IMAP UTF-7)
+ VASSERT_EQ("1", FC("A\xe2\x89\xa2\xce\x91."), IMAPUtils::fromModifiedUTF7("A&ImIDkQ-."));
+ VASSERT_EQ("2", FC("Hi Mum \xe2\x98\xba!"), IMAPUtils::fromModifiedUTF7("Hi Mum &Jjo-!"));
+ VASSERT_EQ("3", FC("\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e"), IMAPUtils::fromModifiedUTF7("&ZeVnLIqe-"));
+ VASSERT_EQ("4", FC("Item 3 is \xc2\xa3 1."), IMAPUtils::fromModifiedUTF7("Item 3 is &AKM- 1."));
+
+ VASSERT_EQ("escape char", FC("&"), IMAPUtils::fromModifiedUTF7("&-"));
+ VASSERT_EQ("ascii", FC("plain ascii text"), IMAPUtils::fromModifiedUTF7("plain ascii text"));
+ VASSERT_EQ("special", FC("!\"#$%*+;<=>@[]^_`{|}"), IMAPUtils::fromModifiedUTF7("!\"#$%*+-;<=>@[]^_`{|}"));
+
+ #undef FC
+ }
+
+ void testConvertAddressList() {
+
+ IMAPParser parser;
+ IMAPParser::address_list addrList;
+
+ vmime::string line("((\"name\" NIL \"mailbox\" \"host\")(\"name2\" NIL \"mailbox2\" \"host2\"))");
+ vmime::size_t pos = 0;
+
+ VASSERT("parse", addrList.parseImpl(parser, line, &pos));
+
+ vmime::mailboxList mboxList;
+ IMAPUtils::convertAddressList(addrList, mboxList);
+
+ VASSERT_EQ("mbox-count", 2, mboxList.getMailboxCount());
+ VASSERT_EQ("mbox-1", "mailbox@host", mboxList.getMailboxAt(0)->getEmail().toString());
+ VASSERT_EQ("mbox-1", "name", mboxList.getMailboxAt(0)->getName().getWholeBuffer());
+ VASSERT_EQ("mbox-2", "mailbox2@host2", mboxList.getMailboxAt(1)->getEmail().toString());
+ VASSERT_EQ("mbox-2", "name2", mboxList.getMailboxAt(1)->getName().getWholeBuffer());
+ }
+
+ void testMessageFlagList() {
+
+ int flags = 0;
+ std::vector <vmime::string> flagList;
+
+ // Test each flag
+ flags = vmime::net::message::FLAG_REPLIED;
+ flagList = IMAPUtils::messageFlagList(flags);
+ VASSERT("replied", std::find(flagList.begin(), flagList.end(), "\\Answered") != flagList.end());
+
+ flags = vmime::net::message::FLAG_MARKED;
+ flagList = IMAPUtils::messageFlagList(flags);
+ VASSERT("marked", std::find(flagList.begin(), flagList.end(), "\\Flagged") != flagList.end());
+
+ flags = vmime::net::message::FLAG_DELETED;
+ flagList = IMAPUtils::messageFlagList(flags);
+ VASSERT("deleted", std::find(flagList.begin(), flagList.end(), "\\Deleted") != flagList.end());
+
+ flags = vmime::net::message::FLAG_SEEN;
+ flagList = IMAPUtils::messageFlagList(flags);
+ VASSERT("seen", std::find(flagList.begin(), flagList.end(), "\\Seen") != flagList.end());
+
+ flags = vmime::net::message::FLAG_DRAFT;
+ flagList = IMAPUtils::messageFlagList(flags);
+ VASSERT("draft", std::find(flagList.begin(), flagList.end(), "\\Draft") != flagList.end());
+
+ // Multiple flags
+ flags = vmime::net::message::FLAG_REPLIED;
+ flagList = IMAPUtils::messageFlagList(flags);
+
+ VASSERT_EQ("1.size", 1, flagList.size());
+ VASSERT("1.found", std::find(flagList.begin(), flagList.end(), "\\Answered") != flagList.end());
+
+ flags |= vmime::net::message::FLAG_SEEN;
+ flagList = IMAPUtils::messageFlagList(flags);
+
+ VASSERT_EQ("2.size", 2, flagList.size());
+ VASSERT("2.found1", std::find(flagList.begin(), flagList.end(), "\\Answered") != flagList.end());
+ VASSERT("2.found2", std::find(flagList.begin(), flagList.end(), "\\Seen") != flagList.end());
+ }
+
+ void testDateTime() {
+
+ vmime::datetime dt(2014, 3, 17, 23, 26, 22, vmime::datetime::GMT2);
+ VASSERT_EQ("datetime", "\"17-Mar-2014 23:26:22 +0200\"", IMAPUtils::dateTime(dt));
+ }
+
+ void testPathToString() {
+
+ #define FC(x) vmime::net::folder::path::component(x, vmime::charsets::UTF_8)
+
+ vmime::net::folder::path path;
+ path /= FC("Hi Mum \xe2\x98\xba!");
+ path /= FC("\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e");
+
+ VASSERT_EQ("string", "Hi Mum &Jjo-!/&ZeVnLIqe-", IMAPUtils::pathToString('/', path));
+
+ #undef FC
+ }
+
+ void testStringToPath() {
+
+ #define FC(x) vmime::net::folder::path::component(x, vmime::charsets::UTF_8)
+
+ vmime::net::folder::path path = IMAPUtils::stringToPath('/', "Hi Mum &Jjo-!/&ZeVnLIqe-");
+
+ VASSERT_EQ("count", 2, path.getSize());
+ VASSERT_EQ("component1", FC("Hi Mum \xe2\x98\xba!"), path[0]);
+ VASSERT_EQ("component2", FC("\xe6\x97\xa5\xe6\x9c\xac\xe8\xaa\x9e"), path[1]);
+
+ #undef FC
+ }
+
+ void testBuildFetchCommand() {
+
+ vmime::shared_ptr <IMAPConnection> cnt;
+ vmime::net::messageSet msgs = vmime::net::messageSet::byNumber(42);
+
+ // SIZE
+ {
+ vmime::net::fetchAttributes attribs = vmime::net::fetchAttributes::SIZE;
+
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPUtils::buildFetchCommand(cnt, msgs, attribs);
+ VASSERT_EQ("size", "FETCH 42 RFC822.SIZE", cmd->getText());
+ }
+
+ // FLAGS
+ {
+ vmime::net::fetchAttributes attribs = vmime::net::fetchAttributes::FLAGS;
+
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPUtils::buildFetchCommand(cnt, msgs, attribs);
+ VASSERT_EQ("flags", "FETCH 42 FLAGS", cmd->getText());
+ }
+
+ // STRUCTURE
+ {
+ vmime::net::fetchAttributes attribs = vmime::net::fetchAttributes::STRUCTURE;
+
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPUtils::buildFetchCommand(cnt, msgs, attribs);
+ VASSERT_EQ("structure", "FETCH 42 BODYSTRUCTURE", cmd->getText());
+ }
+
+ // UID
+ {
+ vmime::net::fetchAttributes attribs = vmime::net::fetchAttributes::UID;
+
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPUtils::buildFetchCommand(cnt, msgs, attribs);
+ VASSERT_EQ("uid", "FETCH 42 UID", cmd->getText());
+ }
+
+ // ENVELOPE
+ {
+ vmime::net::fetchAttributes attribs = vmime::net::fetchAttributes::ENVELOPE;
+
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPUtils::buildFetchCommand(cnt, msgs, attribs);
+ VASSERT_EQ("envelope", "FETCH 42 ENVELOPE", cmd->getText());
+ }
+
+ // CONTENT_INFO
+ {
+ vmime::net::fetchAttributes attribs = vmime::net::fetchAttributes::CONTENT_INFO;
+
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPUtils::buildFetchCommand(cnt, msgs, attribs);
+ VASSERT_EQ("content", "FETCH 42 BODY[HEADER.FIELDS (CONTENT_TYPE)]", cmd->getText());
+ }
+
+ // IMPORTANCE
+ {
+ vmime::net::fetchAttributes attribs = vmime::net::fetchAttributes::IMPORTANCE;
+
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPUtils::buildFetchCommand(cnt, msgs, attribs);
+ VASSERT_EQ("importance", "FETCH 42 BODY[HEADER.FIELDS (IMPORTANCE X-PRIORITY)]", cmd->getText());
+ }
+
+ // Any header attribute + full header should give RFC822.HEADER
+ {
+ vmime::net::fetchAttributes attribs;
+ attribs.add(vmime::net::fetchAttributes::ENVELOPE);
+ attribs.add(vmime::net::fetchAttributes::FULL_HEADER);
+
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPUtils::buildFetchCommand(cnt, msgs, attribs);
+ VASSERT_EQ("full-header", "FETCH 42 RFC822.HEADER", cmd->getText());
+ }
+
+ // Test custom header
+ {
+ vmime::net::fetchAttributes attribs;
+ attribs.add("X-MyHeader");
+
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPUtils::buildFetchCommand(cnt, msgs, attribs);
+ VASSERT_EQ("custom-header", "FETCH 42 BODY[HEADER.FIELDS (x-myheader)]", cmd->getText());
+ }
+
+ // Test multiple flags
+ {
+ vmime::net::fetchAttributes attribs =
+ vmime::net::fetchAttributes::UID | vmime::net::fetchAttributes::FLAGS;
+
+ vmime::shared_ptr <IMAPCommand> cmd = IMAPUtils::buildFetchCommand(cnt, msgs, attribs);
+ VASSERT_EQ("multiple", "FETCH 42 (FLAGS UID)", cmd->getText());
+ }
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/net/maildir/maildirStoreTest.cpp b/vmime-master/tests/net/maildir/maildirStoreTest.cpp
new file mode 100644
index 0000000..1f418e8
--- /dev/null
+++ b/vmime-master/tests/net/maildir/maildirStoreTest.cpp
@@ -0,0 +1,584 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/platform.hpp"
+
+#include "vmime/net/maildir/maildirStore.hpp"
+#include "vmime/net/maildir/maildirFormat.hpp"
+
+
+// Shortcuts and helpers
+typedef vmime::utility::file::path fspath;
+typedef vmime::utility::file::path::component fspathc;
+
+typedef vmime::net::folder::path fpath;
+typedef vmime::net::folder::path::component fpathc;
+
+
+const fpath operator/(const fpath& path, const std::string& c) {
+
+ return path / fpathc(c);
+}
+
+
+/** Test messages */
+static const vmime::string TEST_MESSAGE_1 =
+ "From: <test@vmime.org>\r\n"
+ "Subject: VMime Test\r\n"
+ "Date: Thu, 01 Mar 2007 09:49:35 +0100\r\n"
+ "\r\n"
+ "Hello, world!";
+
+
+/** Maildir trees used in tests.
+ * Structure:
+ *
+ * .
+ * |-- Folder
+ * | `-- SubFolder
+ * | |-- SubSubFolder1
+ * | `-- SubSubFolder2
+ * `-- Folder2
+ *
+ */
+
+// KMail format
+static const vmime::string TEST_MAILDIR_KMAIL[] = { // directories to create
+ "/Folder",
+ "/Folder/new",
+ "/Folder/tmp",
+ "/Folder/cur",
+ "/.Folder.directory",
+ "/.Folder.directory/SubFolder",
+ "/.Folder.directory/SubFolder/new",
+ "/.Folder.directory/SubFolder/tmp",
+ "/.Folder.directory/SubFolder/cur",
+ "/.Folder.directory/.SubFolder.directory",
+ "/.Folder.directory/.SubFolder.directory/SubSubFolder1",
+ "/.Folder.directory/.SubFolder.directory/SubSubFolder1/new",
+ "/.Folder.directory/.SubFolder.directory/SubSubFolder1/tmp",
+ "/.Folder.directory/.SubFolder.directory/SubSubFolder1/cur",
+ "/.Folder.directory/.SubFolder.directory/SubSubFolder2",
+ "/.Folder.directory/.SubFolder.directory/SubSubFolder2/new",
+ "/.Folder.directory/.SubFolder.directory/SubSubFolder2/tmp",
+ "/.Folder.directory/.SubFolder.directory/SubSubFolder2/cur",
+ "/Folder2",
+ "/Folder2/new",
+ "/Folder2/tmp",
+ "/Folder2/cur",
+ "*" // end
+};
+
+static const vmime::string TEST_MAILDIRFILES_KMAIL[] = { // files to create and their contents
+ "/.Folder.directory/.SubFolder.directory/SubSubFolder2/cur/1043236113.351.EmqD:S", TEST_MESSAGE_1,
+ "*" // end
+};
+
+// Courier format
+static const vmime::string TEST_MAILDIR_COURIER[] = { // directories to create
+ "/.Folder",
+ "/.Folder/new",
+ "/.Folder/tmp",
+ "/.Folder/cur",
+ "/.Folder.SubFolder",
+ "/.Folder.SubFolder",
+ "/.Folder.SubFolder/new",
+ "/.Folder.SubFolder/tmp",
+ "/.Folder.SubFolder/cur",
+ "/.Folder.SubFolder.SubSubFolder1",
+ "/.Folder.SubFolder.SubSubFolder1/new",
+ "/.Folder.SubFolder.SubSubFolder1/tmp",
+ "/.Folder.SubFolder.SubSubFolder1/cur",
+ "/.Folder.SubFolder.SubSubFolder2",
+ "/.Folder.SubFolder.SubSubFolder2/new",
+ "/.Folder.SubFolder.SubSubFolder2/tmp",
+ "/.Folder.SubFolder.SubSubFolder2/cur",
+ "/.Folder2",
+ "/.Folder2/new",
+ "/.Folder2/tmp",
+ "/.Folder2/cur",
+ "*" // end
+};
+
+static const vmime::string TEST_MAILDIRFILES_COURIER[] = { // files to create and their contents
+ "/.Folder/maildirfolder", "",
+ "/.Folder.SubFolder/maildirfolder", "",
+ "/.Folder.SubFolder.SubSubFolder1/maildirfolder", "",
+ "/.Folder.SubFolder.SubSubFolder2/maildirfolder", "",
+ "/.Folder.SubFolder.SubSubFolder2/cur/1043236113.351.EmqD:S", TEST_MESSAGE_1,
+ "/.Folder2/maildirfolder", "",
+ "*" // end
+};
+
+
+
+VMIME_TEST_SUITE_BEGIN(maildirStoreTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testDetectFormat_KMail)
+ VMIME_TEST(testDetectFormat_Courier)
+
+ VMIME_TEST(testListRootFolders_KMail)
+ VMIME_TEST(testListAllFolders_KMail)
+
+ VMIME_TEST(testListRootFolders_Courier)
+ VMIME_TEST(testListAllFolders_Courier)
+
+ VMIME_TEST(testListMessages_KMail)
+ VMIME_TEST(testListMessages_Courier)
+
+ VMIME_TEST(testRenameFolder_KMail)
+ VMIME_TEST(testRenameFolder_Courier)
+
+ VMIME_TEST(testDestroyFolder_KMail)
+ VMIME_TEST(testDestroyFolder_Courier)
+
+ VMIME_TEST(testFolderExists_KMail)
+ VMIME_TEST(testFolderExists_Courier)
+
+ VMIME_TEST(testCreateFolder_KMail)
+ VMIME_TEST(testCreateFolder_Courier)
+ VMIME_TEST_LIST_END
+
+
+public:
+
+ maildirStoreTest() {
+
+ // Temporary directory
+ m_tempPath = fspath() / fspathc("tmp") // Use /tmp
+ / fspathc("vmime" + vmime::utility::stringUtils::toString(std::time(NULL))
+ + vmime::utility::stringUtils::toString(std::rand()));
+ }
+
+ void tearDown() {
+
+ // In case of an uncaught exception
+ destroyMaildir();
+ }
+
+ void testDetectFormat_KMail() {
+
+ createMaildir(TEST_MAILDIR_KMAIL, TEST_MAILDIRFILES_KMAIL);
+
+ vmime::shared_ptr <vmime::net::maildir::maildirStore> store =
+ vmime::dynamicCast <vmime::net::maildir::maildirStore>(createAndConnectStore());
+
+ VASSERT_EQ("*", "kmail", store->getFormat()->getName());
+
+ destroyMaildir();
+ }
+
+ void testDetectFormat_Courier() {
+
+ createMaildir(TEST_MAILDIR_COURIER, TEST_MAILDIRFILES_COURIER);
+
+ vmime::shared_ptr <vmime::net::maildir::maildirStore> store =
+ vmime::dynamicCast <vmime::net::maildir::maildirStore>(createAndConnectStore());
+
+ VASSERT_EQ("*", "courier", store->getFormat()->getName());
+
+ destroyMaildir();
+ }
+
+
+ void testListRootFolders_KMail() {
+
+ testListRootFoldersImpl(TEST_MAILDIR_KMAIL, TEST_MAILDIRFILES_KMAIL);
+ }
+
+ void testListRootFolders_Courier() {
+
+ testListRootFoldersImpl(TEST_MAILDIR_COURIER, TEST_MAILDIRFILES_COURIER);
+ }
+
+ void testListRootFoldersImpl(const vmime::string* const dirs, const vmime::string* const files) {
+
+ createMaildir(dirs, files);
+
+ // Connect to store
+ vmime::shared_ptr <vmime::net::store> store = createAndConnectStore();
+ vmime::shared_ptr <vmime::net::folder> rootFolder = store->getRootFolder();
+
+ // Get root folders, not recursive
+ const std::vector <vmime::shared_ptr <vmime::net::folder> >
+ rootFolders = rootFolder->getFolders(false);
+
+ VASSERT_EQ("1", 2, rootFolders.size());
+ VASSERT("2", findFolder(rootFolders, fpath() / "Folder") != NULL);
+ VASSERT("3", findFolder(rootFolders, fpath() / "Folder2") != NULL);
+
+ destroyMaildir();
+ }
+
+
+ void testListAllFolders_KMail() {
+
+ testListAllFoldersImpl(TEST_MAILDIR_KMAIL, TEST_MAILDIRFILES_KMAIL);
+ }
+
+ void testListAllFolders_Courier() {
+
+ testListAllFoldersImpl(TEST_MAILDIR_COURIER, TEST_MAILDIRFILES_COURIER);
+ }
+
+ void testListAllFoldersImpl(const vmime::string* const dirs, const vmime::string* const files) {
+
+ createMaildir(dirs, files);
+
+ // Connect to store
+ vmime::shared_ptr <vmime::net::store> store = createAndConnectStore();
+ vmime::shared_ptr <vmime::net::folder> rootFolder = store->getRootFolder();
+
+ // Get all folders, recursive
+ const std::vector <vmime::shared_ptr <vmime::net::folder> >
+ allFolders = rootFolder->getFolders(true);
+
+ VASSERT_EQ("1", 5, allFolders.size());
+ VASSERT("2", findFolder(allFolders, fpath() / "Folder") != NULL);
+ VASSERT("3", findFolder(allFolders, fpath() / "Folder" / "SubFolder") != NULL);
+ VASSERT("4", findFolder(allFolders, fpath() / "Folder" / "SubFolder" / "SubSubFolder1") != NULL);
+ VASSERT("5", findFolder(allFolders, fpath() / "Folder" / "SubFolder" / "SubSubFolder2") != NULL);
+ VASSERT("6", findFolder(allFolders, fpath() / "Folder2") != NULL);
+
+ destroyMaildir();
+ }
+
+
+ void testListMessages_KMail() {
+
+ testListMessagesImpl(TEST_MAILDIR_KMAIL, TEST_MAILDIRFILES_KMAIL);
+ }
+
+ void testListMessages_Courier() {
+
+ testListMessagesImpl(TEST_MAILDIR_COURIER, TEST_MAILDIRFILES_COURIER);
+ }
+
+ void testListMessagesImpl(const vmime::string* const dirs, const vmime::string* const files) {
+
+ createMaildir(dirs, files);
+
+ vmime::shared_ptr <vmime::net::store> store = createAndConnectStore();
+ vmime::shared_ptr <vmime::net::folder> rootFolder = store->getRootFolder();
+
+ vmime::shared_ptr <vmime::net::folder> folder = store->getFolder(
+ fpath() / "Folder" / "SubFolder" / "SubSubFolder2"
+ );
+
+ vmime::size_t count, unseen;
+ folder->status(count, unseen);
+
+ VASSERT_EQ("Message count", 1, count);
+
+ folder->open(vmime::net::folder::MODE_READ_ONLY);
+
+ vmime::shared_ptr <vmime::net::message> msg = folder->getMessage(1);
+
+ folder->fetchMessage(msg, vmime::net::fetchAttributes::SIZE);
+
+ VASSERT_EQ("Message size", TEST_MESSAGE_1.length(), msg->getSize());
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter os(oss);
+ msg->extract(os);
+
+ VASSERT_EQ("Message contents", TEST_MESSAGE_1, oss.str());
+
+ folder->close(false);
+
+ destroyMaildir();
+ }
+
+
+ void testRenameFolder_KMail() {
+
+ try {
+
+ testRenameFolderImpl(TEST_MAILDIR_KMAIL, TEST_MAILDIRFILES_KMAIL);
+
+ } catch (vmime::exception& e) {
+
+ std::cerr << e;
+ throw e;
+ }
+ }
+
+ void testRenameFolder_Courier()
+ {
+ try {
+
+ testRenameFolderImpl(TEST_MAILDIR_COURIER, TEST_MAILDIRFILES_COURIER);
+
+ } catch (vmime::exception& e) {
+
+ std::cerr << e;
+ throw e;
+ }
+ }
+
+ void testRenameFolderImpl(const vmime::string* const dirs, const vmime::string* const files) {
+
+ createMaildir(dirs, files);
+
+ vmime::shared_ptr <vmime::net::store> store = createAndConnectStore();
+ vmime::shared_ptr <vmime::net::folder> rootFolder = store->getRootFolder();
+
+ // Rename "Folder/SubFolder" to "Folder/foo"
+ vmime::shared_ptr <vmime::net::folder> folder =
+ store->getFolder(fpath() / "Folder" / "SubFolder");
+
+ folder->rename(fpath() / "Folder" / "foo");
+
+ // Ensure folder and its subfolders have been renamed
+ const std::vector <vmime::shared_ptr <vmime::net::folder> >
+ allFolders = rootFolder->getFolders(true);
+
+ VASSERT_EQ("1", 5, allFolders.size());
+ VASSERT("2", findFolder(allFolders, fpath() / "Folder") != NULL);
+ VASSERT("3", findFolder(allFolders, fpath() / "Folder" / "SubFolder") == NULL);
+ VASSERT("4", findFolder(allFolders, fpath() / "Folder" / "SubFolder" / "SubSubFolder1") == NULL);
+ VASSERT("5", findFolder(allFolders, fpath() / "Folder" / "SubFolder" / "SubSubFolder2") == NULL);
+ VASSERT("6", findFolder(allFolders, fpath() / "Folder2") != NULL);
+ VASSERT("7", findFolder(allFolders, fpath() / "Folder" / "foo") != NULL);
+ VASSERT("8", findFolder(allFolders, fpath() / "Folder" / "foo" / "SubSubFolder1") != NULL);
+ VASSERT("9", findFolder(allFolders, fpath() / "Folder" / "foo" / "SubSubFolder2") != NULL);
+
+ destroyMaildir();
+ }
+
+
+ void testDestroyFolder_KMail() {
+
+ testDestroyFolderImpl(TEST_MAILDIR_KMAIL, TEST_MAILDIRFILES_KMAIL);
+ }
+
+ void testDestroyFolder_Courier() {
+
+ testDestroyFolderImpl(TEST_MAILDIR_COURIER, TEST_MAILDIRFILES_COURIER);
+ }
+
+ void testDestroyFolderImpl(const vmime::string* const dirs, const vmime::string* const files) {
+
+ createMaildir(dirs, files);
+
+ vmime::shared_ptr <vmime::net::store> store = createAndConnectStore();
+ vmime::shared_ptr <vmime::net::folder> rootFolder = store->getRootFolder();
+
+ // Destroy "Folder/SubFolder" (total: 3 folders)
+ vmime::shared_ptr <vmime::net::folder> folder =
+ store->getFolder(fpath() / "Folder" / "SubFolder");
+
+ folder->destroy();
+
+ // Ensure folder and its subfolders have been deleted and other folders still exist
+ const std::vector <vmime::shared_ptr <vmime::net::folder> >
+ allFolders = rootFolder->getFolders(true);
+
+ VASSERT_EQ("1", 2, allFolders.size());
+ VASSERT("2", findFolder(allFolders, fpath() / "Folder") != NULL);
+ VASSERT("3", findFolder(allFolders, fpath() / "Folder" / "SubFolder") == NULL);
+ VASSERT("4", findFolder(allFolders, fpath() / "Folder" / "SubFolder" / "SubSubFolder1") == NULL);
+ VASSERT("5", findFolder(allFolders, fpath() / "Folder" / "SubFolder" / "SubSubFolder2") == NULL);
+ VASSERT("6", findFolder(allFolders, fpath() / "Folder2") != NULL);
+
+ destroyMaildir();
+ }
+
+
+ void testFolderExists_KMail() {
+
+ testFolderExistsImpl(TEST_MAILDIR_KMAIL, TEST_MAILDIRFILES_KMAIL);
+ }
+
+ void testFolderExists_Courier() {
+
+ testFolderExistsImpl(TEST_MAILDIR_COURIER, TEST_MAILDIRFILES_COURIER);
+ }
+
+ void testFolderExistsImpl(const vmime::string* const dirs, const vmime::string* const files) {
+
+ createMaildir(dirs, files);
+
+ vmime::shared_ptr <vmime::net::store> store = createAndConnectStore();
+ vmime::shared_ptr <vmime::net::folder> rootFolder = store->getRootFolder();
+
+ VASSERT("1", store->getFolder(fpath() / "Folder" / "SubFolder")->exists());
+ VASSERT("2", !store->getFolder(fpath() / "Folder" / "SubSubFolder1")->exists());
+ VASSERT("3", store->getFolder(fpath() / "Folder2")->exists());
+ VASSERT("4", store->getFolder(fpath() / "Folder" / "SubFolder" / "SubSubFolder2")->exists());
+
+ destroyMaildir();
+ }
+
+
+ void testCreateFolder_KMail() {
+
+ testCreateFolderImpl(TEST_MAILDIR_KMAIL, TEST_MAILDIRFILES_KMAIL);
+ }
+
+ void testCreateFolder_Courier() {
+
+ testCreateFolderImpl(TEST_MAILDIR_COURIER, TEST_MAILDIRFILES_COURIER);
+ }
+
+ void testCreateFolderImpl(const vmime::string* const dirs, const vmime::string* const files) {
+
+ createMaildir(dirs, files);
+
+ vmime::shared_ptr <vmime::net::store> store = createAndConnectStore();
+ vmime::shared_ptr <vmime::net::folder> rootFolder = store->getRootFolder();
+
+ VASSERT("Before", !store->getFolder(fpath() / "Folder" / "NewFolder")->exists());
+
+ vmime::net::folderAttributes attribs;
+ attribs.setType(vmime::net::folderAttributes::TYPE_CONTAINS_MESSAGES);
+
+ VASSERT_NO_THROW("Creation", store->getFolder(fpath() / "Folder" / "NewFolder")->create(attribs));
+
+ VASSERT("After", store->getFolder(fpath() / "Folder" / "NewFolder")->exists());
+
+ destroyMaildir();
+ }
+
+private:
+
+ vmime::utility::file::path m_tempPath;
+
+
+ vmime::shared_ptr <vmime::net::store> createAndConnectStore() {
+
+ vmime::shared_ptr <vmime::net::session> session = vmime::net::session::create();
+
+ vmime::shared_ptr <vmime::net::store> store =
+ session->getStore(getStoreURL());
+
+ store->connect();
+
+ return store;
+ }
+
+ const vmime::shared_ptr <vmime::net::folder> findFolder(
+ const std::vector <vmime::shared_ptr <vmime::net::folder> >& folders,
+ const vmime::net::folder::path& path
+ ) {
+
+ for (size_t i = 0, n = folders.size() ; i < n ; ++i) {
+
+ if (folders[i]->getFullPath() == path) {
+ return folders[i];
+ }
+ }
+
+ return vmime::null;
+ }
+
+ const vmime::utility::url getStoreURL() {
+
+ vmime::shared_ptr <vmime::utility::fileSystemFactory> fsf =
+ vmime::platform::getHandler()->getFileSystemFactory();
+
+ vmime::utility::url url(std::string("maildir://localhost")
+ + fsf->pathToString(m_tempPath));
+
+ return url;
+ }
+
+ void createMaildir(const vmime::string* const dirs, const vmime::string* const files) {
+
+ vmime::shared_ptr <vmime::utility::fileSystemFactory> fsf =
+ vmime::platform::getHandler()->getFileSystemFactory();
+
+ vmime::shared_ptr <vmime::utility::file> rootDir = fsf->create(m_tempPath);
+ rootDir->createDirectory(false);
+
+ for (vmime::string const* dir = dirs ; *dir != "*" ; ++dir) {
+
+ vmime::shared_ptr <vmime::utility::file> fdir = fsf->create(m_tempPath / fsf->stringToPath(*dir));
+ fdir->createDirectory(false);
+ }
+
+ for (vmime::string const* file = files ; *file != "*" ; file += 2) {
+
+ const vmime::string& contents = *(file + 1);
+
+ vmime::shared_ptr <vmime::utility::file> ffile = fsf->create(m_tempPath / fsf->stringToPath(*file));
+ ffile->createFile();
+
+ vmime::shared_ptr <vmime::utility::fileWriter> fileWriter = ffile->getFileWriter();
+ vmime::shared_ptr <vmime::utility::outputStream> os = fileWriter->getOutputStream();
+
+ os->write(contents.data(), contents.length());
+ os->flush();
+
+ fileWriter = vmime::null;
+ }
+
+ }
+
+ void destroyMaildir() {
+
+ vmime::shared_ptr <vmime::utility::fileSystemFactory> fsf =
+ vmime::platform::getHandler()->getFileSystemFactory();
+
+ recursiveDelete(fsf->create(m_tempPath));
+ }
+
+ void recursiveDelete(vmime::shared_ptr <vmime::utility::file> dir) {
+
+ if (!dir->exists() || !dir->isDirectory()) {
+ return;
+ }
+
+ vmime::shared_ptr <vmime::utility::fileIterator> files = dir->getFiles();
+
+ // First, delete files and subdirectories in this directory
+ while (files->hasMoreElements()) {
+
+ vmime::shared_ptr <vmime::utility::file> file = files->nextElement();
+
+ if (file->isDirectory()) {
+
+ recursiveDelete(file);
+
+ } else {
+
+ try {
+ file->remove();
+ } catch (vmime::exceptions::filesystem_exception&) {
+ // Ignore
+ }
+ }
+ }
+
+ // Then, delete this (empty) directory
+ try {
+ dir->remove();
+ } catch (vmime::exceptions::filesystem_exception&) {
+ // Ignore
+ }
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/net/maildir/maildirUtilsTest.cpp b/vmime-master/tests/net/maildir/maildirUtilsTest.cpp
new file mode 100644
index 0000000..9deeebf
--- /dev/null
+++ b/vmime-master/tests/net/maildir/maildirUtilsTest.cpp
@@ -0,0 +1,54 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/net/maildir/maildirUtils.hpp"
+
+
+using namespace vmime::net::maildir;
+
+
+VMIME_TEST_SUITE_BEGIN(maildirUtilsTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testMessageSetToNumberList)
+ VMIME_TEST_LIST_END
+
+
+ void testMessageSetToNumberList() {
+
+ const std::vector <size_t> msgNums =
+ maildirUtils::messageSetToNumberList(
+ vmime::net::messageSet::byNumber(5, -1),
+ /* msgCount */ 8
+ );
+
+ VASSERT_EQ("Count", 4, msgNums.size());
+ VASSERT_EQ("1", 5, msgNums[0]);
+ VASSERT_EQ("2", 6, msgNums[1]);
+ VASSERT_EQ("3", 7, msgNums[2]);
+ VASSERT_EQ("4", 8, msgNums[3]);
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/net/messageSetTest.cpp b/vmime-master/tests/net/messageSetTest.cpp
new file mode 100644
index 0000000..dee5dc8
--- /dev/null
+++ b/vmime-master/tests/net/messageSetTest.cpp
@@ -0,0 +1,229 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/net/messageSet.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(messageSetTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testNumberSet_Single)
+ VMIME_TEST(testNumberSet_Range)
+ VMIME_TEST(testNumberSet_InvalidRange)
+ VMIME_TEST(testNumberSet_InvalidFirst)
+ VMIME_TEST(testNumberSet_InfiniteRange)
+ VMIME_TEST(testNumberSet_Multiple)
+ VMIME_TEST(testUIDSet_Single)
+ VMIME_TEST(testUIDSet_Range)
+ VMIME_TEST(testUIDSet_InfiniteRange)
+ VMIME_TEST(testUIDSet_MultipleNumeric)
+ VMIME_TEST(testUIDSet_MultipleNonNumeric)
+ VMIME_TEST(testIsNumberSet)
+ VMIME_TEST(testIsUIDSet)
+ VMIME_TEST(testMixedRanges)
+ VMIME_TEST_LIST_END
+
+
+ class messageSetStringEnumerator : public vmime::net::messageSetEnumerator {
+
+ public:
+
+ messageSetStringEnumerator()
+ : m_first(true) {
+
+ }
+
+ void enumerateNumberMessageRange(const vmime::net::numberMessageRange& range) {
+
+ if (!m_first) {
+ m_oss << ",";
+ }
+
+ if (range.getFirst() == range.getLast()) {
+ m_oss << range.getFirst();
+ } else if (range.getLast() == size_t(-1)) {
+ m_oss << range.getFirst() << ":(LAST)";
+ } else {
+ m_oss << range.getFirst() << ":" << range.getLast();
+ }
+
+ m_first = false;
+ }
+
+ void enumerateUIDMessageRange(const vmime::net::UIDMessageRange& range) {
+
+ if (!m_first) {
+ m_oss << ",";
+ }
+
+ if (range.getFirst() == range.getLast()) {
+ m_oss << range.getFirst();
+ } else if (range.getLast() == size_t(-1)) {
+ m_oss << range.getFirst() << ":(LAST)";
+ } else {
+ m_oss << range.getFirst() << ":" << range.getLast();
+ }
+
+ m_first = false;
+ }
+
+ const std::string str() const {
+
+ return m_oss.str();
+ }
+
+ private:
+
+ std::ostringstream m_oss;
+ bool m_first;
+ };
+
+
+ const std::string enumerateAsString(const vmime::net::messageSet& set) {
+
+ messageSetStringEnumerator en;
+ set.enumerate(en);
+
+ return en.str();
+ }
+
+
+ void testNumberSet_Single() {
+
+ VASSERT_EQ("str", "42", enumerateAsString(vmime::net::messageSet::byNumber(42)));
+ }
+
+ void testNumberSet_Range() {
+
+ VASSERT_EQ("str", "42:100", enumerateAsString(vmime::net::messageSet::byNumber(42, 100)));
+ }
+
+ void testNumberSet_InvalidRange() {
+
+ VASSERT_THROW("first > last", vmime::net::messageSet::byNumber(100, 42), std::invalid_argument);
+ }
+
+ void testNumberSet_InvalidFirst() {
+
+ VASSERT_THROW("first == -1", vmime::net::messageSet::byNumber(-1, 42), std::invalid_argument);
+ }
+
+ void testNumberSet_InfiniteRange() {
+
+ VASSERT_EQ("str", "42:(LAST)", enumerateAsString(vmime::net::messageSet::byNumber(42, -1)));
+ }
+
+ void testNumberSet_Multiple() {
+
+ std::vector <vmime::size_t> numbers;
+ numbers.push_back(1); // test grouping 1:3
+ numbers.push_back(89); // test sorting
+ numbers.push_back(2);
+ numbers.push_back(3);
+ numbers.push_back(42);
+ numbers.push_back(53); // test grouping 53:57
+ numbers.push_back(54);
+ numbers.push_back(55);
+ numbers.push_back(56);
+ numbers.push_back(56); // test duplicates
+ numbers.push_back(57);
+ numbers.push_back(99);
+
+ VASSERT_EQ("str", "1:3,42,53:57,89,99", enumerateAsString(vmime::net::messageSet::byNumber(numbers)));
+ }
+
+
+ void testUIDSet_Single() {
+
+ VASSERT_EQ("str", "abcdef", enumerateAsString(vmime::net::messageSet::byUID("abcdef")));
+ }
+
+ void testUIDSet_Range() {
+
+ VASSERT_EQ("str", "abc:def", enumerateAsString(vmime::net::messageSet::byUID("abc:def")));
+ }
+
+ void testUIDSet_InfiniteRange() {
+
+ VASSERT_EQ("str", "abc:*", enumerateAsString(vmime::net::messageSet::byUID("abc", "*")));
+ }
+
+ void testUIDSet_MultipleNumeric() {
+
+ std::vector <vmime::net::message::uid> uids;
+ uids.push_back("1"); // test grouping 1:3
+ uids.push_back("89"); // test sorting
+ uids.push_back("2");
+ uids.push_back("3");
+ uids.push_back("42");
+ uids.push_back("53"); // test grouping 53:57
+ uids.push_back("54");
+ uids.push_back("55");
+ uids.push_back("56");
+ uids.push_back("56"); // test duplicates
+ uids.push_back("57");
+ uids.push_back("99");
+
+ VASSERT_EQ("str", "1:3,42,53:57,89,99", enumerateAsString(vmime::net::messageSet::byUID(uids)));
+ }
+
+ void testUIDSet_MultipleNonNumeric() {
+
+ std::vector <vmime::net::message::uid> uids;
+ uids.push_back("12");
+ uids.push_back("34");
+ uids.push_back("ab56");
+ uids.push_back("78cd");
+
+ VASSERT_EQ("str", "12,34,ab56,78cd", enumerateAsString(vmime::net::messageSet::byUID(uids)));
+ }
+
+ void testIsNumberSet() {
+
+ VASSERT_TRUE("number1", vmime::net::messageSet::byNumber(42).isNumberSet());
+ VASSERT_FALSE("uid1", vmime::net::messageSet::byUID("42").isNumberSet());
+
+ VASSERT_TRUE("number2", vmime::net::messageSet::byNumber(42, -1).isNumberSet());
+ VASSERT_FALSE("uid2", vmime::net::messageSet::byUID("42", "*").isNumberSet());
+ }
+
+ void testIsUIDSet() {
+
+ VASSERT_FALSE("number1", vmime::net::messageSet::byNumber(42).isUIDSet());
+ VASSERT_TRUE("uid1", vmime::net::messageSet::byUID("42").isUIDSet());
+
+ VASSERT_FALSE("number2", vmime::net::messageSet::byNumber(42, -1).isUIDSet());
+ VASSERT_TRUE("uid2", vmime::net::messageSet::byUID("42", "*").isUIDSet());
+ }
+
+ void testMixedRanges() {
+
+ vmime::net::messageSet set = vmime::net::messageSet::byNumber(1, 5);
+ set.addRange(vmime::net::numberMessageRange(6, 8));
+
+ VASSERT_THROW("mixed ranges", set.addRange(vmime::net::UIDMessageRange("123")), std::invalid_argument);
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/net/pop3/POP3CommandTest.cpp b/vmime-master/tests/net/pop3/POP3CommandTest.cpp
new file mode 100644
index 0000000..3ed579e
--- /dev/null
+++ b/vmime-master/tests/net/pop3/POP3CommandTest.cpp
@@ -0,0 +1,241 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "tests/net/pop3/POP3TestUtils.hpp"
+
+#include "vmime/net/pop3/POP3Command.hpp"
+
+
+using namespace vmime::net::pop3;
+
+
+VMIME_TEST_SUITE_BEGIN(POP3CommandTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testCreateCommand)
+ VMIME_TEST(testCreateCommandParams)
+ VMIME_TEST(testCAPA)
+ VMIME_TEST(testNOOP)
+ VMIME_TEST(testAUTH)
+ VMIME_TEST(testAUTH_InitialResponse)
+ VMIME_TEST(testSTLS)
+ VMIME_TEST(testAPOP)
+ VMIME_TEST(testUSER)
+ VMIME_TEST(testPASS)
+ VMIME_TEST(testSTAT)
+ VMIME_TEST(testLIST)
+ VMIME_TEST(testLISTMessage)
+ VMIME_TEST(testUIDL)
+ VMIME_TEST(testUIDLMessage)
+ VMIME_TEST(testDELE)
+ VMIME_TEST(testRETR)
+ VMIME_TEST(testTOP)
+ VMIME_TEST(testRSET)
+ VMIME_TEST(testQUIT)
+ VMIME_TEST(testWriteToSocket)
+ VMIME_TEST_LIST_END
+
+
+ void testCreateCommand() {
+
+ vmime::shared_ptr <POP3Command> cmd = POP3Command::createCommand("MY_COMMAND");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "MY_COMMAND", cmd->getText());
+ }
+
+ void testCreateCommandParams() {
+
+ vmime::shared_ptr <POP3Command> cmd = POP3Command::createCommand("MY_COMMAND param1 param2");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "MY_COMMAND param1 param2", cmd->getText());
+ }
+
+ void testCAPA() {
+
+ vmime::shared_ptr <POP3Command> cmd = POP3Command::CAPA();
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "CAPA", cmd->getText());
+ }
+
+ void testNOOP() {
+
+ vmime::shared_ptr <POP3Command> cmd = POP3Command::NOOP();
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "NOOP", cmd->getText());
+ }
+
+ void testAUTH() {
+
+ vmime::shared_ptr <POP3Command> cmd = POP3Command::AUTH("saslmechanism");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "AUTH saslmechanism", cmd->getText());
+ }
+
+ void testAUTH_InitialResponse() {
+
+ vmime::shared_ptr <POP3Command> cmd = POP3Command::AUTH("saslmechanism", "initial-response");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "AUTH saslmechanism initial-response", cmd->getText());
+ }
+
+ void testSTLS() {
+
+ vmime::shared_ptr <POP3Command> cmd = POP3Command::STLS();
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "STLS", cmd->getText());
+ }
+
+ void testAPOP() {
+
+ vmime::shared_ptr <POP3Command> cmd = POP3Command::APOP("user", "digest");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "APOP user digest", cmd->getText());
+ }
+
+ void testUSER() {
+
+ vmime::shared_ptr <POP3Command> cmd = POP3Command::USER("user");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "USER user", cmd->getText());
+ }
+
+ void testPASS() {
+
+ vmime::shared_ptr <POP3Command> cmd = POP3Command::PASS("pass");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "PASS pass", cmd->getText());
+ }
+
+ void testSTAT() {
+
+ vmime::shared_ptr <POP3Command> cmd = POP3Command::STAT();
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "STAT", cmd->getText());
+ }
+
+ void testLIST() {
+
+ vmime::shared_ptr <POP3Command> cmd = POP3Command::LIST();
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "LIST", cmd->getText());
+ }
+
+ void testLISTMessage() {
+
+ vmime::shared_ptr <POP3Command> cmd = POP3Command::LIST(42);
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "LIST 42", cmd->getText());
+ }
+
+ void testUIDL() {
+
+ vmime::shared_ptr <POP3Command> cmd = POP3Command::UIDL();
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "UIDL", cmd->getText());
+ }
+
+ void testUIDLMessage() {
+
+ vmime::shared_ptr <POP3Command> cmd = POP3Command::UIDL(42);
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "UIDL 42", cmd->getText());
+ }
+
+ void testDELE() {
+
+ vmime::shared_ptr <POP3Command> cmd = POP3Command::DELE(42);
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "DELE 42", cmd->getText());
+ }
+
+ void testRETR() {
+
+ vmime::shared_ptr <POP3Command> cmd = POP3Command::RETR(42);
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "RETR 42", cmd->getText());
+ }
+
+ void testTOP() {
+
+ vmime::shared_ptr <POP3Command> cmd = POP3Command::TOP(42, 567);
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "TOP 42 567", cmd->getText());
+ }
+
+ void testRSET() {
+
+ vmime::shared_ptr <POP3Command> cmd = POP3Command::RSET();
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "RSET", cmd->getText());
+ }
+
+ void testQUIT() {
+
+ vmime::shared_ptr <POP3Command> cmd = POP3Command::QUIT();
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "QUIT", cmd->getText());
+ }
+
+ void testWriteToSocket() {
+
+ vmime::shared_ptr <POP3Command> cmd = POP3Command::createCommand("MY_COMMAND param1 param2");
+
+ vmime::shared_ptr <testSocket> sok = vmime::make_shared <testSocket>();
+
+ vmime::shared_ptr <POP3ConnectionTest> conn =
+ vmime::make_shared <POP3ConnectionTest>(
+ vmime::dynamicCast <vmime::net::socket>(sok),
+ vmime::shared_ptr <vmime::net::timeoutHandler>()
+ );
+
+ cmd->send(conn);
+
+ vmime::string response;
+ sok->localReceive(response);
+
+ VASSERT_EQ("Sent buffer", "MY_COMMAND param1 param2\r\n", response);
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/net/pop3/POP3ResponseTest.cpp b/vmime-master/tests/net/pop3/POP3ResponseTest.cpp
new file mode 100644
index 0000000..8fecb74
--- /dev/null
+++ b/vmime-master/tests/net/pop3/POP3ResponseTest.cpp
@@ -0,0 +1,244 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "tests/net/pop3/POP3TestUtils.hpp"
+
+#include "vmime/net/pop3/POP3Response.hpp"
+
+
+using namespace vmime::net::pop3;
+
+
+VMIME_TEST_SUITE_BEGIN(POP3ResponseTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testSingleLineResponseOK)
+ VMIME_TEST(testSingleLineResponseERR)
+ VMIME_TEST(testSingleLineResponseReady)
+ VMIME_TEST(testSingleLineResponseInvalid)
+ VMIME_TEST(testSingleLineResponseLF)
+ VMIME_TEST(testMultiLineResponse)
+ VMIME_TEST(testMultiLineResponseLF)
+ VMIME_TEST(testLargeResponse)
+ VMIME_TEST_LIST_END
+
+
+ void testSingleLineResponseOK() {
+
+ vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
+ vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>();
+
+ vmime::shared_ptr <POP3ConnectionTest> conn =
+ vmime::make_shared <POP3ConnectionTest>(
+ vmime::dynamicCast <vmime::net::socket>(socket), toh
+ );
+
+ socket->localSend("+OK Response Text\r\n");
+
+ vmime::shared_ptr <POP3Response> resp =
+ POP3Response::readResponse(conn);
+
+ VASSERT_EQ("Code", POP3Response::CODE_OK, resp->getCode());
+ VASSERT_TRUE("Success", resp->isSuccess());
+ VASSERT_EQ("Lines", 0, resp->getLineCount());
+ VASSERT_EQ("Text", "Response Text", resp->getText());
+ VASSERT_EQ("First Line", "+OK Response Text", resp->getFirstLine());
+ }
+
+ void testSingleLineResponseERR() {
+
+ vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
+ vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>();
+
+ vmime::shared_ptr <POP3ConnectionTest> conn =
+ vmime::make_shared <POP3ConnectionTest>(
+ vmime::dynamicCast <vmime::net::socket>(socket), toh
+ );
+
+ socket->localSend("-ERR Response Text\r\n");
+
+ vmime::shared_ptr <POP3Response> resp =
+ POP3Response::readResponse(conn);
+
+ VASSERT_EQ("Code", POP3Response::CODE_ERR, resp->getCode());
+ VASSERT_FALSE("Success", resp->isSuccess());
+ VASSERT_EQ("Lines", 0, resp->getLineCount());
+ VASSERT_EQ("Text", "Response Text", resp->getText());
+ VASSERT_EQ("First Line", "-ERR Response Text", resp->getFirstLine());
+ }
+
+ void testSingleLineResponseReady() {
+
+ vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
+ vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>();
+
+ vmime::shared_ptr <POP3ConnectionTest> conn =
+ vmime::make_shared <POP3ConnectionTest>(
+ vmime::dynamicCast <vmime::net::socket>(socket), toh
+ );
+
+ socket->localSend("+ challenge_string\r\n");
+
+ vmime::shared_ptr <POP3Response> resp =
+ POP3Response::readResponse(conn);
+
+ VASSERT_EQ("Code", POP3Response::CODE_READY, resp->getCode());
+ VASSERT_FALSE("Success", resp->isSuccess());
+ VASSERT_EQ("Lines", 0, resp->getLineCount());
+ VASSERT_EQ("Text", "challenge_string", resp->getText());
+ VASSERT_EQ("First Line", "+ challenge_string", resp->getFirstLine());
+ }
+
+ void testSingleLineResponseInvalid() {
+
+ vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
+ vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>();
+
+ vmime::shared_ptr <POP3ConnectionTest> conn = vmime::make_shared <POP3ConnectionTest>
+ (vmime::dynamicCast <vmime::net::socket>(socket), toh);
+
+ socket->localSend("Invalid Response Text\r\n");
+
+ vmime::shared_ptr <POP3Response> resp =
+ POP3Response::readResponse(conn);
+
+ VASSERT_EQ("Code", POP3Response::CODE_ERR, resp->getCode());
+ VASSERT_FALSE("Success", resp->isSuccess());
+ VASSERT_EQ("Lines", 0, resp->getLineCount());
+ VASSERT_EQ("Text", "Response Text", resp->getText());
+ VASSERT_EQ("First Line", "Invalid Response Text", resp->getFirstLine());
+ }
+
+ void testSingleLineResponseLF() {
+
+ vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
+ vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>();
+
+ vmime::shared_ptr <POP3ConnectionTest> conn =
+ vmime::make_shared <POP3ConnectionTest>(
+ vmime::dynamicCast <vmime::net::socket>(socket), toh
+ );
+
+ socket->localSend("+OK Response terminated by LF\n");
+
+ vmime::shared_ptr <POP3Response> resp =
+ POP3Response::readResponse(conn);
+
+ VASSERT_EQ("Code", POP3Response::CODE_OK, resp->getCode());
+ VASSERT_TRUE("Success", resp->isSuccess());
+ VASSERT_EQ("Lines", 0, resp->getLineCount());
+ VASSERT_EQ("Text", "Response terminated by LF", resp->getText());
+ VASSERT_EQ("First Line", "+OK Response terminated by LF", resp->getFirstLine());
+ }
+
+ void testMultiLineResponse() {
+
+ vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
+ vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>();
+
+ vmime::shared_ptr <POP3ConnectionTest> conn =
+ vmime::make_shared <POP3ConnectionTest>(
+ vmime::dynamicCast <vmime::net::socket>(socket), toh
+ );
+
+ socket->localSend("+OK Response Text\r\n");
+ socket->localSend("Line 1\r\n");
+ socket->localSend("Line 2\r\n");
+ socket->localSend(".\r\n");
+
+ vmime::shared_ptr <POP3Response> resp =
+ POP3Response::readMultilineResponse(conn);
+
+ VASSERT_EQ("Code", POP3Response::CODE_OK, resp->getCode());
+ VASSERT_TRUE("Success", resp->isSuccess());
+ VASSERT_EQ("Lines", 2, resp->getLineCount());
+ VASSERT_EQ("Text", "Response Text", resp->getText());
+ VASSERT_EQ("First Line", "+OK Response Text", resp->getFirstLine());
+ VASSERT_EQ("Line 1", "Line 1", resp->getLineAt(0));
+ VASSERT_EQ("Line 2", "Line 2", resp->getLineAt(1));
+ }
+
+ void testMultiLineResponseLF() {
+
+ vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
+ vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>();
+
+ vmime::shared_ptr <POP3ConnectionTest> conn =
+ vmime::make_shared <POP3ConnectionTest>(
+ vmime::dynamicCast <vmime::net::socket>(socket), toh
+ );
+
+ socket->localSend("+OK Response Text\n");
+ socket->localSend("Line 1\n");
+ socket->localSend("Line 2\n");
+ socket->localSend(".\n");
+
+ vmime::shared_ptr <POP3Response> resp =
+ POP3Response::readMultilineResponse(conn);
+
+ VASSERT_EQ("Code", POP3Response::CODE_OK, resp->getCode());
+ VASSERT_TRUE("Success", resp->isSuccess());
+ VASSERT_EQ("Lines", 2, resp->getLineCount());
+ VASSERT_EQ("Text", "Response Text", resp->getText());
+ VASSERT_EQ("First Line", "+OK Response Text", resp->getFirstLine());
+ VASSERT_EQ("Line 1", "Line 1", resp->getLineAt(0));
+ VASSERT_EQ("Line 2", "Line 2", resp->getLineAt(1));
+ }
+
+ void testLargeResponse() {
+
+ std::ostringstream data;
+
+ for (unsigned int i = 0 ; i < 5000 ; ++i) {
+ data << "VMIME.VMIME\nVMIME\r\nVMIME_VMIME";
+ }
+
+ vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
+ vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>();
+
+ vmime::shared_ptr <POP3ConnectionTest> conn =
+ vmime::make_shared <POP3ConnectionTest>(
+ vmime::dynamicCast <vmime::net::socket>(socket), toh
+ );
+
+ socket->localSend("+OK Large Response Follows\n");
+ socket->localSend(data.str());
+ socket->localSend("\r\n.\r\n");
+
+ vmime::string receivedData;
+ vmime::utility::outputStreamStringAdapter receivedDataStream(receivedData);
+
+ vmime::shared_ptr <POP3Response> resp =
+ POP3Response::readLargeResponse(conn, receivedDataStream, NULL, 0);
+
+ VASSERT_EQ("Code", POP3Response::CODE_OK, resp->getCode());
+ VASSERT_TRUE("Success", resp->isSuccess());
+ VASSERT_EQ("Lines", 0, resp->getLineCount());
+ VASSERT_EQ("Text", "Large Response Follows", resp->getText());
+ VASSERT_EQ("Data Length", data.str().length(), receivedData.length());
+ VASSERT_EQ("Data Bytes", data.str(), receivedData);
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/net/pop3/POP3StoreTest.cpp b/vmime-master/tests/net/pop3/POP3StoreTest.cpp
new file mode 100644
index 0000000..5d9e3c2
--- /dev/null
+++ b/vmime-master/tests/net/pop3/POP3StoreTest.cpp
@@ -0,0 +1,67 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "tests/net/pop3/POP3TestUtils.hpp"
+
+#include "vmime/net/pop3/POP3Store.hpp"
+#include "vmime/net/pop3/POP3SStore.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(POP3StoreTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testCreateFromURL)
+ VMIME_TEST(testConnectToInvalidServer)
+ VMIME_TEST_LIST_END
+
+
+ void testCreateFromURL() {
+
+ vmime::shared_ptr <vmime::net::session> sess = vmime::net::session::create();
+
+ // POP3
+ vmime::utility::url url("pop3://pop3.vmime.org");
+ vmime::shared_ptr <vmime::net::store> store = sess->getStore(url);
+
+ VASSERT_TRUE("pop3", typeid(*store) == typeid(vmime::net::pop3::POP3Store));
+
+ // POP3S
+ vmime::utility::url url2("pop3s://pop3s.vmime.org");
+ vmime::shared_ptr <vmime::net::store> store2 = sess->getStore(url2);
+
+ VASSERT_TRUE("pop3s", typeid(*store2) == typeid(vmime::net::pop3::POP3SStore));
+ }
+
+ void testConnectToInvalidServer() {
+
+ vmime::shared_ptr <vmime::net::session> sess = vmime::net::session::create();
+
+ vmime::utility::url url("pop3://invalid-pop3-server");
+ vmime::shared_ptr <vmime::net::store> store = sess->getStore(url);
+
+ VASSERT_THROW("connect", store->connect(), vmime::exceptions::connection_error);
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/net/pop3/POP3TestUtils.hpp b/vmime-master/tests/net/pop3/POP3TestUtils.hpp
new file mode 100644
index 0000000..24efb8b
--- /dev/null
+++ b/vmime-master/tests/net/pop3/POP3TestUtils.hpp
@@ -0,0 +1,69 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "vmime/net/pop3/POP3Connection.hpp"
+#include "vmime/net/pop3/POP3Store.hpp"
+
+
+class POP3TestStore : public vmime::net::pop3::POP3Store {
+
+public:
+
+ POP3TestStore()
+ : POP3Store(vmime::net::session::create(),
+ vmime::shared_ptr <vmime::security::authenticator>()) {
+
+ }
+};
+
+
+class POP3ConnectionTest : public vmime::net::pop3::POP3Connection {
+
+public:
+
+ POP3ConnectionTest(
+ vmime::shared_ptr <vmime::net::socket> socket,
+ vmime::shared_ptr <vmime::net::timeoutHandler> timeoutHandler
+ )
+ : POP3Connection(vmime::make_shared <POP3TestStore>(),
+ vmime::shared_ptr <vmime::security::authenticator>()),
+ m_socket(socket),
+ m_timeoutHandler(timeoutHandler) {
+
+ }
+
+ vmime::shared_ptr <vmime::net::socket> getSocket() {
+
+ return m_socket;
+ }
+
+ vmime::shared_ptr <vmime::net::timeoutHandler> getTimeoutHandler() {
+
+ return m_timeoutHandler;
+ }
+
+private:
+
+ vmime::shared_ptr <vmime::net::socket> m_socket;
+ vmime::shared_ptr <vmime::net::timeoutHandler> m_timeoutHandler;
+};
diff --git a/vmime-master/tests/net/pop3/POP3UtilsTest.cpp b/vmime-master/tests/net/pop3/POP3UtilsTest.cpp
new file mode 100644
index 0000000..1cded39
--- /dev/null
+++ b/vmime-master/tests/net/pop3/POP3UtilsTest.cpp
@@ -0,0 +1,88 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "tests/net/pop3/POP3TestUtils.hpp"
+
+#include "vmime/net/pop3/POP3Utils.hpp"
+#include "vmime/net/pop3/POP3Response.hpp"
+
+
+using namespace vmime::net::pop3;
+
+
+VMIME_TEST_SUITE_BEGIN(POP3UtilsTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testParseMultiListOrUidlResponse)
+ VMIME_TEST(testMessageSetToNumberList)
+ VMIME_TEST_LIST_END
+
+
+ void testParseMultiListOrUidlResponse() {
+
+ vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
+ vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>();
+
+ vmime::shared_ptr <POP3ConnectionTest> conn =
+ vmime::make_shared <POP3ConnectionTest>(
+ vmime::dynamicCast <vmime::net::socket>(socket), toh
+ );
+
+ socket->localSend("+OK Response Text\r\n");
+ socket->localSend("1 abcdef\r\n");
+ socket->localSend("23 ghijkl\r\n");
+ socket->localSend("4\tmnopqr\r\n");
+ socket->localSend("567xx\tstuvwx\r\n");
+ socket->localSend("8 yz \r\n");
+ socket->localSend(".\r\n");
+
+ vmime::shared_ptr <POP3Response> resp =
+ POP3Response::readMultilineResponse(conn);
+
+ std::map <vmime::size_t, vmime::string> result;
+ POP3Utils::parseMultiListOrUidlResponse(resp, result);
+
+ VASSERT_EQ("Count", 5, result.size());
+ VASSERT_EQ("1", "abcdef", result[1]);
+ VASSERT_EQ("2 (multiple spaces)", "ghijkl", result[23]);
+ VASSERT_EQ("3 (with tab)", "mnopqr", result[4]);
+ VASSERT_EQ("4 (with invalid digit)", "stuvwx", result[567]);
+ VASSERT_EQ("5 (with extra space)", "yz", result[8]);
+ }
+
+ void testMessageSetToNumberList() {
+
+ const std::vector <size_t> msgNums = POP3Utils::messageSetToNumberList(
+ vmime::net::messageSet::byNumber(5, -1), /* msgCount */ 8
+ );
+
+ VASSERT_EQ("Count", 4, msgNums.size());
+ VASSERT_EQ("1", 5, msgNums[0]);
+ VASSERT_EQ("2", 6, msgNums[1]);
+ VASSERT_EQ("3", 7, msgNums[2]);
+ VASSERT_EQ("4", 8, msgNums[3]);
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/net/smtp/SMTPCommandSetTest.cpp b/vmime-master/tests/net/smtp/SMTPCommandSetTest.cpp
new file mode 100644
index 0000000..7ea3578
--- /dev/null
+++ b/vmime-master/tests/net/smtp/SMTPCommandSetTest.cpp
@@ -0,0 +1,181 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/net/smtp/SMTPCommandSet.hpp"
+#include "vmime/net/smtp/SMTPCommand.hpp"
+
+
+using namespace vmime::net::smtp;
+
+
+VMIME_TEST_SUITE_BEGIN(SMTPCommandSetTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testCreate)
+ VMIME_TEST(testCreatePipeline)
+ VMIME_TEST(testAddCommand)
+ VMIME_TEST(testAddCommandPipeline)
+ VMIME_TEST(testWriteToSocket)
+ VMIME_TEST(testWriteToSocketPipeline)
+ VMIME_TEST(testGetLastCommandSent)
+ VMIME_TEST(testGetLastCommandSentPipeline)
+ VMIME_TEST_LIST_END
+
+
+ void testCreate() {
+
+ vmime::shared_ptr <SMTPCommandSet> cset = SMTPCommandSet::create(/* pipelining */ false);
+
+ VASSERT_NOT_NULL("Not null", cset);
+ VASSERT_FALSE("Finished", cset->isFinished());
+ }
+
+ void testCreatePipeline() {
+
+ vmime::shared_ptr <SMTPCommandSet> cset = SMTPCommandSet::create(/* pipelining */ true);
+
+ VASSERT_NOT_NULL("Not null", cset);
+ VASSERT_FALSE("Finished", cset->isFinished());
+ }
+
+ void testAddCommand() {
+
+ vmime::shared_ptr <SMTPCommandSet> cset = SMTPCommandSet::create(/* pipelining */ false);
+
+ VASSERT_NO_THROW("No throw 1", cset->addCommand(SMTPCommand::createCommand("MY_COMMAND1")));
+ VASSERT_EQ("Text", "MY_COMMAND1\r\n", cset->getText());
+ VASSERT_NO_THROW("No throw 2", cset->addCommand(SMTPCommand::createCommand("MY_COMMAND2")));
+ VASSERT_EQ("Text", "MY_COMMAND1\r\nMY_COMMAND2\r\n", cset->getText());
+
+ vmime::shared_ptr <vmime::net::tracer> tracer;
+ vmime::shared_ptr <testSocket> sok = vmime::make_shared <testSocket>();
+
+ cset->writeToSocket(sok, tracer);
+ VASSERT_FALSE("Finished", cset->isFinished());
+
+ // Can't add commands when writing to socket has started
+ VASSERT_THROW("Throw", cset->addCommand(SMTPCommand::createCommand("MY_COMMAND3")), std::runtime_error);
+
+ cset->writeToSocket(sok, tracer);
+ VASSERT_TRUE("Finished", cset->isFinished());
+ }
+
+ void testAddCommandPipeline() {
+
+ vmime::shared_ptr <SMTPCommandSet> cset = SMTPCommandSet::create(/* pipelining */ true);
+
+ VASSERT_NO_THROW("No throw 1", cset->addCommand(SMTPCommand::createCommand("MY_COMMAND1")));
+ VASSERT_EQ("Text", "MY_COMMAND1\r\n", cset->getText());
+ VASSERT_NO_THROW("No throw 2", cset->addCommand(SMTPCommand::createCommand("MY_COMMAND2")));
+ VASSERT_EQ("Text", "MY_COMMAND1\r\nMY_COMMAND2\r\n", cset->getText());
+
+ vmime::shared_ptr <vmime::net::tracer> tracer;
+ vmime::shared_ptr <testSocket> sok = vmime::make_shared <testSocket>();
+ vmime::string response;
+
+ cset->writeToSocket(sok, tracer);
+ VASSERT_TRUE("Finished", cset->isFinished());
+
+ sok->localReceive(response);
+ VASSERT_EQ("Receive cmds", "MY_COMMAND1\r\nMY_COMMAND2\r\n", response);
+
+ // Can't add commands when writing to socket has started
+ VASSERT_THROW("Throw", cset->addCommand(SMTPCommand::createCommand("MY_COMMAND3")), std::runtime_error);
+ }
+
+ void testWriteToSocket() {
+
+ vmime::shared_ptr <SMTPCommandSet> cset = SMTPCommandSet::create(/* pipelining */ false);
+
+ cset->addCommand(SMTPCommand::createCommand("MY_COMMAND1"));
+ cset->addCommand(SMTPCommand::createCommand("MY_COMMAND2"));
+
+ vmime::shared_ptr <vmime::net::tracer> tracer;
+ vmime::shared_ptr <testSocket> sok = vmime::make_shared <testSocket>();
+ vmime::string response;
+
+ cset->writeToSocket(sok, tracer);
+
+ sok->localReceive(response);
+ VASSERT_EQ("Receive cmd 1", "MY_COMMAND1\r\n", response);
+
+ cset->writeToSocket(sok, tracer);
+
+ sok->localReceive(response);
+ VASSERT_EQ("Receive cmd 2", "MY_COMMAND2\r\n", response);
+ }
+
+ void testWriteToSocketPipeline() {
+
+ vmime::shared_ptr <SMTPCommandSet> cset = SMTPCommandSet::create(/* pipelining */ true);
+
+ cset->addCommand(SMTPCommand::createCommand("MY_COMMAND1"));
+ cset->addCommand(SMTPCommand::createCommand("MY_COMMAND2"));
+
+ vmime::shared_ptr <vmime::net::tracer> tracer;
+ vmime::shared_ptr <testSocket> sok = vmime::make_shared <testSocket>();
+ vmime::string response;
+
+ cset->writeToSocket(sok, tracer);
+
+ sok->localReceive(response);
+ VASSERT_EQ("Receive cmds", "MY_COMMAND1\r\nMY_COMMAND2\r\n", response);
+ }
+
+ void testGetLastCommandSent() {
+
+ vmime::shared_ptr <SMTPCommandSet> cset = SMTPCommandSet::create(/* pipelining */ false);
+
+ cset->addCommand(SMTPCommand::createCommand("MY_COMMAND1"));
+ cset->addCommand(SMTPCommand::createCommand("MY_COMMAND2"));
+
+ vmime::shared_ptr <vmime::net::tracer> tracer;
+ vmime::shared_ptr <testSocket> sok = vmime::make_shared <testSocket>();
+
+ cset->writeToSocket(sok, tracer);
+ VASSERT_EQ("Cmd 1", "MY_COMMAND1", cset->getLastCommandSent()->getText());
+
+ cset->writeToSocket(sok, tracer);
+ VASSERT_EQ("Cmd 2", "MY_COMMAND2", cset->getLastCommandSent()->getText());
+ }
+
+ void testGetLastCommandSentPipeline() {
+
+ vmime::shared_ptr <SMTPCommandSet> cset = SMTPCommandSet::create(/* pipelining */ true);
+
+ cset->addCommand(SMTPCommand::createCommand("MY_COMMAND1"));
+ cset->addCommand(SMTPCommand::createCommand("MY_COMMAND2"));
+
+ vmime::shared_ptr <vmime::net::tracer> tracer;
+ vmime::shared_ptr <testSocket> sok = vmime::make_shared <testSocket>();
+
+ cset->writeToSocket(sok, tracer);
+ VASSERT_EQ("Cmd 1", "MY_COMMAND1", cset->getLastCommandSent()->getText());
+
+ cset->writeToSocket(sok, tracer);
+ VASSERT_EQ("Cmd 2", "MY_COMMAND2", cset->getLastCommandSent()->getText());
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/net/smtp/SMTPCommandTest.cpp b/vmime-master/tests/net/smtp/SMTPCommandTest.cpp
new file mode 100644
index 0000000..ecaf292
--- /dev/null
+++ b/vmime-master/tests/net/smtp/SMTPCommandTest.cpp
@@ -0,0 +1,252 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/net/smtp/SMTPCommand.hpp"
+
+
+using namespace vmime::net::smtp;
+
+
+VMIME_TEST_SUITE_BEGIN(SMTPCommandTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testCreateCommand)
+ VMIME_TEST(testCreateCommandParams)
+ VMIME_TEST(testHELO)
+ VMIME_TEST(testEHLO)
+ VMIME_TEST(testAUTH)
+ VMIME_TEST(testAUTH_InitialResponse)
+ VMIME_TEST(testSTARTTLS)
+ VMIME_TEST(testMAIL)
+ VMIME_TEST(testMAIL_Encoded)
+ VMIME_TEST(testMAIL_UTF8)
+ VMIME_TEST(testMAIL_SIZE)
+ VMIME_TEST(testMAIL_SIZE_UTF8)
+ VMIME_TEST(testRCPT)
+ VMIME_TEST(testRCPT_Encoded)
+ VMIME_TEST(testRCPT_UTF8)
+ VMIME_TEST(testRSET)
+ VMIME_TEST(testDATA)
+ VMIME_TEST(testBDAT)
+ VMIME_TEST(testNOOP)
+ VMIME_TEST(testQUIT)
+ VMIME_TEST(testWriteToSocket)
+ VMIME_TEST_LIST_END
+
+
+ void testCreateCommand() {
+
+ vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::createCommand("MY_COMMAND");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "MY_COMMAND", cmd->getText());
+ }
+
+ void testCreateCommandParams() {
+
+ vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::createCommand("MY_COMMAND param1 param2");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "MY_COMMAND param1 param2", cmd->getText());
+ }
+
+ void testHELO() {
+
+ vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::HELO("hostname");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "HELO hostname", cmd->getText());
+ }
+
+ void testEHLO() {
+
+ vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::EHLO("hostname");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "EHLO hostname", cmd->getText());
+ }
+
+ void testAUTH() {
+
+ vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::AUTH("saslmechanism");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "AUTH saslmechanism", cmd->getText());
+ }
+
+ void testAUTH_InitialResponse() {
+
+ vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::AUTH("saslmechanism", "initial-response");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "AUTH saslmechanism initial-response", cmd->getText());
+ }
+
+ void testSTARTTLS() {
+
+ vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::STARTTLS();
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "STARTTLS", cmd->getText());
+ }
+
+ void testMAIL() {
+
+ vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::MAIL(vmime::mailbox("me@vmime.org"), false, "FULL", "dsn-unique-id");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "MAIL FROM:<me@vmime.org> RET=FULL ENVID=<dsn-unique-id>", cmd->getText());
+ }
+
+ void testMAIL_Encoded() {
+
+ vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::MAIL(
+ vmime::mailbox(vmime::emailAddress("mailtest", "例え.テスト")), false, "FULL", "dsn-unique-id"
+ );
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "MAIL FROM:<mailtest@xn--r8jz45g.xn--zckzah> RET=FULL ENVID=<dsn-unique-id>", cmd->getText());
+ }
+
+ void testMAIL_UTF8() {
+
+ vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::MAIL(
+ vmime::mailbox(vmime::emailAddress("mailtest", "例え.テスト")), true, "FULL", "dsn-unique-id"
+ );
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "MAIL FROM:<mailtest@例え.テスト> RET=FULL ENVID=<dsn-unique-id> SMTPUTF8", cmd->getText());
+ }
+
+ void testMAIL_SIZE() {
+
+ vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::MAIL(
+ vmime::mailbox("me@vmime.org"), false, 123456789, "FULL", "dsn-unique-id"
+ );
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "MAIL FROM:<me@vmime.org> RET=FULL ENVID=<dsn-unique-id> SIZE=123456789", cmd->getText());
+ }
+
+ void testMAIL_SIZE_UTF8() {
+
+ vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::MAIL(
+ vmime::mailbox(vmime::emailAddress("mailtest", "例え.テスト")), true, 123456789, "FULL", "dsn-unique-id"
+ );
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "MAIL FROM:<mailtest@例え.テスト> RET=FULL ENVID=<dsn-unique-id> SMTPUTF8 SIZE=123456789", cmd->getText());
+ }
+
+ void testRCPT() {
+
+ vmime::shared_ptr <SMTPCommand> cmd =
+ SMTPCommand::RCPT(vmime::mailbox("someone@vmime.org"), false, "NEVER");
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "RCPT TO:<someone@vmime.org> NOTIFY=NEVER", cmd->getText());
+ }
+
+ void testRCPT_Encoded() {
+
+ vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::RCPT(
+ vmime::mailbox(vmime::emailAddress("mailtest", "例え.テスト")), false, "NEVER"
+ );
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "RCPT TO:<mailtest@xn--r8jz45g.xn--zckzah> NOTIFY=NEVER", cmd->getText());
+ }
+
+ void testRCPT_UTF8() {
+
+ vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::RCPT(
+ vmime::mailbox(vmime::emailAddress("mailtest", "例え.テスト")), true, "NEVER"
+ );
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "RCPT TO:<mailtest@例え.テスト> NOTIFY=NEVER", cmd->getText());
+ }
+
+ void testRSET() {
+
+ vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::RSET();
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "RSET", cmd->getText());
+ }
+
+ void testDATA() {
+
+ vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::DATA();
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "DATA", cmd->getText());
+ }
+
+ void testBDAT() {
+
+ vmime::shared_ptr <SMTPCommand> cmd1 = SMTPCommand::BDAT(12345, false);
+
+ VASSERT_NOT_NULL("Not null", cmd1);
+ VASSERT_EQ("Text", "BDAT 12345", cmd1->getText());
+
+ vmime::shared_ptr <SMTPCommand> cmd2 = SMTPCommand::BDAT(67890, true);
+
+ VASSERT_NOT_NULL("Not null", cmd2);
+ VASSERT_EQ("Text", "BDAT 67890 LAST", cmd2->getText());
+ }
+
+ void testNOOP() {
+
+ vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::NOOP();
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "NOOP", cmd->getText());
+ }
+
+ void testQUIT() {
+
+ vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::QUIT();
+
+ VASSERT_NOT_NULL("Not null", cmd);
+ VASSERT_EQ("Text", "QUIT", cmd->getText());
+ }
+
+ void testWriteToSocket() {
+
+ vmime::shared_ptr <SMTPCommand> cmd = SMTPCommand::createCommand("MY_COMMAND param1 param2");
+
+ vmime::shared_ptr <vmime::net::tracer> tracer;
+ vmime::shared_ptr <testSocket> sok = vmime::make_shared <testSocket>();
+
+ cmd->writeToSocket(sok, tracer);
+
+ vmime::string response;
+ sok->localReceive(response);
+
+ VASSERT_EQ("Sent buffer", "MY_COMMAND param1 param2\r\n", response);
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/net/smtp/SMTPResponseTest.cpp b/vmime-master/tests/net/smtp/SMTPResponseTest.cpp
new file mode 100644
index 0000000..f899a82
--- /dev/null
+++ b/vmime-master/tests/net/smtp/SMTPResponseTest.cpp
@@ -0,0 +1,238 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/net/smtp/SMTPResponse.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(SMTPResponseTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testSingleLineResponse)
+ VMIME_TEST(testSingleLineResponseLF)
+ VMIME_TEST(testMultiLineResponse)
+ VMIME_TEST(testMultiLineResponseDifferentCode)
+ VMIME_TEST(testIncompleteMultiLineResponse)
+ VMIME_TEST(testNoResponseText)
+ VMIME_TEST(testEnhancedStatusCode)
+ VMIME_TEST(testNoEnhancedStatusCode)
+ VMIME_TEST(testInvalidEnhancedStatusCode)
+ VMIME_TEST_LIST_END
+
+
+ void testSingleLineResponse() {
+
+ vmime::shared_ptr <vmime::net::tracer> tracer;
+ vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
+ vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>();
+
+ socket->localSend("123 Response Text\r\n");
+
+ vmime::net::smtp::SMTPResponse::state responseState;
+
+ vmime::shared_ptr <vmime::net::smtp::SMTPResponse> resp =
+ vmime::net::smtp::SMTPResponse::readResponse(tracer, socket, toh, responseState);
+
+ VASSERT_EQ("Code", 123, resp->getCode());
+ VASSERT_EQ("Lines", 1, resp->getLineCount());
+ VASSERT_EQ("Text", "Response Text", resp->getText());
+ }
+
+ void testSingleLineResponseLF() {
+
+ vmime::shared_ptr <vmime::net::tracer> tracer;
+ vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
+ vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>();
+
+ socket->localSend("123 Response Text\n");
+
+ vmime::net::smtp::SMTPResponse::state responseState;
+
+ vmime::shared_ptr <vmime::net::smtp::SMTPResponse> resp =
+ vmime::net::smtp::SMTPResponse::readResponse(tracer, socket, toh, responseState);
+
+ VASSERT_EQ("Code", 123, resp->getCode());
+ VASSERT_EQ("Lines", 1, resp->getLineCount());
+ VASSERT_EQ("Text", "Response Text", resp->getText());
+ }
+
+ void testMultiLineResponse() {
+
+ vmime::shared_ptr <vmime::net::tracer> tracer;
+ vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
+ vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>();
+
+ socket->localSend(
+ "123-Response\r\n"
+ "123 Text\r\n"
+ );
+
+ vmime::net::smtp::SMTPResponse::state responseState;
+
+ vmime::shared_ptr <vmime::net::smtp::SMTPResponse> resp =
+ vmime::net::smtp::SMTPResponse::readResponse(tracer, socket, toh, responseState);
+
+ VASSERT_EQ("Code", 123, resp->getCode());
+ VASSERT_EQ("Lines", 2, resp->getLineCount());
+ VASSERT_EQ("Text", "Response\nText", resp->getText());
+
+ VASSERT_EQ("Code", 123, resp->getLineAt(0).getCode());
+ VASSERT_EQ("Text", "Response", resp->getLineAt(0).getText());
+
+ VASSERT_EQ("Code", 123, resp->getLineAt(1).getCode());
+ VASSERT_EQ("Text", "Text", resp->getLineAt(1).getText());
+ }
+
+ void testMultiLineResponseDifferentCode() {
+
+ vmime::shared_ptr <vmime::net::tracer> tracer;
+ vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
+ vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>();
+
+ socket->localSend(
+ "123-Response\r\n"
+ "456 Text\r\n"
+ );
+
+ vmime::net::smtp::SMTPResponse::state responseState;
+
+ vmime::shared_ptr <vmime::net::smtp::SMTPResponse> resp =
+ vmime::net::smtp::SMTPResponse::readResponse(tracer, socket, toh, responseState);
+
+ VASSERT_EQ("Code", 0, resp->getCode());
+ VASSERT_EQ("Lines", 2, resp->getLineCount());
+ VASSERT_EQ("Text", "Response\nText", resp->getText());
+
+ VASSERT_EQ("Code", 123, resp->getLineAt(0).getCode());
+ VASSERT_EQ("Text", "Response", resp->getLineAt(0).getText());
+
+ VASSERT_EQ("Code", 456, resp->getLineAt(1).getCode());
+ VASSERT_EQ("Text", "Text", resp->getLineAt(1).getText());
+ }
+
+ void testIncompleteMultiLineResponse() {
+
+ vmime::shared_ptr <vmime::net::tracer> tracer;
+ vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
+ vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>(1);
+
+ socket->localSend(
+ "123-Response\r\n"
+ "123-Text\r\n"
+ // Missing data
+ );
+
+ vmime::net::smtp::SMTPResponse::state responseState;
+
+ VASSERT_THROW(
+ "Incomplete response",
+ vmime::net::smtp::SMTPResponse::readResponse(tracer, socket, toh, responseState),
+ vmime::exceptions::operation_timed_out
+ );
+ }
+
+ void testNoResponseText() {
+
+ vmime::shared_ptr <vmime::net::tracer> tracer;
+ vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
+ vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>(1);
+
+ socket->localSend(
+ "250\r\n"
+ );
+
+ vmime::net::smtp::SMTPResponse::state responseState;
+
+ vmime::shared_ptr <vmime::net::smtp::SMTPResponse> resp =
+ vmime::net::smtp::SMTPResponse::readResponse(tracer, socket, toh, responseState);
+
+ VASSERT_EQ("Code", 250, resp->getCode());
+ VASSERT_EQ("Lines", 1, resp->getLineCount());
+ VASSERT_EQ("Text", "", resp->getText());
+ }
+
+ void testEnhancedStatusCode() {
+
+ vmime::shared_ptr <vmime::net::tracer> tracer;
+ vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
+ vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>();
+
+ socket->localSend("250 2.1.5 OK fu13sm4720601wic.7 - gsmtp\r\n");
+
+ vmime::net::smtp::SMTPResponse::state responseState;
+
+ vmime::shared_ptr <vmime::net::smtp::SMTPResponse> resp =
+ vmime::net::smtp::SMTPResponse::readResponse(tracer, socket, toh, responseState);
+
+ VASSERT_EQ("Code", 250, resp->getCode());
+ VASSERT_EQ("Lines", 1, resp->getLineCount());
+ VASSERT_EQ("Text", "2.1.5 OK fu13sm4720601wic.7 - gsmtp", resp->getText());
+ VASSERT_EQ("Enh.class", 2, resp->getEnhancedCode().klass);
+ VASSERT_EQ("Enh.subject", 1, resp->getEnhancedCode().subject);
+ VASSERT_EQ("Enh.detail", 5, resp->getEnhancedCode().detail);
+ }
+
+ void testNoEnhancedStatusCode() {
+
+ vmime::shared_ptr <vmime::net::tracer> tracer;
+ vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
+ vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>();
+
+ socket->localSend("354 Go ahead fu13sm4720601wic.7 - gsmtp\r\n");
+
+ vmime::net::smtp::SMTPResponse::state responseState;
+
+ vmime::shared_ptr <vmime::net::smtp::SMTPResponse> resp =
+ vmime::net::smtp::SMTPResponse::readResponse(tracer, socket, toh, responseState);
+
+ VASSERT_EQ("Code", 354, resp->getCode());
+ VASSERT_EQ("Lines", 1, resp->getLineCount());
+ VASSERT_EQ("Text", "Go ahead fu13sm4720601wic.7 - gsmtp", resp->getText());
+ VASSERT_EQ("Enh.class", 0, resp->getEnhancedCode().klass);
+ VASSERT_EQ("Enh.subject", 0, resp->getEnhancedCode().subject);
+ VASSERT_EQ("Enh.detail", 0, resp->getEnhancedCode().detail);
+ }
+
+ void testInvalidEnhancedStatusCode() {
+
+ vmime::shared_ptr <vmime::net::tracer> tracer;
+ vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
+ vmime::shared_ptr <vmime::net::timeoutHandler> toh = vmime::make_shared <testTimeoutHandler>();
+
+ socket->localSend("250 4.2 xxx\r\n");
+
+ vmime::net::smtp::SMTPResponse::state responseState;
+
+ vmime::shared_ptr <vmime::net::smtp::SMTPResponse> resp =
+ vmime::net::smtp::SMTPResponse::readResponse(tracer, socket, toh, responseState);
+
+ VASSERT_EQ("Code", 250, resp->getCode());
+ VASSERT_EQ("Lines", 1, resp->getLineCount());
+ VASSERT_EQ("Text", "4.2 xxx", resp->getText());
+ VASSERT_EQ("Enh.class", 0, resp->getEnhancedCode().klass);
+ VASSERT_EQ("Enh.subject", 0, resp->getEnhancedCode().subject);
+ VASSERT_EQ("Enh.detail", 0, resp->getEnhancedCode().detail);
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/net/smtp/SMTPTransportTest.cpp b/vmime-master/tests/net/smtp/SMTPTransportTest.cpp
new file mode 100644
index 0000000..8ea4ba7
--- /dev/null
+++ b/vmime-master/tests/net/smtp/SMTPTransportTest.cpp
@@ -0,0 +1,324 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/net/smtp/SMTPTransport.hpp"
+#include "vmime/net/smtp/SMTPChunkingOutputStreamAdapter.hpp"
+#include "vmime/net/smtp/SMTPExceptions.hpp"
+
+#include "SMTPTransportTestUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(SMTPTransportTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testConnectToInvalidServer)
+ VMIME_TEST(testGreetingError)
+ VMIME_TEST(testMAILandRCPT)
+ VMIME_TEST(testChunking)
+ VMIME_TEST(testSize_Chunking)
+ VMIME_TEST(testSize_NoChunking)
+ VMIME_TEST(testSMTPUTF8_available)
+ VMIME_TEST(testSMTPUTF8_notAvailable)
+ VMIME_TEST_LIST_END
+
+
+ void testConnectToInvalidServer() {
+
+ vmime::shared_ptr <vmime::net::session> sess = vmime::net::session::create();
+
+ vmime::utility::url url("smtp://invalid-smtp-server");
+ vmime::shared_ptr <vmime::net::transport> store = sess->getTransport(url);
+
+ VASSERT_THROW("connect", store->connect(), vmime::exceptions::connection_error);
+ }
+
+ void testGreetingError() {
+
+ vmime::shared_ptr <vmime::net::session> session = vmime::net::session::create();
+
+ vmime::shared_ptr <vmime::net::transport> tr =
+ session->getTransport(vmime::utility::url("smtp://localhost"));
+
+ tr->setSocketFactory(vmime::make_shared <testSocketFactory <greetingErrorSMTPTestSocket> >());
+ tr->setTimeoutHandlerFactory(vmime::make_shared <testTimeoutHandlerFactory>());
+
+ VASSERT_THROW(
+ "Connection",
+ tr->connect(),
+ vmime::exceptions::connection_greeting_error
+ );
+ }
+
+ void testMAILandRCPT() {
+
+ vmime::shared_ptr <vmime::net::session> session = vmime::net::session::create();
+
+ vmime::shared_ptr <vmime::net::transport> tr =
+ session->getTransport(vmime::utility::url("smtp://localhost"));
+
+ tr->setSocketFactory(vmime::make_shared <testSocketFactory <MAILandRCPTSMTPTestSocket> >());
+ tr->setTimeoutHandlerFactory(vmime::make_shared <testTimeoutHandlerFactory>());
+
+ VASSERT_NO_THROW("Connection", tr->connect());
+
+ vmime::mailbox exp("expeditor@test.vmime.org");
+
+ vmime::mailboxList recips;
+ recips.appendMailbox(vmime::make_shared <vmime::mailbox>("recipient1@test.vmime.org"));
+ recips.appendMailbox(vmime::make_shared <vmime::mailbox>("recipient2@test.vmime.org"));
+ recips.appendMailbox(vmime::make_shared <vmime::mailbox>("recipient3@test.vmime.org"));
+
+ vmime::string data("Message data");
+ vmime::utility::inputStreamStringAdapter is(data);
+
+ tr->send(exp, recips, is, 0);
+ }
+
+ void testChunking() {
+
+ vmime::shared_ptr <vmime::net::session> session = vmime::net::session::create();
+
+ vmime::shared_ptr <vmime::net::transport> tr =
+ session->getTransport(vmime::utility::url("smtp://localhost"));
+
+ tr->setSocketFactory(vmime::make_shared <testSocketFactory <chunkingSMTPTestSocket> >());
+ tr->setTimeoutHandlerFactory(vmime::make_shared <testTimeoutHandlerFactory>());
+
+ tr->connect();
+
+ VASSERT(
+ "Test server should report it supports the CHUNKING extension!",
+ vmime::dynamicCast <vmime::net::smtp::SMTPTransport>(tr)->getConnection()->hasExtension("CHUNKING")
+ );
+
+ vmime::mailbox exp("expeditor@test.vmime.org");
+
+ vmime::mailboxList recips;
+ recips.appendMailbox(vmime::make_shared <vmime::mailbox>("recipient@test.vmime.org"));
+
+ vmime::shared_ptr <vmime::message> msg = vmime::make_shared <SMTPTestMessage>();
+
+ tr->send(msg, exp, recips);
+ }
+
+ void testSize_Chunking() {
+
+ vmime::shared_ptr <vmime::net::session> session = vmime::net::session::create();
+
+ vmime::shared_ptr <vmime::net::transport> tr =
+ session->getTransport(vmime::utility::url("smtp://localhost"));
+
+ tr->setSocketFactory(vmime::make_shared <testSocketFactory <bigMessageSMTPTestSocket <true> > >());
+ tr->setTimeoutHandlerFactory(vmime::make_shared <testTimeoutHandlerFactory>());
+
+ tr->connect();
+
+ VASSERT(
+ "Test server should report it supports the SIZE extension!",
+ vmime::dynamicCast <vmime::net::smtp::SMTPTransport>(tr)->getConnection()->hasExtension("SIZE")
+ );
+
+ vmime::mailbox exp("expeditor@test.vmime.org");
+
+ vmime::mailboxList recips;
+ recips.appendMailbox(vmime::make_shared <vmime::mailbox>("recipient@test.vmime.org"));
+
+ vmime::shared_ptr <vmime::message> msg = vmime::make_shared <SMTPBigTestMessage4MB>();
+
+ VASSERT_THROW(
+ "Max size limit exception",
+ tr->send(msg, exp, recips),
+ vmime::net::smtp::SMTPMessageSizeExceedsMaxLimitsException
+ );
+ }
+
+ void testSize_NoChunking() {
+
+ vmime::shared_ptr <vmime::net::session> session = vmime::net::session::create();
+
+ vmime::shared_ptr <vmime::net::transport> tr =
+ session->getTransport(vmime::utility::url("smtp://localhost"));
+
+ tr->setSocketFactory(vmime::make_shared <testSocketFactory <bigMessageSMTPTestSocket <false> > >());
+ tr->setTimeoutHandlerFactory(vmime::make_shared <testTimeoutHandlerFactory>());
+
+ tr->connect();
+
+ VASSERT(
+ "Test server should report it supports the SIZE extension!",
+ vmime::dynamicCast <vmime::net::smtp::SMTPTransport>(tr)->getConnection()->hasExtension("SIZE")
+ );
+
+ vmime::mailbox exp("expeditor@test.vmime.org");
+
+ vmime::mailboxList recips;
+ recips.appendMailbox(vmime::make_shared <vmime::mailbox>("recipient@test.vmime.org"));
+
+ vmime::shared_ptr <vmime::message> msg = vmime::make_shared <SMTPBigTestMessage4MB>();
+
+ VASSERT_THROW(
+ "Max size limit exception",
+ tr->send(msg, exp, recips),
+ vmime::net::smtp::SMTPMessageSizeExceedsMaxLimitsException
+ );
+ }
+
+ void testSMTPUTF8_available() {
+
+ // Test with UTF8 sender
+ {
+ vmime::shared_ptr <vmime::net::session> session = vmime::net::session::create();
+
+ vmime::shared_ptr <vmime::net::transport> tr =
+ session->getTransport(vmime::utility::url("smtp://localhost"));
+
+ tr->setSocketFactory(vmime::make_shared <testSocketFactory <UTF8SMTPTestSocket <true> > >());
+ tr->setTimeoutHandlerFactory(vmime::make_shared <testTimeoutHandlerFactory>());
+
+ VASSERT_NO_THROW("Connection", tr->connect());
+
+ vmime::mailbox exp(
+ vmime::emailAddress(
+ vmime::word("expéditeur", vmime::charsets::UTF_8),
+ vmime::word("test.vmime.org")
+ )
+ );
+
+ vmime::mailboxList recips;
+ recips.appendMailbox(vmime::make_shared <vmime::mailbox>("recipient1@test.vmime.org"));
+ recips.appendMailbox(vmime::make_shared <vmime::mailbox>("recipient2@test.vmime.org"));
+ recips.appendMailbox(vmime::make_shared <vmime::mailbox>(
+ vmime::emailAddress(
+ vmime::word("récepteur", vmime::charsets::UTF_8),
+ vmime::word("test.vmime.org")
+ )
+ ));
+
+ vmime::string data("Message data");
+ vmime::utility::inputStreamStringAdapter is(data);
+
+ tr->send(exp, recips, is, 0);
+ }
+
+ // Test with UTF8 recipient only
+ {
+ vmime::shared_ptr <vmime::net::session> session = vmime::net::session::create();
+
+ vmime::shared_ptr <vmime::net::transport> tr =
+ session->getTransport(vmime::utility::url("smtp://localhost"));
+
+ tr->setSocketFactory(vmime::make_shared <testSocketFactory <UTF8SMTPTestSocket <true> > >());
+ tr->setTimeoutHandlerFactory(vmime::make_shared <testTimeoutHandlerFactory>());
+
+ VASSERT_NO_THROW("Connection", tr->connect());
+
+ vmime::mailbox exp("expediteur@test.vmime.org");
+
+ vmime::mailboxList recips;
+ recips.appendMailbox(vmime::make_shared <vmime::mailbox>("recipient1@test.vmime.org"));
+ recips.appendMailbox(vmime::make_shared <vmime::mailbox>("recipient2@test.vmime.org"));
+ recips.appendMailbox(vmime::make_shared <vmime::mailbox>(
+ vmime::emailAddress(
+ vmime::word("récepteur", vmime::charsets::UTF_8),
+ vmime::word("test.vmime.org")
+ )
+ ));
+
+ vmime::string data("Message data");
+ vmime::utility::inputStreamStringAdapter is(data);
+
+ tr->send(exp, recips, is, 0);
+ }
+ }
+
+ void testSMTPUTF8_notAvailable() {
+
+ // Test with UTF8 sender
+ {
+ vmime::shared_ptr <vmime::net::session> session = vmime::net::session::create();
+
+ vmime::shared_ptr <vmime::net::transport> tr =
+ session->getTransport(vmime::utility::url("smtp://localhost"));
+
+ tr->setSocketFactory(vmime::make_shared <testSocketFactory <UTF8SMTPTestSocket <false> > >());
+ tr->setTimeoutHandlerFactory(vmime::make_shared <testTimeoutHandlerFactory>());
+
+ VASSERT_NO_THROW("Connection", tr->connect());
+
+ vmime::mailbox exp(
+ vmime::emailAddress(
+ vmime::word("expéditeur", vmime::charsets::UTF_8),
+ vmime::word("test.vmime.org")
+ )
+ );
+
+ vmime::mailboxList recips;
+ recips.appendMailbox(vmime::make_shared <vmime::mailbox>("recipient1@test.vmime.org"));
+ recips.appendMailbox(vmime::make_shared <vmime::mailbox>("recipient2@test.vmime.org"));
+ recips.appendMailbox(vmime::make_shared <vmime::mailbox>(
+ vmime::emailAddress(
+ vmime::word("récepteur", vmime::charsets::UTF_8),
+ vmime::word("test.vmime.org")
+ )
+ ));
+
+ vmime::string data("Message data");
+ vmime::utility::inputStreamStringAdapter is(data);
+
+ tr->send(exp, recips, is, 0);
+ }
+
+ // Test with UTF8 recipient only
+ {
+ vmime::shared_ptr <vmime::net::session> session = vmime::net::session::create();
+
+ vmime::shared_ptr <vmime::net::transport> tr =
+ session->getTransport(vmime::utility::url("smtp://localhost"));
+
+ tr->setSocketFactory(vmime::make_shared <testSocketFactory <UTF8SMTPTestSocket <false> > >());
+ tr->setTimeoutHandlerFactory(vmime::make_shared <testTimeoutHandlerFactory>());
+
+ VASSERT_NO_THROW("Connection", tr->connect());
+
+ vmime::mailbox exp("expediteur@test.vmime.org");
+
+ vmime::mailboxList recips;
+ recips.appendMailbox(vmime::make_shared <vmime::mailbox>("recipient1@test.vmime.org"));
+ recips.appendMailbox(vmime::make_shared <vmime::mailbox>("recipient2@test.vmime.org"));
+ recips.appendMailbox(vmime::make_shared <vmime::mailbox>(
+ vmime::emailAddress(
+ vmime::word("récepteur", vmime::charsets::UTF_8),
+ vmime::word("test.vmime.org")
+ )
+ ));
+
+ vmime::string data("Message data");
+ vmime::utility::inputStreamStringAdapter is(data);
+
+ tr->send(exp, recips, is, 0);
+ }
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/net/smtp/SMTPTransportTestUtils.hpp b/vmime-master/tests/net/smtp/SMTPTransportTestUtils.hpp
new file mode 100644
index 0000000..8710639
--- /dev/null
+++ b/vmime-master/tests/net/smtp/SMTPTransportTestUtils.hpp
@@ -0,0 +1,792 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+
+/** Accepts connection and fails on greeting.
+ */
+class greetingErrorSMTPTestSocket : public lineBasedTestSocket {
+
+public:
+
+ void onConnected() {
+
+ localSend("421 test.vmime.org Service not available, closing transmission channel\r\n");
+ disconnect();
+ }
+
+ void processCommand() {
+
+ if (!haveMoreLines()) {
+ return;
+ }
+
+ getNextLine();
+
+ localSend("502 Command not implemented\r\n");
+ processCommand();
+ }
+};
+
+
+/** SMTP test server 1.
+ *
+ * Test send().
+ * Ensure MAIL and RCPT commands are sent correctly.
+ */
+class MAILandRCPTSMTPTestSocket : public lineBasedTestSocket {
+
+public:
+
+ MAILandRCPTSMTPTestSocket() {
+
+ m_recipients.insert("recipient1@test.vmime.org");
+ m_recipients.insert("recipient2@test.vmime.org");
+ m_recipients.insert("recipient3@test.vmime.org");
+
+ m_state = STATE_NOT_CONNECTED;
+ m_ehloSent = m_heloSent = m_mailSent = m_rcptSent = m_dataSent = m_quitSent = false;
+ }
+
+ ~MAILandRCPTSMTPTestSocket() {
+
+ VASSERT("Client must send the DATA command", m_dataSent);
+ VASSERT("Client must send the QUIT command", m_quitSent);
+ }
+
+ void onConnected() {
+
+ localSend("220 test.vmime.org Service ready\r\n");
+ processCommand();
+
+ m_state = STATE_COMMAND;
+ }
+
+ void processCommand() {
+
+ if (!haveMoreLines()) {
+ return;
+ }
+
+ vmime::string line = getNextLine();
+ std::istringstream iss(line);
+
+ switch (m_state) {
+
+ case STATE_NOT_CONNECTED:
+
+ localSend("451 Requested action aborted: invalid state\r\n");
+ break;
+
+ case STATE_COMMAND: {
+
+ std::string cmd;
+ iss >> cmd;
+
+ if (cmd.empty()) {
+
+ localSend("500 Syntax error, command unrecognized\r\n");
+
+ } else if (cmd == "EHLO") {
+
+ localSend("502 Command not implemented\r\n");
+
+ m_ehloSent = true;
+
+ } else if (cmd == "HELO") {
+
+ VASSERT("Client must send the EHLO command before HELO", m_ehloSent);
+
+ localSend("250 OK\r\n");
+
+ m_heloSent = true;
+
+ } else if (cmd == "MAIL") {
+
+ VASSERT("Client must send the HELO command", m_heloSent);
+ VASSERT("The MAIL command must be sent only one time", !m_mailSent);
+
+ VASSERT_EQ("MAIL", std::string("MAIL FROM:<expeditor@test.vmime.org>"), line);
+
+ localSend("250 OK\r\n");
+
+ m_mailSent = true;
+
+ } else if (cmd == "RCPT") {
+
+ const vmime::size_t lt = line.find('<');
+ const vmime::size_t gt = line.find('>');
+
+ VASSERT("RCPT <", lt != vmime::string::npos);
+ VASSERT("RCPT >", gt != vmime::string::npos);
+ VASSERT("RCPT ><", gt >= lt);
+
+ const vmime::string recip =
+ vmime::string(line.begin() + lt + 1, line.begin() + gt);
+
+ std::set <vmime::string>::iterator it =
+ m_recipients.find(recip);
+
+ VASSERT(
+ std::string("Recipient not found: '") + recip + "'",
+ it != m_recipients.end()
+ );
+
+ m_recipients.erase(it);
+
+ localSend("250 OK, recipient accepted\r\n");
+
+ m_rcptSent = true;
+
+ } else if (cmd == "DATA") {
+
+ VASSERT("Client must send the MAIL command", m_mailSent);
+ VASSERT("Client must send the RCPT command", m_rcptSent);
+ VASSERT("All recipients", m_recipients.empty());
+
+ localSend("354 Ready to accept data; end with <CRLF>.<CRLF>\r\n");
+
+ m_state = STATE_DATA;
+ m_msgData.clear();
+
+ m_dataSent = true;
+
+ } else if (cmd == "NOOP") {
+
+ localSend("250 Completed\r\n");
+
+ } else if (cmd == "QUIT") {
+
+ m_quitSent = true;
+
+ localSend("221 test.vmime.org Service closing transmission channel\r\n");
+
+ } else {
+
+ localSend("502 Command not implemented\r\n");
+ }
+
+ break;
+ }
+ case STATE_DATA: {
+
+ if (line == ".") {
+
+ VASSERT_EQ("Data", "Message data\r\n", m_msgData);
+
+ localSend("250 Message accepted for delivery\r\n");
+ m_state = STATE_COMMAND;
+
+ } else {
+
+ m_msgData += line + "\r\n";
+ }
+
+ break;
+ }
+
+ }
+
+ processCommand();
+ }
+
+private:
+
+ enum State {
+ STATE_NOT_CONNECTED,
+ STATE_COMMAND,
+ STATE_DATA
+ };
+
+ int m_state;
+
+ std::set <vmime::string> m_recipients;
+
+ std::string m_msgData;
+
+ bool m_ehloSent, m_heloSent, m_mailSent, m_rcptSent,
+ m_dataSent, m_quitSent;
+};
+
+
+
+/** SMTP test server 2.
+ *
+ * Test CHUNKING extension/BDAT command.
+ */
+class chunkingSMTPTestSocket : public testSocket {
+
+public:
+
+ chunkingSMTPTestSocket() {
+
+ m_state = STATE_NOT_CONNECTED;
+ m_bdatChunkCount = 0;
+ m_ehloSent = m_mailSent = m_rcptSent = m_quitSent = false;
+ }
+
+ ~chunkingSMTPTestSocket() {
+
+ VASSERT_EQ("BDAT chunk count", 3, m_bdatChunkCount);
+ VASSERT("Client must send the QUIT command", m_quitSent);
+ }
+
+ void onConnected() {
+
+ localSend("220 test.vmime.org Service ready\r\n");
+ processCommand();
+
+ m_state = STATE_COMMAND;
+ }
+
+ void onDataReceived() {
+
+ if (m_state == STATE_DATA) {
+
+ if (m_bdatChunkReceived != m_bdatChunkSize) {
+
+ const size_t remaining = m_bdatChunkSize - m_bdatChunkReceived;
+ const size_t received = localReceiveRaw(NULL, remaining);
+
+ m_bdatChunkReceived += received;
+ }
+
+ if (m_bdatChunkReceived == m_bdatChunkSize) {
+
+ m_state = STATE_COMMAND;
+ }
+ }
+
+ processCommand();
+ }
+
+ void processCommand() {
+
+ vmime::string line;
+
+ if (!localReceiveLine(line)) {
+ return;
+ }
+
+ std::istringstream iss(line);
+
+ switch (m_state) {
+
+ case STATE_NOT_CONNECTED:
+
+ localSend("451 Requested action aborted: invalid state\r\n");
+ break;
+
+ case STATE_COMMAND: {
+
+ std::string cmd;
+ iss >> cmd;
+
+ if (cmd == "EHLO") {
+
+ localSend("250-test.vmime.org says hello\r\n");
+ localSend("250 CHUNKING\r\n");
+
+ m_ehloSent = true;
+
+ } else if (cmd == "HELO") {
+
+ VASSERT("Client must not send the HELO command, as EHLO succeeded", false);
+
+ } else if (cmd == "MAIL") {
+
+ VASSERT("The MAIL command must be sent only one time", !m_mailSent);
+
+ localSend("250 OK\r\n");
+
+ m_mailSent = true;
+
+ } else if (cmd == "RCPT") {
+
+ localSend("250 OK, recipient accepted\r\n");
+
+ m_rcptSent = true;
+
+ } else if (cmd == "DATA") {
+
+ VASSERT("BDAT must be used here!", false);
+
+ } else if (cmd == "BDAT") {
+
+ VASSERT("Client must send the MAIL command", m_mailSent);
+ VASSERT("Client must send the RCPT command", m_rcptSent);
+
+ unsigned long chunkSize = 0;
+ iss >> chunkSize;
+
+ std::string last;
+ iss >> last;
+
+ if (m_bdatChunkCount == 0) {
+
+ VASSERT_EQ("BDAT chunk1 size", 262144, chunkSize);
+ VASSERT_EQ("BDAT chunk1 last", "", last);
+
+ } else if (m_bdatChunkCount == 1) {
+
+ VASSERT_EQ("BDAT chunk2 size", 262144, chunkSize);
+ VASSERT_EQ("BDAT chunk2 last", "", last);
+
+ } else if (m_bdatChunkCount == 2) {
+
+ VASSERT_EQ("BDAT chunk3 size", 4712, chunkSize);
+ VASSERT_EQ("BDAT chunk3 last", "LAST", last);
+
+ } else {
+
+ VASSERT("No more BDAT command should be issued!", false);
+ }
+
+ m_bdatChunkSize = chunkSize;
+ m_bdatChunkReceived = 0;
+ m_bdatChunkCount++;
+ m_state = STATE_DATA;
+
+ localSend("250 chunk received\r\n");
+
+ } else if (cmd == "NOOP") {
+
+ localSend("250 Completed\r\n");
+
+ } else if (cmd == "QUIT") {
+
+ localSend("221 test.vmime.org Service closing transmission channel\r\n");
+
+ m_quitSent = true;
+
+ } else {
+
+ localSend("502 Command not implemented\r\n");
+ }
+
+ break;
+ }
+
+ }
+
+ processCommand();
+ }
+
+private:
+
+ enum State {
+ STATE_NOT_CONNECTED,
+ STATE_COMMAND,
+ STATE_DATA
+ };
+
+ int m_state;
+ int m_bdatChunkCount;
+ size_t m_bdatChunkSize, m_bdatChunkReceived;
+
+ bool m_ehloSent, m_mailSent, m_rcptSent, m_quitSent;
+};
+
+
+class SMTPTestMessage : public vmime::message {
+
+public:
+
+ vmime::size_t getChunkBufferSize() const {
+
+ static vmime::net::smtp::SMTPChunkingOutputStreamAdapter chunkStream(vmime::null, 0, NULL);
+ return chunkStream.getBlockSize();
+ }
+
+ const std::vector <vmime::string>& getChunks() const {
+
+ static std::vector <vmime::string> chunks;
+
+ if (chunks.size() == 0) {
+ chunks.push_back(vmime::string(1000, 'A'));
+ chunks.push_back(vmime::string(3000, 'B'));
+ chunks.push_back(vmime::string(500000, 'C'));
+ chunks.push_back(vmime::string(25000, 'D'));
+ }
+
+ return chunks;
+ }
+
+ void generateImpl(
+ const vmime::generationContext& /* ctx */,
+ vmime::utility::outputStream& outputStream,
+ const size_t /* curLinePos */ = 0,
+ size_t* /* newLinePos */ = NULL
+ ) const {
+
+ for (size_t i = 0, n = getChunks().size() ; i < n ; ++i) {
+
+ const vmime::string& chunk = getChunks()[i];
+ outputStream.write(chunk.data(), chunk.size());
+ }
+ }
+};
+
+
+
+/** SMTP test server 3.
+ *
+ * Test SIZE extension.
+ */
+template <bool WITH_CHUNKING>
+class bigMessageSMTPTestSocket : public testSocket {
+
+public:
+
+ bigMessageSMTPTestSocket() {
+
+ m_state = STATE_NOT_CONNECTED;
+ m_ehloSent = m_mailSent = m_rcptSent = m_quitSent = false;
+ }
+
+ ~bigMessageSMTPTestSocket() {
+
+ VASSERT("Client must send the QUIT command", m_quitSent);
+ }
+
+ void onConnected() {
+
+ localSend("220 test.vmime.org Service ready\r\n");
+ processCommand();
+
+ m_state = STATE_COMMAND;
+ }
+
+ void onDataReceived() {
+
+ processCommand();
+ }
+
+ void processCommand() {
+
+ vmime::string line;
+
+ if (!localReceiveLine(line)) {
+ return;
+ }
+
+ std::istringstream iss(line);
+
+ switch (m_state) {
+
+ case STATE_NOT_CONNECTED:
+
+ localSend("451 Requested action aborted: invalid state\r\n");
+ break;
+
+ case STATE_COMMAND: {
+
+ std::string cmd;
+ iss >> cmd;
+
+ if (cmd == "EHLO") {
+
+ localSend("250-test.vmime.org says hello\r\n");
+
+ if (WITH_CHUNKING) {
+ localSend("250-CHUNKING\r\n");
+ }
+
+ localSend("250 SIZE 1000000\r\n");
+
+ m_ehloSent = true;
+
+ } else if (cmd == "HELO") {
+
+ VASSERT("Client must not send the HELO command, as EHLO succeeded", false);
+
+ } else if (cmd == "MAIL") {
+
+ VASSERT("The MAIL command must be sent only one time", !m_mailSent);
+
+ std::string address;
+ iss >> address;
+
+ VASSERT_EQ("MAIL/address", "FROM:<expeditor@test.vmime.org>", address);
+
+ std::string option;
+ iss >> option;
+
+ VASSERT_EQ("MAIL/size", "SIZE=4194304", option);
+
+ localSend("552 Channel size limit exceeded\r\n");
+
+ m_mailSent = true;
+
+ } else if (cmd == "NOOP") {
+
+ localSend("250 Completed\r\n");
+
+ } else if (cmd == "QUIT") {
+
+ localSend("221 test.vmime.org Service closing transmission channel\r\n");
+
+ m_quitSent = true;
+
+ } else {
+
+ VASSERT("No other command should be sent", false);
+
+ localSend("502 Command not implemented\r\n");
+ }
+
+ break;
+ }
+
+ }
+
+ processCommand();
+ }
+
+private:
+
+ enum State {
+ STATE_NOT_CONNECTED,
+ STATE_COMMAND,
+ STATE_DATA
+ };
+
+ int m_state;
+
+ bool m_ehloSent, m_mailSent, m_rcptSent, m_quitSent;
+};
+
+
+template <unsigned long SIZE>
+class SMTPBigTestMessage : public vmime::message {
+
+public:
+
+ size_t getGeneratedSize(const vmime::generationContext& /* ctx */) {
+
+ return SIZE;
+ }
+
+ void generateImpl(
+ const vmime::generationContext& /* ctx */,
+ vmime::utility::outputStream& outputStream,
+ const vmime::size_t /* curLinePos */ = 0,
+ vmime::size_t* /* newLinePos */ = NULL
+ ) const {
+
+ for (unsigned int i = 0, n = SIZE ; i < n ; ++i) {
+ outputStream.write("X", 1);
+ }
+ }
+};
+
+typedef SMTPBigTestMessage <4194304> SMTPBigTestMessage4MB;
+
+
+
+/** SMTP test server for SMTPUTF8 extension.
+ */
+template <bool SUPPORTS_UTF8>
+class UTF8SMTPTestSocket : public lineBasedTestSocket {
+
+public:
+
+ UTF8SMTPTestSocket() {
+
+ if (SUPPORTS_UTF8) {
+
+ m_rcptLines.insert("RCPT TO:<recipient1@test.vmime.org>");
+ m_rcptLines.insert("RCPT TO:<recipient2@test.vmime.org>");
+ m_rcptLines.insert("RCPT TO:<récepteur@test.vmime.org>");
+
+ } else {
+
+ m_rcptLines.insert("RCPT TO:<recipient1@test.vmime.org>");
+ m_rcptLines.insert("RCPT TO:<recipient2@test.vmime.org>");
+ m_rcptLines.insert("RCPT TO:<=?utf-8?Q?r=C3=A9cepteur?=@test.vmime.org>");
+ }
+
+ m_state = STATE_NOT_CONNECTED;
+ m_ehloSent = m_mailSent = m_rcptSent = m_dataSent = m_quitSent = false;
+ }
+
+ ~UTF8SMTPTestSocket() {
+
+ }
+
+ void onConnected() {
+
+ localSend("220 test.vmime.org Service ready\r\n");
+ processCommand();
+
+ m_state = STATE_COMMAND;
+ }
+
+ void processCommand() {
+
+ if (!haveMoreLines()) {
+ return;
+ }
+
+ vmime::string line = getNextLine();
+ std::istringstream iss(line);
+
+ switch (m_state) {
+
+ case STATE_NOT_CONNECTED:
+
+ localSend("451 Requested action aborted: invalid state\r\n");
+ break;
+
+ case STATE_COMMAND: {
+
+ std::string cmd;
+ iss >> cmd;
+
+ if (cmd.empty()) {
+
+ localSend("500 Syntax error, command unrecognized\r\n");
+
+ } else if (cmd == "EHLO") {
+
+ if (SUPPORTS_UTF8) {
+
+ localSend("250-test.vmime.org\r\n");
+ localSend("250 SMTPUTF8\r\n");
+
+ } else {
+
+ localSend("250 test.vmime.org\r\n");
+ }
+
+ m_ehloSent = true;
+
+ } else if (cmd == "HELO") {
+
+ VASSERT("Client must not send the HELO command, as EHLO succeeded", false);
+
+ } else if (cmd == "MAIL") {
+
+ VASSERT("Client must send the EHLO command", m_ehloSent);
+ VASSERT("The MAIL command must be sent only one time", !m_mailSent);
+
+ if (SUPPORTS_UTF8) {
+
+ VASSERT(
+ "MAIL",
+ std::string("MAIL FROM:<expediteur@test.vmime.org> SMTPUTF8") == line
+ || std::string("MAIL FROM:<expéditeur@test.vmime.org> SMTPUTF8") == line
+ );
+
+ } else {
+
+ VASSERT(
+ "MAIL",
+ std::string("MAIL FROM:<expediteur@test.vmime.org>") == line
+ || std::string("MAIL FROM:<=?utf-8?Q?exp=C3=A9diteur?=@test.vmime.org>") == line
+ );
+ }
+
+ localSend("250 OK\r\n");
+
+ m_mailSent = true;
+
+ } else if (cmd == "RCPT") {
+
+ std::set <vmime::string>::iterator it = m_rcptLines.find(line);
+
+ VASSERT(std::string("RCPT not found: '") + line + "'", it != m_rcptLines.end());
+
+ m_rcptLines.erase(it);
+
+ localSend("250 OK, recipient accepted\r\n");
+
+ m_rcptSent = true;
+
+ } else if (cmd == "DATA") {
+
+ VASSERT("Client must send the MAIL command", m_mailSent);
+ VASSERT("Client must send the RCPT command", m_rcptSent);
+ VASSERT("All recipients", m_rcptLines.empty());
+
+ localSend("354 Ready to accept data; end with <CRLF>.<CRLF>\r\n");
+
+ m_state = STATE_DATA;
+ m_msgData.clear();
+
+ m_dataSent = true;
+
+ } else if (cmd == "NOOP") {
+
+ localSend("250 Completed\r\n");
+
+ } else if (cmd == "QUIT") {
+
+ m_quitSent = true;
+
+ localSend("221 test.vmime.org Service closing transmission channel\r\n");
+
+ } else {
+
+ localSend("502 Command not implemented\r\n");
+ }
+
+ break;
+ }
+ case STATE_DATA: {
+
+ if (line == ".") {
+
+ VASSERT_EQ("Data", "Message data\r\n", m_msgData);
+
+ localSend("250 Message accepted for delivery\r\n");
+ m_state = STATE_COMMAND;
+
+ } else {
+
+ m_msgData += line + "\r\n";
+ }
+
+ break;
+ }
+
+ }
+
+ processCommand();
+ }
+
+private:
+
+ enum State {
+ STATE_NOT_CONNECTED,
+ STATE_COMMAND,
+ STATE_DATA
+ };
+
+ int m_state;
+
+ std::set <vmime::string> m_rcptLines;
+
+ std::string m_msgData;
+
+ bool m_ehloSent, m_mailSent, m_rcptSent, m_dataSent, m_quitSent;
+};
diff --git a/vmime-master/tests/parser/attachmentHelperTest.cpp b/vmime-master/tests/parser/attachmentHelperTest.cpp
new file mode 100644
index 0000000..866f8de
--- /dev/null
+++ b/vmime-master/tests/parser/attachmentHelperTest.cpp
@@ -0,0 +1,335 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(attachmentHelperTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testAddAttachment1)
+ VMIME_TEST(testAddAttachment2)
+ VMIME_TEST(testAddAttachment3)
+ VMIME_TEST(testIsBodyPartAnAttachment1)
+ VMIME_TEST(testIsBodyPartAnAttachment2)
+ VMIME_TEST(testIsBodyPartAnAttachment3)
+ VMIME_TEST(testGetBodyPartAttachment)
+ VMIME_TEST(testAddAttachmentMessage1)
+ VMIME_TEST(testGetBodyPartAttachmentMessage)
+ VMIME_TEST_LIST_END
+
+
+ static const vmime::string getStructure(const vmime::shared_ptr <vmime::bodyPart>& part) {
+
+ vmime::shared_ptr <vmime::body> bdy = part->getBody();
+
+ vmime::string res = part->getBody()->getContentType().generate();
+
+ if (bdy->getPartCount() == 0) {
+ return res;
+ }
+
+ res += "[";
+
+ for (size_t i = 0 ; i < bdy->getPartCount() ; ++i) {
+
+ vmime::shared_ptr <vmime::bodyPart> subPart = bdy->getPartAt(i);
+
+ if (i != 0) {
+ res += ",";
+ }
+
+ res += getStructure(subPart);
+ }
+
+ return res + "]";
+ }
+
+ static const vmime::string extractBodyContents(
+ const vmime::shared_ptr <const vmime::bodyPart>& part
+ ) {
+
+ vmime::shared_ptr <const vmime::contentHandler> cth = part->getBody()->getContents();
+
+ vmime::string data;
+ vmime::utility::outputStreamStringAdapter os(data);
+
+ cth->extract(os);
+
+ return data;
+ }
+
+ void testAddAttachment1() {
+
+ vmime::string data =
+"Content-Type: text/plain\r\n"
+"\r\n"
+"The text\r\n"
+"";
+
+ vmime::shared_ptr <vmime::message> msg = vmime::make_shared <vmime::message>();
+ msg->parse(data);
+
+ vmime::shared_ptr <vmime::attachment> att =
+ vmime::make_shared <vmime::defaultAttachment>(
+ vmime::make_shared <vmime::stringContentHandler>("test"),
+ vmime::mediaType("image/jpeg")
+ );
+
+ vmime::attachmentHelper::addAttachment(msg, att);
+
+ VASSERT_EQ("1", "multipart/mixed[text/plain,image/jpeg]", getStructure(msg));
+ VASSERT_EQ("2", "The text\r\n", extractBodyContents(msg->getBody()->getPartAt(0)));
+ }
+
+ void testAddAttachment2() {
+
+ vmime::string data =
+"Content-Type: multipart/mixed; boundary=\"foo\"\r\n"
+"\r\n"
+"--foo\r\n"
+"Content-Type: text/plain\r\n"
+"\r\n"
+"The text\r\n"
+"--foo\r\n"
+"Content-Type: application/octet-stream\r\n"
+"\r\n"
+"Blah\r\n"
+"--foo--\r\n"
+"";
+
+ vmime::shared_ptr <vmime::message> msg = vmime::make_shared <vmime::message>();
+ msg->parse(data);
+
+ vmime::shared_ptr <vmime::attachment> att =
+ vmime::make_shared <vmime::defaultAttachment>(
+ vmime::make_shared <vmime::stringContentHandler>("test"),
+ vmime::mediaType("image/jpeg")
+ );
+
+ vmime::attachmentHelper::addAttachment(msg, att);
+
+ VASSERT_EQ("1", "multipart/mixed[text/plain,application/octet-stream,image/jpeg]", getStructure(msg));
+ VASSERT_EQ("2", "The text", extractBodyContents(msg->getBody()->getPartAt(0)));
+ VASSERT_EQ("3", "Blah", extractBodyContents(msg->getBody()->getPartAt(1)));
+ VASSERT_EQ("4", "test", extractBodyContents(msg->getBody()->getPartAt(2)));
+ }
+
+ // Initial part is encoded
+ void testAddAttachment3() {
+
+ vmime::string data =
+"Content-Type: text/plain\r\n"
+"Content-Transfer-Encoding: base64\r\n"
+"\r\n"
+"TWVzc2FnZSBib2R5";
+
+ vmime::shared_ptr <vmime::message> msg = vmime::make_shared <vmime::message>();
+ msg->parse(data);
+
+ vmime::shared_ptr <vmime::attachment> att =
+ vmime::make_shared <vmime::defaultAttachment>(
+ vmime::make_shared <vmime::stringContentHandler>("test"),
+ vmime::mediaType("image/jpeg")
+ );
+
+ vmime::attachmentHelper::addAttachment(msg, att);
+
+ VASSERT_EQ("1", "multipart/mixed[text/plain,image/jpeg]", getStructure(msg));
+ VASSERT_EQ("2", "Message body", extractBodyContents(msg->getBody()->getPartAt(0)));
+ }
+
+ // Content-Disposition: attachment
+ // No other field
+ void testIsBodyPartAnAttachment1() {
+
+ vmime::string data = "Content-Disposition: attachment\r\n\r\nFoo\r\n";
+
+ vmime::shared_ptr <vmime::bodyPart> p = vmime::make_shared <vmime::bodyPart>();
+ p->parse(data);
+
+ VASSERT_EQ("1", true, vmime::attachmentHelper::isBodyPartAnAttachment(p));
+ }
+
+ // No Content-Disposition field
+ // Content-Type: multipart/* or text/*
+ void testIsBodyPartAnAttachment2() {
+
+ vmime::string data = "Content-Type: multipart/*\r\n\r\nFoo\r\n";
+
+ vmime::shared_ptr <vmime::bodyPart> p = vmime::make_shared <vmime::bodyPart>();
+ p->parse(data);
+
+ VASSERT_EQ("1", false, vmime::attachmentHelper::isBodyPartAnAttachment(p));
+
+ data = "Content-Type: text/*\r\n\r\nFoo\r\n";
+
+ p->parse(data);
+
+ VASSERT_EQ("2", false, vmime::attachmentHelper::isBodyPartAnAttachment(p));
+ }
+
+ // No Content-Disposition field
+ void testIsBodyPartAnAttachment3() {
+
+ vmime::string data = "Content-Type: application/octet-stream\r\n\r\nFoo\r\n";
+
+ vmime::shared_ptr <vmime::bodyPart> p = vmime::make_shared <vmime::bodyPart>();
+ p->parse(data);
+
+ VASSERT_EQ("1", true, vmime::attachmentHelper::isBodyPartAnAttachment(p));
+ }
+
+ // Content-Disposition: attachment
+ // Content-Id field present
+ void testIsBodyPartAnAttachment4() {
+
+ vmime::string data = "Content-Disposition: attachment\r\n"
+ "Content-Type: application/octet-stream\r\n"
+ "Content-Id: bar\r\n"
+ "\r\nFoo\r\n";
+
+ vmime::shared_ptr <vmime::bodyPart> p = vmime::make_shared <vmime::bodyPart>();
+ p->parse(data);
+
+ VASSERT_EQ("1", false, vmime::attachmentHelper::isBodyPartAnAttachment(p));
+ }
+
+ void testGetBodyPartAttachment() {
+
+ vmime::string data =
+ "Content-Type: image/jpeg\r\n"
+ "Content-Description: foobar\r\n"
+ "Content-Transfer-Encoding: x-baz\r\n"
+ "Content-Disposition: attachment; filename=\"foobar.baz\"\r\n"
+ "\r\n"
+ "Foo bar baz";
+
+ vmime::shared_ptr <vmime::bodyPart> part = vmime::make_shared <vmime::bodyPart>();
+ part->parse(data);
+
+ vmime::shared_ptr <const vmime::attachment> att =
+ vmime::attachmentHelper::getBodyPartAttachment(part);
+
+ VASSERT_EQ("1", "image/jpeg", att->getType().generate());
+ VASSERT_EQ("2", "foobar", att->getDescription().generate());
+ VASSERT_EQ("3", "x-baz", att->getEncoding().generate());
+ VASSERT_EQ("4", "foobar.baz", att->getName().generate());
+
+ vmime::string attData;
+ vmime::utility::outputStreamStringAdapter out(attData);
+ att->getData()->extractRaw(out); // 'x-baz' encoding not supported
+
+ VASSERT_EQ("5", "Foo bar baz", attData);
+
+ //VASSERT_EQ("6", part, att->getPart());
+ VASSERT_EQ("6", part->generate(), vmime::dynamicCast <const vmime::component>(att->getPart())->generate());
+ //VASSERT_EQ("7", part->getHeader(), att->getHeader());
+ VASSERT_EQ("7", part->getHeader()->generate(), att->getHeader()->generate());
+ }
+
+ void testAddAttachmentMessage1() {
+
+ const vmime::string data =
+"Subject: Test message\r\n"
+"Content-Type: text/plain\r\n"
+"\r\n"
+"Message body";
+
+ vmime::shared_ptr <vmime::message> msg = vmime::make_shared <vmime::message>();
+ msg->parse(data);
+
+ const vmime::string attData =
+"Subject: Attached message\r\n"
+"Content-Type: text/plain\r\n"
+"Content-Transfer-Encoding: base64\r\n"
+"\r\n"
+"QXR0YWNoZWQgbWVzc2FnZSBib2R5";
+
+ vmime::shared_ptr <vmime::message> amsg = vmime::make_shared <vmime::message>();
+ amsg->parse(attData);
+
+ vmime::attachmentHelper::addAttachment(msg, amsg);
+
+ VASSERT_EQ("1", "multipart/mixed[text/plain,message/rfc822]", getStructure(msg));
+ VASSERT_EQ("2", "Message body", extractBodyContents(msg->getBody()->getPartAt(0)));
+
+ // Ensure message has been encoded properly
+ vmime::shared_ptr <const vmime::bodyPart> attPart = msg->getBody()->getPartAt(1);
+ vmime::shared_ptr <const vmime::contentHandler> attCth = attPart->getBody()->getContents();
+
+ vmime::string attDataOut;
+ vmime::utility::outputStreamStringAdapter attDataOutOs(attDataOut);
+
+ attCth->extract(attDataOutOs);
+
+ vmime::shared_ptr <vmime::message> amsgOut = vmime::make_shared <vmime::message>();
+ amsgOut->parse(attDataOut);
+
+ vmime::shared_ptr <vmime::header> hdr = amsgOut->getHeader();
+
+ VASSERT_EQ("3", "Attached message", hdr->Subject()->getValue <vmime::text>()->generate());
+ VASSERT_EQ("4", "Attached message body", extractBodyContents(amsgOut));
+ }
+
+ void testGetBodyPartAttachmentMessage() {
+
+ const vmime::string data =
+"Subject: Test message\r\n"
+"Content-Type: multipart/mixed; boundary=\"foo\"\r\n"
+"\r\n"
+"--foo\r\n"
+"Content-Type: message/rfc822\r\n"
+"\r\n"
+"Subject: Attached message\r\n"
+"\r\n"
+"Attached message body\r\n"
+"--foo\r\n"
+"Content-Type: text/plain\r\n"
+"\r\n"
+"FooBar\r\n"
+"--foo--\r\n";
+
+ vmime::shared_ptr <vmime::message> msg = vmime::make_shared <vmime::message>();
+ msg->parse(data);
+
+ VASSERT_EQ("0", 2, msg->getBody()->getPartCount());
+
+ vmime::shared_ptr <const vmime::attachment> att =
+ vmime::attachmentHelper::getBodyPartAttachment(msg->getBody()->getPartAt(0));
+
+ VASSERT("1", att != NULL);
+
+ vmime::shared_ptr <const vmime::messageAttachment> msgAtt =
+ vmime::dynamicCast <const vmime::messageAttachment>(att);
+
+ VASSERT("2", msgAtt != NULL);
+
+ vmime::shared_ptr <vmime::message> amsg = msgAtt->getMessage();
+ vmime::shared_ptr <vmime::header> hdr = amsg->getHeader();
+
+ VASSERT_EQ("3", "Attached message", hdr->Subject()->getValue <vmime::text>()->generate());
+ VASSERT_EQ("4", "Attached message body", extractBodyContents(amsg));
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/bodyPartTest.cpp b/vmime-master/tests/parser/bodyPartTest.cpp
new file mode 100644
index 0000000..3aaadd0
--- /dev/null
+++ b/vmime-master/tests/parser/bodyPartTest.cpp
@@ -0,0 +1,414 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(bodyPartTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testParse)
+ VMIME_TEST(testGenerate)
+ VMIME_TEST(testParseGuessBoundary)
+ VMIME_TEST(testParseGuessBoundaryWithTransportPadding)
+ VMIME_TEST(testParseMissingLastBoundary)
+ VMIME_TEST(testPrologEpilog)
+ VMIME_TEST(testPrologEncoding)
+ VMIME_TEST(testSuccessiveBoundaries)
+ VMIME_TEST(testTransportPaddingInBoundary)
+ VMIME_TEST(testGenerate7bit)
+ VMIME_TEST(testTextUsageForQPEncoding)
+ VMIME_TEST(testParseVeryBigMessage)
+ VMIME_TEST(testParseBoundaryPrefix)
+ VMIME_TEST_LIST_END
+
+
+ static const vmime::string extractComponentString(
+ const vmime::string& buffer,
+ const vmime::component& c
+ ) {
+
+ return vmime::string(
+ buffer.begin() + c.getParsedOffset(),
+ buffer.begin() + c.getParsedOffset() + c.getParsedLength()
+ );
+ }
+
+ static const vmime::string extractContents(
+ const vmime::shared_ptr <const vmime::contentHandler>& cts
+ ) {
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter os(oss);
+
+ cts->extract(os);
+
+ return oss.str();
+ }
+
+
+ void testParse() {
+
+ vmime::string str1 = "HEADER\r\n\r\nBODY";
+ vmime::bodyPart p1;
+ p1.parse(str1);
+
+ VASSERT_EQ("1", "HEADER\r\n\r\n", extractComponentString(str1, *p1.getHeader()));
+ VASSERT_EQ("2", "BODY", extractComponentString(str1, *p1.getBody()));
+
+ vmime::string str2 = "HEADER\n\nBODY";
+ vmime::bodyPart p2;
+ p2.parse(str2);
+
+ VASSERT_EQ("3", "HEADER\n\n", extractComponentString(str2, *p2.getHeader()));
+ VASSERT_EQ("4", "BODY", extractComponentString(str2, *p2.getBody()));
+
+ vmime::string str3 = "HEADER\r\n\nBODY";
+ vmime::bodyPart p3;
+ p3.parse(str3);
+
+ VASSERT_EQ("5", "HEADER\r\n\n", extractComponentString(str3, *p3.getHeader()));
+ VASSERT_EQ("6", "BODY", extractComponentString(str3, *p3.getBody()));
+ }
+
+ void testParseMissingLastBoundary() {
+
+ vmime::string str =
+ "Content-Type: multipart/mixed; boundary=\"MY-BOUNDARY\""
+ "\r\n\r\n"
+ "--MY-BOUNDARY\r\nHEADER1\r\n\r\nBODY1\r\n"
+ "--MY-BOUNDARY\r\nHEADER2\r\n\r\nBODY2";
+
+ vmime::bodyPart p;
+ p.parse(str);
+
+ VASSERT_EQ("count", 2, p.getBody()->getPartCount());
+
+ VASSERT_EQ("part1-body", "BODY1", extractContents(p.getBody()->getPartAt(0)->getBody()->getContents()));
+ VASSERT_EQ("part2-body", "BODY2", extractContents(p.getBody()->getPartAt(1)->getBody()->getContents()));
+ }
+
+ void testGenerate() {
+
+ vmime::bodyPart p1;
+ p1.getHeader()->getField("Foo")->setValue(vmime::string("bar"));
+ p1.getBody()->setContents(vmime::make_shared <vmime::stringContentHandler>("Baz"));
+
+ VASSERT_EQ("1", "Foo: bar\r\n\r\nBaz", p1.generate());
+ }
+
+ void testPrologEpilog() {
+
+ const char testMail[] =
+ "To: test@vmime.org\r\n"
+ "From: test@vmime.org\r\n"
+ "Subject: Prolog and epilog test\r\n"
+ "Content-Type: multipart/mixed; \r\n"
+ " boundary=\"=_boundary\"\r\n"
+ "\r\n"
+ "Prolog text\r\n"
+ "--=_boundary\r\n"
+ "Content-Type: text/plain\r\n"
+ "\r\n"
+ "Part1\r\n"
+ "--=_boundary--\r\n"
+ "Epilog text";
+
+ vmime::bodyPart part;
+ part.parse(testMail);
+
+ VASSERT_EQ("prolog", "Prolog text", part.getBody()->getPrologText());
+ VASSERT_EQ("epilog", "Epilog text", part.getBody()->getEpilogText());
+ }
+
+ // Test for bug fix: prolog should not be encoded
+ // http://sourceforge.net/tracker/?func=detail&atid=525568&aid=3174903&group_id=69724
+ void testPrologEncoding() {
+
+ const char testmail[] =
+ "To: test@vmime.org\r\n"
+ "From: test@vmime.org\r\n"
+ "Subject: Prolog encoding test\r\n"
+ "Content-Type: multipart/mixed; \r\n"
+ " boundary=\"=_+ZWjySayKqSf2CyrfnNpaAcO6-G1HpoXdHZ4YyswAWqEY39Q\"\r\n"
+ "\r\n"
+ "This is a multi-part message in MIME format. Your mail reader does not\r\n"
+ "understand MIME message format.\r\n"
+ "--=_+ZWjySayKqSf2CyrfnNpaAcO6-G1HpoXdHZ4YyswAWqEY39Q\r\n"
+ "Content-Type: text/html; charset=windows-1251\r\n"
+ "Content-Transfer-Encoding: quoted-printable\r\n"
+ "\r\n"
+ "=DD=F2=EE =F2=E5=EA=F1=F2=EE=E2=E0=FF =F7=E0=F1=F2=FC =F1=EB=EE=E6=ED=EE=E3=\r\n"
+ "=EE =F1=EE=EE=E1=F9=E5=ED=E8=FF\r\n"
+ "--=_+ZWjySayKqSf2CyrfnNpaAcO6-G1HpoXdHZ4YyswAWqEY39Q\r\n"
+ "Content-Type: application/octet-stream; charset=windows-1251\r\n"
+ "Content-Disposition: attachment; filename=FNS.zip\r\n"
+ "Content-Transfer-Encoding: base64\r\n"
+ "\r\n"
+ "UEsDBB...snap...EEAAAAAA==\r\n"
+ "--=_+ZWjySayKqSf2CyrfnNpaAcO6-G1HpoXdHZ4YyswAWqEY39Q--\r\n"
+ "Epilog text";
+
+ vmime::shared_ptr<vmime::message> msg = vmime::make_shared<vmime::message>();
+
+ std::string istr(testmail);
+
+ std::string ostr;
+ vmime::utility::outputStreamStringAdapter out(ostr);
+
+ for (int i = 0 ; i < 10 ; ++i) {
+
+ ostr.clear();
+
+ msg->parse(istr);
+ msg->generate(out);
+
+ istr = ostr;
+ }
+
+ VASSERT_EQ("prolog", "This is a multi-part message in MIME format. Your mail reader"
+ " does not understand MIME message format.", msg->getBody()->getPrologText());
+ VASSERT_EQ("epilog", "Epilog text", msg->getBody()->getEpilogText());
+ }
+
+ void testSuccessiveBoundaries() {
+
+ vmime::string str =
+ "Content-Type: multipart/mixed; boundary=\"MY-BOUNDARY\""
+ "\r\n\r\n"
+ "--MY-BOUNDARY\r\nHEADER1\r\n\r\nBODY1\r\n"
+ "--MY-BOUNDARY\r\n"
+ "--MY-BOUNDARY--\r\n";
+
+ vmime::bodyPart p;
+ p.parse(str);
+
+ VASSERT_EQ("count", 2, p.getBody()->getPartCount());
+
+ VASSERT_EQ("part1-body", "BODY1", extractContents(p.getBody()->getPartAt(0)->getBody()->getContents()));
+ VASSERT_EQ("part2-body", "", extractContents(p.getBody()->getPartAt(1)->getBody()->getContents()));
+ }
+
+ void testTransportPaddingInBoundary() {
+
+ vmime::string str =
+ "Content-Type: multipart/mixed; boundary=\"MY-BOUNDARY\""
+ "\r\n\r\n"
+ "--MY-BOUNDARY \t \r\nHEADER1\r\n\r\nBODY1\r\n"
+ "--MY-BOUNDARY\r\n"
+ "--MY-BOUNDARY-- \r\n";
+
+ vmime::bodyPart p;
+ p.parse(str);
+
+ VASSERT_EQ("count", 2, p.getBody()->getPartCount());
+
+ VASSERT_EQ("part1-body", "BODY1", extractContents(p.getBody()->getPartAt(0)->getBody()->getContents()));
+ VASSERT_EQ("part2-body", "", extractContents(p.getBody()->getPartAt(1)->getBody()->getContents()));
+ }
+
+ /** Ensure '7bit' encoding is used when body is 7-bit only. */
+ void testGenerate7bit() {
+
+ vmime::shared_ptr <vmime::plainTextPart> p1 = vmime::make_shared <vmime::plainTextPart>();
+ p1->setText(vmime::make_shared <vmime::stringContentHandler>("Part1 is US-ASCII only."));
+
+ vmime::shared_ptr <vmime::message> msg = vmime::make_shared <vmime::message>();
+ p1->generateIn(msg, msg);
+
+ vmime::shared_ptr <vmime::header> header1 = msg->getBody()->getPartAt(0)->getHeader();
+ VASSERT_EQ("1", "7bit", header1->ContentTransferEncoding()->getValue()->generate());
+ }
+
+ void testTextUsageForQPEncoding() {
+
+ vmime::shared_ptr <vmime::plainTextPart> part = vmime::make_shared <vmime::plainTextPart>();
+ part->setText(vmime::make_shared <vmime::stringContentHandler>("Part1-line1\r\nPart1-line2\r\n\x89"));
+
+ vmime::shared_ptr <vmime::message> msg = vmime::make_shared <vmime::message>();
+ part->generateIn(msg, msg);
+
+ vmime::shared_ptr <vmime::body> body = msg->getBody()->getPartAt(0)->getBody();
+ vmime::shared_ptr <vmime::header> header = msg->getBody()->getPartAt(0)->getHeader();
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter os(oss);
+ body->generate(os, 80);
+
+ VASSERT_EQ("1", "quoted-printable", header->ContentTransferEncoding()->getValue()->generate());
+
+ // This should *NOT* be:
+ // Part1-line1=0D=0APart1-line2=0D=0A=89
+ VASSERT_EQ("2", "Part1-line1\r\nPart1-line2\r\n=89", oss.str());
+ }
+
+ void testParseGuessBoundary() {
+
+ // Boundary is not specified in "Content-Type" field
+ // Parser will try to guess it from message contents.
+
+ vmime::string str =
+ "Content-Type: multipart/mixed"
+ "\r\n\r\n"
+ "--UNKNOWN-BOUNDARY\r\nHEADER1\r\n\r\nBODY1\r\n"
+ "--UNKNOWN-BOUNDARY\r\nHEADER2\r\n\r\nBODY2\r\n"
+ "--UNKNOWN-BOUNDARY--";
+
+ vmime::bodyPart p;
+ p.parse(str);
+
+ VASSERT_EQ("count", 2, p.getBody()->getPartCount());
+
+ VASSERT_EQ("part1-body", "BODY1", extractContents(p.getBody()->getPartAt(0)->getBody()->getContents()));
+ VASSERT_EQ("part2-body", "BODY2", extractContents(p.getBody()->getPartAt(1)->getBody()->getContents()));
+ }
+
+ void testParseGuessBoundaryWithTransportPadding() {
+
+ // Boundary is not specified in "Content-Type" field
+ // Parser will try to guess it from message contents.
+ // Transport padding white spaces should be ignored.
+
+ vmime::string str =
+ "Content-Type: multipart/mixed"
+ "\r\n\r\n"
+ "--UNKNOWN-BOUNDARY \t \r\nHEADER1\r\n\r\nBODY1\r\n"
+ "--UNKNOWN-BOUNDARY\r\nHEADER2\r\n\r\nBODY2\r\n"
+ "--UNKNOWN-BOUNDARY--";
+
+ vmime::bodyPart p;
+ p.parse(str);
+
+ VASSERT_EQ("count", 2, p.getBody()->getPartCount());
+
+ VASSERT_EQ("part1-body", "BODY1", extractContents(p.getBody()->getPartAt(0)->getBody()->getContents()));
+ VASSERT_EQ("part2-body", "BODY2", extractContents(p.getBody()->getPartAt(1)->getBody()->getContents()));
+ }
+
+ void testParseVeryBigMessage() {
+
+ // When parsing from a seekable input stream, body contents should not
+ // be kept in memory in a "stringContentHandler" object. Instead, content
+ // should be accessible via a "streamContentHandler" object.
+
+ static const std::string BODY1_BEGIN = "BEGIN1BEGIN1BEGIN1";
+ static const std::string BODY1_LINE = "BODY1BODY1BODY1BODY1BODY1BODY1BODY1BODY1BODY1BODY1BODY1BODY1BODY1";
+ static const std::string BODY1_END = "END1END1";
+ static const unsigned int BODY1_REPEAT = 35000;
+ static const size_t BODY1_LENGTH =
+ BODY1_BEGIN.length() + BODY1_LINE.length() * BODY1_REPEAT + BODY1_END.length();
+
+ static const std::string BODY2_LINE = "BODY2BODY2BODY2BODY2BODY2BODY2BODY2BODY2BODY2BODY2BODY2BODY2BODY2";
+ static const unsigned int BODY2_REPEAT = 20000;
+
+ std::ostringstream oss;
+ oss << "Content-Type: multipart/mixed; boundary=\"MY-BOUNDARY\""
+ << "\r\n\r\n"
+ << "--MY-BOUNDARY\r\n"
+ << "HEADER1\r\n"
+ << "\r\n";
+
+ oss << BODY1_BEGIN;
+
+ for (unsigned int i = 0 ; i < BODY1_REPEAT ; ++i) {
+ oss << BODY1_LINE;
+ }
+
+ oss << BODY1_END;
+
+ oss << "\r\n"
+ << "--MY-BOUNDARY\r\n"
+ << "HEADER2\r\n"
+ << "\r\n";
+
+ for (unsigned int i = 0 ; i < BODY2_REPEAT ; ++i) {
+ oss << BODY2_LINE;
+ }
+
+ oss << "\r\n"
+ << "--MY-BOUNDARY--\r\n";
+
+ vmime::shared_ptr <vmime::utility::inputStreamStringAdapter> is =
+ vmime::make_shared <vmime::utility::inputStreamStringAdapter>(oss.str());
+
+ vmime::shared_ptr <vmime::message> msg = vmime::make_shared <vmime::message>();
+ msg->parse(is, oss.str().length());
+
+ vmime::shared_ptr <vmime::body> body1 = msg->getBody()->getPartAt(0)->getBody();
+ vmime::shared_ptr <const vmime::contentHandler> body1Cts = body1->getContents();
+
+ vmime::shared_ptr <vmime::body> body2 = msg->getBody()->getPartAt(1)->getBody();
+ vmime::shared_ptr <const vmime::contentHandler> body2Cts = body2->getContents();
+
+ vmime::string body1CtsExtracted;
+ vmime::utility::outputStreamStringAdapter body1CtsExtractStream(body1CtsExtracted);
+ body1Cts->extract(body1CtsExtractStream);
+
+ VASSERT_EQ("1.1", BODY1_LENGTH, body1Cts->getLength());
+ VASSERT("1.2", vmime::dynamicCast <const vmime::streamContentHandler>(body1Cts) != NULL);
+ VASSERT_EQ("1.3", BODY1_LENGTH, body1CtsExtracted.length());
+ VASSERT_EQ("1.4", BODY1_BEGIN, body1CtsExtracted.substr(0, BODY1_BEGIN.length()));
+ VASSERT_EQ("1.5", BODY1_END, body1CtsExtracted.substr(BODY1_LENGTH - BODY1_END.length(), BODY1_END.length()));
+
+ VASSERT_EQ("2.1", BODY2_LINE.length() * BODY2_REPEAT, body2Cts->getLength());
+ VASSERT("2.2", vmime::dynamicCast <const vmime::streamContentHandler>(body2Cts) != NULL);
+ }
+
+ void testParseBoundaryPrefix() {
+ /*
+ * Clients are not supposed to create boundary identifiers that
+ * contain a prefix of another (RFC 2046 section 5.1), but alas
+ * CANCOM FortiMail produces this garbage.
+ */
+ vmime::string str =
+ "Content-Type: multipart/related; boundary=\"--b12\"\r\n"
+ "\r\n"
+ "----b12\r\n"
+ "Content-Type: multipart/alternative; boundary=\"--b12-1\"\r\n"
+ "\r\n"
+ "----b12-1\r\n"
+ "Content-Type: text/plain; charset=utf-8\r\n"
+ "\r\n"
+ "P11\r\n"
+ "----b12-1\r\n"
+ "Content-Type: text/html; charset=utf-8\r\n"
+ "\r\n"
+ "P12\r\n"
+ "----b12-1--\r\n"
+ "----b12\r\n"
+ "\r\n"
+ "P2\r\n"
+ "----b12--\r\n";
+
+ vmime::bodyPart relco;
+ relco.parse(str);
+ auto relbd = relco.getBody();
+ VASSERT_EQ("global-partcount", 2, relbd->getPartCount());
+ auto altbd = relbd->getPartAt(0)->getBody();
+ VASSERT_EQ("part1-partcount", 2, altbd->getPartCount());
+ VASSERT_EQ("part1.1-body", "P11", extractContents(altbd->getPartAt(0)->getBody()->getContents()));
+ VASSERT_EQ("part1.2-body", "P12", extractContents(altbd->getPartAt(1)->getBody()->getContents()));
+ VASSERT_EQ("part2-body", "P2", extractContents(relbd->getPartAt(1)->getBody()->getContents()));
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/bodyTest.cpp b/vmime-master/tests/parser/bodyTest.cpp
new file mode 100644
index 0000000..31054f3
--- /dev/null
+++ b/vmime-master/tests/parser/bodyTest.cpp
@@ -0,0 +1,79 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(bodyTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testGenerate_Text)
+ VMIME_TEST(testGenerate_NonText)
+ VMIME_TEST_LIST_END
+
+ void testGenerate_Text() {
+
+ // RFC-2015: [Quoted-Printable encoding] A line break in a text body,
+ // represented as a CRLF sequence in the text canonical form, must be
+ // represented by a line break which is also a CRLF sequence, in the
+ // Quoted-Printable encoding
+
+ vmime::bodyPart p;
+ p.getBody()->setContents(
+ vmime::make_shared <vmime::stringContentHandler>(
+ "Foo éé\r\né bar\r\nbaz"
+ ),
+ vmime::mediaType("text", "plain"),
+ vmime::charset("utf-8"),
+ vmime::encoding("quoted-printable")
+ );
+
+ VASSERT_EQ(
+ "generate",
+ "Foo =C3=A9=C3=A9\r\n"
+ "=C3=A9 bar\r\n"
+ "baz",
+ p.getBody()->generate()
+ );
+ }
+
+ void testGenerate_NonText() {
+
+ vmime::bodyPart p;
+ p.getBody()->setContents(
+ vmime::make_shared <vmime::stringContentHandler>(
+ "Binary\xfa\xfb\r\ndata\r\n\r\n\xfc"
+ ),
+ vmime::mediaType("application", "octet-stream"),
+ vmime::charset("utf-8"),
+ vmime::encoding("quoted-printable")
+ );
+
+ VASSERT_EQ(
+ "generate",
+ "Binary=FA=FB=0D=0Adata=0D=0A=0D=0A=FC",
+ p.getBody()->generate()
+ );
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/charsetFilteredOutputStreamTest.cpp b/vmime-master/tests/parser/charsetFilteredOutputStreamTest.cpp
new file mode 100644
index 0000000..0ebd83a
--- /dev/null
+++ b/vmime-master/tests/parser/charsetFilteredOutputStreamTest.cpp
@@ -0,0 +1,213 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/charset.hpp"
+#include "vmime/charsetConverter.hpp"
+
+#include "charsetTestSuites.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(charsetFilteredOutputStreamTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testInputBufferUnderflow)
+ VMIME_TEST(testInvalidInput1)
+ VMIME_TEST(testStreamCopy)
+ VMIME_TEST(testOneByteAtTime)
+ VMIME_TEST(testVariableInputChunk)
+ VMIME_TEST_LIST_END
+
+
+ void testInputBufferUnderflow() {
+
+ vmime::shared_ptr <vmime::charsetConverter> cc =
+ vmime::charsetConverter::create("utf-8", "iso-8859-1");
+
+ vmime::string output;
+ vmime::utility::outputStreamStringAdapter os(output);
+ vmime::shared_ptr <vmime::utility::filteredOutputStream> cfos = cc->getFilteredOutputStream(os);
+
+ VASSERT_NOT_NULL("filteredOutputStream availability", cfos);
+
+ // føo = 66 c3 b8 6f [UTF8]
+ // føo = 66 f8 6f [latin1]
+
+ cfos->write("\x66\xc3", 2);
+
+ // Incomplete UTF-8 sequence was not converted
+ VASSERT_EQ("chunk 1", toHex("f"), toHex(output));
+
+ // Write second byte of UTF-8 sequence
+ cfos->write("\xb8\x6f", 2);
+
+ VASSERT_EQ("chunk 2", toHex("f\xf8o"), toHex(output));
+ }
+
+ void testInvalidInput1() {
+
+ vmime::string in("foo\xab\xcd\xef bar");
+ vmime::string expectedOut("foo??? bar");
+
+ vmime::string actualOut;
+ vmime::utility::outputStreamStringAdapter osa(actualOut);
+
+ vmime::shared_ptr <vmime::charsetConverter> conv =
+ vmime::charsetConverter::create(vmime::charset("utf-8"), vmime::charset("iso-8859-1"));
+
+ vmime::shared_ptr <vmime::utility::charsetFilteredOutputStream> os =
+ conv->getFilteredOutputStream(osa);
+
+ VASSERT_NOT_NULL("filteredOutputStream availability", os);
+
+ vmime::utility::inputStreamStringAdapter is(in);
+
+ vmime::byte_t buffer[16];
+
+ for (int i = 0 ; !is.eof() ; ++i)
+ os->write(buffer, is.read(buffer, 1));
+
+ os->flush();
+
+ VASSERT_EQ("1", toHex(expectedOut), toHex(actualOut));
+ }
+
+ // Using 'bufferedStreamCopy'
+ void testStreamCopy() {
+
+ for (unsigned int i = 0 ; i < charsetTestSuitesCount ; ++i) {
+
+ const charsetTestSuiteStruct& entry = charsetTestSuites[i];
+
+ std::ostringstream testName;
+ testName << i << ": " << entry.fromCharset << " -> " << entry.toCharset;
+
+ const unsigned long inLength = (entry.fromLength == 0 ? strlen(entry.fromBytes) : entry.fromLength);
+ vmime::string in(entry.fromBytes, entry.fromBytes + inLength);
+
+ const unsigned long outLength = (entry.toLength == 0 ? strlen(entry.toBytes) : entry.toLength);
+ vmime::string expectedOut(entry.toBytes, entry.toBytes + outLength);
+
+ vmime::string actualOut;
+ vmime::utility::outputStreamStringAdapter osa(actualOut);
+
+ vmime::shared_ptr <vmime::charsetConverter> conv =
+ vmime::charsetConverter::create(entry.fromCharset, entry.toCharset);
+
+ vmime::shared_ptr <vmime::utility::charsetFilteredOutputStream> os =
+ conv->getFilteredOutputStream(osa);
+
+ VASSERT_NOT_NULL("filteredOutputStream availability", os);
+
+ vmime::utility::inputStreamStringAdapter is(in);
+
+ vmime::utility::bufferedStreamCopy(is, *os);
+
+ os->flush();
+
+ VASSERT_EQ(testName.str(), toHex(expectedOut), toHex(actualOut));
+ }
+ }
+
+ // One byte at a time
+ void testOneByteAtTime() {
+
+ for (unsigned int i = 0 ; i < charsetTestSuitesCount ; ++i) {
+
+ const charsetTestSuiteStruct& entry = charsetTestSuites[i];
+
+ std::ostringstream testName;
+ testName << i << ": " << entry.fromCharset << " -> " << entry.toCharset;
+
+ const unsigned long inLength = (entry.fromLength == 0 ? strlen(entry.fromBytes) : entry.fromLength);
+ vmime::string in(entry.fromBytes, entry.fromBytes + inLength);
+
+ const unsigned long outLength = (entry.toLength == 0 ? strlen(entry.toBytes) : entry.toLength);
+ vmime::string expectedOut(entry.toBytes, entry.toBytes + outLength);
+
+ vmime::string actualOut;
+ vmime::utility::outputStreamStringAdapter osa(actualOut);
+
+ vmime::shared_ptr <vmime::charsetConverter> conv =
+ vmime::charsetConverter::create(entry.fromCharset, entry.toCharset);
+
+ vmime::shared_ptr <vmime::utility::charsetFilteredOutputStream> os =
+ conv->getFilteredOutputStream(osa);
+
+ VASSERT_NOT_NULL("filteredOutputStream availability", os);
+
+ vmime::utility::inputStreamStringAdapter is(in);
+
+ vmime::byte_t buffer[16];
+
+ for (int i = 0 ; !is.eof() ; ++i)
+ os->write(buffer, is.read(buffer, 1));
+
+ os->flush();
+
+ VASSERT_EQ(testName.str(), toHex(expectedOut), toHex(actualOut));
+ }
+ }
+
+ // Variable chunks
+ void testVariableInputChunk() {
+
+ for (unsigned int i = 0 ; i < charsetTestSuitesCount ; ++i) {
+
+ const charsetTestSuiteStruct& entry = charsetTestSuites[i];
+
+ std::ostringstream testName;
+ testName << i << ": " << entry.fromCharset << " -> " << entry.toCharset;
+
+ const unsigned long inLength = (entry.fromLength == 0 ? strlen(entry.fromBytes) : entry.fromLength);
+ vmime::string in(entry.fromBytes, entry.fromBytes + inLength);
+
+ const unsigned long outLength = (entry.toLength == 0 ? strlen(entry.toBytes) : entry.toLength);
+ vmime::string expectedOut(entry.toBytes, entry.toBytes + outLength);
+
+ vmime::string actualOut;
+ vmime::utility::outputStreamStringAdapter osa(actualOut);
+
+ vmime::shared_ptr <vmime::charsetConverter> conv =
+ vmime::charsetConverter::create(entry.fromCharset, entry.toCharset);
+
+ vmime::shared_ptr <vmime::utility::charsetFilteredOutputStream> os =
+ conv->getFilteredOutputStream(osa);
+
+ VASSERT_NOT_NULL("filteredOutputStream availability", os);
+
+ vmime::utility::inputStreamStringAdapter is(in);
+
+ vmime::byte_t buffer[16];
+
+ for (int i = 0 ; !is.eof() ; ++i)
+ os->write(buffer, is.read(buffer, (i % 5) + 1));
+
+ os->flush();
+
+ VASSERT_EQ(testName.str(), toHex(expectedOut), toHex(actualOut));
+ }
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/charsetTest.cpp b/vmime-master/tests/parser/charsetTest.cpp
new file mode 100644
index 0000000..e44bef5
--- /dev/null
+++ b/vmime-master/tests/parser/charsetTest.cpp
@@ -0,0 +1,252 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include <algorithm>
+
+#include "tests/testUtils.hpp"
+
+#include "charsetTestSuites.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(charsetTest)
+
+ VMIME_TEST_LIST_BEGIN
+ // Test valid input
+ VMIME_TEST(testConvertStringValid)
+ VMIME_TEST(testConvertStreamValid)
+ VMIME_TEST(testEncodingHebrew1255)
+
+ // IDNA
+ VMIME_TEST(testEncodeIDNA)
+ VMIME_TEST(testDecodeIDNA)
+
+ VMIME_TEST(testUTF7Support)
+
+ VMIME_TEST(testReplaceInvalidSequence)
+ VMIME_TEST(testStopOnInvalidSequence)
+
+ VMIME_TEST(testStatus)
+ VMIME_TEST(testStatusWithInvalidSequence)
+
+ VMIME_TEST(testIsValidText)
+ VMIME_TEST_LIST_END
+
+
+ void testConvertStringValid() {
+
+ for (unsigned int i = 0 ; i < charsetTestSuitesCount ; ++i) {
+
+ const charsetTestSuiteStruct& entry = charsetTestSuites[i];
+
+ std::ostringstream testName;
+ testName << i << ": " << entry.fromCharset << " -> " << entry.toCharset;
+
+ const unsigned long inLength = (entry.fromLength == 0 ? strlen(entry.fromBytes) : entry.fromLength);
+ vmime::string in(entry.fromBytes, entry.fromBytes + inLength);
+
+ const unsigned long outLength = (entry.toLength == 0 ? strlen(entry.toBytes) : entry.toLength);
+ vmime::string expectedOut(entry.toBytes, entry.toBytes + outLength);
+
+ vmime::string actualOut;
+
+ vmime::charset::convert
+ (in, actualOut, entry.fromCharset, entry.toCharset);
+
+ VASSERT_EQ(testName.str(), toHex(expectedOut), toHex(actualOut));
+ }
+ }
+
+ void testConvertStreamValid() {
+
+ for (unsigned int i = 0 ; i < charsetTestSuitesCount ; ++i) {
+
+ const charsetTestSuiteStruct& entry = charsetTestSuites[i];
+
+ std::ostringstream testName;
+ testName << i << ": " << entry.fromCharset << " -> " << entry.toCharset;
+
+ const unsigned long inLength = (entry.fromLength == 0 ? strlen(entry.fromBytes) : entry.fromLength);
+ vmime::string in(entry.fromBytes, entry.fromBytes + inLength);
+
+ const unsigned long outLength = (entry.toLength == 0 ? strlen(entry.toBytes) : entry.toLength);
+ vmime::string expectedOut(entry.toBytes, entry.toBytes + outLength);
+
+ vmime::string actualOut;
+ vmime::utility::outputStreamStringAdapter os(actualOut);
+
+ vmime::utility::inputStreamStringAdapter is(in);
+
+ vmime::charset::convert(is, os, entry.fromCharset, entry.toCharset);
+
+ os.flush();
+
+ VASSERT_EQ(testName.str(), toHex(expectedOut), toHex(actualOut));
+ }
+ }
+
+ void testEncodingHebrew1255() {
+
+ // hewbrew string in windows-1255 charset
+ const char data[] = "\xe9\xf9\xf7\xf8\xe9\xf9\xf8\xf7\xe9\xe9\xf9";
+ vmime::word w = vmime::word(data, "windows-1255");
+ vmime::string encoded = w.generate();
+ // less than 60% ascii, base64 received
+ VASSERT_EQ("1", "=?windows-1255?B?6fn3+On5+Pfp6fk=?=", encoded);
+ }
+
+ static const vmime::string convertHelper(
+ const vmime::string& in,
+ const vmime::charset& csrc,
+ const vmime::charset& cdest,
+ const vmime::charsetConverterOptions& opts = vmime::charsetConverterOptions(),
+ vmime::charsetConverter::status* st = NULL
+ ) {
+
+ vmime::shared_ptr <vmime::charsetConverter> conv =
+ vmime::charsetConverter::create(csrc, cdest, opts);
+
+ vmime::string out;
+ conv->convert(in, out, st);
+
+ return out;
+ }
+
+ void testEncodeIDNA() {
+
+ VASSERT_EQ("1", "xn--espaol-zwa", convertHelper("español", "utf-8", "idna"));
+
+ // Tests from ICANN
+ VASSERT_EQ("2.1", "xn--hxajbheg2az3al", convertHelper("παράδειγμα", "utf-8", "idna"));
+ VASSERT_EQ("2.2", "xn--jxalpdlp", convertHelper("δοκιμή", "utf-8", "idna"));
+
+ VASSERT_EQ("3.1", "xn--mgbh0fb", convertHelper("مثال", "utf-8", "idna"));
+ VASSERT_EQ("3.2", "xn--kgbechtv", convertHelper("إختبار", "utf-8", "idna"));
+ }
+
+ void testDecodeIDNA() {
+
+ VASSERT_EQ("1", "español", convertHelper("xn--espaol-zwa", "idna", "utf-8"));
+
+ // Tests from ICANN
+ VASSERT_EQ("2.1", "παράδειγμα", convertHelper("xn--hxajbheg2az3al", "idna", "utf-8"));
+ VASSERT_EQ("2.2", "δοκιμή", convertHelper("xn--jxalpdlp", "idna", "utf-8"));
+
+ VASSERT_EQ("3.1", "مثال", convertHelper("xn--mgbh0fb", "idna", "utf-8"));
+ VASSERT_EQ("3.2", "إختبار", convertHelper("xn--kgbechtv", "idna", "utf-8"));
+ }
+
+ void testUTF7Support() {
+
+ // Ensure UTF-7 is supported, because it is used for IMAP
+ VASSERT_EQ("1", "VMime +- UTF-7 encoding", convertHelper("VMime + UTF-7 encoding", "utf-8", "utf-7"));
+ VASSERT_EQ("2", "f+APg-o", convertHelper("\x66\xc3\xb8\x6f", "utf-8", "utf-7"));
+ }
+
+ void testReplaceInvalidSequence() {
+
+ vmime::charsetConverterOptions opts;
+ opts.silentlyReplaceInvalidSequences = true;
+ opts.invalidSequence = "?";
+
+ vmime::string res = convertHelper(
+ "\x61\xf1\x80\x80\xe1\x80\xc2\x62\x80\x63\x80\xbf\x64",
+ "utf-8", "iso-8859-1", opts
+ );
+
+ // Result should be in the form "a???b?c??d" or "a??????b?c??d"...
+ // Remove consecutive question marks for easier matching.
+ res.erase(std::unique(res.begin(), res.end()), res.end());
+
+ VASSERT_EQ(
+ "Illegal UTF-8 sequence",
+ "a?b?c?d",
+ res
+ );
+ }
+
+ void testStopOnInvalidSequence() {
+
+ vmime::charsetConverterOptions opts;
+ opts.silentlyReplaceInvalidSequences = false;
+
+ VASSERT_THROW(
+ "Illegal UTF-8 sequence",
+ convertHelper("\x61\xf1\x80\x80\xe1\x80\xc2\x62\x80\x63\x80\xbf\x64", "utf-8", "iso-8859-1", opts),
+ vmime::exceptions::illegal_byte_sequence_for_charset
+ );
+ }
+
+ void testStatus() {
+
+ vmime::charsetConverterOptions opts;
+ opts.silentlyReplaceInvalidSequences = false;
+
+ vmime::charsetConverter::status st;
+
+ // 012345 6 7
+ convertHelper("Gwena\xc3\xabl", "utf-8", "iso-8859-1", opts, &st);
+
+ VASSERT_EQ("inputBytesRead", 8, st.inputBytesRead);
+ VASSERT_EQ("outputBytesWritten", 7, st.outputBytesWritten);
+ }
+
+ void testStatusWithInvalidSequence() {
+
+ vmime::charsetConverterOptions opts;
+ opts.silentlyReplaceInvalidSequences = false;
+
+ vmime::charsetConverter::status st;
+
+ try {
+
+ // 01234 5 6789 0 1
+ convertHelper("Fran\xc3\xa7ois\xf1\x80\x65", "utf-8", "iso-8859-1", opts, &st);
+
+ } catch (vmime::exceptions::illegal_byte_sequence_for_charset& e) {
+
+ } catch (...) {
+
+ throw;
+ }
+
+ VASSERT_EQ("inputBytesRead", 9, st.inputBytesRead);
+ VASSERT_EQ("outputBytesWritten", 8, st.outputBytesWritten);
+ }
+
+ void testIsValidText() {
+
+ // Invalid text
+ const vmime::string invalidText("Fran\xc3\xa7ois\xf1\x80\x65");
+ vmime::string::size_type firstInvalidByte;
+
+ VASSERT_EQ("invalid.isValidText", false, vmime::charset("utf-8").isValidText(invalidText, &firstInvalidByte));
+ VASSERT_EQ("invalid.firstInvalidByte", 9, firstInvalidByte);
+
+ // Valid text
+ const vmime::string validText("Gwena\xc3\xabl");
+
+ VASSERT_EQ("valid.isValidText", true, vmime::charset("utf-8").isValidText(validText, &firstInvalidByte));
+ VASSERT_EQ("valid.firstInvalidByte", 8, firstInvalidByte);
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/charsetTestSuites.hpp b/vmime-master/tests/parser/charsetTestSuites.hpp
new file mode 100644
index 0000000..9653016
--- /dev/null
+++ b/vmime-master/tests/parser/charsetTestSuites.hpp
@@ -0,0 +1,102 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+
+struct charsetTestSuiteStruct {
+
+ const char* fromCharset;
+ const char* toCharset;
+ const char* fromBytes;
+ const unsigned int fromLength;
+ const char* toBytes;
+ const unsigned int toLength;
+};
+
+
+static const charsetTestSuiteStruct charsetTestSuites[] = {
+
+ // Test data 1 (excerpt from http://www.gnu.org)
+ {
+ "gb2312", "utf-8",
+
+ "\xbb\xb6\xd3\xad\xc0\xb4\xb5\xbd\x20\x47\x4e\x55\x20\xb9\xa4\xb3"
+ "\xcc\xb5\xc4\xcd\xf8\xd2\xb3\xcb\xc5\xb7\xfe\xd6\xf7\xbb\xfa\x20"
+ "\x77\x77\x77\x2e\x67\x6e\x75\x2e\x6f\x72\x67\x20\xa1\xa3\x20\x47"
+ "\x4e\x55\x20\xb9\xa4\xb3\xcc\x20\xbf\xaa\xca\xbc\xec\xb6\xd2\xbb"
+ "\xbe\xc5\xb0\xcb\xcb\xc4\xc4\xea\xa3\xac\xd6\xbc\xd4\xda\xb7\xa2"
+ "\xd5\xb9\xd2\xbb\xb8\xf6\xc0\xe0\xcb\xc6\x20\x55\x6e\x69\x78\x20"
+ "\xa3\xac\xc7\xd2\xce\xaa\x20\xd7\xd4\xd3\xc9\xc8\xed\xbc\xfe\x20"
+ "\xb5\xc4\xcd\xea\xd5\xfb\xb2\xd9\xd7\xf7\xcf\xb5\xcd\xb3\xa3\xba"
+ "\x20\x47\x4e\x55\x20\xcf\xb5\xcd\xb3\xa1\xa3\xa3\xa8\x47\x4e\x55"
+ "\x20\xca\xc7\xd3\xc9\xa1\xb0\x47\x4e\x55\x27\x73\x20\x4e\x6f\x74"
+ "\x20\x55\x6e\x69\x78\xa1\xb1\xcb\xf9\xb5\xdd\xbb\xd8\xb6\xa8\xd2"
+ "\xe5\xb3\xf6\xb5\xc4\xca\xd7\xd7\xd6\xc4\xb8\xcb\xf5\xd0\xb4\xd3"
+ "\xef\xa3\xbb\xcb\xfc\xb5\xc4\xb7\xa2\xd2\xf4\xce\xaa\xa1\xb0\x67"
+ "\x75\x68\x2d\x4e\x45\x57\xa1\xb1\xa3\xa9\xa1\xa3\xb8\xf7\xd6\xd6"
+ "\xca\xb9\xd3\xc3\x20\x4c\x69\x6e\x75\x78\x20\xd7\xf7\xce\xaa\xc4"
+ "\xda\xba\xcb\xb5\xc4\x20\x47\x4e\x55\x20\xb2\xd9\xd7\xf7\xcf\xb5"
+ "\xcd\xb3\xd5\xfd\xb1\xbb\xb9\xe3\xb7\xba\xb5\xd8\xca\xb9\xd3\xc3"
+ "\xd6\xf8\xa3\xbb\xcb\xe4\xc8\xbb\xd5\xe2\xd0\xa9\xcf\xb5\xcd\xb3"
+ "\xcd\xa8\xb3\xa3\xb1\xbb\xb3\xc6\xd7\xf7\xce\xaa\xa1\xb0\x4c\x69"
+ "\x6e\x75\x78\xa1\xb1\xa3\xac\xb5\xab\xca\xc7\xcb\xfc\xc3\xc7\xd3"
+ "\xa6\xb8\xc3\xb8\xfc\xbe\xab\xc8\xb7\xb5\xd8\xb1\xbb\xb3\xc6\xce"
+ "\xaa\x20\x47\x4e\x55\x2f\x4c\x69\x6e\x75\x78\x20\xcf\xb5\xcd\xb3"
+ "\x20\xa1\xa3\x0a",
+ 0,
+
+ "\xe6\xac\xa2\xe8\xbf\x8e\xe6\x9d\xa5\xe5\x88\xb0\x20\x47\x4e\x55"
+ "\x20\xe5\xb7\xa5\xe7\xa8\x8b\xe7\x9a\x84\xe7\xbd\x91\xe9\xa1\xb5"
+ "\xe4\xbc\xba\xe6\x9c\x8d\xe4\xb8\xbb\xe6\x9c\xba\x20\x77\x77\x77"
+ "\x2e\x67\x6e\x75\x2e\x6f\x72\x67\x20\xe3\x80\x82\x20\x47\x4e\x55"
+ "\x20\xe5\xb7\xa5\xe7\xa8\x8b\x20\xe5\xbc\x80\xe5\xa7\x8b\xe6\x96"
+ "\xbc\xe4\xb8\x80\xe4\xb9\x9d\xe5\x85\xab\xe5\x9b\x9b\xe5\xb9\xb4"
+ "\xef\xbc\x8c\xe6\x97\xa8\xe5\x9c\xa8\xe5\x8f\x91\xe5\xb1\x95\xe4"
+ "\xb8\x80\xe4\xb8\xaa\xe7\xb1\xbb\xe4\xbc\xbc\x20\x55\x6e\x69\x78"
+ "\x20\xef\xbc\x8c\xe4\xb8\x94\xe4\xb8\xba\x20\xe8\x87\xaa\xe7\x94"
+ "\xb1\xe8\xbd\xaf\xe4\xbb\xb6\x20\xe7\x9a\x84\xe5\xae\x8c\xe6\x95"
+ "\xb4\xe6\x93\x8d\xe4\xbd\x9c\xe7\xb3\xbb\xe7\xbb\x9f\xef\xbc\x9a"
+ "\x20\x47\x4e\x55\x20\xe7\xb3\xbb\xe7\xbb\x9f\xe3\x80\x82\xef\xbc"
+ "\x88\x47\x4e\x55\x20\xe6\x98\xaf\xe7\x94\xb1\xe2\x80\x9c\x47\x4e"
+ "\x55\x27\x73\x20\x4e\x6f\x74\x20\x55\x6e\x69\x78\xe2\x80\x9d\xe6"
+ "\x89\x80\xe9\x80\x92\xe5\x9b\x9e\xe5\xae\x9a\xe4\xb9\x89\xe5\x87"
+ "\xba\xe7\x9a\x84\xe9\xa6\x96\xe5\xad\x97\xe6\xaf\x8d\xe7\xbc\xa9"
+ "\xe5\x86\x99\xe8\xaf\xad\xef\xbc\x9b\xe5\xae\x83\xe7\x9a\x84\xe5"
+ "\x8f\x91\xe9\x9f\xb3\xe4\xb8\xba\xe2\x80\x9c\x67\x75\x68\x2d\x4e"
+ "\x45\x57\xe2\x80\x9d\xef\xbc\x89\xe3\x80\x82\xe5\x90\x84\xe7\xa7"
+ "\x8d\xe4\xbd\xbf\xe7\x94\xa8\x20\x4c\x69\x6e\x75\x78\x20\xe4\xbd"
+ "\x9c\xe4\xb8\xba\xe5\x86\x85\xe6\xa0\xb8\xe7\x9a\x84\x20\x47\x4e"
+ "\x55\x20\xe6\x93\x8d\xe4\xbd\x9c\xe7\xb3\xbb\xe7\xbb\x9f\xe6\xad"
+ "\xa3\xe8\xa2\xab\xe5\xb9\xbf\xe6\xb3\x9b\xe5\x9c\xb0\xe4\xbd\xbf"
+ "\xe7\x94\xa8\xe8\x91\x97\xef\xbc\x9b\xe8\x99\xbd\xe7\x84\xb6\xe8"
+ "\xbf\x99\xe4\xba\x9b\xe7\xb3\xbb\xe7\xbb\x9f\xe9\x80\x9a\xe5\xb8"
+ "\xb8\xe8\xa2\xab\xe7\xa7\xb0\xe4\xbd\x9c\xe4\xb8\xba\xe2\x80\x9c"
+ "\x4c\x69\x6e\x75\x78\xe2\x80\x9d\xef\xbc\x8c\xe4\xbd\x86\xe6\x98"
+ "\xaf\xe5\xae\x83\xe4\xbb\xac\xe5\xba\x94\xe8\xaf\xa5\xe6\x9b\xb4"
+ "\xe7\xb2\xbe\xe7\xa1\xae\xe5\x9c\xb0\xe8\xa2\xab\xe7\xa7\xb0\xe4"
+ "\xb8\xba\x20\x47\x4e\x55\x2f\x4c\x69\x6e\x75\x78\x20\xe7\xb3\xbb"
+ "\xe7\xbb\x9f\x20\xe3\x80\x82\x0a",
+ 0
+ }
+};
+
+static const vmime::size_t charsetTestSuitesCount = sizeof(charsetTestSuites) / sizeof(charsetTestSuites[0]);
diff --git a/vmime-master/tests/parser/datetimeTest.cpp b/vmime-master/tests/parser/datetimeTest.cpp
new file mode 100644
index 0000000..61c8522
--- /dev/null
+++ b/vmime-master/tests/parser/datetimeTest.cpp
@@ -0,0 +1,123 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(datetimeTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testParse)
+ VMIME_TEST(testGenerate)
+ VMIME_TEST(testCompare)
+ VMIME_TEST_LIST_END
+
+
+ void testParse() {
+
+ struct datetimePair {
+ vmime::string parseBuffer;
+ vmime::datetime result;
+ };
+
+ // Here, we can't test all the possible structures for date/time,
+ // so we test some cases. Don't forget to add a new test case
+ // each time you encounter a bug in date/time parsing (after
+ // you have fixed it).
+ datetimePair pairs[] = {
+
+ { /* 1 */ "Mon, 8 Nov 2004 13:42:56 +0000 (GMT)",
+ vmime::datetime(2004, 11, 8, 13, 42, 56, vmime::datetime::GMT) },
+
+ { /* 2 */ "Sun, 7 Nov 2004 00:43:22 -0500 (EST)",
+ vmime::datetime(2004, 11, 7, 0, 43, 22, vmime::datetime::GMT_5) },
+
+ { /* 3 */ "Thu Nov 18 12:11:16 2004",
+ vmime::datetime(vmime::datetime::now().getYear(), 11, 18, 12, 11, 16, vmime::datetime::GMT) },
+
+ { /* 4 */ "Sat, 18, 2004 22:36:32 -0400",
+ vmime::datetime(2004, 1, 18, 22, 36, 32, vmime::datetime::GMT_4) },
+
+ { /* 5 */ "Mon Dec 13 21:57:18 2004",
+ vmime::datetime(vmime::datetime::now().getYear(), 12, 13, 21, 57, 18, vmime::datetime::GMT) },
+
+ { /* 6 */ "18 Nov 2004 21:44:54 +0300",
+ vmime::datetime(2004, 11, 18, 21, 44, 54, vmime::datetime::GMT3) }
+ };
+
+ for (unsigned int i = 0 ; i < sizeof(pairs) / sizeof(pairs[0]) ; ++i) {
+
+ vmime::datetime d;
+ d.parse(pairs[i].parseBuffer);
+
+ std::ostringstream oss;
+ oss << (i + 1);
+
+ VASSERT_EQ(oss.str(), pairs[i].result, d);
+ }
+ }
+
+ void testGenerate() {
+
+ vmime::datetime d1(2005, 7, 8, 4, 5, 6, 1 * 60 + 23);
+
+ VASSERT_EQ("1", "Fri, 8 Jul 2005 04:05:06 +0123", d1.generate());
+ }
+
+ void testCompare() {
+
+ // Date1 = Date2
+ vmime::datetime d1(2005, 4, 22, 14, 6, 0, vmime::datetime::GMT2);
+ vmime::datetime d2(2005, 4, 22, 10, 6, 0, vmime::datetime::GMT_2);
+
+ VASSERT_EQ("1.1", true, d1 == d2);
+ VASSERT_EQ("1.2", false, d1 != d2);
+ VASSERT_EQ("1.3", true, d1 <= d2);
+ VASSERT_EQ("1.4", false, d1 < d2);
+ VASSERT_EQ("1.5", true, d1 >= d2);
+ VASSERT_EQ("1.6", false, d1 > d2);
+
+ // Date1 < Date2
+ vmime::datetime d3(2005, 4, 22, 14, 6, 0);
+ vmime::datetime d4(2005, 4, 22, 15, 6, 0);
+
+ VASSERT_EQ("2.1", false, d3 == d4);
+ VASSERT_EQ("2.2", true, d3 != d4);
+ VASSERT_EQ("2.3", true, d3 <= d4);
+ VASSERT_EQ("2.4", true, d3 < d4);
+ VASSERT_EQ("2.5", false, d3 >= d4);
+ VASSERT_EQ("2.6", false, d3 > d4);
+
+ // Date1 > Date2
+ vmime::datetime d5(2005, 4, 22, 15, 6, 0);
+ vmime::datetime d6(2005, 4, 22, 14, 6, 0);
+
+ VASSERT_EQ("3.1", false, d5 == d6);
+ VASSERT_EQ("3.2", true, d5 != d6);
+ VASSERT_EQ("3.3", false, d5 <= d6);
+ VASSERT_EQ("3.4", false, d5 < d6);
+ VASSERT_EQ("3.5", true, d5 >= d6);
+ VASSERT_EQ("3.6", true, d5 > d6);
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/dispositionTest.cpp b/vmime-master/tests/parser/dispositionTest.cpp
new file mode 100644
index 0000000..f51c51e
--- /dev/null
+++ b/vmime-master/tests/parser/dispositionTest.cpp
@@ -0,0 +1,150 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(dispositionTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testParse)
+ VMIME_TEST(testGenerate)
+ VMIME_TEST(testModifiers)
+ VMIME_TEST_LIST_END
+
+
+ void testParse() {
+
+ // disposition-mode ";" disposition-type
+ // [ "/" disposition-modifier *( "," disposition-modifier ) ]
+ //
+ // disposition-mode = action-mode "/" sending-mode
+
+ vmime::disposition disp1;
+ disp1.parse("mode");
+
+ VASSERT_EQ("1.1", "mode", disp1.getActionMode());
+ VASSERT_EQ("1.2", "", disp1.getSendingMode());
+ VASSERT_EQ("1.3", "", disp1.getType());
+ VASSERT_EQ("1.4", 0, static_cast <int>(disp1.getModifierList().size()));
+
+ vmime::disposition disp2;
+ disp2.parse("amode/smode");
+
+ VASSERT_EQ("2.1", "amode", disp2.getActionMode());
+ VASSERT_EQ("2.2", "smode", disp2.getSendingMode());
+ VASSERT_EQ("2.3", "", disp2.getType());
+ VASSERT_EQ("2.4", 0, static_cast <int>(disp2.getModifierList().size()));
+
+ vmime::disposition disp3;
+ disp3.parse("amode/smode;type");
+
+ VASSERT_EQ("3.1", "amode", disp3.getActionMode());
+ VASSERT_EQ("3.2", "smode", disp3.getSendingMode());
+ VASSERT_EQ("3.3", "type", disp3.getType());
+ VASSERT_EQ("3.4", 0, static_cast <int>(disp3.getModifierList().size()));
+
+ vmime::disposition disp4;
+ disp4.parse("amode/smode;type/modif");
+
+ VASSERT_EQ("4.1", "amode", disp4.getActionMode());
+ VASSERT_EQ("4.2", "smode", disp4.getSendingMode());
+ VASSERT_EQ("4.3", "type", disp4.getType());
+ VASSERT_EQ("4.4", 1, static_cast <int>(disp4.getModifierList().size()));
+ VASSERT_EQ("4.5", "modif", disp4.getModifierList()[0]);
+
+ vmime::disposition disp5;
+ disp5.parse("amode/smode;type/modif1,modif2");
+
+ VASSERT_EQ("5.1", "amode", disp5.getActionMode());
+ VASSERT_EQ("5.2", "smode", disp5.getSendingMode());
+ VASSERT_EQ("5.3", "type", disp5.getType());
+ VASSERT_EQ("5.4", 2, static_cast <int>(disp5.getModifierList().size()));
+ VASSERT_EQ("5.5", "modif1", disp5.getModifierList()[0]);
+ VASSERT_EQ("5.6", "modif2", disp5.getModifierList()[1]);
+ }
+
+ void testGenerate() {
+
+ vmime::disposition disp;
+
+ VASSERT_EQ("1", "automatic-action/MDN-sent-automatically;displayed", disp.generate());
+
+ disp.setActionMode("amode");
+
+ VASSERT_EQ("2", "amode/MDN-sent-automatically;displayed", disp.generate());
+
+ disp.setActionMode("amode");
+ disp.setSendingMode("smode");
+
+ VASSERT_EQ("3", "amode/smode;displayed", disp.generate());
+
+ disp.setType("type");
+
+ VASSERT_EQ("4", "amode/smode;type", disp.generate());
+
+ disp.addModifier("modif1");
+
+ VASSERT_EQ("5", "amode/smode;type/modif1", disp.generate());
+
+ disp.addModifier("modif2");
+
+ VASSERT_EQ("6", "amode/smode;type/modif1,modif2", disp.generate());
+ }
+
+ void testModifiers() {
+
+ vmime::disposition disp1;
+
+ VASSERT_EQ("1", false, disp1.hasModifier("foo"));
+ VASSERT_EQ("2", 0, static_cast <int>(disp1.getModifierList().size()));
+
+ disp1.addModifier("bar");
+
+ VASSERT_EQ("3", false, disp1.hasModifier("foo"));
+ VASSERT_EQ("4", true, disp1.hasModifier("bar"));
+ VASSERT_EQ("5", 1, static_cast <int>(disp1.getModifierList().size()));
+
+ disp1.addModifier("plop");
+
+ VASSERT_EQ("6", false, disp1.hasModifier("foo"));
+ VASSERT_EQ("7", true, disp1.hasModifier("bar"));
+ VASSERT_EQ("8", true, disp1.hasModifier("plop"));
+ VASSERT_EQ("9", 2, static_cast <int>(disp1.getModifierList().size()));
+
+ disp1.removeModifier("bar");
+
+ VASSERT_EQ("10", false, disp1.hasModifier("foo"));
+ VASSERT_EQ("11", false, disp1.hasModifier("bar"));
+ VASSERT_EQ("12", true, disp1.hasModifier("plop"));
+ VASSERT_EQ("13", 1, static_cast <int>(disp1.getModifierList().size()));
+
+ disp1.removeModifier("PlOp");
+
+ VASSERT_EQ("14", false, disp1.hasModifier("foo"));
+ VASSERT_EQ("15", false, disp1.hasModifier("bar"));
+ VASSERT_EQ("16", false, disp1.hasModifier("plop"));
+ VASSERT_EQ("17", 0, static_cast <int>(disp1.getModifierList().size()));
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/emailAddressTest.cpp b/vmime-master/tests/parser/emailAddressTest.cpp
new file mode 100644
index 0000000..f2a7070
--- /dev/null
+++ b/vmime-master/tests/parser/emailAddressTest.cpp
@@ -0,0 +1,281 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/platform.hpp"
+
+#include <locale>
+#include <clocale>
+
+
+VMIME_TEST_SUITE_BEGIN(emailAddressTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testParseASCII)
+ VMIME_TEST(testParseEAI)
+ VMIME_TEST(testParseInvalid)
+ VMIME_TEST(testGenerateASCII)
+ VMIME_TEST(testGenerateEAI)
+ VMIME_TEST(testParseSpecialChars)
+ VMIME_TEST(testParseCommentInLocalPart)
+ VMIME_TEST(testParseCommentInDomainPart)
+ VMIME_TEST(testParseRFC2047EncodedLocalPart)
+ VMIME_TEST(testGenerateSpecialChars)
+ VMIME_TEST_LIST_END
+
+
+ void setUp() {
+
+ // Set the global C and C++ locale to the user-configured locale.
+ // The locale should use UTF-8 encoding for these tests to run successfully.
+ try {
+ std::locale::global(std::locale(""));
+ } catch (std::exception &) {
+ std::setlocale(LC_ALL, "");
+ }
+ }
+
+ void tearDown() {
+
+ // Restore default locale
+ std::locale::global(std::locale("C"));
+ }
+
+
+ void testParseASCII() {
+
+ vmime::emailAddress eml1("local@domain");
+ VASSERT_EQ("1/local", "local", eml1.getLocalName());
+ VASSERT_EQ("1/domain", "domain", eml1.getDomainName());
+
+ // When not specified, domain should be local host name
+ vmime::emailAddress eml2("local");
+ VASSERT_EQ("2/local", "local", eml2.getLocalName());
+ VASSERT_EQ("2/domain", vmime::platform::getHandler()->getHostName(), eml2.getDomainName());
+ }
+
+ void testParseEAI() {
+
+ // Examples taken from Wikipedia (http://en.wikipedia.org/wiki/Email_address)
+
+ // Latin Alphabet (with diacritics):
+ vmime::emailAddress eml1("Pelé@example.com");
+ VASSERT_EQ("1/local", "Pelé", eml1.getLocalName());
+ VASSERT_EQ("1/domain", "example.com", eml1.getDomainName());
+
+ // Greek Alphabet
+ vmime::emailAddress eml2("δοκιμή@παράδειγμα.δοκιμή");
+ VASSERT_EQ("2/local", "δοκιμή", eml2.getLocalName());
+ VASSERT_EQ("2/domain", "παράδειγμα.δοκιμή", eml2.getDomainName());
+
+ // Japanese Characters
+ vmime::emailAddress eml3("甲斐@黒川.日本");
+ VASSERT_EQ("3/local", "甲斐", eml3.getLocalName());
+ VASSERT_EQ("3/domain", "黒川.日本", eml3.getDomainName());
+
+ // Cyrillic Characters
+ vmime::emailAddress eml4("чебурашка@ящик-с-апельсинами.рф");
+ VASSERT_EQ("4/local", "чебурашка", eml4.getLocalName());
+ VASSERT_EQ("4/domain", "ящик-с-апельсинами.рф", eml4.getDomainName());
+ }
+
+ void testParseInvalid() {
+
+ // Only one @ is allowed outside quotation marks
+ vmime::emailAddress eml1("local@part@domain");
+ VASSERT_EQ("1/local", "local", eml1.getLocalName());
+ VASSERT_EQ("1/domain", "part@domain", eml1.getDomainName());
+
+ // Quoted strings must be dot separated, or the only element making up
+ // the local-part: should be parsed correctly, but it still represents
+ // an invalid email address
+ vmime::emailAddress eml2("Just\"not\"right@example.com");
+ VASSERT_EQ("2/local", "Just\"not\"right", eml2.getLocalName());
+ VASSERT_EQ("2/domain", "example.com", eml2.getDomainName());
+
+ // An @ character must separate the local and domain parts
+ vmime::emailAddress eml3("Abc.example.com");
+ VASSERT_EQ("3/local", "Abc.example.com", eml3.getLocalName());
+ VASSERT_EQ("3/domain", vmime::platform::getHandler()->getHostName(), eml3.getDomainName());
+
+ // Whitespace must be escaped
+ vmime::emailAddress eml4("local part@domain");
+ VASSERT_EQ("4/local", "local", eml4.getLocalName());
+ VASSERT_EQ("4/domain", vmime::platform::getHandler()->getHostName(), eml4.getDomainName());
+
+ vmime::emailAddress eml5("this\\ still\\\"not\\\\allowed@example.com");
+ VASSERT_EQ("5/local", "this\\", eml5.getLocalName());
+ VASSERT_EQ("5/domain", vmime::platform::getHandler()->getHostName(), eml5.getDomainName());
+ }
+
+ void testParseSpecialChars() {
+
+ // Examples taken from Wikipedia (http://en.wikipedia.org/wiki/Email_address)
+
+ vmime::emailAddress eml1("\" \"@example.org");
+ VASSERT_EQ("1/local", " ", eml1.getLocalName());
+ VASSERT_EQ("1/domain", "example.org", eml1.getDomainName());
+
+ vmime::emailAddress eml2("\"()<>[]:,;@\\\\\\\"!#$%&'*+-/=?^_`{}| ~.a\"@example.org");
+ VASSERT_EQ("2/local", "()<>[]:,;@\\\"!#$%&'*+-/=?^_`{}| ~.a", eml2.getLocalName());
+ VASSERT_EQ("3/domain", "example.org", eml2.getDomainName());
+
+ vmime::emailAddress eml3("!#$%&'*+-/=?^_`{}|~@example.org");
+ VASSERT_EQ("3/local", "!#$%&'*+-/=?^_`{}|~", eml3.getLocalName());
+ VASSERT_EQ("3/domain", "example.org", eml3.getDomainName());
+
+ vmime::emailAddress eml4("!#$%&'*+-/=?^_`{}|~@example.org");
+ VASSERT_EQ("4/local", "!#$%&'*+-/=?^_`{}|~", eml4.getLocalName());
+ VASSERT_EQ("4/domain", "example.org", eml4.getDomainName());
+
+ vmime::emailAddress eml5("\"very.unusual.@.unusual.com\"@example.com");
+ VASSERT_EQ("5/local", "very.unusual.@.unusual.com", eml5.getLocalName());
+ VASSERT_EQ("5/domain", "example.com", eml5.getDomainName());
+
+ vmime::emailAddress eml6("\"very.(),:;<>[]\\\".VERY.\\\"very@\\\\ \\\"very\\\".unusual\"@strange.example.com");
+ VASSERT_EQ("6/local", "very.(),:;<>[]\".VERY.\"very@\\ \"very\".unusual", eml6.getLocalName());
+ VASSERT_EQ("6/domain", "strange.example.com", eml6.getDomainName());
+ }
+
+ void testParseCommentInLocalPart() {
+
+ vmime::emailAddress eml1("john.smith(comment)@example.com");
+ VASSERT_EQ("1/local", "john.smith", eml1.getLocalName());
+ VASSERT_EQ("1/domain", "example.com", eml1.getDomainName());
+
+ vmime::emailAddress eml2("(comment)john.smith@example.com");
+ VASSERT_EQ("2/local", "john.smith", eml2.getLocalName());
+ VASSERT_EQ("2/domain", "example.com", eml2.getDomainName());
+
+ vmime::emailAddress eml3("(comment (comment in comment))john.smith@example.com");
+ VASSERT_EQ("3/local", "john.smith", eml3.getLocalName());
+ VASSERT_EQ("3/domain", "example.com", eml3.getDomainName());
+
+ vmime::emailAddress eml4("(comment \\) end comment)john.smith@example.com");
+ VASSERT_EQ("4/local", "john.smith", eml4.getLocalName());
+ VASSERT_EQ("4/domain", "example.com", eml4.getDomainName());
+ }
+
+ void testParseCommentInDomainPart() {
+
+ vmime::emailAddress eml1("john.smith@(comment)example.com");
+ VASSERT_EQ("1/local", "john.smith", eml1.getLocalName());
+ VASSERT_EQ("1/domain", "example.com", eml1.getDomainName());
+
+ vmime::emailAddress eml2("john.smith@example.com(comment)");
+ VASSERT_EQ("2/local", "john.smith", eml2.getLocalName());
+ VASSERT_EQ("2/domain", "example.com", eml2.getDomainName());
+
+ vmime::emailAddress eml3("john.smith@(comment (comment in comment))example.com");
+ VASSERT_EQ("3/local", "john.smith", eml3.getLocalName());
+ VASSERT_EQ("3/domain", "example.com", eml3.getDomainName());
+
+ vmime::emailAddress eml4("john.smith@(comment \\) end comment)example.com");
+ VASSERT_EQ("4/local", "john.smith", eml4.getLocalName());
+ VASSERT_EQ("4/domain", "example.com", eml4.getDomainName());
+ }
+
+ void testParseRFC2047EncodedLocalPart() {
+
+ vmime::emailAddress eml1("=?utf-8?Q?Pel=C3=A9?=@example.com");
+ VASSERT_EQ("1/local", "Pelé", eml1.getLocalName());
+ VASSERT_EQ("1/domain", "example.com", eml1.getDomainName());
+
+ vmime::emailAddress eml2("=?utf-8?B?55Sy5paQ?=@xn--5rtw95l.xn--wgv71a");
+ VASSERT_EQ("2/local", "甲斐", eml2.getLocalName());
+ VASSERT_EQ("2/domain", "黒川.日本", eml2.getDomainName());
+
+ vmime::emailAddress eml3("=?utf-8?B?55Sy5paQ?=@xn--5rtw95l.com");
+ VASSERT_EQ("3/local", "甲斐", eml3.getLocalName());
+ VASSERT_EQ("3/domain", "黒川.com", eml3.getDomainName());
+ }
+
+ void testGenerateASCII() {
+
+ VASSERT_EQ(
+ "email 1", "local@domain",
+ vmime::emailAddress("local", "domain").generate()
+ );
+ VASSERT_EQ(
+ "email 2", "=?utf-8?Q?Pel=C3=A9?=@example.com",
+ vmime::emailAddress("Pelé", "example.com").generate()
+ );
+ VASSERT_EQ(
+ "email 3", "=?utf-8?B?55Sy5paQ?=@xn--5rtw95l.xn--wgv71a",
+ vmime::emailAddress("甲斐", "黒川.日本").generate()
+ );
+ VASSERT_EQ(
+ "email 4", "mailtest@xn--r8jz45g.xn--zckzah",
+ vmime::emailAddress("mailtest", "例え.テスト").generate()
+ );
+ VASSERT_EQ(
+ "email 5", "mailtest@xn--mgbh0fb.xn--kgbechtv",
+ vmime::emailAddress("mailtest", "مثال.إختبار").generate()
+ );
+ }
+
+ void testGenerateEAI() {
+
+ vmime::generationContext ctx(vmime::generationContext::getDefaultContext());
+ ctx.setInternationalizedEmailSupport(true);
+
+ vmime::generationContext::switcher <vmime::generationContext> contextSwitcher(ctx);
+
+ VASSERT_EQ(
+ "email 1", "Pelé@example.com",
+ vmime::emailAddress("Pelé", "example.com").generate()
+ );
+ VASSERT_EQ(
+ "email 2", "δοκιμή@παράδειγμα.δοκιμή",
+ vmime::emailAddress("δοκιμή", "παράδειγμα.δοκιμή").generate()
+ );
+ VASSERT_EQ(
+ "email 3", "甲斐@黒川.日本",
+ vmime::emailAddress("甲斐", "黒川.日本").generate()
+ );
+ VASSERT_EQ(
+ "email 4", "чебурашка@ящик-с-апельсинами.рф",
+ vmime::emailAddress("чебурашка", "ящик-с-апельсинами.рф").generate()
+ );
+ }
+
+ void testGenerateSpecialChars() {
+
+ VASSERT_EQ(
+ "email 1", "\"very.unusual.@.unusual.com\"@example.com",
+ vmime::emailAddress("very.unusual.@.unusual.com", "example.com").generate()
+ );
+
+ VASSERT_EQ(
+ "email 2", "\"very.(),:;<>[]\\\".VERY.\\\"very@\\\\ \\\"very\\\".unusual\"@strange.example.com",
+ vmime::emailAddress("very.(),:;<>[]\".VERY.\"very@\\ \"very\".unusual", "strange.example.com").generate()
+ );
+
+ VASSERT_EQ(
+ "email 3", "\" \"@example.com",
+ vmime::emailAddress(" ", "example.com").generate()
+ );
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/emptyContentHandlerTest.cpp b/vmime-master/tests/parser/emptyContentHandlerTest.cpp
new file mode 100644
index 0000000..43cd8c2
--- /dev/null
+++ b/vmime-master/tests/parser/emptyContentHandlerTest.cpp
@@ -0,0 +1,99 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/utility/outputStreamAdapter.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(emptyContentHandlerTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testIsEmpty)
+ VMIME_TEST(testGetLength)
+ VMIME_TEST(testIsEncoded)
+ VMIME_TEST(testExtract)
+ VMIME_TEST(testExtractRaw)
+ VMIME_TEST(testGenerate)
+ VMIME_TEST_LIST_END
+
+
+ void testIsEmpty() {
+
+ vmime::emptyContentHandler cth;
+
+ VASSERT_TRUE("empty", cth.isEmpty());
+ }
+
+ void testGetLength() {
+
+ vmime::emptyContentHandler cth;
+
+ VASSERT_EQ("length", 0, cth.getLength());
+ }
+
+ void testIsEncoded() {
+
+ vmime::emptyContentHandler cth;
+
+ VASSERT_FALSE("encoded", cth.isEncoded());
+ VASSERT_EQ("encoding", vmime::contentHandler::NO_ENCODING, cth.getEncoding());
+ }
+
+ void testExtract() {
+
+ vmime::emptyContentHandler cth;
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth.extract(osa);
+
+ VASSERT_EQ("extract", "", oss.str());
+ }
+
+ void testExtractRaw() {
+
+ vmime::emptyContentHandler cth;
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth.extractRaw(osa);
+
+ VASSERT_EQ("extractRaw", "", oss.str());
+ }
+
+ void testGenerate() {
+
+ vmime::emptyContentHandler cth;
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth.generate(osa, vmime::encoding("base64"));
+
+ VASSERT_EQ("generate", "", oss.str());
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/fileContentHandlerTest.cpp b/vmime-master/tests/parser/fileContentHandlerTest.cpp
new file mode 100644
index 0000000..e979b52
--- /dev/null
+++ b/vmime-master/tests/parser/fileContentHandlerTest.cpp
@@ -0,0 +1,134 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/utility/outputStreamAdapter.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(fileContentHandlerTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testIsEmpty)
+ VMIME_TEST(testGetLength)
+ VMIME_TEST(testIsEncoded)
+ VMIME_TEST(testExtract)
+ VMIME_TEST(testExtractRaw)
+ VMIME_TEST(testGenerate)
+ VMIME_TEST_LIST_END
+
+
+ vmime::shared_ptr <vmime::utility::file> testFile;
+ vmime::string testDataEncoded, testDataDecoded;
+
+
+ void setUp() {
+
+ testDataDecoded = "ABCDEFGHIJKLMNOPQRSTUVWXYZ \x12\x34\x56\x78\x90 abcdefghijklmnopqrstuvwxyz0123456789";
+ testDataEncoded = "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVogEjRWeJAgYWJjZGVmZ2hpamtsbW5vcHFyc3R1dnd4eXowMTIzNDU2Nzg5";
+
+ std::ostringstream testFilePath;
+ testFilePath << "/tmp/vmime_test_" << (rand() % 999999999);
+
+ vmime::shared_ptr <vmime::utility::fileSystemFactory> fsf =
+ vmime::platform::getHandler()->getFileSystemFactory();
+
+ testFile = fsf->create(fsf->stringToPath(testFilePath.str()));
+ testFile->createFile();
+ testFile->getFileWriter()->getOutputStream()->write(testDataEncoded.data(), testDataEncoded.length());
+ }
+
+ void tearDown() {
+
+ testFile->remove();
+ testFile = vmime::null;
+ }
+
+
+ void testIsEmpty() {
+
+ vmime::fileContentHandler cth;
+
+ VASSERT_TRUE("empty", cth.isEmpty());
+ }
+
+ void testGetLength() {
+
+ vmime::fileContentHandler cth(testFile);
+
+ VASSERT_FALSE("empty", cth.isEmpty());
+ VASSERT_EQ("length", testDataEncoded.length(), cth.getLength());
+ }
+
+ void testIsEncoded() {
+
+ vmime::fileContentHandler cth(testFile, vmime::encoding("base64"));
+
+ VASSERT_TRUE("encoded", cth.isEncoded());
+ VASSERT_EQ("encoding", "base64", cth.getEncoding().generate());
+ }
+
+ void testExtract() {
+
+ vmime::fileContentHandler cth(testFile, vmime::encoding("base64"));
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth.extract(osa);
+
+ // Data should be decoded from B64
+ VASSERT_EQ("extract", testDataDecoded, oss.str());
+ }
+
+ void testExtractRaw() {
+
+ vmime::fileContentHandler cth(testFile, vmime::encoding("base64"));
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth.extractRaw(osa);
+
+ // Data should not be decoded
+ VASSERT_EQ("extractRaw", testDataEncoded, oss.str());
+ }
+
+ void testGenerate() {
+
+ vmime::fileContentHandler cth(testFile, vmime::encoding("base64"));
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth.generate(osa, vmime::encoding("quoted-printable"));
+
+ // Data should be reencoded from B64 to QP
+ VASSERT_EQ(
+ "generate",
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ =124Vx=90 abcdefghijklmnopqrstuvwxyz0123456789",
+ oss.str()
+ );
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/headerFieldTest.cpp b/vmime-master/tests/parser/headerFieldTest.cpp
new file mode 100644
index 0000000..78d0480
--- /dev/null
+++ b/vmime-master/tests/parser/headerFieldTest.cpp
@@ -0,0 +1,112 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(headerFieldTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testBadValueType)
+ VMIME_TEST(testValueOnNextLine)
+ VMIME_TEST(testStripSpacesAtEnd)
+ VMIME_TEST(testValueWithEmptyLine)
+ VMIME_TEST_LIST_END
+
+
+ void testBadValueType() {
+
+ vmime::shared_ptr <vmime::headerFieldFactory> hfactory =
+ vmime::headerFieldFactory::getInstance();
+
+ // "To" header field accepts values of type "addressList"
+ vmime::shared_ptr <vmime::headerField> to = hfactory->create(vmime::fields::TO);
+
+ VASSERT_THROW(
+ "to",
+ to->setValue(vmime::mailbox("email@vmime.org")),
+ vmime::exceptions::bad_field_value_type
+ );
+
+ // Unregistered header field accepts any value type
+ vmime::shared_ptr <vmime::headerField> custom = hfactory->create("X-MyCustomHeader");
+
+ VASSERT_NO_THROW(
+ "custom/1",
+ custom->setValue(vmime::mailbox("email@vmime.org"))
+ );
+ VASSERT_NO_THROW(
+ "custom/2",
+ custom->setValue(vmime::text("field value text"))
+ );
+ }
+
+ void testValueOnNextLine() {
+
+ vmime::parsingContext ctx;
+
+ const vmime::string buffer = "Field: \r\n\tfield data";
+
+ vmime::shared_ptr <vmime::headerField> hfield =
+ vmime::headerField::parseNext(ctx, buffer, 0, buffer.size());
+
+ vmime::shared_ptr <vmime::text> hvalue =
+ hfield->getValue <vmime::text>();
+
+ VASSERT_EQ("Field name", "Field", hfield->getName());
+ VASSERT_EQ("Field value", "field data", hvalue->getWholeBuffer());
+ }
+
+ void testStripSpacesAtEnd() {
+
+ vmime::parsingContext ctx;
+
+ const vmime::string buffer = "Field: \r\n\tfield data ";
+
+ vmime::shared_ptr <vmime::headerField> hfield =
+ vmime::headerField::parseNext(ctx, buffer, 0, buffer.size());
+
+ vmime::shared_ptr <vmime::text> hvalue =
+ hfield->getValue <vmime::text>();
+
+ VASSERT_EQ("Field name", "Field", hfield->getName());
+ VASSERT_EQ("Field value", toHex("field data"), toHex(hvalue->getWholeBuffer()));
+ }
+
+ void testValueWithEmptyLine() {
+
+ vmime::parsingContext ctx;
+
+ const vmime::string buffer = "Field: \r\n\tdata1\r\n\tdata2\r\n\t\r\n\tdata3";
+
+ vmime::shared_ptr <vmime::headerField> hfield =
+ vmime::headerField::parseNext(ctx, buffer, 0, buffer.size());
+
+ vmime::shared_ptr <vmime::text> hvalue =
+ hfield->getValue <vmime::text>();
+
+ VASSERT_EQ("Field name", "Field", hfield->getName());
+ VASSERT_EQ("Field value", "data1 data2 data3", hvalue->getWholeBuffer());
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/headerTest.cpp b/vmime-master/tests/parser/headerTest.cpp
new file mode 100644
index 0000000..839acee
--- /dev/null
+++ b/vmime-master/tests/parser/headerTest.cpp
@@ -0,0 +1,375 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(headerTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testHas1)
+ VMIME_TEST(testHas2)
+
+ VMIME_TEST(testAppend1)
+ VMIME_TEST(testAppend2)
+
+ VMIME_TEST(testInsertFieldBefore1)
+ VMIME_TEST(testInsertFieldBefore2)
+
+ VMIME_TEST(testInsertFieldAfter1)
+ VMIME_TEST(testInsertFieldAfter2)
+
+ VMIME_TEST(testReplaceField)
+
+ VMIME_TEST(testRemoveField1)
+ VMIME_TEST(testRemoveField2)
+
+ VMIME_TEST(testRemoveAllFields)
+
+ VMIME_TEST(testgetFieldCount)
+
+ VMIME_TEST(testIsEmpty1)
+ VMIME_TEST(testIsEmpty2)
+
+ VMIME_TEST(testGetFieldAt)
+
+ VMIME_TEST(testGetFieldList1)
+ VMIME_TEST(testGetFieldList2)
+
+ VMIME_TEST(testFind1)
+
+ VMIME_TEST(testFindAllFields1)
+ VMIME_TEST(testFindAllFields2)
+ VMIME_TEST(testFindAllFields3)
+ VMIME_TEST_LIST_END
+
+
+ static const std::string getFieldValue(const vmime::headerField& field) {
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter voss(oss);
+ field.generate(voss);
+
+ return oss.str();
+ }
+
+ // has function tests
+ void testHas1() {
+
+ vmime::header hdr;
+ hdr.parse("From: x\r\nTo: y\r\nTo: z\r\n");
+
+ bool res = hdr.hasField("Z");
+
+ VASSERT_EQ("Value", false, res);
+ }
+
+ void testHas2() {
+
+ vmime::header hdr;
+ hdr.parse("X: x\r\nTo: y\r\nTo: z\r\n");
+
+ bool res = hdr.hasField("To");
+
+ VASSERT_EQ("Value", true, res);
+ }
+
+ // appendField function tests
+ void testAppend1() {
+
+ vmime::header hdr;
+ hdr.parse("");
+
+ vmime::shared_ptr <vmime::headerField> hf = vmime::headerFieldFactory::getInstance()->create("A", "a");
+ hdr.appendField(hf);
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res = hdr.getFieldList();
+
+ VASSERT_EQ("Count", static_cast <unsigned int>(1), res.size());
+ VASSERT_EQ("First value", "A: a", headerTest::getFieldValue(*res[0]));
+ }
+
+ void testAppend2() {
+
+ vmime::header hdr;
+ hdr.parse("A: a\r\n");
+
+ vmime::shared_ptr <vmime::headerField> hf = vmime::headerFieldFactory::getInstance()->create("B", "b");
+ hdr.appendField(hf);
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res = hdr.getFieldList();
+
+ VASSERT_EQ("Count", static_cast <unsigned int>(2), res.size());
+ VASSERT_EQ("First value", "A: a", headerTest::getFieldValue(*res[0]));
+ VASSERT_EQ("Second value", "B: b", headerTest::getFieldValue(*res[1]));
+ }
+
+ // insertFieldBefore
+ void testInsertFieldBefore1() {
+
+ vmime::header hdr;
+ hdr.parse("A: a\r\nC: c\r\n");
+
+ vmime::shared_ptr <vmime::headerField> hf = vmime::headerFieldFactory::getInstance()->create("B", "b");
+ hdr.insertFieldBefore(hdr.getField("C"), hf);
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res = hdr.getFieldList();
+
+ VASSERT_EQ("Count", static_cast <unsigned int>(3), res.size());
+ VASSERT_EQ("First value", "A: a", headerTest::getFieldValue(*res[0]));
+ VASSERT_EQ("Second value", "B: b", headerTest::getFieldValue(*res[1]));
+ VASSERT_EQ("Third value", "C: c", headerTest::getFieldValue(*res[2]));
+ }
+
+ void testInsertFieldBefore2() {
+
+ vmime::header hdr;
+ hdr.parse("A: a\r\nC: c\r\n");
+
+ vmime::shared_ptr <vmime::headerField> hf = vmime::headerFieldFactory::getInstance()->create("B", "b");
+ hdr.insertFieldBefore(1, hf);
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res = hdr.getFieldList();
+
+ VASSERT_EQ("Count", static_cast <unsigned int>(3), res.size());
+ VASSERT_EQ("First value", "A: a", headerTest::getFieldValue(*res[0]));
+ VASSERT_EQ("Second value", "B: b", headerTest::getFieldValue(*res[1]));
+ VASSERT_EQ("Third value", "C: c", headerTest::getFieldValue(*res[2]));
+ }
+
+ // insertFieldAfter
+ void testInsertFieldAfter1() {
+
+ vmime::header hdr;
+ hdr.parse("A: a\r\nC: c\r\n");
+
+ vmime::shared_ptr <vmime::headerField> hf = vmime::headerFieldFactory::getInstance()->create("B", "b");
+ hdr.insertFieldAfter(hdr.getField("A"), hf);
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res = hdr.getFieldList();
+
+ VASSERT_EQ("Count", static_cast <unsigned int>(3), res.size());
+ VASSERT_EQ("First value", "A: a", headerTest::getFieldValue(*res[0]));
+ VASSERT_EQ("Second value", "B: b", headerTest::getFieldValue(*res[1]));
+ VASSERT_EQ("Third value", "C: c", headerTest::getFieldValue(*res[2]));
+ }
+
+ void testInsertFieldAfter2() {
+
+ vmime::header hdr;
+ hdr.parse("A: a\r\nC: c\r\n");
+
+ vmime::shared_ptr <vmime::headerField> hf = vmime::headerFieldFactory::getInstance()->create("B", "b");
+ hdr.insertFieldAfter(0, hf);
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res = hdr.getFieldList();
+
+ VASSERT_EQ("Count", static_cast <unsigned int>(3), res.size());
+ VASSERT_EQ("First value", "A: a", headerTest::getFieldValue(*res[0]));
+ VASSERT_EQ("Second value", "B: b", headerTest::getFieldValue(*res[1]));
+ VASSERT_EQ("Third value", "C: c", headerTest::getFieldValue(*res[2]));
+ }
+
+ // replaceField
+ void testReplaceField() {
+
+ vmime::header hdr;
+ hdr.parse("A: a\r\nB: b\r\nC: c\r\n");
+
+ vmime::shared_ptr <vmime::headerField> hf = vmime::headerFieldFactory::getInstance()->create("Z", "z");
+ hdr.replaceField(hdr.getField("B"), hf);
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res = hdr.getFieldList();
+
+ VASSERT_EQ("Count", static_cast <unsigned int>(3), res.size());
+ VASSERT_EQ("First value", "A: a", headerTest::getFieldValue(*res[0]));
+ VASSERT_EQ("Second value", "Z: z", headerTest::getFieldValue(*res[1]));
+ VASSERT_EQ("Third value", "C: c", headerTest::getFieldValue(*res[2]));
+ }
+
+ // removeField
+ void testRemoveField1() {
+
+ vmime::header hdr1, hdr2;
+ hdr1.parse("A: a\r\nB: b\r\nC: c\r\n");
+ hdr2.parse("A: a\r\nB: b\r\nC: c\r\n");
+
+ hdr1.removeField(hdr1.getField("B"));
+ hdr2.removeField(1);
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res1 = hdr1.getFieldList();
+
+ VASSERT_EQ("Count", static_cast <unsigned int>(2), res1.size());
+ VASSERT_EQ("First value", "A: a", headerTest::getFieldValue(*res1[0]));
+ VASSERT_EQ("Second value", "C: c", headerTest::getFieldValue(*res1[1]));
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res2 = hdr2.getFieldList();
+
+ VASSERT_EQ("Count", static_cast <unsigned int>(2), res2.size());
+ VASSERT_EQ("First value", "A: a", headerTest::getFieldValue(*res2[0]));
+ VASSERT_EQ("Second value", "C: c", headerTest::getFieldValue(*res2[1]));
+ }
+
+ void testRemoveField2() {
+
+ vmime::header hdr1, hdr2;
+ hdr1.parse("A: a\r\n");
+ hdr2.parse("A: a\r\n");
+
+ hdr1.removeField(hdr1.getField("A"));
+ hdr2.removeField(0);
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res1 = hdr1.getFieldList();
+ VASSERT_EQ("Count", static_cast <unsigned int>(0), res1.size());
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res2 = hdr2.getFieldList();
+ VASSERT_EQ("Count", static_cast <unsigned int>(0), res2.size());
+ }
+
+ // removeAllFields
+ void testRemoveAllFields() {
+
+ vmime::header hdr1, hdr2;
+ hdr1.parse("A: a\r\n");
+ hdr2.parse("A: a\r\nB: b\r\n");
+
+ hdr1.removeAllFields();
+ hdr2.removeAllFields();
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res1 = hdr1.getFieldList();
+ VASSERT_EQ("Count", static_cast <unsigned int>(0), res1.size());
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res2 = hdr2.getFieldList();
+ VASSERT_EQ("Count", static_cast <unsigned int>(0), res2.size());
+ }
+
+ // getFieldCount
+ void testgetFieldCount() {
+
+ vmime::header hdr;
+ hdr.parse("A: a\r\nB: b\r\nC: c\r\nD: d\r\n");
+
+ VASSERT_EQ("Value", 4, hdr.getFieldCount());
+ }
+
+ // isEmpty
+ void testIsEmpty1() {
+
+ vmime::header hdr;
+ hdr.parse("A: a\r\nB: b\r\nC: c\r\n");
+
+ VASSERT_EQ("Value", false, hdr.isEmpty());
+ }
+
+ void testIsEmpty2() {
+
+ vmime::header hdr;
+ hdr.parse("\r\n");
+
+ VASSERT_EQ("Value", true, hdr.isEmpty());
+ }
+
+ // getFieldAt
+ void testGetFieldAt() {
+
+ vmime::header hdr;
+ hdr.parse("B: b\r\nA: a\r\nC: c\r\n");
+
+ vmime::shared_ptr <vmime::headerField> res = hdr.getFieldAt(2);
+
+ VASSERT_EQ("Value", "C: c", getFieldValue(*res));
+ }
+
+ // getFieldList
+ void testGetFieldList1() {
+
+ vmime::header hdr;
+ hdr.parse("A: a\r\nB: b1\r\nC: c\r\nB: b2\r\n");
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res = hdr.getFieldList();
+
+ VASSERT_EQ("Count", static_cast <unsigned int>(4), res.size());
+ VASSERT_EQ("First value", "A: a", headerTest::getFieldValue(*res[0]));
+ VASSERT_EQ("Second value", "B: b1", headerTest::getFieldValue(*res[1]));
+ VASSERT_EQ("Third value", "C: c", headerTest::getFieldValue(*res[2]));
+ VASSERT_EQ("Thourth value", "B: b2", headerTest::getFieldValue(*res[3]));
+ }
+
+ void testGetFieldList2() {
+
+ vmime::header hdr;
+ hdr.parse("\r\n");
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res = hdr.getFieldList();
+
+ VASSERT_EQ("Count", static_cast <unsigned int>(0), res.size());
+ }
+
+ // find function tests
+ void testFind1() {
+
+ vmime::header hdr;
+ hdr.parse("A: a\r\nB: b\r\nC: c\r\nB: d\r\n");
+
+ vmime::shared_ptr <vmime::headerField> res = hdr.findField("B");
+
+ VASSERT_EQ("Value", "B: b", getFieldValue(*res));
+ }
+
+ // getAllByName function tests
+ void testFindAllFields1() {
+
+ vmime::header hdr;
+ hdr.parse("A: a1\nC: c1\n");
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res = hdr.findAllFields("B");
+
+ VASSERT_EQ("Count", static_cast <unsigned int>(0), res.size());
+ }
+
+ void testFindAllFields2() {
+
+ vmime::header hdr;
+ hdr.parse("A: a1\nB: b1\nB: b2\nC: c1\n");
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res = hdr.findAllFields("B");
+
+ VASSERT_EQ("Count", static_cast <unsigned int>(2), res.size());
+ VASSERT_EQ("First value", "B: b1", headerTest::getFieldValue(*res[0]));
+ VASSERT_EQ("Second value", "B: b2", headerTest::getFieldValue(*res[1]));
+ }
+
+ void testFindAllFields3() {
+
+ vmime::header hdr;
+ hdr.parse("A: a1\nB: b1\nB: b2\nC: c1\nC: c3\nC: c2\n");
+
+ std::vector <vmime::shared_ptr <vmime::headerField> > res = hdr.findAllFields("C");
+
+ VASSERT_EQ("Count", static_cast <unsigned int>(3), res.size());
+ VASSERT_EQ("First value", "C: c1", headerTest::getFieldValue(*res[0]));
+ VASSERT_EQ("Second value", "C: c3", headerTest::getFieldValue(*res[1]));
+ VASSERT_EQ("Second value", "C: c2", headerTest::getFieldValue(*res[2]));
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/htmlTextPartTest.cpp b/vmime-master/tests/parser/htmlTextPartTest.cpp
new file mode 100644
index 0000000..6dfaaa0
--- /dev/null
+++ b/vmime-master/tests/parser/htmlTextPartTest.cpp
@@ -0,0 +1,241 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+#include "vmime/htmlTextPart.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(htmlTextPartTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testParseText)
+ VMIME_TEST(testParseEmbeddedObjectsCID)
+ VMIME_TEST(testParseEmbeddedObjectsLocation)
+ VMIME_TEST_LIST_END
+
+
+ static const vmime::string extractContent(
+ const vmime::shared_ptr <const vmime::contentHandler>& cth
+ ) {
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth->extract(osa);
+
+ return oss.str();
+ }
+
+
+ void testParseText() {
+
+ const vmime::string msgString = ""
+"MIME-Version: 1.0\r\n"
+"Content-Type: multipart/alternative; boundary=\"LEVEL1\"\r\n"
+"\r\n"
+"--LEVEL1\r\n"
+"Content-Type: text/plain; charset=\"x-ch1\"\r\n"
+"\r\n"
+"Plain text part\r\n"
+"--LEVEL1\r\n"
+"Content-Type: multipart/related; boundary=\"LEVEL2\"\r\n"
+"\r\n"
+"--LEVEL2\r\n"
+"Content-Type: text/html; charset=\"x-ch2\"\r\n"
+"\r\n"
+"<img src=\"cid:image@test\"/>\r\n"
+"--LEVEL2\r\n"
+"Content-Type: image/png; name=\"image.png\"\r\n"
+"Content-Disposition: inline; filename=\"image.png\"\r\n"
+"Content-ID: <image@test>\r\n"
+"\r\n"
+"Image\r\n"
+"--LEVEL2--\r\n"
+"\r\n"
+"--LEVEL1--\r\n"
+"";
+
+ vmime::shared_ptr <vmime::message> msg = vmime::make_shared <vmime::message>();
+ msg->parse(msgString);
+
+ // Sanity checks
+ VASSERT_EQ("part-count1", 2, msg->getBody()->getPartCount());
+ VASSERT_EQ("part-count2", 2, msg->getBody()->getPartAt(1)->getBody()->getPartCount());
+
+ vmime::htmlTextPart htmlPart;
+ htmlPart.parse(msg, msg->getBody()->getPartAt(1),
+ msg->getBody()->getPartAt(1)->getBody()->getPartAt(0));
+
+ VASSERT_EQ("plain", "Plain text part", extractContent(htmlPart.getPlainText()));
+ VASSERT_EQ("html", "<img src=\"cid:image@test\"/>", extractContent(htmlPart.getText()));
+
+ // Should return the charset of the HTML part
+ VASSERT_EQ("charset", "x-ch2", htmlPart.getCharset().generate());
+ }
+
+ /** Test parsing of embedded objects by CID (Content-Id).
+ */
+ void testParseEmbeddedObjectsCID() {
+
+ const vmime::string msgString = ""
+"MIME-Version: 1.0\r\n"
+"Content-Type: multipart/alternative; boundary=\"LEVEL1\"\r\n"
+"\r\n"
+"--LEVEL1\r\n"
+"Content-Type: text/plain; charset=\"x-ch1\"\r\n"
+"\r\n"
+"Plain text part\r\n"
+"--LEVEL1\r\n"
+"Content-Type: multipart/related; boundary=\"LEVEL2\"\r\n"
+"\r\n"
+"--LEVEL2\r\n" // one embedded object before...
+"Content-Type: image/png; name=\"image1.png\"\r\n"
+"Content-Disposition: inline; filename=\"image1.png\"\r\n"
+"Content-ID: <image1@test>\r\n"
+"\r\n"
+"Image1\r\n"
+"--LEVEL2\r\n" // ...the actual text part...
+"Content-Type: text/html; charset=\"x-ch2\"\r\n"
+"\r\n"
+"<img src=\"cid:image1@test\"/>\r\n"
+"<img src=\"CID:image2@test\"/>\r\n"
+"--LEVEL2\r\n" // ...and one after
+"Content-Type: image/jpeg; name=\"image2.jpg\"\r\n"
+"Content-Disposition: inline; filename=\"image2.jpg\"\r\n"
+"Content-ID: <image2@test>\r\n"
+"\r\n"
+"Image2\r\n"
+"--LEVEL2--\r\n"
+"\r\n"
+"--LEVEL1--\r\n"
+"";
+
+ vmime::shared_ptr <vmime::message> msg = vmime::make_shared <vmime::message>();
+ msg->parse(msgString);
+
+ // Sanity checks
+ VASSERT_EQ("part-count1", 2, msg->getBody()->getPartCount());
+ VASSERT_EQ("part-count2", 3, msg->getBody()->getPartAt(1)->getBody()->getPartCount());
+
+ vmime::htmlTextPart htmlPart;
+ htmlPart.parse(
+ msg, msg->getBody()->getPartAt(1),
+ msg->getBody()->getPartAt(1)->getBody()->getPartAt(1)
+ );
+
+ // Two embedded objects should be found.
+ // BUGFIX: "CID:" prefix is not case-sensitive.
+ VASSERT_EQ("count", 2, htmlPart.getObjectCount());
+
+ // Ensure the right objects have been found.
+ VASSERT_EQ("has-obj1", true, htmlPart.hasObject("image1@test"));
+ VASSERT_EQ("has-obj2", true, htmlPart.hasObject("image2@test"));
+
+ // hasObject() should also work with prefixes
+ VASSERT_EQ("has-obj1-pre", true, htmlPart.hasObject("CID:image1@test"));
+ VASSERT_EQ("has-obj2-pre", true, htmlPart.hasObject("cid:image2@test"));
+
+ // Check data in objects
+ vmime::shared_ptr <const vmime::htmlTextPart::embeddedObject> obj;
+
+ obj = htmlPart.findObject("image1@test");
+
+ VASSERT_EQ("ref-type1", vmime::htmlTextPart::embeddedObject::REFERENCED_BY_ID, obj->getReferenceType());
+ VASSERT_EQ("id-obj1", "image1@test", obj->getId());
+ VASSERT_EQ("data-obj1", "Image1", extractContent(obj->getData()));
+ VASSERT_EQ("type-obj1", "image/png", obj->getType().generate());
+
+ obj = htmlPart.findObject("image2@test");
+
+ VASSERT_EQ("ref-type2", vmime::htmlTextPart::embeddedObject::REFERENCED_BY_ID, obj->getReferenceType());
+ VASSERT_EQ("id-obj2", "image2@test", obj->getId());
+ VASSERT_EQ("data-obj2", "Image2", extractContent(obj->getData()));
+ VASSERT_EQ("type-obj2", "image/jpeg", obj->getType().generate());
+ }
+
+ /** Test parsing of embedded objects by location.
+ */
+ void testParseEmbeddedObjectsLocation() {
+
+ const vmime::string msgString = ""
+"MIME-Version: 1.0\r\n"
+"Content-Type: multipart/alternative; boundary=\"LEVEL1\"\r\n"
+"\r\n"
+"--LEVEL1\r\n"
+"Content-Type: text/plain; charset=\"x-ch1\"\r\n"
+"\r\n"
+"Plain text part\r\n"
+"--LEVEL1\r\n"
+"Content-Type: multipart/related; boundary=\"LEVEL2\"\r\n"
+"\r\n"
+"--LEVEL2\r\n"
+"Content-Type: image/png; name=\"image1.png\"\r\n"
+"Content-Location: http://www.vmime.org/test/image1.png\r\n"
+"Content-Disposition: inline; filename=\"image1.png\"\r\n"
+"Content-Id: <image1@test>\r\n"
+"\r\n"
+"Image1\r\n"
+"--LEVEL2\r\n"
+"Content-Type: text/html; charset=\"x-ch2\"\r\n"
+"\r\n"
+"<img src=\"http://www.vmime.org/test/image1.png\"/>\r\n"
+"--LEVEL2--\r\n"
+"\r\n"
+"--LEVEL1--\r\n"
+"";
+
+ vmime::shared_ptr <vmime::message> msg = vmime::make_shared <vmime::message>();
+ msg->parse(msgString);
+
+ // Sanity checks
+ VASSERT_EQ("part-count1", 2, msg->getBody()->getPartCount());
+ VASSERT_EQ("part-count2", 2, msg->getBody()->getPartAt(1)->getBody()->getPartCount());
+
+ vmime::htmlTextPart htmlPart;
+ htmlPart.parse(
+ msg, msg->getBody()->getPartAt(1),
+ msg->getBody()->getPartAt(1)->getBody()->getPartAt(1)
+ );
+
+ // Only one embedded object
+ VASSERT_EQ("count", 1, htmlPart.getObjectCount());
+
+ // Should work only with Content-Location as the Content-Id is
+ // not referenced in the HTML contents
+ VASSERT_EQ("has-obj-loc", true, htmlPart.hasObject("http://www.vmime.org/test/image1.png"));
+ VASSERT_EQ("has-obj-cid", false, htmlPart.hasObject("image1@test"));
+
+ // Check data
+ vmime::shared_ptr <const vmime::htmlTextPart::embeddedObject> obj;
+
+ obj = htmlPart.findObject("http://www.vmime.org/test/image1.png");
+
+ VASSERT_EQ("ref-type", vmime::htmlTextPart::embeddedObject::REFERENCED_BY_LOCATION, obj->getReferenceType());
+ VASSERT_EQ("id-obj", "http://www.vmime.org/test/image1.png", obj->getId());
+ VASSERT_EQ("data-obj", "Image1", extractContent(obj->getData()));
+ VASSERT_EQ("type-obj", "image/png", obj->getType().generate());
+ }
+
+ // TODO: test generation of text parts
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/mailboxGroupTest.cpp b/vmime-master/tests/parser/mailboxGroupTest.cpp
new file mode 100644
index 0000000..18ff425
--- /dev/null
+++ b/vmime-master/tests/parser/mailboxGroupTest.cpp
@@ -0,0 +1,107 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(mailboxGroupTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testParseExtraWhitespaces)
+ VMIME_TEST(testParseNoEndDelimiter)
+ VMIME_TEST(testParseExtraChars)
+ VMIME_TEST(testEmptyGroup)
+ VMIME_TEST(testEncodedEmptyGroup)
+ VMIME_TEST_LIST_END
+
+
+ void testParseExtraWhitespaces() {
+
+ vmime::mailboxGroup mgrp;
+ mgrp.parse(" \t group : aaa <aaa@vmime.org>, bbb <bbb@vmime.org>");
+
+ VASSERT_EQ("name", "group", mgrp.getName().getWholeBuffer());
+ VASSERT_EQ("count", 2, mgrp.getMailboxCount());
+
+ VASSERT_EQ("mbox1.email", "aaa@vmime.org", mgrp.getMailboxAt(0)->getEmail());
+ VASSERT_EQ("mbox1.name", "aaa", mgrp.getMailboxAt(0)->getName());
+
+ VASSERT_EQ("mbox2.email", "bbb@vmime.org", mgrp.getMailboxAt(1)->getEmail());
+ VASSERT_EQ("mbox2.name", "bbb", mgrp.getMailboxAt(1)->getName());
+ }
+
+ void testParseNoEndDelimiter() {
+
+ vmime::addressList addrs;
+ addrs.parse("group: aaa <aaa@vmime.org>, bbb <bbb@vmime.org>");
+
+ VASSERT_EQ("count", 1, addrs.getAddressCount());
+ VASSERT_TRUE("is group", addrs.getAddressAt(0)->isGroup());
+
+ vmime::shared_ptr <vmime::mailboxGroup> mgrp =
+ vmime::dynamicCast <vmime::mailboxGroup>(addrs.getAddressAt(0));
+
+ VASSERT_EQ("name", "group", mgrp->getName().getWholeBuffer());
+ VASSERT_EQ("count", 2, mgrp->getMailboxCount());
+
+ VASSERT_EQ("mbox1.email", "aaa@vmime.org", mgrp->getMailboxAt(0)->getEmail());
+ VASSERT_EQ("mbox1.name", "aaa", mgrp->getMailboxAt(0)->getName());
+
+ VASSERT_EQ("mbox2.email", "bbb@vmime.org", mgrp->getMailboxAt(1)->getEmail());
+ VASSERT_EQ("mbox2.name", "bbb", mgrp->getMailboxAt(1)->getName());
+ }
+
+ void testParseExtraChars() {
+
+ vmime::mailboxGroup mgrp;
+ mgrp.parse("group: aaa <aaa@vmime.org>, bbb <bbb@vmime.org>; extra chars here...");
+
+ VASSERT_EQ("name", "group", mgrp.getName().getWholeBuffer());
+ VASSERT_EQ("count", 2, mgrp.getMailboxCount());
+
+ VASSERT_EQ("mbox1.email", "aaa@vmime.org", mgrp.getMailboxAt(0)->getEmail());
+ VASSERT_EQ("mbox1.name", "aaa", mgrp.getMailboxAt(0)->getName());
+
+ VASSERT_EQ("mbox2.email", "bbb@vmime.org", mgrp.getMailboxAt(1)->getEmail());
+ VASSERT_EQ("mbox2.name", "bbb", mgrp.getMailboxAt(1)->getName());
+ }
+
+ void testEmptyGroup() {
+
+ vmime::mailboxGroup mgrp;
+ mgrp.parse("Undisclosed recipients:;");
+
+ VASSERT_EQ("name", "Undisclosed recipients", mgrp.getName().getWholeBuffer());
+ VASSERT_EQ("count", 0, mgrp.getMailboxCount());
+ }
+
+ void testEncodedEmptyGroup() {
+
+ vmime::mailboxGroup mgrp;
+ mgrp.parse("=?us-ascii?Q?Undisclosed_recipients?=:;");
+
+ VASSERT_EQ("name", "Undisclosed recipients", mgrp.getName().getWholeBuffer());
+ VASSERT_EQ("count", 0, mgrp.getMailboxCount());
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/mailboxListTest.cpp b/vmime-master/tests/parser/mailboxListTest.cpp
new file mode 100644
index 0000000..7505acd
--- /dev/null
+++ b/vmime-master/tests/parser/mailboxListTest.cpp
@@ -0,0 +1,47 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(mailboxListTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testParseGroup)
+ VMIME_TEST_LIST_END
+
+
+ // Disposition-Notification-To:: <email@domain.com>
+ void testParseGroup() {
+
+ // Groups should be extracted to multiple mailboxes in mailbox lists
+ vmime::mailboxList mboxList;
+ mboxList.parse("email1@domain1.com, : <email2@domain2.com>, email3@domain3.com");
+
+ VASSERT_EQ("count", 3, mboxList.getMailboxCount());
+ VASSERT_EQ("email", "email1@domain1.com", mboxList.getMailboxAt(0)->getEmail().generate());
+ VASSERT_EQ("email", "email2@domain2.com", mboxList.getMailboxAt(1)->getEmail().generate());
+ VASSERT_EQ("email", "email3@domain3.com", mboxList.getMailboxAt(2)->getEmail().generate());
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/mailboxTest.cpp b/vmime-master/tests/parser/mailboxTest.cpp
new file mode 100644
index 0000000..997a6a3
--- /dev/null
+++ b/vmime-master/tests/parser/mailboxTest.cpp
@@ -0,0 +1,187 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(mailboxTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testParse)
+ VMIME_TEST(testEmptyEmailAddress)
+ VMIME_TEST(testSeparatorInComment)
+ VMIME_TEST(testMalformations)
+ VMIME_TEST(testExcessiveQuoting)
+ VMIME_TEST_LIST_END
+
+
+ void testParse() {
+
+ static const vmime::string testSuitesParse[] = {
+
+ // Test 1
+ "My (this is a comment)name <me(another \\)comment) @ somewhere(else).com>",
+
+ "[address-list: [[mailbox: name=[text: [[word: charset=us-ascii, buffer=My name]]], email=me@somewhere.com]]]",
+
+ // Test 2
+ "mailbox1 <mailbox@one>,;,,, ,, ,,;group1:mailbox1@group1, mailbox2@group2,,\"mailbox #3\" <mailbox3@group2>;, <mailbox@two>,,,,,,,,=?iso-8859-1?q?mailbox_number_3?= <mailbox@three>, =?abc?Q?mailbox?= =?def?Q?_number_4?= <mailbox@four>",
+
+ "[address-list: [[mailbox: name=[text: [[word: charset=us-ascii, buffer=mailbox1]]], email=mailbox@one],[mailbox-group: name=[text: [[word: charset=us-ascii, buffer=group1]]], list=[[mailbox: name=[text: []], email=mailbox1@group1],[mailbox: name=[text: []], email=mailbox2@group2],[mailbox: name=[text: [[word: charset=us-ascii, buffer=mailbox #3]]], email=mailbox3@group2]]],[mailbox: name=[text: []], email=mailbox@two],[mailbox: name=[text: [[word: charset=iso-8859-1, buffer=mailbox number 3]]], email=mailbox@three],[mailbox: name=[text: [[word: charset=abc, buffer=mailbox],[word: charset=def, buffer= number 4]]], email=mailbox@four]]]",
+
+ // Test 3
+ "John Doe <john.doe@acme.com>",
+
+ "[address-list: [[mailbox: name=[text: [[word: charset=us-ascii, buffer=John Doe]]], email=john.doe@acme.com]]]",
+
+ // Test 4
+ "john.doe@acme.com (John Doe)",
+
+ "[address-list: [[mailbox: name=[text: []], email=john.doe@acme.com]]]",
+
+ // Test 5
+ "John.Doe(ignore)@acme.com (John Doe)",
+
+ "[address-list: [[mailbox: name=[text: []], email=John.Doe@acme.com]]]",
+
+ // Test 6
+ "<john.doe@acme.com>",
+
+ "[address-list: [[mailbox: name=[text: []], email=john.doe@acme.com]]]",
+
+ // Test 7
+ "john.doe@acme.com",
+
+ "[address-list: [[mailbox: name=[text: []], email=john.doe@acme.com]]]",
+
+ // Test 8
+ "\"John Doe\" <john.doe@acme.com>",
+
+ "[address-list: [[mailbox: name=[text: [[word: charset=us-ascii, buffer=John Doe]]], email=john.doe@acme.com]]]",
+
+ // Test 9
+ "=?us-ascii?q?John?=<john.doe@acme.com>",
+
+ "[address-list: [[mailbox: name=[text: [[word: charset=us-ascii, buffer=John]]], email=john.doe@acme.com]]]",
+
+ // Test 10
+ "\"John\"<john.doe@acme.com>",
+
+ "[address-list: [[mailbox: name=[text: [[word: charset=us-ascii, buffer=John]]], email=john.doe@acme.com]]]",
+
+ // Test 11
+ "John<john.doe@acme.com>",
+
+ "[address-list: [[mailbox: name=[text: [[word: charset=us-ascii, buffer=John]]], email=john.doe@acme.com]]]"
+ };
+
+ for (unsigned int i = 0 ; i < sizeof(testSuitesParse) / sizeof(testSuitesParse[0]) / 2 ; ++i) {
+
+ vmime::string in = testSuitesParse[i * 2];
+ vmime::string out = testSuitesParse[i * 2 + 1];
+
+ std::ostringstream oss;
+ oss << "Test " << (i + 1);
+
+ vmime::addressList addrList;
+ addrList.parse(in);
+
+ std::ostringstream cmp;
+ cmp << addrList;
+
+ VASSERT_EQ(oss.str(), out, cmp.str());
+ }
+ }
+
+ void testEmptyEmailAddress() {
+
+ vmime::addressList addrList;
+ addrList.parse("\"Full Name\" <>");
+
+ VASSERT_EQ("count", 1, addrList.getAddressCount());
+ VASSERT_EQ("!group", false, addrList.getAddressAt(0)->isGroup());
+
+ vmime::shared_ptr <vmime::mailbox> mbox =
+ vmime::dynamicCast <vmime::mailbox>(addrList.getAddressAt(0));
+
+ VASSERT_EQ("name", "Full Name", mbox->getName());
+ VASSERT_EQ("email", "", mbox->getEmail());
+ }
+
+ void testSeparatorInComment() {
+
+ vmime::addressList addrList;
+ addrList.parse("aaa(comment,comment)@vmime.org, bbb@vmime.org");
+
+ VASSERT_EQ("count", 2, addrList.getAddressCount());
+
+ vmime::shared_ptr <vmime::mailbox> mbox1 =
+ vmime::dynamicCast <vmime::mailbox>(addrList.getAddressAt(0));
+ vmime::shared_ptr <vmime::mailbox> mbox2 =
+ vmime::dynamicCast <vmime::mailbox>(addrList.getAddressAt(1));
+
+ VASSERT_EQ("name1", vmime::text(), mbox1->getName());
+ VASSERT_EQ("email1", "aaa@vmime.org", mbox1->getEmail());
+
+ VASSERT_EQ("name2", vmime::text(), mbox2->getName());
+ VASSERT_EQ("email2", "bbb@vmime.org", mbox2->getEmail());
+ }
+
+ void testMalformations() {
+ vmime::mailbox mbox;
+
+ mbox.parse("a@b.c <e@f.g>");
+ VASSERT_EQ("name", vmime::text("a@b.c"), mbox.getName());
+ VASSERT_EQ("email", "e@f.g", mbox.getEmail());
+
+ mbox.parse("a@b.c e@f.g <h@i.j>");
+ VASSERT_EQ("name", vmime::text("a@b.c e@f.g"), mbox.getName());
+ VASSERT_EQ("email", "h@i.j", mbox.getEmail());
+
+ mbox.parse("Foo <bar<baz@quux.com>");
+ VASSERT_EQ("name", vmime::text("Foo <bar"), mbox.getName());
+ VASSERT_EQ("email", "baz@quux.com", mbox.getEmail());
+
+ mbox.parse("Foo <foo@x.com> <bar@x.com>");
+ VASSERT_EQ("name", vmime::text("Foo <foo@x.com>"), mbox.getName());
+ VASSERT_EQ("email", "bar@x.com", mbox.getEmail());
+
+ mbox.parse("Foo <foo@x.com> Bar <bar@y.com>");
+ VASSERT_EQ("name", vmime::text("Foo <foo@x.com> Bar"), mbox.getName());
+ VASSERT_EQ("email", "bar@y.com", mbox.getEmail());
+ }
+
+ void testExcessiveQuoting() {
+ using namespace vmime;
+
+ // Check that ASCII display names are not encoded more than necessary
+ emailAddress e("a@b.com");
+ auto a = make_shared<mailbox>(text(word("Foo B@r", charsets::US_ASCII)), e);
+ VASSERT_EQ("generate", "\"Foo B@r\" <a@b.com>", a->generate());
+ VASSERT_NEQ("generate", "=?utf-8?Q?Foo_B=40r?= <a@b.com>", a->generate());
+
+ a = make_shared<mailbox>(text(word("Foo B@r", charsets::UTF_8)), e);
+ VASSERT_EQ("generate", "=?utf-8?Q?Foo_B=40r?= <a@b.com>", a->generate());
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/mediaTypeTest.cpp b/vmime-master/tests/parser/mediaTypeTest.cpp
new file mode 100644
index 0000000..e98cfcd
--- /dev/null
+++ b/vmime-master/tests/parser/mediaTypeTest.cpp
@@ -0,0 +1,100 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(mediaTypeTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testConstructors)
+ VMIME_TEST(testCopy)
+ VMIME_TEST(testSetFromString)
+ VMIME_TEST(testParse)
+ VMIME_TEST(testGenerate)
+ VMIME_TEST_LIST_END
+
+
+ void testConstructors() {
+
+ vmime::mediaType t1;
+
+ VASSERT_EQ("1.1", vmime::mediaTypes::APPLICATION, t1.getType());
+ VASSERT_EQ("1.2", vmime::mediaTypes::APPLICATION_OCTET_STREAM, t1.getSubType());
+
+ vmime::mediaType t2("type", "sub");
+
+ VASSERT_EQ("2.1", "type", t2.getType());
+ VASSERT_EQ("2.2", "sub", t2.getSubType());
+
+ vmime::mediaType t3("type/sub");
+
+ VASSERT_EQ("3.1", "type", t3.getType());
+ VASSERT_EQ("3.2", "sub", t3.getSubType());
+ }
+
+ void testCopy() {
+
+ vmime::mediaType t1("type/sub");
+
+ VASSERT_EQ("eq1", "type", t1.getType());
+ VASSERT_EQ("eq2", "sub", t1.getSubType());
+
+ VASSERT("operator==", t1 == t1);
+ VASSERT("clone", t1 == *vmime::clone(t1));
+
+ VASSERT_EQ("eq3", "type", vmime::clone(t1)->getType());
+ VASSERT_EQ("eq4", "sub", vmime::clone(t1)->getSubType());
+
+ vmime::mediaType t2;
+ t2.copyFrom(t1);
+
+ VASSERT("copyFrom", t1 == t2);
+ }
+
+ void testSetFromString() {
+
+ vmime::mediaType t1;
+ t1.setFromString("type/sub");
+
+ VASSERT_EQ("1.1", "type", t1.getType());
+ VASSERT_EQ("1.2", "sub", t1.getSubType());
+ }
+
+ void testParse() {
+
+ vmime::mediaType t1;
+ t1.parse("type/sub");
+
+ VASSERT_EQ("1.1", "type", t1.getType());
+ VASSERT_EQ("1.2", "sub", t1.getSubType());
+ }
+
+ void testGenerate() {
+
+ vmime::mediaType t1("type", "sub");
+
+ VASSERT_EQ("1", "type/sub", t1.generate());
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/messageIdSequenceTest.cpp b/vmime-master/tests/parser/messageIdSequenceTest.cpp
new file mode 100644
index 0000000..0237108
--- /dev/null
+++ b/vmime-master/tests/parser/messageIdSequenceTest.cpp
@@ -0,0 +1,78 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(messageIdSequenceTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testParse)
+ VMIME_TEST(testGenerate)
+ VMIME_TEST_LIST_END
+
+
+ void testParse() {
+
+ vmime::messageIdSequence s1;
+ s1.parse("");
+
+ VASSERT_EQ("1", 0, s1.getMessageIdCount());
+
+ vmime::messageIdSequence s2;
+ s2.parse(" \t ");
+
+ VASSERT_EQ("2", 0, s2.getMessageIdCount());
+
+ vmime::messageIdSequence s3;
+ s3.parse("<a@b>");
+
+ VASSERT_EQ("3.1", 1, s3.getMessageIdCount());
+ VASSERT_EQ("3.2", "a", s3.getMessageIdAt(0)->getLeft());
+ VASSERT_EQ("3.3", "b", s3.getMessageIdAt(0)->getRight());
+
+ vmime::messageIdSequence s4;
+ s4.parse("<a@b> \r\n\t<c@d>");
+
+ VASSERT_EQ("4.1", 2, s4.getMessageIdCount());
+ VASSERT_EQ("4.2", "a", s4.getMessageIdAt(0)->getLeft());
+ VASSERT_EQ("4.3", "b", s4.getMessageIdAt(0)->getRight());
+ VASSERT_EQ("4.4", "c", s4.getMessageIdAt(1)->getLeft());
+ VASSERT_EQ("4.5", "d", s4.getMessageIdAt(1)->getRight());
+ }
+
+ void testGenerate() {
+
+ vmime::messageIdSequence s1;
+ s1.appendMessageId(vmime::make_shared <vmime::messageId>("a", "b"));
+
+ VASSERT_EQ("1", "<a@b>", s1.generate());
+
+ vmime::messageIdSequence s2;
+ s2.appendMessageId(vmime::make_shared <vmime::messageId>("a", "b"));
+ s2.appendMessageId(vmime::make_shared <vmime::messageId>("c", "d"));
+
+ VASSERT_EQ("2", "<a@b> <c@d>", s2.generate());
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/messageIdTest.cpp b/vmime-master/tests/parser/messageIdTest.cpp
new file mode 100644
index 0000000..8433093
--- /dev/null
+++ b/vmime-master/tests/parser/messageIdTest.cpp
@@ -0,0 +1,77 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(messageIdTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testParse)
+ VMIME_TEST(testParseInvalid)
+ VMIME_TEST(testGenerate)
+ VMIME_TEST_LIST_END
+
+
+ void testParse() {
+
+ vmime::messageId m1;
+ m1.parse("<a@b>");
+
+ VASSERT_EQ("1.1", "a", m1.getLeft());
+ VASSERT_EQ("1.2", "b", m1.getRight());
+ }
+
+ void testParseInvalid() {
+
+ vmime::messageId m1;
+ m1.parse("foo@bar");
+
+ VASSERT_EQ("1.1", "foo", m1.getLeft());
+ VASSERT_EQ("1.2", "bar", m1.getRight());
+ }
+
+ void testGenerate() {
+
+ vmime::messageId m1;
+
+ VASSERT_EQ("1", "<>", m1.generate());
+
+ vmime::messageId m2;
+ m2.setLeft("a");
+
+ VASSERT_EQ("2", "<a>", m2.generate());
+
+ vmime::messageId m3;
+ m3.setRight("b");
+
+ VASSERT_EQ("3", "<@b>", m3.generate());
+
+ vmime::messageId m4;
+ m4.setLeft("a");
+ m4.setRight("b");
+
+ VASSERT_EQ("4", "<a@b>", m4.generate());
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/messageTest.cpp b/vmime-master/tests/parser/messageTest.cpp
new file mode 100644
index 0000000..b89d63e
--- /dev/null
+++ b/vmime-master/tests/parser/messageTest.cpp
@@ -0,0 +1,64 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(messageTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testGetGeneratedSize)
+ VMIME_TEST_LIST_END
+
+
+ void testGetGeneratedSize() {
+
+ vmime::generationContext ctx;
+
+ vmime::shared_ptr <vmime::message> msg = vmime::make_shared <vmime::message>();
+ msg->getHeader()->getField("Foo")->setValue(vmime::string("bar"));
+
+ vmime::htmlTextPart textPart;
+ textPart.setPlainText(
+ vmime::make_shared <vmime::stringContentHandler>(
+ "Foo bar bazé foo foo foo"
+ )
+ );
+ textPart.setText(
+ vmime::make_shared <vmime::stringContentHandler>(
+ "Foo bar <strong>bazé</strong> foo foo foo"
+ )
+ );
+ textPart.generateIn(msg, msg);
+
+ // Estimated/computed generated size must be greater than the actual generated size
+ const vmime::size_t genSize = msg->getGeneratedSize(ctx);
+ const vmime::size_t actualSize = msg->generate().length();
+
+ std::ostringstream oss;
+ oss << "estimated size (" << genSize << ") >= actual size (" << actualSize << ")";
+
+ VASSERT(oss.str(), genSize >= actualSize);
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/parameterTest.cpp b/vmime-master/tests/parser/parameterTest.cpp
new file mode 100644
index 0000000..464c305
--- /dev/null
+++ b/vmime-master/tests/parser/parameterTest.cpp
@@ -0,0 +1,722 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include <locale>
+#include <clocale>
+
+
+VMIME_TEST_SUITE_BEGIN(parameterTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testParse)
+ VMIME_TEST(testParseRFC2231)
+ VMIME_TEST(testGenerate)
+ VMIME_TEST(testGetGeneratedSize)
+ VMIME_TEST(testGenerateRFC2231)
+ VMIME_TEST(testGetGeneratedSizeRFC2231)
+ VMIME_TEST(testNonStandardEncodedParam)
+ VMIME_TEST(testParseNonSignificantWS)
+ VMIME_TEST(testEncodeTSpecials)
+ VMIME_TEST(testEncodeTSpecialsInRFC2231)
+ VMIME_TEST(testWhitespaceBreaksTheValue)
+ VMIME_TEST_LIST_END
+
+
+ // HACK: parameterizedHeaderField constructor is private
+ class parameterizedHeaderField : public vmime::parameterizedHeaderField {
+
+ public:
+
+ parameterizedHeaderField() {
+
+ setName("F");
+ setValue(vmime::headerFieldFactory::getInstance()->createValue(getName()));
+ setValue(vmime::word("X"));
+ }
+
+ using vmime::parameterizedHeaderField::generate;
+
+ const vmime::string generate(
+ const vmime::generationContext::EncodedParameterValueModes genMode,
+ const vmime::size_t maxLineLength = 0
+ ) const {
+
+ vmime::generationContext ctx(vmime::generationContext::getDefaultContext());
+ ctx.setEncodedParameterValueMode(genMode);
+
+ if (maxLineLength != 0) {
+ ctx.setMaxLineLength(maxLineLength);
+ }
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter adapter(oss);
+
+ vmime::parameterizedHeaderField::generate(ctx, adapter);
+
+ return oss.str();
+ }
+ };
+
+
+ const vmime::string generateParameter(
+ const vmime::parameter& param,
+ const vmime::generationContext& ctx,
+ const vmime::size_t maxLineLength = 0
+ ) const {
+
+ vmime::generationContext ctx2(ctx);
+
+ if (maxLineLength != 0) {
+ ctx2.setMaxLineLength(maxLineLength);
+ }
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter adapter(oss);
+
+ param.generate(ctx2, adapter);
+
+ return oss.str();
+ }
+
+
+#define FIELD_VALUE(f) (f.getValue()->generate())
+#define PARAM_VALUE(p, n) (p.getParameterAt(n)->getValue().generate())
+#define PARAM_NAME(p, n) (p.getParameterAt(n)->getName())
+#define PARAM_CHARSET(p, n) \
+ (p.getParameterAt(n)->getValue().getCharset().generate())
+#define PARAM_LANG(p, n) \
+ (p.getParameterAt(n)->getValue().getLanguage())
+#define PARAM_BUFFER(p, n) \
+ (p.getParameterAt(n)->getValue().getBuffer())
+
+
+ void setUp() {
+
+ // Set the global C and C++ locale to the user-configured locale.
+ // The locale should use UTF-8 encoding for these tests to run successfully.
+ try {
+ std::locale::global(std::locale(""));
+ } catch (std::exception &) {
+ std::setlocale(LC_ALL, "");
+ }
+ }
+
+ void tearDown() {
+
+ // Restore default locale
+ std::locale::global(std::locale("C"));
+ }
+
+
+ void testParse() {
+
+ // Simple parameter
+ parameterizedHeaderField p1;
+ p1.parse("X; param1=value1;\r\n");
+
+ VASSERT_EQ("1.1", 1, p1.getParameterCount());
+ VASSERT_EQ("1.2", "param1", PARAM_NAME(p1, 0));
+ VASSERT_EQ("1.3", "value1", PARAM_VALUE(p1, 0));
+
+ // Multi-section parameters (1/2)
+ parameterizedHeaderField p2a;
+ p2a.parse(
+ "X; param1=value1;\r\n"
+ " param2*0=\"val\";\r\n"
+ " param2*1=\"ue2\";"
+ );
+
+ VASSERT_EQ("2a.1", 2, p2a.getParameterCount());
+ VASSERT_EQ("2a.2", "param1", PARAM_NAME(p2a, 0));
+ VASSERT_EQ("2a.3", "value1", PARAM_VALUE(p2a, 0));
+ VASSERT_EQ("2a.4", "param2", PARAM_NAME(p2a, 1));
+ VASSERT_EQ("2a.5", "value2", PARAM_VALUE(p2a, 1));
+
+ // Multi-section parameters (2/2)
+ parameterizedHeaderField p2b;
+ p2b.parse(
+ "X; param1=value1;\r\n"
+ " param2=\"should be ignored\";\r\n"
+ " param2*0=\"val\";\r\n"
+ " param2*1=\"ue2\";"
+ );
+
+ VASSERT_EQ("2b.1", 2, p2b.getParameterCount());
+ VASSERT_EQ("2b.2", "param1", PARAM_NAME(p2b, 0));
+ VASSERT_EQ("2b.3", "value1", PARAM_VALUE(p2b, 0));
+ VASSERT_EQ("2b.4", "param2", PARAM_NAME(p2b, 1));
+ VASSERT_EQ("2b.5", "value2", PARAM_VALUE(p2b, 1));
+
+ // Extended parameter (charset and language information)
+ parameterizedHeaderField p3;
+ p3.parse("X; param1*=charset'language'value1;\r\n");
+
+ VASSERT_EQ("3.1", 1, p3.getParameterCount());
+ VASSERT_EQ("3.2", "param1", PARAM_NAME(p3, 0));
+ VASSERT_EQ("3.3", "charset", PARAM_CHARSET(p3, 0));
+ VASSERT_EQ("3.4", "value1", PARAM_BUFFER(p3, 0));
+
+ // Encoded characters in extended parameter values
+ parameterizedHeaderField p4;
+ p4.parse("X; param1*=a%20value%20with%20multiple%20word%73"); // 0x73 = 's'
+
+ VASSERT_EQ("4.1", 1, p4.getParameterCount());
+ VASSERT_EQ("4.2", "param1", PARAM_NAME(p4, 0));
+ VASSERT_EQ("4.3", "a value with multiple words", PARAM_VALUE(p4, 0));
+
+ // Invalid encoded character
+ parameterizedHeaderField p5;
+ p5.parse("X; param1*=test%20value%");
+
+ VASSERT_EQ("5.1", 1, p5.getParameterCount());
+ VASSERT_EQ("5.2", "param1", PARAM_NAME(p5, 0));
+ VASSERT_EQ("5.3", "test value%", PARAM_VALUE(p5, 0));
+
+ // Spaces before and after '='
+ parameterizedHeaderField p6;
+ p6.parse("X; param1\t= \"value1\"");
+
+ VASSERT_EQ("6.1", 1, p6.getParameterCount());
+ VASSERT_EQ("6.2", "param1", PARAM_NAME(p6, 0));
+ VASSERT_EQ("6.3", "value1", PARAM_VALUE(p6, 0));
+
+ // Quoted strings and escaped chars
+ parameterizedHeaderField p7;
+ p7.parse("X; param1=\"this is a slash: \\\"\\\\\\\"\""); // \"\\\"
+
+ VASSERT_EQ("7.1", 1, p7.getParameterCount());
+ VASSERT_EQ("7.2", "param1", PARAM_NAME(p7, 0));
+ VASSERT_EQ("7.3", "this is a slash: \"\\\"", PARAM_VALUE(p7, 0));
+ }
+
+ void testParseRFC2231() {
+
+ // Extended parameter with charset specified in more than one
+ // section (this is forbidden by RFC, but is should not fail)
+ parameterizedHeaderField p1;
+ p1.parse(
+ "X; param1*0*=charset1'language1'value1;\r\n"
+ " param1*1*=charset2'language2'value2;"
+ );
+
+ VASSERT_EQ("1.1", 1, p1.getParameterCount());
+ VASSERT_EQ("1.2", "param1", PARAM_NAME(p1, 0));
+ VASSERT_EQ("1.3", "charset1", PARAM_CHARSET(p1, 0));
+ VASSERT_EQ("1.4", "value1charset2'language2'value2", PARAM_BUFFER(p1, 0));
+
+ // Charset not specified in the first section (that is not encoded),
+ // but specified in the second one (legal)
+ parameterizedHeaderField p2;
+ p2.parse(
+ "X; param1*0=value1;\r\n"
+ " param1*1*=charset'language'value2;"
+ );
+
+ VASSERT_EQ("2.1", 1, p2.getParameterCount());
+ VASSERT_EQ("2.2", "param1", PARAM_NAME(p2, 0));
+ VASSERT_EQ("2.3", "charset", PARAM_CHARSET(p2, 0));
+ VASSERT_EQ("2.4", "value1value2", PARAM_BUFFER(p2, 0));
+
+ // Characters prefixed with '%' in a simple (not extended) section
+ // should not be decoded
+ parameterizedHeaderField p3;
+ p3.parse("X; param1=val%20ue1");
+
+ VASSERT_EQ("3.1", 1, p3.getParameterCount());
+ VASSERT_EQ("3.2", "param1", PARAM_NAME(p3, 0));
+ VASSERT_EQ("3.3", "val%20ue1", PARAM_VALUE(p3, 0));
+
+ // Multiple sections + charset specified and encoding
+ parameterizedHeaderField p4;
+ p4.parse(
+ "X; param1*0*=charset'language'value1a%20;"
+ " param1*1*=value1b%20;"
+ " param1*2=value1c"
+ );
+
+ VASSERT_EQ("4.1", 1, p4.getParameterCount());
+ VASSERT_EQ("4.2", "param1", PARAM_NAME(p4, 0));
+ VASSERT_EQ("4.3", "charset", PARAM_CHARSET(p4, 0));
+ VASSERT_EQ("4.4", "value1a value1b value1c", PARAM_BUFFER(p4, 0));
+
+ // No charset specified: defaults to US-ASCII
+ parameterizedHeaderField p5;
+ p5.parse("X; param1*='language'value1");
+
+ VASSERT_EQ("5.1", 1, p5.getParameterCount());
+ VASSERT_EQ("5.2", "param1", PARAM_NAME(p5, 0));
+ VASSERT_EQ("5.3", "us-ascii", PARAM_CHARSET(p5, 0));
+ VASSERT_EQ("5.4", "value1", PARAM_BUFFER(p5, 0));
+
+ // Language specification
+ parameterizedHeaderField p6;
+ p6.parse("X; param1*=us-ascii'en-us'This%20is%20%2A%2A%2Afun%2A%2A%2A");
+
+ VASSERT_EQ("6.1", 1, p6.getParameterCount());
+ VASSERT_EQ("6.2", "param1", PARAM_NAME(p6, 0));
+ VASSERT_EQ("6.3", "us-ascii", PARAM_CHARSET(p6, 0));
+ VASSERT_EQ("6.4", "en-us", PARAM_LANG(p6, 0));
+ VASSERT_EQ("6.5", "This is ***fun***", PARAM_BUFFER(p6, 0));
+ }
+
+ void testGenerate() {
+
+ // Simple parameter/value
+ parameterizedHeaderField p1;
+ p1.appendParameter(vmime::make_shared <vmime::parameter>("param1", "value1"));
+
+ VASSERT_EQ("1", "F: X; param1=value1", p1.generate());
+
+ // Value that needs quoting (1/2)
+ parameterizedHeaderField p2a;
+ p2a.appendParameter(vmime::make_shared <vmime::parameter>("param1", "value1a;value1b"));
+
+ VASSERT_EQ("2a", "F: X; param1=\"value1a;value1b\"", p2a.generate());
+
+ // Value that needs quoting (2/2)
+ parameterizedHeaderField p2b;
+ p2b.appendParameter(vmime::make_shared <vmime::parameter>("param1", "va\\lue\"1"));
+
+ VASSERT_EQ("2b", "F: X; param1=\"va\\\\lue\\\"1\"", p2b.generate());
+ }
+
+ void testGetGeneratedSize() {
+
+ vmime::generationContext ctx(vmime::generationContext::getDefaultContext());
+
+ vmime::parameter p1("param1", "value1");
+ VASSERT("1", p1.getGeneratedSize(ctx) >= generateParameter(p1, ctx).length());
+
+ vmime::parameter p2a("param1", "value1a;value1b");
+ VASSERT("2&", p2a.getGeneratedSize(ctx) >= generateParameter(p2a, ctx).length());
+
+ vmime::parameter p2b("param1", "va\\lue\"1");
+ VASSERT("1", p2b.getGeneratedSize(ctx) >= generateParameter(p2b, ctx).length());
+ }
+
+ void testGenerateRFC2231() {
+
+ // Extended parameter with charset specifier
+ parameterizedHeaderField p1;
+ p1.appendParameter(
+ vmime::make_shared <vmime::parameter>(
+ "param1",
+ vmime::word("value 1\xe9", vmime::charset("charset"))
+ )
+ );
+
+ VASSERT_EQ(
+ "1.no-encoding",
+ "F: X; param1=\"value 1\"",
+ p1.generate(vmime::generationContext::PARAMETER_VALUE_NO_ENCODING)
+ );
+
+ VASSERT_EQ(
+ "1.rfc2047",
+ "F: X; param1=\"=?charset?Q?value_1=E9?=\"",
+ p1.generate(vmime::generationContext::PARAMETER_VALUE_RFC2047_ONLY)
+ );
+
+ VASSERT_EQ(
+ "1.rfc2231",
+ "F: X; param1*=charset''value%201%E9",
+ p1.generate(vmime::generationContext::PARAMETER_VALUE_RFC2231_ONLY)
+ );
+
+ VASSERT_EQ(
+ "1.both",
+ "F: X; param1=\"=?charset?Q?value_1=E9?=\";param1*=charset''value%201%E9",
+ p1.generate(vmime::generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047)
+ );
+
+ // Value that spans on multiple lines
+ parameterizedHeaderField p2;
+ p2.appendParameter(
+ vmime::make_shared <vmime::parameter>(
+ "param1",
+ vmime::word(
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
+ vmime::charset("charset")
+ )
+ )
+ );
+
+ VASSERT_EQ(
+ "2.no-encoding",
+ "F: X; \r\n "
+ "param1=abcdefghijkl",
+ p2.generate(vmime::generationContext::PARAMETER_VALUE_NO_ENCODING, 25) // max line length = 25
+ );
+
+ VASSERT_EQ(
+ "2.rfc2047",
+ "F: X; \r\n "
+ "param1=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
+ p2.generate(vmime::generationContext::PARAMETER_VALUE_RFC2047_ONLY, 25) // max line length = 25
+ );
+
+ VASSERT_EQ(
+ "2.rfc2231",
+ "F: X; \r\n "
+ "param1*0*=charset''abc;\r\n "
+ "param1*1*=defghijkl;\r\n "
+ "param1*2*=mnopqrstu;\r\n "
+ "param1*3*=vwxyzABCD;\r\n "
+ "param1*4*=EFGHIJKLM;\r\n "
+ "param1*5*=NOPQRSTUV;\r\n "
+ "param1*6*=WXYZ",
+ p2.generate(vmime::generationContext::PARAMETER_VALUE_RFC2231_ONLY, 25) // max line length = 25
+ );
+
+ VASSERT_EQ(
+ "2.both",
+ "F: X; \r\n "
+ "param1=abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ;\r\n "
+ "param1*0*=charset''abc;\r\n "
+ "param1*1*=defghijkl;\r\n "
+ "param1*2*=mnopqrstu;\r\n "
+ "param1*3*=vwxyzABCD;\r\n "
+ "param1*4*=EFGHIJKLM;\r\n "
+ "param1*5*=NOPQRSTUV;\r\n "
+ "param1*6*=WXYZ",
+ p2.generate(vmime::generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047, 25) // max line length = 25
+ );
+
+ // Non-ASCII parameter value
+ parameterizedHeaderField p3;
+ p3.appendParameter(
+ vmime::make_shared <vmime::parameter>(
+ "param1",
+ vmime::word(
+ "δσσσσσσσσσσσσσσσσσσσσδσδα δσαδσδσαδσαδασδασ δσαδασδσα δσαδασδσα δασδασδασ δασαχφδδσα 2008.doc",
+ vmime::charset("utf-8")
+ )
+ )
+ );
+
+ VASSERT_EQ(
+ "3.no-encoding",
+ "F: X; \r\n "
+ "param1=\" 2008.doc\"",
+ p3.generate(vmime::generationContext::PARAMETER_VALUE_NO_ENCODING, 80) // max line length = 80
+ );
+
+ VASSERT_EQ(
+ "3.7bit-only",
+ "F: X; \r\n "
+ "param1=\"=?utf-8?B?zrTPg8+Dz4PPg8+Dz4PPg8+Dz4PPg8+Dz4PPg8+Dz4PPg8+Dz4PPg8+DzrTPg860?=\r\n "
+ "=?utf-8?B?zrEgzrTPg86xzrTPg860z4POsc60z4POsc60zrHPg860zrHPgyDOtM+DzrHOtM6x?=\r\n "
+ "=?utf-8?B?z4POtM+DzrEgzrTPg86xzrTOsc+DzrTPg86xIM60zrHPg860zrHPg860zrHPgyDOtA==?=\r\n "
+ "=?utf-8?B?zrHPg86xz4fPhs60zrTPg86xIDIwMDguZG9j?=\"",
+ p3.generate(vmime::generationContext::PARAMETER_VALUE_RFC2047_ONLY, 80) // max line length = 80
+ );
+
+ VASSERT_EQ(
+ "3.both",
+ "F: X; \r\n "
+ "param1=\"=?utf-8?B?zrTPg8+Dz4PPg8+Dz4PPg8+Dz4PPg8+Dz4PPg8+Dz4PPg8+Dz4PPg8+DzrTPg860?=\r\n "
+ "=?utf-8?B?zrEgzrTPg86xzrTPg860z4POsc60z4POsc60zrHPg860zrHPgyDOtM+DzrHOtM6x?=\r\n "
+ "=?utf-8?B?z4POtM+DzrEgzrTPg86xzrTOsc+DzrTPg86xIM60zrHPg860zrHPg860zrHPgyDOtA==?=\r\n "
+ "=?utf-8?B?zrHPg86xz4fPhs60zrTPg86xIDIwMDguZG9j?=\";\r\n "
+ "param1*0*=utf-8''%CE%B4%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83;\r\n "
+ "param1*1*=%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83;\r\n "
+ "param1*2*=%CE%B4%CF%83%CE%B4%CE%B1%20%CE%B4%CF%83%CE%B1%CE%B4%CF%83%CE%B4%CF;\r\n "
+ "param1*3*=%83%CE%B1%CE%B4%CF%83%CE%B1%CE%B4%CE%B1%CF%83%CE%B4%CE%B1%CF%83%20;\r\n "
+ "param1*4*=%CE%B4%CF%83%CE%B1%CE%B4%CE%B1%CF%83%CE%B4%CF%83%CE%B1%20%CE%B4%CF;\r\n "
+ "param1*5*=%83%CE%B1%CE%B4%CE%B1%CF%83%CE%B4%CF%83%CE%B1%20%CE%B4%CE%B1%CF%83;\r\n "
+ "param1*6*=%CE%B4%CE%B1%CF%83%CE%B4%CE%B1%CF%83%20%CE%B4%CE%B1%CF%83%CE%B1%CF;\r\n "
+ "param1*7*=%87%CF%86%CE%B4%CE%B4%CF%83%CE%B1%202008.doc",
+ p3.generate(vmime::generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047, 80) // max line length = 80
+ );
+
+ VASSERT_EQ(
+ "3.either",
+ "F: X; param1*0*=utf-8''%CE%B4%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83;\r\n "
+ "param1*1*=%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83%CF%83;\r\n "
+ "param1*2*=%CE%B4%CF%83%CE%B4%CE%B1%20%CE%B4%CF%83%CE%B1%CE%B4%CF%83%CE%B4%CF;\r\n "
+ "param1*3*=%83%CE%B1%CE%B4%CF%83%CE%B1%CE%B4%CE%B1%CF%83%CE%B4%CE%B1%CF%83%20;\r\n "
+ "param1*4*=%CE%B4%CF%83%CE%B1%CE%B4%CE%B1%CF%83%CE%B4%CF%83%CE%B1%20%CE%B4%CF;\r\n "
+ "param1*5*=%83%CE%B1%CE%B4%CE%B1%CF%83%CE%B4%CF%83%CE%B1%20%CE%B4%CE%B1%CF%83;\r\n "
+ "param1*6*=%CE%B4%CE%B1%CF%83%CE%B4%CE%B1%CF%83%20%CE%B4%CE%B1%CF%83%CE%B1%CF;\r\n "
+ "param1*7*=%87%CF%86%CE%B4%CE%B4%CF%83%CE%B1%202008.doc",
+ p3.generate(vmime::generationContext::PARAMETER_VALUE_RFC2231_ONLY, 80) // max line length = 80
+ );
+
+ // No encoding needed
+ parameterizedHeaderField p4;
+ p4.appendParameter(
+ vmime::make_shared <vmime::parameter>(
+ "param1",
+ vmime::word("va lue", vmime::charset("charset"))
+ )
+ );
+
+ VASSERT_EQ(
+ "4.no-encoding",
+ "F: X; param1=\"va lue\"",
+ p4.generate(vmime::generationContext::PARAMETER_VALUE_NO_ENCODING)
+ );
+
+ VASSERT_EQ(
+ "4.rfc2047",
+ "F: X; param1=\"va lue\"",
+ p4.generate(vmime::generationContext::PARAMETER_VALUE_RFC2047_ONLY)
+ );
+
+ VASSERT_EQ(
+ "4.rfc2231",
+ "F: X; param1=\"va lue\"",
+ p4.generate(vmime::generationContext::PARAMETER_VALUE_RFC2231_ONLY)
+ );
+
+ VASSERT_EQ(
+ "4.both",
+ "F: X; param1=\"va lue\"",
+ p4.generate(vmime::generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047)
+ );
+
+ // Language specification
+ parameterizedHeaderField p5;
+ p5.appendParameter(
+ vmime::make_shared <vmime::parameter>("param1",
+ vmime::word("This is ***fun***", vmime::charset("us-ascii"), "en-us"))
+ );
+
+ VASSERT_EQ(
+ "5.no-encoding",
+ "F: X; param1=\"This is ***fun***\"",
+ p5.generate(vmime::generationContext::PARAMETER_VALUE_NO_ENCODING)
+ );
+
+ VASSERT_EQ(
+ "5.rfc2047",
+ "F: X; param1=\"=?us-ascii*en-us?Q?This_is_***fun***?=\"",
+ p5.generate(vmime::generationContext::PARAMETER_VALUE_RFC2047_ONLY)
+ );
+
+ VASSERT_EQ(
+ "5.rfc2231",
+ "F: X; param1*=us-ascii''This%20is%20***fun***",
+ p5.generate(vmime::generationContext::PARAMETER_VALUE_RFC2231_ONLY)
+ );
+
+ VASSERT_EQ(
+ "5.both",
+ "F: X; "
+ "param1=\"=?us-ascii*en-us?Q?This_is_***fun***?=\";\r\n "
+ "param1*=us-ascii''This%20is%20***fun***",
+ p5.generate(vmime::generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047));
+ }
+
+ void testGetGeneratedSizeRFC2231() {
+
+ vmime::generationContext ctx(vmime::generationContext::getDefaultContext());
+
+ // Extended parameter with charset specifier
+ vmime::parameter p1(
+ "param1",
+ vmime::word("value 1\xe9", vmime::charset("charset"))
+ );
+
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_NO_ENCODING);
+ VASSERT("1.no-encoding", p1.getGeneratedSize(ctx) >= generateParameter(p1, ctx).length());
+
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2047_ONLY);
+ VASSERT("1.rfc2047", p1.getGeneratedSize(ctx) >= generateParameter(p1, ctx).length());
+
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_ONLY);
+ VASSERT("1.rfc2231", p1.getGeneratedSize(ctx) >= generateParameter(p1, ctx).length());
+
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047);
+ VASSERT("1.both", p1.getGeneratedSize(ctx) >= generateParameter(p1, ctx).length());
+
+ // Value that spans on multiple lines
+ vmime::parameter p2(
+ "param1",
+ vmime::word(
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
+ vmime::charset("charset")
+ )
+ );
+
+ ctx.setMaxLineLength(25);
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_NO_ENCODING);
+ VASSERT("2.no-encoding", p2.getGeneratedSize(ctx) >= generateParameter(p2, ctx).length());
+
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2047_ONLY);
+ VASSERT("2.rfc2047", p2.getGeneratedSize(ctx) >= generateParameter(p2, ctx).length());
+
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_ONLY);
+ VASSERT("2.rfc2231", p2.getGeneratedSize(ctx) >= generateParameter(p2, ctx).length());
+
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047);
+ VASSERT("2.both", p2.getGeneratedSize(ctx) >= generateParameter(p2, ctx).length());
+
+ // Non-ASCII parameter value
+ vmime::parameter p3(
+ "param1",
+ vmime::word(
+ "δσσσσσσσσσσσσσσσσσσσσδσδα δσαδσδσαδσαδασδασ δσαδασδσα δσαδασδσα δασδασδασ δασαχφδδσα 2008.doc",
+ vmime::charset("utf-8")
+ )
+ );
+
+ ctx.setMaxLineLength(vmime::generationContext::getDefaultContext().getMaxLineLength());
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_NO_ENCODING);
+ VASSERT("3.no-encoding", p3.getGeneratedSize(ctx) >= generateParameter(p3, ctx).length());
+
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2047_ONLY);
+ VASSERT("3.rfc2047", p3.getGeneratedSize(ctx) >= generateParameter(p3, ctx).length());
+
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_ONLY);
+ VASSERT("3.rfc2231", p3.getGeneratedSize(ctx) >= generateParameter(p3, ctx).length());
+
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047);
+ VASSERT("3.both", p3.getGeneratedSize(ctx) >= generateParameter(p3, ctx).length());
+
+ // No encoding needed
+ vmime::parameter p4(
+ "param1",
+ vmime::word("va lue", vmime::charset("charset"))
+ );
+
+ ctx.setMaxLineLength(vmime::generationContext::getDefaultContext().getMaxLineLength());
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_NO_ENCODING);
+ VASSERT("4.no-encoding", p4.getGeneratedSize(ctx) >= generateParameter(p4, ctx).length());
+
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2047_ONLY);
+ VASSERT("4.rfc2047", p4.getGeneratedSize(ctx) >= generateParameter(p4, ctx).length());
+
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_ONLY);
+ VASSERT("4.rfc2231", p4.getGeneratedSize(ctx) >= generateParameter(p4, ctx).length());
+
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047);
+ VASSERT("4.both", p4.getGeneratedSize(ctx) >= generateParameter(p4, ctx).length());
+
+ // Language specification
+ vmime::parameter p5(
+ "param1",
+ vmime::word("This is ***fun***", vmime::charset("us-ascii"), "en-us")
+ );
+
+ ctx.setMaxLineLength(vmime::generationContext::getDefaultContext().getMaxLineLength());
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_NO_ENCODING);
+ VASSERT("5.no-encoding", p5.getGeneratedSize(ctx) >= generateParameter(p5, ctx).length());
+
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2047_ONLY);
+ VASSERT("5.rfc2047", p5.getGeneratedSize(ctx) >= generateParameter(p5, ctx).length());
+
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_ONLY);
+ VASSERT("5.rfc2231", p5.getGeneratedSize(ctx) >= generateParameter(p5, ctx).length());
+
+ ctx.setEncodedParameterValueMode(vmime::generationContext::PARAMETER_VALUE_RFC2231_AND_RFC2047);
+ VASSERT("5.both", p5.getGeneratedSize(ctx) >= generateParameter(p5, ctx).length());
+ }
+
+ void testNonStandardEncodedParam() {
+
+ // This syntax is non-standard (expressly prohibited
+ // by RFC-2047), but is used by Mozilla:
+ //
+ // Content-Type: image/png;
+ // name="=?us-ascii?Q?Logo_VMime=2Epng?="
+
+ parameterizedHeaderField p1;
+ p1.parse("image/png; name=\"=?us-ascii?Q?Logo_VMime=2Epng?=\"");
+
+ VASSERT_EQ("1.1", 1, p1.getParameterCount());
+ VASSERT_EQ("1.2", "name", PARAM_NAME(p1, 0));
+ VASSERT_EQ("1.3", "Logo VMime.png", PARAM_VALUE(p1, 0));
+
+ parameterizedHeaderField p2;
+ p2.parse("image/png; name=\"Logo =?us-ascii?Q?VMime=2Epng?=\"");
+
+ VASSERT_EQ("2.1", 1, p2.getParameterCount());
+ VASSERT_EQ("2.2", "name", PARAM_NAME(p2, 0));
+ VASSERT_EQ("2.3", "Logo VMime.png", PARAM_VALUE(p2, 0));
+ }
+
+ // Parse parameters with non-significant whitespaces
+ void testParseNonSignificantWS() {
+
+ parameterizedHeaderField p1;
+ p1.parse(" \t X \r\n");
+
+ VASSERT_EQ("1.1", "X", FIELD_VALUE(p1));
+
+ parameterizedHeaderField p2;
+ p2.parse(" X ; param1 = value1 \r\n");
+
+ VASSERT_EQ("2.1", 1, p2.getParameterCount());
+ VASSERT_EQ("2.2", "X", FIELD_VALUE(p2));
+ VASSERT_EQ("2.3", "param1", PARAM_NAME(p2, 0));
+ VASSERT_EQ("2.4", "value1", PARAM_VALUE(p2, 0));
+ }
+
+ // Encode "tspecials"
+ void testEncodeTSpecials() {
+
+ VASSERT_EQ(" 1", "p=\"val(ue\"", vmime::make_shared <vmime::parameter>("p", "val(ue")->generate());
+ VASSERT_EQ(" 2", "p=\"val)ue\"", vmime::make_shared <vmime::parameter>("p", "val)ue")->generate());
+ VASSERT_EQ(" 3", "p=\"val<ue\"", vmime::make_shared <vmime::parameter>("p", "val<ue")->generate());
+ VASSERT_EQ(" 4", "p=\"val>ue\"", vmime::make_shared <vmime::parameter>("p", "val>ue")->generate());
+ VASSERT_EQ(" 5", "p=\"val@ue\"", vmime::make_shared <vmime::parameter>("p", "val@ue")->generate());
+ VASSERT_EQ(" 6", "p=\"val,ue\"", vmime::make_shared <vmime::parameter>("p", "val,ue")->generate());
+ VASSERT_EQ(" 7", "p=\"val;ue\"", vmime::make_shared <vmime::parameter>("p", "val;ue")->generate());
+ VASSERT_EQ(" 8", "p=\"val:ue\"", vmime::make_shared <vmime::parameter>("p", "val:ue")->generate());
+ VASSERT_EQ(" 9", "p=\"val/ue\"", vmime::make_shared <vmime::parameter>("p", "val/ue")->generate());
+ VASSERT_EQ("10", "p=\"val[ue\"", vmime::make_shared <vmime::parameter>("p", "val[ue")->generate());
+ VASSERT_EQ("11", "p=\"val]ue\"", vmime::make_shared <vmime::parameter>("p", "val]ue")->generate());
+ VASSERT_EQ("12", "p=\"val?ue\"", vmime::make_shared <vmime::parameter>("p", "val?ue")->generate());
+ VASSERT_EQ("13", "p=\"val=ue\"", vmime::make_shared <vmime::parameter>("p", "val=ue")->generate());
+ VASSERT_EQ("14", "p=\"val ue\"", vmime::make_shared <vmime::parameter>("p", "val ue")->generate());
+ VASSERT_EQ("15", "p=\"val\tue\"", vmime::make_shared <vmime::parameter>("p", "val\tue")->generate());
+ }
+
+ // http://sourceforge.net/projects/vmime/forums/forum/237356/topic/3812278
+ void testEncodeTSpecialsInRFC2231() {
+
+ VASSERT_EQ(
+ "1",
+ "filename*=UTF-8''my_file_name_%C3%B6%C3%A4%C3%BC_%281%29.txt",
+ vmime::make_shared <vmime::parameter>(
+ "filename",
+ vmime::word("my_file_name_\xc3\xb6\xc3\xa4\xc3\xbc_(1).txt", "UTF-8")
+ )->generate()
+ );
+ }
+
+ void testWhitespaceBreaksTheValue() {
+
+ parameterizedHeaderField p;
+ p.parse("xxx yyy; param1=value1 \r\n");
+
+ VASSERT_EQ("count", 1, p.getParameterCount());
+ VASSERT_EQ("value", "xxx", FIELD_VALUE(p));
+ VASSERT_EQ("param1.name", "param1", PARAM_NAME(p, 0));
+ VASSERT_EQ("param1.value", "value1", PARAM_VALUE(p, 0));
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/pathTest.cpp b/vmime-master/tests/parser/pathTest.cpp
new file mode 100644
index 0000000..1396911
--- /dev/null
+++ b/vmime-master/tests/parser/pathTest.cpp
@@ -0,0 +1,102 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(pathTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testParse)
+ VMIME_TEST(testParse2)
+ VMIME_TEST(testGenerate)
+ VMIME_TEST_LIST_END
+
+
+ void testParse() {
+
+ vmime::path p1;
+ p1.parse("<>");
+
+ VASSERT_EQ("1.1", "", p1.getLocalPart());
+ VASSERT_EQ("1.2", "", p1.getDomain());
+
+ vmime::path p2;
+ p2.parse("<domain>");
+
+ VASSERT_EQ("2.1", "", p2.getLocalPart());
+ VASSERT_EQ("2.2", "domain", p2.getDomain());
+
+ vmime::path p3;
+ p3.parse("<local@domain>");
+
+ VASSERT_EQ("3.1", "local", p3.getLocalPart());
+ VASSERT_EQ("3.2", "domain", p3.getDomain());
+ }
+
+ void testParse2() {
+
+ // Test some invalid paths (no '<>')
+ vmime::path p1;
+ p1.parse("");
+
+ VASSERT_EQ("1.1", "", p1.getLocalPart());
+ VASSERT_EQ("1.2", "", p1.getDomain());
+
+ vmime::path p2;
+ p2.parse("domain");
+
+ VASSERT_EQ("2.1", "", p2.getLocalPart());
+ VASSERT_EQ("2.2", "domain", p2.getDomain());
+
+ vmime::path p3;
+ p3.parse("local@domain");
+
+ VASSERT_EQ("3.1", "local", p3.getLocalPart());
+ VASSERT_EQ("3.2", "domain", p3.getDomain());
+ }
+
+ void testGenerate() {
+
+ vmime::path p1;
+
+ VASSERT_EQ("1", "<>", p1.generate());
+
+ vmime::path p2;
+ p2.setLocalPart("local");
+
+ VASSERT_EQ("2", "<local@>", p2.generate());
+
+ vmime::path p3;
+ p3.setDomain("domain");
+
+ VASSERT_EQ("3", "<@domain>", p3.generate());
+
+ vmime::path p4;
+ p4.setLocalPart("local");
+ p4.setDomain("domain");
+
+ VASSERT_EQ("4", "<local@domain>", p4.generate());
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/streamContentHandlerTest.cpp b/vmime-master/tests/parser/streamContentHandlerTest.cpp
new file mode 100644
index 0000000..399118e
--- /dev/null
+++ b/vmime-master/tests/parser/streamContentHandlerTest.cpp
@@ -0,0 +1,194 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/utility/outputStreamAdapter.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(streamContentHandlerTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testIsEmpty)
+ VMIME_TEST(testGetLength)
+ VMIME_TEST(testIsEncoded)
+ VMIME_TEST(testGetLength_Encoded)
+ VMIME_TEST(testExtract)
+ VMIME_TEST(testExtract_Encoded)
+ VMIME_TEST(testExtractRaw_Encoded)
+ VMIME_TEST(testGenerate)
+ VMIME_TEST(testGenerate_Encoded)
+ VMIME_TEST_LIST_END
+
+
+ void testIsEmpty() {
+
+ vmime::streamContentHandler cth;
+
+ VASSERT_TRUE("empty", cth.isEmpty());
+ }
+
+ void testGetLength() {
+
+ vmime::string data("Test Data");
+ vmime::shared_ptr <vmime::utility::inputStream> stream =
+ vmime::make_shared <vmime::utility::inputStreamStringAdapter>(data);
+
+ vmime::streamContentHandler cth(stream, data.length());
+
+ VASSERT_FALSE("empty", cth.isEmpty());
+ VASSERT_EQ("length", 9, cth.getLength());
+ }
+
+ void testIsEncoded() {
+
+ vmime::string data("Test Data");
+ vmime::shared_ptr <vmime::utility::inputStream> stream =
+ vmime::make_shared <vmime::utility::inputStreamStringAdapter>(data);
+
+ vmime::streamContentHandler cth(stream, data.length());
+
+ VASSERT_FALSE("encoded", cth.isEncoded());
+ VASSERT_EQ("encoding", vmime::contentHandler::NO_ENCODING, cth.getEncoding());
+
+
+ vmime::string data2("Zm9vEjRWYmFy=");
+ vmime::shared_ptr <vmime::utility::inputStream> stream2 =
+ vmime::make_shared <vmime::utility::inputStreamStringAdapter>(data2);
+
+ vmime::streamContentHandler cth2(stream2, data2.length(), vmime::encoding("base64"));
+
+ VASSERT_TRUE("encoded", cth2.isEncoded());
+ VASSERT_EQ("encoding", "base64", cth2.getEncoding().generate());
+ }
+
+ void testGetLength_Encoded() {
+
+ vmime::string data("foo=12=34=56bar");
+ vmime::shared_ptr <vmime::utility::inputStream> stream =
+ vmime::make_shared <vmime::utility::inputStreamStringAdapter>(data);
+
+ vmime::streamContentHandler cth(stream, data.length(), vmime::encoding("quoted-printable"));
+
+ // Reported length should be the length of encoded data
+ VASSERT_EQ("length", 15, cth.getLength());
+ }
+
+ void testExtract() {
+
+ vmime::string data("Test Data");
+ vmime::shared_ptr <vmime::utility::inputStream> stream =
+ vmime::make_shared <vmime::utility::inputStreamStringAdapter>(data);
+
+ vmime::streamContentHandler cth(stream, data.length());
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth.extract(osa);
+
+ VASSERT_EQ("extract", "Test Data", oss.str());
+ }
+
+ void testExtract_Encoded() {
+
+ vmime::string data(
+ "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAxMjM0NTY3ODk="
+ );
+
+ vmime::shared_ptr <vmime::utility::inputStream> stream =
+ vmime::make_shared <vmime::utility::inputStreamStringAdapter>(data);
+
+ vmime::streamContentHandler cth(stream, data.length(), vmime::encoding("base64"));
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth.extract(osa);
+
+ // Data should be decoded from B64
+ VASSERT_EQ(
+ "extract",
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+ oss.str()
+ );
+ }
+
+ void testExtractRaw_Encoded()
+ {
+ vmime::string data(
+ "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAxMjM0NTY3ODk="
+ );
+ vmime::shared_ptr <vmime::utility::inputStream> stream =
+ vmime::make_shared <vmime::utility::inputStreamStringAdapter>(data);
+
+ vmime::streamContentHandler cth(stream, data.length(), vmime::encoding("base64"));
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth.extractRaw(osa);
+
+ // Data should not be decoded
+ VASSERT_EQ(
+ "extractRaw",
+ "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAxMjM0NTY3ODk=",
+ oss.str()
+ );
+ }
+
+ void testGenerate() {
+
+ vmime::string data("foo\x12\x34\x56 bar");
+ vmime::shared_ptr <vmime::utility::inputStream> stream =
+ vmime::make_shared <vmime::utility::inputStreamStringAdapter>(data);
+
+ vmime::streamContentHandler cth(stream, data.length());
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth.generate(osa, vmime::encoding("base64"));
+
+ // Data should be encoded to B64
+ VASSERT_EQ("generate", "Zm9vEjRWIGJhcg==", oss.str());
+ }
+
+ void testGenerate_Encoded() {
+
+ vmime::string data("foo=12=34=56bar");
+ vmime::shared_ptr <vmime::utility::inputStream> stream =
+ vmime::make_shared <vmime::utility::inputStreamStringAdapter>(data);
+
+ vmime::streamContentHandler cth(stream, data.length(), vmime::encoding("quoted-printable"));
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth.generate(osa, vmime::encoding("base64"));
+
+ // Data should be reencoded from QP to B64
+ VASSERT_EQ("generate", "Zm9vEjRWYmFy", oss.str());
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/stringContentHandlerTest.cpp b/vmime-master/tests/parser/stringContentHandlerTest.cpp
new file mode 100644
index 0000000..c856301
--- /dev/null
+++ b/vmime-master/tests/parser/stringContentHandlerTest.cpp
@@ -0,0 +1,165 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/utility/outputStreamAdapter.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(stringContentHandlerTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testIsEmpty)
+ VMIME_TEST(testGetLength)
+ VMIME_TEST(testIsEncoded)
+ VMIME_TEST(testGetLength_Encoded)
+ VMIME_TEST(testExtract)
+ VMIME_TEST(testExtract_Encoded)
+ VMIME_TEST(testExtractRaw_Encoded)
+ VMIME_TEST(testGenerate)
+ VMIME_TEST(testGenerate_Encoded)
+ VMIME_TEST_LIST_END
+
+
+ void testIsEmpty() {
+
+ vmime::stringContentHandler cth;
+
+ VASSERT_TRUE("empty", cth.isEmpty());
+ }
+
+ void testGetLength() {
+
+ vmime::stringContentHandler cth("Test Data");
+
+ VASSERT_FALSE("empty", cth.isEmpty());
+ VASSERT_EQ("length", 9, cth.getLength());
+ }
+
+ void testIsEncoded() {
+
+ vmime::stringContentHandler cth("Test Data");
+
+ VASSERT_FALSE("encoded", cth.isEncoded());
+ VASSERT_EQ("encoding", vmime::contentHandler::NO_ENCODING, cth.getEncoding());
+
+
+ vmime::stringContentHandler cth2("Zm9vEjRWYmFy=", vmime::encoding("base64"));
+
+ VASSERT_TRUE("encoded", cth2.isEncoded());
+ VASSERT_EQ("encoding", "base64", cth2.getEncoding().generate());
+ }
+
+ void testGetLength_Encoded() {
+
+ vmime::stringContentHandler cth(
+ "foo=12=34=56bar",
+ vmime::encoding("quoted-printable")
+ );
+
+ // Reported length should be the length of encoded data
+ VASSERT_EQ("length", 15, cth.getLength());
+ }
+
+ void testExtract() {
+
+ vmime::stringContentHandler cth("Test Data");
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth.extract(osa);
+
+ VASSERT_EQ("extract", "Test Data", oss.str());
+ }
+
+ void testExtract_Encoded() {
+
+ vmime::stringContentHandler cth(
+ "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAxMjM0NTY3ODk=",
+ vmime::encoding("base64")
+ );
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth.extract(osa);
+
+ // Data should be decoded from B64
+ VASSERT_EQ(
+ "extract",
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+ oss.str()
+ );
+ }
+
+ void testExtractRaw_Encoded() {
+
+ vmime::stringContentHandler cth(
+ "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAxMjM0NTY3ODk=",
+ vmime::encoding("base64")
+ );
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth.extractRaw(osa);
+
+ // Data should not be decoded
+ VASSERT_EQ(
+ "extractRaw",
+ "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAxMjM0NTY3ODk=",
+ oss.str()
+ );
+ }
+
+ void testGenerate() {
+
+ vmime::stringContentHandler cth("foo\x12\x34\x56 bar");
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth.generate(osa, vmime::encoding("base64"));
+
+ // Data should be encoded to B64
+ VASSERT_EQ("generate", "Zm9vEjRWIGJhcg==", oss.str());
+ }
+
+ void testGenerate_Encoded() {
+
+ vmime::stringContentHandler cth(
+ "foo=12=34=56bar",
+ vmime::encoding("quoted-printable")
+ );
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter osa(oss);
+
+ cth.generate(osa, vmime::encoding("base64"));
+
+ // Data should be reencoded from QP to B64
+ VASSERT_EQ("generate", "Zm9vEjRWYmFy", oss.str());
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/textTest.cpp b/vmime-master/tests/parser/textTest.cpp
new file mode 100644
index 0000000..e9ddc26
--- /dev/null
+++ b/vmime-master/tests/parser/textTest.cpp
@@ -0,0 +1,918 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include <locale>
+#include <clocale>
+
+
+VMIME_TEST_SUITE_BEGIN(textTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testConstructors)
+ VMIME_TEST(testCopy)
+ VMIME_TEST(testNewFromString)
+ VMIME_TEST(testDisplayForm)
+ VMIME_TEST(testParse)
+ VMIME_TEST(testGenerate)
+
+ VMIME_TEST(testWordConstructors)
+ VMIME_TEST(testWordParse)
+ VMIME_TEST(testWordGenerate)
+ VMIME_TEST(testWordGenerateSpace)
+ VMIME_TEST(testWordGenerateSpace2)
+ VMIME_TEST(testWordGenerateMultiBytes)
+ VMIME_TEST(testWordGenerateQuote)
+ VMIME_TEST(testWordGenerateSpecialCharsets)
+ VMIME_TEST(testWordGenerateSpecials)
+
+ VMIME_TEST(testWhitespace)
+ VMIME_TEST(testWhitespaceMBox)
+
+ VMIME_TEST(testFoldingAscii)
+ VMIME_TEST(testForcedNonEncoding)
+
+ VMIME_TEST(testBugFix20110511)
+
+ VMIME_TEST(testInternationalizedEmail_specialChars)
+ VMIME_TEST(testInternationalizedEmail_UTF8)
+ VMIME_TEST(testInternationalizedEmail_nonUTF8)
+ VMIME_TEST(testInternationalizedEmail_folding)
+ VMIME_TEST(testInternationalizedEmail_whitespace)
+
+ VMIME_TEST(testWronglyPaddedB64Words)
+ VMIME_TEST(testFixBrokenWords)
+ VMIME_TEST(testUnknownCharset)
+ VMIME_TEST_LIST_END
+
+
+ static const vmime::string getDisplayText(const vmime::text& t) {
+
+ return t.getWholeBuffer();
+ }
+
+ static const vmime::string cleanGeneratedWords(const std::string& str) {
+
+ std::istringstream iss(str);
+
+ std::string res;
+ std::string x;
+
+ while (std::getline(iss, x)) {
+ res += vmime::utility::stringUtils::trim(x);
+ }
+
+ return res;
+ }
+
+
+ void setUp() {
+
+ // Set the global C and C++ locale to the user-configured locale.
+ // The locale should use UTF-8 encoding for these tests to run successfully.
+ try {
+ std::locale::global(std::locale(""));
+ } catch (std::exception &) {
+ std::setlocale(LC_ALL, "");
+ }
+ }
+
+ void tearDown() {
+
+ // Restore default locale
+ std::locale::global(std::locale("C"));
+ }
+
+
+ void testConstructors() {
+
+ vmime::text t1;
+
+ VASSERT_EQ("1.1", 0, t1.getWordCount());
+
+ vmime::text t2("Test\xa9\xc3");
+
+ VASSERT_EQ("2.1", 1, t2.getWordCount());
+ VASSERT_EQ("2.2", "Test\xa9\xc3", t2.getWordAt(0)->getBuffer());
+ VASSERT_EQ("2.3", vmime::charset::getLocalCharset(), t2.getWordAt(0)->getCharset());
+
+ vmime::text t3("Test\xa9\xc3", vmime::charset(vmime::charsets::ISO8859_13));
+
+ VASSERT_EQ("3.1", 1, t3.getWordCount());
+ VASSERT_EQ("3.2", "Test\xa9\xc3", t3.getWordAt(0)->getBuffer());
+ VASSERT_EQ("3.3", vmime::charset(vmime::charsets::ISO8859_13), t3.getWordAt(0)->getCharset());
+
+ vmime::word w1("Test", vmime::charset(vmime::charsets::UTF_8));
+ vmime::text t4(w1);
+
+ VASSERT_EQ("4.1", 1, t4.getWordCount());
+ VASSERT_EQ("4.2", w1.getBuffer(), t4.getWordAt(0)->getBuffer());
+ VASSERT_EQ("4.3", w1.getCharset(), t4.getWordAt(0)->getCharset());
+
+ vmime::word w2("Other", vmime::charset(vmime::charsets::US_ASCII));
+ t4.appendWord(vmime::make_shared <vmime::word>(w2));
+
+ vmime::text t5(t4);
+
+ VASSERT_EQ("5.1", 2, t5.getWordCount());
+ VASSERT_EQ("5.2", w1.getBuffer(), t5.getWordAt(0)->getBuffer());
+ VASSERT_EQ("5.3", w1.getCharset(), t5.getWordAt(0)->getCharset());
+ VASSERT_EQ("5.4", w2.getBuffer(), t5.getWordAt(1)->getBuffer());
+ VASSERT_EQ("5.5", w2.getCharset(), t5.getWordAt(1)->getCharset());
+ }
+
+ void testCopy() {
+
+ vmime::text t1("Test: \xa9\xc3");
+
+ VASSERT("operator==", t1 == t1);
+ VASSERT("clone", *vmime::clone(t1) == t1);
+
+ vmime::text t2;
+ t2.copyFrom(t1);
+
+ VASSERT("copyFrom", t1 == t2);
+ }
+
+ void testNewFromString() {
+
+ vmime::string s1 = "only ASCII characters";
+ vmime::charset c1("test");
+ vmime::text t1;
+
+ t1.createFromString(s1, c1);
+
+ VASSERT_EQ("1.1", 1, t1.getWordCount());
+ VASSERT_EQ("1.2", s1, t1.getWordAt(0)->getBuffer());
+ VASSERT_EQ("1.3", vmime::charset(vmime::charsets::US_ASCII), t1.getWordAt(0)->getCharset());
+
+ vmime::string s2_1 = "some ASCII characters and special chars: ";
+ vmime::string s2_2 = "\xf1\xf2\xf3\xf4 ";
+ vmime::string s2_3 = "and then more ASCII chars.";
+ vmime::string s2 = s2_1 + s2_2 + s2_3;
+ vmime::charset c2("test");
+ vmime::text t2;
+
+ t2.createFromString(s2, c2);
+
+ VASSERT_EQ("2.1", 3, t2.getWordCount());
+ VASSERT_EQ("2.2", "some ASCII characters and special chars: ", t2.getWordAt(0)->getBuffer());
+ VASSERT_EQ("2.3", vmime::charset(vmime::charsets::US_ASCII), t2.getWordAt(0)->getCharset());
+ VASSERT_EQ("2.4", "\xf1\xf2\xf3\xf4", t2.getWordAt(1)->getBuffer());
+ VASSERT_EQ("2.5", c2, t2.getWordAt(1)->getCharset());
+ VASSERT_EQ("2.6", "and then more ASCII chars.", t2.getWordAt(2)->getBuffer());
+ VASSERT_EQ("2.7", vmime::charset(vmime::charsets::US_ASCII), t2.getWordAt(2)->getCharset());
+ }
+
+ static const vmime::string parseText(const vmime::string& buffer) {
+
+ vmime::text t;
+ t.parse(buffer);
+
+ std::ostringstream oss;
+ oss << t;
+
+ return oss.str();
+ }
+
+ void testParse() {
+
+ // From RFC-2047
+ VASSERT_EQ(
+ "1",
+ "[text: [[word: charset=US-ASCII, buffer=Keith Moore]]]",
+ parseText("=?US-ASCII?Q?Keith_Moore?=")
+ );
+
+ VASSERT_EQ(
+ "2",
+ "[text: [[word: charset=ISO-8859-1, buffer=Keld J\xf8rn Simonsen]]]",
+ parseText("=?ISO-8859-1?Q?Keld_J=F8rn_Simonsen?=")
+ );
+
+ VASSERT_EQ(
+ "3",
+ "[text: [[word: charset=ISO-8859-1, buffer=Andr\xe9]," \
+ "[word: charset=us-ascii, buffer= Pirard]]]",
+ parseText("=?ISO-8859-1?Q?Andr=E9?= Pirard")
+ );
+
+ VASSERT_EQ(
+ "4",
+ "[text: [[word: charset=ISO-8859-1, buffer=If you can read this yo]," \
+ "[word: charset=ISO-8859-2, buffer=u understand the example.]]]",
+ parseText(
+ "=?ISO-8859-1?B?SWYgeW91IGNhbiByZWFkIHRoaXMgeW8=?=\r\n " \
+ "=?ISO-8859-2?B?dSB1bmRlcnN0YW5kIHRoZSBleGFtcGxlLg==?="
+ )
+ );
+
+ // Bugfix: in "=?charset?q?=XX=YY?=", the "?=" finish
+ // sequence was not correctly found (should be the one
+ // after '=YY' and not the one after '?q').
+ VASSERT_EQ(
+ "5",
+ "[text: [[word: charset=abc, buffer=\xe9\xe9]]]",
+ parseText("=?abc?q?=E9=E9?=")
+ );
+
+ // Question marks (?) in the middle of the string
+ VASSERT_EQ(
+ "6",
+ "[text: [[word: charset=iso-8859-1, buffer=Know wh\xe4t? It works!]]]",
+ parseText("=?iso-8859-1?Q?Know_wh=E4t?_It_works!?=")
+ );
+
+ // With language specifier
+ VASSERT_EQ(
+ "7",
+ "[text: [[word: charset=US-ASCII, buffer=Keith Moore, lang=EN]]]",
+ parseText("=?US-ASCII*EN?Q?Keith_Moore?=")
+ );
+ }
+
+ void testGenerate() {
+
+ // TODO
+
+ // With language specifier
+ vmime::word wlang1("Émeline", vmime::charset("UTF-8"), "FR");
+ VASSERT_EQ("lang1", "=?UTF-8*FR?Q?=C3=89meline?=", wlang1.generate());
+
+ vmime::word wlang2("Keith Moore", vmime::charset("US-ASCII"), "EN");
+ VASSERT_EQ("lang2", "=?US-ASCII*EN?Q?Keith_Moore?=", wlang2.generate());
+ }
+
+ void testDisplayForm() {
+
+#define DISPLAY_FORM(x) getDisplayText(*vmime::text::decodeAndUnfold(x))
+
+ // From RFC-2047
+ VASSERT_EQ("1", "a", DISPLAY_FORM("=?ISO-8859-1?Q?a?="));
+ VASSERT_EQ("2", "a b", DISPLAY_FORM("=?ISO-8859-1?Q?a?= b"));
+ VASSERT_EQ("3", "ab", DISPLAY_FORM("=?ISO-8859-1?Q?a?= =?ISO-8859-1?Q?b?="));
+ VASSERT_EQ("4", "ab", DISPLAY_FORM("=?ISO-8859-1?Q?a?= \t =?ISO-8859-1?Q?b?="));
+ VASSERT_EQ("5", "ab", DISPLAY_FORM("=?ISO-8859-1?Q?a?= \r\n \t =?ISO-8859-1?Q?b?="));
+ VASSERT_EQ("6", "a b", DISPLAY_FORM("=?ISO-8859-1?Q?a_b?="));
+ VASSERT_EQ("7", "a b", DISPLAY_FORM("=?ISO-8859-1?Q?a?= =?ISO-8859-2?Q?_b?="));
+
+ // Some more tests...
+ VASSERT_EQ("8", "a b", DISPLAY_FORM(" a =?ISO-8859-1?Q?b?= "));
+ VASSERT_EQ("9", "a b ", DISPLAY_FORM(" \t =?ISO-8859-1?Q?a?= b "));
+ VASSERT_EQ("10", "a b", DISPLAY_FORM(" a\r\n\t b"));
+
+ VASSERT_EQ("11", "a b c", DISPLAY_FORM("a =?ISO-8859-1?Q?b?= c"));
+ VASSERT_EQ("12", "a b c ", DISPLAY_FORM("a =?ISO-8859-1?Q?b?= c "));
+ VASSERT_EQ("13", "a b c ", DISPLAY_FORM(" a =?ISO-8859-1?Q?b?= c "));
+ VASSERT_EQ("14", "a b c d", DISPLAY_FORM("a =?ISO-8859-1?Q?b?= c =?ISO-8859-1?Q?d?= "));
+ VASSERT_EQ("15", "a b c d e", DISPLAY_FORM("a =?ISO-8859-1?Q?b?= c =?ISO-8859-1?Q?d?= e"));
+
+ // Whitespaces and multiline
+ VASSERT_EQ("16", "a b c d e", DISPLAY_FORM("=?ISO-8859-1?Q?a_b_?=c\n\t=?ISO-8859-1?Q?d_?=e"));
+
+ // Ignored newlines
+ VASSERT_EQ("17", "ab", DISPLAY_FORM("=?ISO-8859-1?Q?a?=\r\nb"));
+ VASSERT_EQ("18", "a b", DISPLAY_FORM("=?ISO-8859-1?Q?a?= \r\nb"));
+
+#undef DISPLAY_FORM
+ }
+
+ void testWordConstructors() {
+
+ VASSERT_EQ("1.1", vmime::charset::getLocalCharset(), vmime::word().getCharset());
+ VASSERT_EQ("1.2", "", vmime::word().getBuffer());
+
+ VASSERT_EQ("2.1", vmime::charset::getLocalCharset(), vmime::word("foo").getCharset());
+ VASSERT_EQ("2.2", "foo", vmime::word("foo").getBuffer());
+
+ VASSERT_EQ("3.1", "bar", vmime::word("foo", vmime::charset("bar")).getCharset().getName());
+ VASSERT_EQ("3.2", "foo", vmime::word("foo", vmime::charset("bar")).getBuffer());
+ }
+
+ void testWordParse() {
+
+ // Simple encoded word
+ vmime::word w1;
+ w1.parse("=?foo?q?bar=E9 baz?=");
+
+ VASSERT_EQ("1.1", "foo", w1.getCharset().getName());
+ VASSERT_EQ("1.2", "bar\xe9 baz", w1.getBuffer());
+
+ // Unencoded text
+ vmime::word w2;
+ w2.parse(" foo bar \tbaz...");
+
+ VASSERT_EQ("2.1", vmime::charset(vmime::charsets::US_ASCII), w2.getCharset());
+ VASSERT_EQ("2.2", " foo bar \tbaz...", w2.getBuffer());
+
+ // Malformed word
+ vmime::word w3;
+ w3.parse("=?foo bar");
+
+ VASSERT_EQ("3.1", vmime::charset(vmime::charsets::US_ASCII), w3.getCharset());
+ VASSERT_EQ("3.2", "=?foo bar", w3.getBuffer());
+
+ // Unknown encoding
+ vmime::word w4;
+ w4.parse("=?whatever?not_q_or_b?whatever?=");
+
+ VASSERT_EQ("4.1", vmime::charset(vmime::charsets::US_ASCII), w4.getCharset());
+ VASSERT_EQ("4.2", "=?whatever?not_q_or_b?whatever?=", w4.getBuffer());
+ }
+
+ void testWordGenerate() {
+
+ VASSERT_EQ(
+ "1",
+ "=?foo?Q?bar=E9_baz?=",
+ vmime::word("bar\xe9 baz", vmime::charset("foo")).generate()
+ );
+
+ VASSERT_EQ(
+ "2",
+ "=?foo?B?8fLz9PU=?=",
+ vmime::word("\xf1\xf2\xf3\xf4\xf5", vmime::charset("foo")).generate()
+ );
+ }
+
+ void testWordGenerateSpace() {
+
+ // No white-space between an unencoded word and a encoded one
+ VASSERT_EQ(
+ "1",
+ "Bonjour =?utf-8?Q?Fran=C3=A7ois?=",
+ vmime::text::newFromString(
+ "Bonjour Fran\xc3\xa7ois",
+ vmime::charset("utf-8")
+ )->generate()
+ );
+
+ // White-space between two encoded words
+ vmime::text txt;
+ txt.appendWord(vmime::make_shared <vmime::word>("\xc3\x89t\xc3\xa9", "utf-8"));
+ txt.appendWord(vmime::make_shared <vmime::word>("Fran\xc3\xa7ois", "utf-8"));
+
+ const vmime::string decoded = "\xc3\x89t\xc3\xa9""Fran\xc3\xa7ois";
+ const vmime::string encoded = "=?utf-8?B?w4l0w6k=?= =?utf-8?Q?Fran=C3=A7ois?=";
+
+ // -- test encoding
+ VASSERT_EQ("2", encoded, txt.generate());
+
+ // -- ensure no space is added when decoding
+ vmime::text txt2;
+ txt2.parse(encoded, 0, encoded.length());
+
+ VASSERT_EQ("3", decoded, txt2.getWholeBuffer());
+
+ // -- test rencoding
+ VASSERT_EQ("4", encoded, txt2.generate());
+ }
+
+ void testWordGenerateSpace2() {
+
+ // White-space between two encoded words (#2)
+ vmime::text txt;
+ txt.appendWord(vmime::make_shared <vmime::word>("Facture ", "utf-8"));
+ txt.appendWord(vmime::make_shared <vmime::word>("\xc3\xa0", "utf-8"));
+ txt.appendWord(vmime::make_shared <vmime::word>(" envoyer ", "utf-8"));
+ txt.appendWord(vmime::make_shared <vmime::word>("\xc3\xa0", "utf-8"));
+ txt.appendWord(vmime::make_shared <vmime::word>(" Martine", "utf-8"));
+
+ const vmime::string decoded = "Facture ""\xc3\xa0"" envoyer ""\xc3\xa0"" Martine";
+ const vmime::string encoded = "Facture =?utf-8?B?w6A=?= envoyer =?utf-8?B?w6A=?= Martine";
+
+ // -- test encoding
+ VASSERT_EQ("1", encoded, txt.generate());
+
+ // -- ensure no space is added when decoding
+ vmime::text txt2;
+ txt2.parse(encoded, 0, encoded.length());
+
+ VASSERT_EQ("2", decoded, txt2.getWholeBuffer());
+
+ // -- test rencoding
+ VASSERT_EQ("3", encoded, txt2.generate());
+ }
+
+ void testWordGenerateMultiBytes() {
+
+ // Ensure we don't encode a non-integral number of characters
+ VASSERT_EQ(
+ "1",
+ "=?utf-8?Q?aaa?==?utf-8?Q?=C3=A9?==?utf-8?Q?zzz?=",
+ cleanGeneratedWords(
+ vmime::word("aaa\xc3\xa9zzz", vmime::charset("utf-8")).generate(16)
+ )
+ );
+
+ VASSERT_EQ(
+ "2",
+ "=?utf-8?Q?aaa=C3=A9?==?utf-8?Q?zzz?=",
+ cleanGeneratedWords(
+ vmime::word("aaa\xc3\xa9zzz", vmime::charset("utf-8")).generate(17)
+ )
+ );
+ }
+
+ void testWordGenerateQuote() {
+
+ std::string str;
+ vmime::utility::outputStreamStringAdapter os(str);
+
+ vmime::generationContext ctx;
+ ctx.setMaxLineLength(1000);
+
+ // ASCII-only text is quotable
+ str.clear();
+ vmime::word("Quoted text")
+ .generate(ctx, os, 0, NULL, vmime::text::QUOTE_IF_POSSIBLE, NULL);
+
+ VASSERT_EQ("1", "\"Quoted text\"", cleanGeneratedWords(str));
+
+ // Text with CR/LF is not quotable
+ str.clear();
+ vmime::word("Non-quotable\ntext", "us-ascii")
+ .generate(ctx, os, 0, NULL, vmime::text::QUOTE_IF_POSSIBLE, NULL);
+
+ VASSERT_EQ("2", "=?us-ascii?Q?Non-quotable=0Atext?=", cleanGeneratedWords(str));
+
+ // Text with non-ASCII chars is not quotable
+ str.clear();
+ vmime::word("Non-quotable text \xc3\xa9")
+ .generate(ctx, os, 0, NULL, vmime::text::QUOTE_IF_POSSIBLE, NULL);
+
+ VASSERT_EQ("3", "=?UTF-8?Q?Non-quotable_text_=C3=A9?=", cleanGeneratedWords(str));
+ }
+
+ void testWordGenerateSpecialCharsets() {
+
+ // ISO-2022-JP only uses 7-bit chars but should be encoded in Base64
+ VASSERT_EQ(
+ "1",
+ "=?iso-2022-jp?B?XlskQiVRITwlPSVKJWshJiU9JVUlSCUmJSclIl5bKEI=?=",
+ cleanGeneratedWords(
+ vmime::word(
+ "^[$B%Q!<%=%J%k!&%=%U%H%&%'%\"^[(B",
+ vmime::charset("iso-2022-jp")
+ ).generate(100)
+ )
+ );
+ }
+
+ void testWordGenerateSpecials() {
+
+ // In RFC-2047, quotation marks (ASCII 22h) should be encoded
+ VASSERT_EQ(
+ "1",
+ "=?UTF-8?Q?=22=C3=9Cml=C3=A4ute=22?=",
+ vmime::word(
+ "\x22\xC3\x9Cml\xC3\xA4ute\x22",
+ vmime::charset("UTF-8")
+ ).generate()
+ );
+ }
+
+ void testWhitespace() {
+
+ // Create
+ vmime::text text;
+ text.createFromString("Achim Br\xc3\xa4ndt", vmime::charsets::UTF_8);
+
+ VASSERT_EQ("1", 2, text.getWordCount());
+ VASSERT_EQ("2", "Achim ", text.getWordAt(0)->getBuffer());
+ VASSERT_EQ("3", "us-ascii", text.getWordAt(0)->getCharset());
+ VASSERT_EQ("4", "Br\xc3\xa4ndt", text.getWordAt(1)->getBuffer());
+ VASSERT_EQ("5", "utf-8", text.getWordAt(1)->getCharset());
+
+ // Generate
+ VASSERT_EQ("6", "Achim =?utf-8?Q?Br=C3=A4ndt?=", text.generate());
+
+ // Parse
+ text.parse("=?us-ascii?Q?Achim_?= =?utf-8?Q?Br=C3=A4ndt?=");
+
+ VASSERT_EQ("7", 2, text.getWordCount());
+ VASSERT_EQ("8", "Achim ", text.getWordAt(0)->getBuffer());
+ VASSERT_EQ("9", "us-ascii", text.getWordAt(0)->getCharset());
+ VASSERT_EQ("10", "Br\xc3\xa4ndt", text.getWordAt(1)->getBuffer());
+ VASSERT_EQ("11", "utf-8", text.getWordAt(1)->getCharset());
+ }
+
+ void testWhitespaceMBox() {
+
+ // Space MUST be encoded inside a word
+ vmime::mailbox mbox(vmime::text("Achim Br\xc3\xa4ndt", vmime::charsets::UTF_8), "me@vmime.org");
+ VASSERT_EQ("generate1", "=?us-ascii?Q?Achim_?= =?utf-8?Q?Br=C3=A4ndt?= <me@vmime.org>", mbox.generate());
+
+ vmime::text txt;
+ txt.appendWord(vmime::make_shared <vmime::word>("Achim ", "us-ascii"));
+ txt.appendWord(vmime::make_shared <vmime::word>("Br\xc3\xa4ndt", "utf-8"));
+ mbox = vmime::mailbox(txt, "me@vmime.org");
+ VASSERT_EQ("generate2", "=?us-ascii?Q?Achim_?= =?utf-8?Q?Br=C3=A4ndt?= <me@vmime.org>", mbox.generate());
+
+ mbox.parse("=?us-ascii?Q?Achim?= =?utf-8?Q?Br=C3=A4ndt?= <me@vmime.org>");
+ VASSERT_EQ("parse.name.count", 2, mbox.getName().getWordCount());
+ VASSERT_EQ("parse.name.word1.buffer", "Achim", mbox.getName().getWordAt(0)->getBuffer());
+ VASSERT_EQ("parse.name.word1.charset", "us-ascii", mbox.getName().getWordAt(0)->getCharset());
+ VASSERT_EQ("parse.name.word2.buffer", "Br\xc3\xa4ndt", mbox.getName().getWordAt(1)->getBuffer());
+ VASSERT_EQ("parse.name.word2.charset", "utf-8", mbox.getName().getWordAt(1)->getCharset());
+
+ VASSERT_EQ("parse.email", "me@vmime.org", mbox.getEmail());
+ }
+
+ void testFoldingAscii() {
+
+ // In this test, no encoding is needed, but line should be folded anyway
+ vmime::word w("01234567890123456789012345678901234567890123456789"
+ "01234567890123456789012345678901234567890123456789", vmime::charset("us-ascii"));
+
+ VASSERT_EQ(
+ "fold.ascii",
+ "=?us-ascii?Q?01234567890123456789012345678901234?=\r\n"
+ " =?us-ascii?Q?5678901234567890123456789012345678?=\r\n"
+ " =?us-ascii?Q?9012345678901234567890123456789?=", w.generate(50)
+ );
+ }
+
+ void testForcedNonEncoding() {
+
+ // Testing long unbreakable and unencodable header
+ vmime::relay r;
+ r.parse(
+ " from User (Ee9GMqZQ8t7IQwftfAFHd2KyScCYRrFSJ50tKEoXv2bVCG4HcPU80GGWiFabAvG77FekpGgF1h@[127.0.0.1]) by servername.hostname.com\n\t"
+ "with esmtp id 1NGTS9-2C0sqG0; Fri, 4 Dec 2009 09:23:49 +0100"
+ );
+
+ VASSERT_EQ(
+ "received.long",
+ "from User\r\n (Ee9GMqZQ8t7IQwftfAFHd2KyScCYRrFSJ50tKEoXv2bVCG4HcPU80GGWiFabAvG77FekpGgF1h@[127.0.0.1])\r\n by servername.hostname.com with esmtp id 1NGTS9-2C0sqG0; Fri, 4 Dec 2009\r\n 09:23:49 +0100",
+ r.generate(78)
+ );
+ }
+
+ void testBugFix20110511() {
+
+ /*
+
+ Using the latest version of vmime (0.9.1), encoding the following string: Jean
+ Gwenaël Dutourd will result in:
+ Jean =?utf-8?Q?Gwena=C3=ABl_?= Dutourd
+ However, decoding this will result in Jean Gwenaël Dutourd (notice two spaces
+ between the last 2 words). The encoder adds a _ after the second word, but
+ since the last word is not encoded, the space between them is not ignored, and
+ is decoded into an additional space.
+
+ See: http://sourceforge.net/projects/vmime/forums/forum/237357/topic/4531365
+
+ */
+
+ const std::string DECODED_TEXT = "Jean Gwenaël Dutourd";
+ const std::string ENCODED_TEXT = "Jean =?utf-8?Q?Gwena=C3=ABl?= Dutourd";
+
+ // Encode
+ VASSERT_EQ(
+ "encode",
+ ENCODED_TEXT,
+ vmime::text::newFromString(DECODED_TEXT, vmime::charset("utf-8"))->generate()
+ );
+
+ // Decode
+ vmime::text t;
+ t.parse(ENCODED_TEXT);
+
+ // -- words
+ std::ostringstream oss; oss << t;
+ VASSERT_EQ(
+ "decode1",
+ "[text: [[word: charset=us-ascii, buffer=Jean ],"
+ "[word: charset=utf-8, buffer=Gwenaël],"
+ "[word: charset=us-ascii, buffer= Dutourd]]]",
+ oss.str()
+ );
+
+ // -- getWholeBuffer
+ VASSERT_EQ("decode2", DECODED_TEXT, t.getWholeBuffer());
+ }
+
+ void testInternationalizedEmail_specialChars() {
+
+ vmime::generationContext ctx(vmime::generationContext::getDefaultContext());
+ ctx.setInternationalizedEmailSupport(true);
+
+ vmime::generationContext::switcher <vmime::generationContext> contextSwitcher(ctx);
+
+ // Special sequence/chars should still be encoded
+ VASSERT_EQ(
+ "1",
+ "=?us-ascii?Q?Test=3D=3Frfc2047_sequence?=",
+ vmime::word("Test=?rfc2047 sequence", vmime::charset("us-ascii")).generate()
+ );
+
+ VASSERT_EQ(
+ "2",
+ "=?us-ascii?Q?Line_One=0ALine_Two?=",
+ vmime::word("Line One\nLine Two", vmime::charset("us-ascii")).generate()
+ );
+ }
+
+ void testInternationalizedEmail_UTF8() {
+
+ vmime::generationContext ctx(vmime::generationContext::getDefaultContext());
+ ctx.setInternationalizedEmailSupport(true);
+
+ vmime::generationContext::switcher <vmime::generationContext> contextSwitcher(ctx);
+
+ // Already UTF-8 encoded text should be left as is
+ VASSERT_EQ(
+ "1", "Achim Br\xc3\xa4ndt",
+ vmime::word("Achim Br\xc3\xa4ndt", vmime::charset("utf-8")).generate()
+ );
+ }
+
+ void testInternationalizedEmail_nonUTF8() {
+
+ vmime::generationContext ctx(vmime::generationContext::getDefaultContext());
+ ctx.setInternationalizedEmailSupport(true);
+
+ vmime::generationContext::switcher <vmime::generationContext> contextSwitcher(ctx);
+
+ // Non UTF-8 encoded text should first be converted to UTF-8
+ VASSERT_EQ(
+ "1", "Achim Br\xc3\xa4ndt",
+ vmime::word("Achim Br\xe4ndt", vmime::charset("iso-8859-1")).generate()
+ );
+ }
+
+ void testInternationalizedEmail_folding() {
+
+ vmime::generationContext ctx(vmime::generationContext::getDefaultContext());
+ ctx.setInternationalizedEmailSupport(true);
+
+ vmime::generationContext::switcher <vmime::generationContext> contextSwitcher(ctx);
+
+ // RFC-2047 encoding must be performed, as line folding is needed
+ vmime::word w1("01234567890123456789\xc3\xa0x012345678901234567890123456789"
+ "01234567890123456789\xc3\xa0x012345678901234567890123456789", vmime::charset("utf-8"));
+
+ VASSERT_EQ(
+ "1",
+ "=?utf-8?Q?01234567890123456789=C3=A0x01234567890?=\r\n"
+ " =?utf-8?Q?1234567890123456789012345678901234567?=\r\n"
+ " =?utf-8?Q?89=C3=A0x0123456789012345678901234567?=\r\n"
+ " =?utf-8?Q?89?=",
+ w1.generate(50)
+ );
+
+ // RFC-2047 encoding will not be forced, as words can be wrapped in a new line
+ vmime::word w2("bla bla bla This is some '\xc3\xa0\xc3\xa7' UTF-8 encoded text", vmime::charset("utf-8"));
+
+ VASSERT_EQ(
+ "2",
+ "bla bla bla This is\r\n"
+ " some '\xc3\xa0\xc3\xa7' UTF-8\r\n"
+ " encoded text",
+ w2.generate(20)
+ );
+ }
+
+ void testInternationalizedEmail_whitespace() {
+
+ // Sanity checks for running this test
+ {
+ vmime::text t;
+ t.parse("=?utf-8?Q?Adquisi=C3=B3n?= de Laptop y celular");
+
+ VASSERT_EQ("parse", "Adquisión de Laptop y celular", t.getWholeBuffer());
+ }
+
+ {
+ vmime::text t("Adquisi\xc3\xb3n de Laptop y celular", vmime::charset("UTF-8"));
+
+ VASSERT_EQ("generate", "=?UTF-8?Q?Adquisi=C3=B3n?= de Laptop y celular", t.generate());
+ }
+
+ // Ensure a whitespace is added between encoded words in intl email support enabled
+ {
+ vmime::text t;
+ t.parse("=?utf-8?Q?Adquisi=C3=B3n?= de Laptop y celular");
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter ossAdapter(oss);
+ vmime::generationContext gctx(vmime::generationContext::getDefaultContext());
+ gctx.setInternationalizedEmailSupport(true);
+ t.generate(gctx, ossAdapter);
+
+ VASSERT_EQ("generate", "Adquisi\xc3\xb3n de Laptop y celular", oss.str());
+ }
+
+ {
+ vmime::text t;
+ t.parse("=?utf-8?Q?Adquisi=C3=B3n?= de Laptop =?utf-8?Q?y?= celular");
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter ossAdapter(oss);
+ vmime::generationContext gctx(vmime::generationContext::getDefaultContext());
+ gctx.setInternationalizedEmailSupport(true);
+ t.generate(gctx, ossAdapter);
+
+ VASSERT_EQ("generate", "Adquisi\xc3\xb3n de Laptop y celular", oss.str());
+ }
+
+ {
+ vmime::text t;
+ t.parse("=?utf-8?Q?Adquisi=C3=B3n?= de Laptop =?utf-8?Q?y_celular?=");
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter ossAdapter(oss);
+ vmime::generationContext gctx(vmime::generationContext::getDefaultContext());
+ gctx.setInternationalizedEmailSupport(true);
+ t.generate(gctx, ossAdapter);
+
+ VASSERT_EQ("generate", "Adquisi\xc3\xb3n de Laptop y celular", oss.str());
+ }
+
+ // Ensure no whitespace is added with non-encoded words
+ {
+ vmime::text t;
+ t.parse("Laptop y celular");
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter ossAdapter(oss);
+ vmime::generationContext gctx(vmime::generationContext::getDefaultContext());
+ gctx.setInternationalizedEmailSupport(true);
+ t.generate(gctx, ossAdapter);
+
+ VASSERT_EQ("generate", "Laptop y celular", oss.str());
+ }
+
+ {
+ vmime::text t;
+ t.parse("=?utf-8?Q?Laptop_y_celular?=");
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter ossAdapter(oss);
+ vmime::generationContext gctx(vmime::generationContext::getDefaultContext());
+ gctx.setInternationalizedEmailSupport(true);
+ t.generate(gctx, ossAdapter);
+
+ VASSERT_EQ("generate", "Laptop y celular", oss.str());
+ }
+ }
+
+ void testWronglyPaddedB64Words() {
+
+ vmime::text outText;
+
+ vmime::text::decodeAndUnfold("=?utf-8?B?5Lit5?=\n =?utf-8?B?paH?=", &outText);
+
+ VASSERT_EQ(
+ "1",
+ "\xe4\xb8\xad\xe6\x96\x87",
+ outText.getConvertedText(vmime::charset("utf-8"))
+ );
+
+ vmime::text::decodeAndUnfold("=?utf-8?B?5Lit5p?=\n =?utf-8?B?aH?=", &outText);
+
+ VASSERT_EQ(
+ "2",
+ "\xe4\xb8\xad\xe6\x96\x87",
+ outText.getConvertedText(vmime::charset("utf-8"))
+ );
+
+ vmime::text::decodeAndUnfold("=?utf-8?B?5Lit5pa?=\n =?utf-8?B?H?=", &outText);
+
+ VASSERT_EQ(
+ "3",
+ "\xe4\xb8\xad\xe6\x96\x87",
+ outText.getConvertedText(vmime::charset("utf-8"))
+ );
+ }
+
+ // Ensure that words which encode a non-integral number of characters
+ // are correctly decoded.
+ void testFixBrokenWords() {
+
+ vmime::text outText;
+
+ vmime::charsetConverterOptions opts;
+ opts.silentlyReplaceInvalidSequences = false; // just to be sure that broken words are actually fixed
+
+ // Test case 1
+ vmime::text::decodeAndUnfold(
+ "=?utf-8?Q?Gwena=C3?="
+ "=?utf-8?Q?=ABl?=",
+ &outText
+ );
+
+ VASSERT_EQ("1.1", 1, outText.getWordCount());
+ VASSERT_EQ("1.2", "Gwena\xc3\xabl", outText.getWordAt(0)->getBuffer());
+ VASSERT_EQ("1.3", vmime::charset("utf-8"), outText.getWordAt(0)->getCharset());
+
+ // Test case 2
+ vmime::text::decodeAndUnfold(
+ "=?utf-8?B?5Lit6Yu85qmf5qKw6JGj5LqL5pyDMTAz5bm056ysMDXlsYbn?="
+ "=?utf-8?B?rKwwN+asoeitsOeoiw==?=",
+ &outText
+ );
+
+ VASSERT_EQ("2.1", 1, outText.getWordCount());
+ VASSERT_EQ("2.2", "\xe4\xb8\xad\xe9\x8b\xbc\xe6\xa9\x9f\xe6\xa2\xb0"
+ "\xe8\x91\xa3\xe4\xba\x8b\xe6\x9c\x83\x31\x30\x33\xe5\xb9\xb4"
+ "\xe7\xac\xac\x30\x35\xe5\xb1\x86\xe7\xac\xac\x30\x37\xe6\xac"
+ "\xa1\xe8\xad\xb0\xe7\xa8\x8b", outText.getWordAt(0)->getBuffer());
+ VASSERT_EQ("2.3", vmime::charset("utf-8"), outText.getWordAt(0)->getCharset());
+
+ // Test case 3 (a character spanning over 3 words: 'を' = E3 82 92)
+ vmime::text::decodeAndUnfold(
+ "=?utf-8?Q?abc=E3?="
+ "=?utf-8?Q?=82?="
+ "=?utf-8?Q?=92xyz?=",
+ &outText
+ );
+
+ VASSERT_EQ("3.1", 1, outText.getWordCount());
+ VASSERT_EQ("3.2", "abc\xe3\x82\x92xyz", outText.getWordAt(0)->getBuffer());
+ VASSERT_EQ("3.3", vmime::charset("utf-8"), outText.getWordAt(0)->getCharset());
+
+ // Test case 4 (remains invalid)
+ vmime::text::decodeAndUnfold(
+ "=?utf-8?Q?abc=E3?="
+ "=?utf-8?Q?=82?="
+ "=?utf-8?Q?xy?="
+ "=?utf-8?Q?z?=",
+ &outText
+ );
+
+ VASSERT_EQ("4.1", 2, outText.getWordCount());
+ VASSERT_EQ("4.2", "abc", outText.getWordAt(0)->getBuffer());
+ VASSERT_EQ("4.3", vmime::charset("utf-8"), outText.getWordAt(0)->getCharset());
+ VASSERT_EQ("4.4", "\xe3\x82xyz", outText.getWordAt(1)->getBuffer());
+ VASSERT_EQ("4.5", vmime::charset("utf-8"), outText.getWordAt(1)->getCharset());
+
+ // Test case 5 (remains partially invalid)
+ vmime::text::decodeAndUnfold(
+ "=?utf-8?Q?abc=E3?="
+ "=?utf-8?Q?=82?="
+ "=?utf-8?Q?\x92xy?="
+ "=?utf-8?Q?z\xc3?=",
+ &outText
+ );
+
+ VASSERT_EQ("5.1", 2, outText.getWordCount());
+ VASSERT_EQ("5.2", "abc\xe3\x82\x92xyz", outText.getWordAt(0)->getBuffer());
+ VASSERT_EQ("5.3", vmime::charset("utf-8"), outText.getWordAt(0)->getCharset());
+ VASSERT_EQ("5.4", "\xc3", outText.getWordAt(1)->getBuffer());
+ VASSERT_EQ("5.5", vmime::charset("utf-8"), outText.getWordAt(1)->getCharset());
+ }
+
+ void testUnknownCharset() {
+
+ vmime::text t;
+ vmime::text::decodeAndUnfold("=?gb2312?B?wdaRY8PA?=", &t);
+
+ VASSERT_EQ("1.1", 1, t.getWordCount());
+ VASSERT_EQ("1.2", "\xc1\xd6\x91\x63\xc3\xc0", t.getWordAt(0)->getBuffer());
+ VASSERT_EQ("1.3", vmime::charset("gb2312"), t.getWordAt(0)->getCharset());
+
+
+
+ vmime::parsingContext ctx;
+
+ const vmime::string hfieldBuffer = "From: '=?gb2312?B?wdaRY8PA?=' <a.b@c.de>";
+
+ vmime::shared_ptr <vmime::headerField> hfield =
+ vmime::headerField::parseNext(ctx, hfieldBuffer, 0, hfieldBuffer.size());
+
+ vmime::shared_ptr <vmime::mailbox> hvalue =
+ hfield->getValue <vmime::mailbox>();
+
+ VASSERT_EQ("2.1", 3, hvalue->getName().getWordCount());
+ VASSERT_EQ("2.2", "'", hvalue->getName().getWordAt(0)->getBuffer());
+ VASSERT_EQ("2.3", vmime::charset("us-ascii"), hvalue->getName().getWordAt(0)->getCharset());
+ VASSERT_EQ("2.4", "\xc1\xd6\x91\x63\xc3\xc0", hvalue->getName().getWordAt(1)->getBuffer());
+ VASSERT_EQ("2.5", vmime::charset("gb2312"), hvalue->getName().getWordAt(1)->getCharset());
+ VASSERT_EQ("2.6", "'", hvalue->getName().getWordAt(2)->getBuffer());
+ VASSERT_EQ("2.7", vmime::charset("us-ascii"), hvalue->getName().getWordAt(2)->getCharset());
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/parser/wordEncoderTest.cpp b/vmime-master/tests/parser/wordEncoderTest.cpp
new file mode 100644
index 0000000..08d34aa
--- /dev/null
+++ b/vmime-master/tests/parser/wordEncoderTest.cpp
@@ -0,0 +1,174 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/wordEncoder.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(wordEncoderTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testGetNextChunk)
+ VMIME_TEST(testGetNextChunk_integral)
+ VMIME_TEST(testIsEncodingNeeded_ascii)
+ VMIME_TEST(testIsEncodingNeeded_withLanguage)
+ VMIME_TEST(testIsEncodingNeeded_specialChars)
+ VMIME_TEST(testGuessBestEncoding_QP)
+ VMIME_TEST(testGuessBestEncoding_B64)
+ VMIME_TEST(testEncodeQP_RFC2047)
+ VMIME_TEST_LIST_END
+
+
+ void testGetNextChunk() {
+
+ // An integral number of characters should be encoded
+ vmime::wordEncoder we(
+ "bufferfoobarbaz",
+ vmime::charset("utf-8"),
+ vmime::wordEncoder::ENCODING_AUTO
+ );
+
+ VASSERT_EQ("1", "buffer", we.getNextChunk(6));
+ VASSERT_EQ("2", "foo", we.getNextChunk(3));
+ VASSERT_EQ("3", "barbaz", we.getNextChunk(10));
+ }
+
+ void testGetNextChunk_integral() {
+
+ // An integral number of characters should be encoded
+ vmime::wordEncoder we(
+ "buffer\xc3\xa0plop",
+ vmime::charset("utf-8"),
+ vmime::wordEncoder::ENCODING_AUTO
+ );
+
+ VASSERT_EQ("1", "buffer=C3=A0", we.getNextChunk(7));
+ VASSERT_EQ("2", "plop", we.getNextChunk(10));
+ }
+
+ void testIsEncodingNeeded_ascii() {
+
+ vmime::generationContext ctx(vmime::generationContext::getDefaultContext());
+ ctx.setInternationalizedEmailSupport(false);
+
+ VASSERT_FALSE(
+ "ascii",
+ vmime::wordEncoder::isEncodingNeeded(
+ ctx, "ASCII-only buffer", vmime::charset("utf-8"), ""
+ )
+ );
+
+ VASSERT_TRUE(
+ "non-ascii",
+ vmime::wordEncoder::isEncodingNeeded(
+ ctx, "Buffer with some UTF-8 '\xc3\xa0'", vmime::charset("utf-8"), ""
+ )
+ );
+ }
+
+ void testIsEncodingNeeded_withLanguage() {
+
+ VASSERT_TRUE(
+ "ascii",
+ vmime::wordEncoder::isEncodingNeeded(
+ vmime::generationContext::getDefaultContext(),
+ "ASCII-only buffer",
+ vmime::charset("utf-8"),
+ "en"
+ )
+ );
+ }
+
+ void testIsEncodingNeeded_specialChars() {
+
+ VASSERT_TRUE(
+ "rfc2047",
+ vmime::wordEncoder::isEncodingNeeded(
+ vmime::generationContext::getDefaultContext(),
+ "foo bar =? foo bar",
+ vmime::charset("us-ascii"),
+ ""
+ )
+ );
+
+ VASSERT_TRUE(
+ "new line 1",
+ vmime::wordEncoder::isEncodingNeeded(
+ vmime::generationContext::getDefaultContext(),
+ "foo bar \n foo bar",
+ vmime::charset("us-ascii"),
+ ""
+ )
+ );
+
+ VASSERT_TRUE(
+ "new line 2",
+ vmime::wordEncoder::isEncodingNeeded(
+ vmime::generationContext::getDefaultContext(),
+ "foo bar \r foo bar",
+ vmime::charset("us-ascii"),
+ ""
+ )
+ );
+ }
+
+ void testGuessBestEncoding_QP() {
+
+ VASSERT_EQ(
+ "1",
+ vmime::wordEncoder::ENCODING_QP,
+ vmime::wordEncoder::guessBestEncoding("ASCII only buffer", vmime::charset("us-ascii"))
+ );
+ }
+
+ void testGuessBestEncoding_B64() {
+
+ // >= 40% non-ASCII => Base64...
+ VASSERT_EQ(
+ "1",
+ vmime::wordEncoder::ENCODING_B64,
+ vmime::wordEncoder::guessBestEncoding("xxxxx\xc3\xa0\xc3\xa0", vmime::charset("utf-8"))
+ );
+
+ // ...else Quoted-Printable
+ VASSERT_EQ(
+ "2",
+ vmime::wordEncoder::ENCODING_QP,
+ vmime::wordEncoder::guessBestEncoding("xxxxxx\xc3\xa0\xc3\xa0", vmime::charset("utf-8"))
+ );
+ }
+
+ void testEncodeQP_RFC2047() {
+
+ // When Quoted-Printable is used, it should be RFC-2047 QP encoding
+ vmime::wordEncoder we(
+ "buffer\xc3\xa0 foo_bar",
+ vmime::charset("utf-8"),
+ vmime::wordEncoder::ENCODING_AUTO
+ );
+
+ VASSERT_EQ("1", "buffer=C3=A0_foo=5Fbar", we.getNextChunk(100));
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/security/digest/md5Test.cpp b/vmime-master/tests/security/digest/md5Test.cpp
new file mode 100644
index 0000000..ca6d3d4
--- /dev/null
+++ b/vmime-master/tests/security/digest/md5Test.cpp
@@ -0,0 +1,228 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/security/digest/messageDigestFactory.hpp"
+
+
+#define INIT_DIGEST(var, algo) \
+ vmime::shared_ptr <vmime::security::digest::messageDigest> var = \
+ vmime::security::digest::messageDigestFactory::getInstance()->create(algo)
+
+
+
+VMIME_TEST_SUITE_BEGIN(md5Test)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testRFC1321_1)
+ VMIME_TEST(testRFC1321_2)
+ VMIME_TEST(testRFC1321_3)
+ VMIME_TEST(testRFC1321_4)
+ VMIME_TEST(testRFC1321_5)
+ VMIME_TEST(testRFC1321_6)
+ VMIME_TEST(testRFC1321_7)
+ VMIME_TEST(testUpdate1)
+ VMIME_TEST(testUpdate2)
+ VMIME_TEST(testUpdate3)
+ VMIME_TEST(testUpdate4)
+ VMIME_TEST(testUpdate5)
+ VMIME_TEST(testUpdate6)
+ VMIME_TEST(testUpdate7)
+ VMIME_TEST_LIST_END
+
+
+ // Test suites from RFC #1321
+
+ void testRFC1321_1() {
+
+ INIT_DIGEST(algo, "md5");
+
+ algo->update("");
+ algo->finalize();
+
+ VASSERT_EQ("*", "d41d8cd98f00b204e9800998ecf8427e", algo->getHexDigest());
+ }
+
+ void testRFC1321_2() {
+
+ INIT_DIGEST(algo, "md5");
+
+ algo->update("a");
+ algo->finalize();
+
+ VASSERT_EQ("*", "0cc175b9c0f1b6a831c399e269772661", algo->getHexDigest());
+ }
+
+ void testRFC1321_3() {
+
+ INIT_DIGEST(algo, "md5");
+
+ algo->update("abc");
+ algo->finalize();
+
+ VASSERT_EQ("*", "900150983cd24fb0d6963f7d28e17f72", algo->getHexDigest());
+ }
+
+ void testRFC1321_4() {
+
+ INIT_DIGEST(algo, "md5");
+
+ algo->update("message digest");
+ algo->finalize();
+
+ VASSERT_EQ("*", "f96b697d7cb7938d525a2f31aaf161d0", algo->getHexDigest());
+ }
+
+ void testRFC1321_5() {
+
+ INIT_DIGEST(algo, "md5");
+
+ algo->update("abcdefghijklmnopqrstuvwxyz");
+ algo->finalize();
+
+ VASSERT_EQ("*", "c3fcd3d76192e4007dfb496cca67e13b", algo->getHexDigest());
+ }
+
+ void testRFC1321_6() {
+
+ INIT_DIGEST(algo, "md5");
+
+ algo->update("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789");
+ algo->finalize();
+
+ VASSERT_EQ("*", "d174ab98d277d9f5a5611c2c9f419d9f", algo->getHexDigest());
+ }
+
+ void testRFC1321_7() {
+
+ INIT_DIGEST(algo, "md5");
+
+ algo->update("12345678901234567890123456789012345678901234567890123456789012345678901234567890");
+ algo->finalize();
+
+ VASSERT_EQ("*", "57edf4a22be3c955ac49da2e2107b67a", algo->getHexDigest());
+ }
+
+ void testReset() {
+
+ INIT_DIGEST(algo, "md5");
+
+ algo->update("foo");
+ algo->update("bar");
+ algo->finalize();
+
+ algo->reset();
+ algo->finalize();
+
+ VASSERT_EQ("*", "d41d8cd98f00b204e9800998ecf8427e", algo->getHexDigest()); // empty string
+ }
+
+ void testUpdate1() {
+
+ INIT_DIGEST(algo, "md5");
+
+ algo->update("");
+ algo->finalize();
+
+ VASSERT_EQ("*", "d41d8cd98f00b204e9800998ecf8427e", algo->getHexDigest());
+ }
+
+ void testUpdate2() {
+
+ INIT_DIGEST(algo, "md5");
+
+ algo->update("a");
+ algo->update("");
+ algo->finalize();
+
+ VASSERT_EQ("2", "0cc175b9c0f1b6a831c399e269772661", algo->getHexDigest());
+ }
+
+ void testUpdate3() {
+
+ INIT_DIGEST(algo, "md5");
+
+ algo->update("ab");
+ algo->update("c");
+ algo->finalize();
+
+ VASSERT_EQ("3", "900150983cd24fb0d6963f7d28e17f72", algo->getHexDigest());
+ }
+
+ void testUpdate4() {
+
+ INIT_DIGEST(algo, "md5");
+
+ algo->update("");
+ algo->update("message");
+ algo->update(" ");
+ algo->update("digest");
+ algo->finalize();
+
+ VASSERT_EQ("4", "f96b697d7cb7938d525a2f31aaf161d0", algo->getHexDigest());
+ }
+
+ void testUpdate5() {
+
+ INIT_DIGEST(algo, "md5");
+
+ algo->update("abcd");
+ algo->update("");
+ algo->update("efghijklmnop");
+ algo->update("qrstuvwx");
+ algo->update("yz");
+ algo->finalize();
+
+ VASSERT_EQ("5", "c3fcd3d76192e4007dfb496cca67e13b", algo->getHexDigest());
+ }
+
+ void testUpdate6() {
+
+ INIT_DIGEST(algo, "md5");
+
+ algo->update("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz012");
+ algo->update("345");
+ algo->update("6");
+ algo->update("7");
+ algo->update("89");
+ algo->finalize();
+
+ VASSERT_EQ("6", "d174ab98d277d9f5a5611c2c9f419d9f", algo->getHexDigest());
+ }
+
+ void testUpdate7() {
+
+ INIT_DIGEST(algo, "md5");
+
+ algo->update("12345678901234567890123456789");
+ algo->update("01234567890123456789012345678901");
+ algo->update("234567890123456789");
+ algo->update("");
+ algo->update("0");
+ algo->finalize();
+
+ VASSERT_EQ("7", "57edf4a22be3c955ac49da2e2107b67a", algo->getHexDigest());
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/security/digest/sha1Test.cpp b/vmime-master/tests/security/digest/sha1Test.cpp
new file mode 100644
index 0000000..cbcd1cf
--- /dev/null
+++ b/vmime-master/tests/security/digest/sha1Test.cpp
@@ -0,0 +1,119 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/security/digest/messageDigestFactory.hpp"
+
+
+#define INIT_DIGEST(var, algo) \
+ vmime::shared_ptr <vmime::security::digest::messageDigest> var = \
+ vmime::security::digest::messageDigestFactory::getInstance()->create(algo)
+
+
+
+VMIME_TEST_SUITE_BEGIN(sha1Test)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testFIPS180_1)
+ VMIME_TEST(testFIPS180_2)
+ VMIME_TEST(testFIPS180_3)
+ VMIME_TEST(testReset)
+ VMIME_TEST(testUpdate)
+ VMIME_TEST_LIST_END
+
+
+ // Test suites from FIPS PUB 180-1
+ // http://www.itl.nist.gov/fipspubs/fip180-1.htm
+
+ void testFIPS180_1() {
+
+ INIT_DIGEST(algo, "sha1");
+
+ algo->update("abc");
+ algo->finalize();
+
+ VASSERT_EQ("*", "a9993e364706816aba3e25717850c26c9cd0d89d", algo->getHexDigest());
+ }
+
+ void testFIPS180_2() {
+
+ INIT_DIGEST(algo, "sha1");
+
+ algo->update("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq");
+ algo->finalize();
+
+ VASSERT_EQ("*", "84983e441c3bd26ebaae4aa1f95129e5e54670f1", algo->getHexDigest());
+ }
+
+ void testFIPS180_3() {
+
+ INIT_DIGEST(algo, "sha1");
+
+ vmime::byte_t* buffer = new vmime::byte_t[1000000];
+
+ for (int i = 0 ; i < 1000000 ; ++i) {
+ buffer[i] = 'a';
+ }
+
+ algo->update(buffer, 1000000);
+ algo->finalize();
+
+ delete [] buffer;
+
+ VASSERT_EQ("*", "34aa973cd4c4daa4f61eeb2bdbad27316534016f", algo->getHexDigest());
+ }
+
+ void testReset() {
+
+ INIT_DIGEST(algo, "sha1");
+
+ algo->update("ab");
+ algo->update("c");
+ algo->finalize();
+
+ algo->reset();
+ algo->finalize();
+
+ VASSERT_EQ("*", "da39a3ee5e6b4b0d3255bfef95601890afd80709", algo->getHexDigest()); // empty string
+ }
+
+ void testUpdate() {
+
+ INIT_DIGEST(algo, "sha1");
+
+ algo->update("a");
+ algo->update("");
+ algo->update("bcdbcdecdefd");
+ algo->update("efgef");
+ algo->update("ghfghighijhijkijkljklmklmnlmnomnopnop");
+ algo->update("");
+ algo->update("q");
+ algo->update("");
+ algo->update("");
+ algo->finalize();
+
+ VASSERT_EQ("*", "84983e441c3bd26ebaae4aa1f95129e5e54670f1", algo->getHexDigest());
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/testRunner.cpp b/vmime-master/tests/testRunner.cpp
new file mode 100644
index 0000000..f1f13b2
--- /dev/null
+++ b/vmime-master/tests/testRunner.cpp
@@ -0,0 +1,305 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include <sys/time.h>
+#include <time.h>
+
+#include <iostream>
+#include <vector>
+#include <algorithm>
+#include <memory>
+
+#include <cppunit/XmlOutputter.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+#include <cppunit/ui/text/TestRunner.h>
+#include <cppunit/TestListener.h>
+#include <cppunit/TestResult.h>
+#include <cppunit/TestResultCollector.h>
+#include <cppunit/TestFailure.h>
+#include <cppunit/SourceLine.h>
+#include <cppunit/Exception.h>
+#include <cppunit/tools/XmlDocument.h>
+#include <cppunit/tools/XmlElement.h>
+
+#include "vmime/vmime.hpp"
+#include "vmime/platforms/posix/posixHandler.hpp"
+
+
+class Clock {
+
+public:
+
+ void reset() {
+
+ struct timezone tz;
+
+ gettimeofday(&m_start, &tz);
+ }
+
+ double getDuration() const {
+
+ struct timeval tv;
+ struct timezone tz;
+
+ gettimeofday(&tv, &tz);
+
+ return static_cast <double>(tv.tv_sec - m_start.tv_sec)
+ + static_cast <double>(tv.tv_usec - m_start.tv_usec) / 1000000.0;
+ }
+
+private:
+
+ struct timeval m_start;
+};
+
+
+class XmlTestListener : public CppUnit::TestListener {
+
+public:
+
+ XmlTestListener()
+ : m_doc("utf-8"),
+ m_testElt(NULL) {
+
+ m_doc.setRootElement(new CppUnit::XmlElement("TestRun"));
+ }
+
+ void startTest(CppUnit::Test* test) {
+
+ m_testElt = new CppUnit::XmlElement("Test");
+ m_suiteElt.back()->addElement(m_testElt);
+
+ m_testElt->addElement(new CppUnit::XmlElement("Name", test->getName()));
+
+ m_chrono.reset();
+ }
+
+ void addFailure(const CppUnit::TestFailure& failure) {
+
+ CppUnit::XmlElement* failElt = new CppUnit::XmlElement("Failure");
+ m_testElt->addElement(failElt);
+
+ failElt->addElement(
+ new CppUnit::XmlElement("FailureType", failure.isError() ? "Error" : "Assertion")
+ );
+
+ if (failure.sourceLine().isValid()) {
+
+ CppUnit::XmlElement* locElt = new CppUnit::XmlElement("Location");
+ failElt->addElement(locElt);
+
+ locElt->addElement(new CppUnit::XmlElement("File", failure.sourceLine().fileName()));
+ locElt->addElement(new CppUnit::XmlElement("Line", failure.sourceLine().lineNumber()));
+ }
+
+ CppUnit::XmlElement* exElt = new CppUnit::XmlElement("Exception");
+ failElt->addElement(exElt);
+
+ exElt->addElement(new CppUnit::XmlElement("Message", failure.thrownException()->what()));
+ }
+
+ void endTest(CppUnit::Test* /* test */) {
+
+ std::ostringstream ossTime;
+ ossTime << (m_chrono.getDuration() * 1000.0);
+
+ m_testElt->addElement(new CppUnit::XmlElement("Time", ossTime.str()));
+
+ m_testElt = NULL;
+ }
+
+ void startSuite(CppUnit::Test* suite) {
+
+ if (suite->getName() == "All Tests") {
+ return;
+ }
+
+ CppUnit::XmlElement* suiteElt = new CppUnit::XmlElement("Suite");
+
+ if (m_suiteElt.size() == 0) {
+ m_doc.rootElement().addElement(suiteElt);
+ } else {
+ m_suiteElt.back()->addElement(suiteElt);
+ }
+
+ m_suiteElt.push_back(suiteElt);
+
+ suiteElt->addElement(new CppUnit::XmlElement("Name", suite->getName()));
+ }
+
+ void endSuite(CppUnit::Test* /* suite */) {
+
+ if (m_suiteElt.size()) {
+ m_suiteElt.pop_back();
+ }
+ }
+
+ void startTestRun(CppUnit::Test* /* test */, CppUnit::TestResult* /* eventManager */) {
+
+ }
+
+ void endTestRun(CppUnit::Test* /* test */, CppUnit::TestResult* /* eventManager */) {
+
+ }
+
+ void output(std::ostream& os) {
+
+ os << m_doc.toString();
+ }
+
+private:
+
+ Clock m_chrono;
+
+ CppUnit::XmlDocument m_doc;
+ std::vector <CppUnit::XmlElement*> m_suiteElt;
+ CppUnit::XmlElement* m_testElt;
+};
+
+
+
+// see testUtils.hpp
+
+std::vector <std::string>& getTestModules() {
+
+ static std::vector <std::string> allModules;
+ return allModules;
+}
+
+
+void registerTestModule(const char* name_) {
+
+ std::vector <std::string>& testModules = getTestModules();
+ std::string name(name_);
+
+ if (std::find(testModules.begin(), testModules.end(), name) == testModules.end()) {
+ testModules.push_back(name);
+ }
+}
+
+
+const std::string getNormalizedPath(const std::string& path) {
+
+ std::string res = path;
+
+ for (std::size_t i = 0, n = res.length() ; i < n ; ++i) {
+
+ if (res[i] == '\\') {
+ res[i] = '/';
+ }
+ }
+
+ return res;
+}
+
+
+const std::string getFileNameFromPath(const std::string& path) {
+
+ const std::size_t pos = path.find_last_of('/');
+
+ if (pos == std::string::npos) {
+ return "";
+ }
+
+ return path.substr(pos + 1);
+}
+
+
+static char g_moduleNameBuffer[2048];
+
+
+const char* getTestModuleNameFromSourceFile(const char *path_) {
+
+ static const std::string testRunnerPath(getNormalizedPath(__FILE__));
+ static const std::string testRunnerFileName(getFileNameFromPath(testRunnerPath));
+
+ const std::string path = getNormalizedPath(path_);
+
+ // "/path/to/testRunner.cpp" --> "/path/to/"
+ const std::string basePath
+ (testRunnerPath.begin(), testRunnerPath.end() - testRunnerFileName.length());
+
+ // "/path/to/module/testFile.cpp" --> "module/testFile.cpp"
+ const std::string testFileName(getFileNameFromPath(path));
+ const std::string testPath(path.begin() + basePath.length(), path.end());
+
+ // "module/testFile.cpp" --> "module"
+ const std::string moduleName(testPath.substr(0, testPath.length() - testFileName.length() - 1));
+ std::copy(moduleName.begin(), moduleName.end(), g_moduleNameBuffer);
+ g_moduleNameBuffer[moduleName.length()] = 0;
+
+ return g_moduleNameBuffer;
+}
+
+
+int main(int argc, char* argv[]) {
+
+ // Parse arguments
+ bool xmlOutput = false;
+
+ for (int c = 1 ; c < argc ; ++c) {
+
+ const std::string arg = argv[c];
+
+ if (arg == "--xml") {
+ xmlOutput = true;
+ }
+ }
+
+ // Run the tests
+ if (xmlOutput) {
+
+ // Get the test suites from the registry and add them to the list of tests to run
+ CppUnit::TestRunner runner;
+
+ for (unsigned int i = 0 ; i < getTestModules().size() ; ++i) {
+
+ runner.addTest(
+ CppUnit::TestFactoryRegistry::getRegistry(getTestModules()[i]).makeTest()
+ );
+ }
+
+ XmlTestListener xmlListener;
+
+ CppUnit::TestResult controller;
+ controller.addListener(&xmlListener);
+
+ CppUnit::TestResultCollector result;
+ controller.addListener(&result);
+
+ runner.run(controller);
+
+ xmlListener.output(std::cout);
+
+ // Return error code 1 if a test failed
+ return result.wasSuccessful() ? 0 : 1;
+
+ } else {
+
+ // Get the top level suite from the registry
+ CppUnit::TextUi::TestRunner runner;
+ runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest());
+
+ return runner.run() ? 0 : 1;
+ }
+}
diff --git a/vmime-master/tests/testUtils.cpp b/vmime-master/tests/testUtils.cpp
new file mode 100644
index 0000000..ae75547
--- /dev/null
+++ b/vmime-master/tests/testUtils.cpp
@@ -0,0 +1,404 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "testUtils.hpp"
+
+#include "vmime/utility/stringUtils.hpp"
+
+#include <cstring>
+#include <iostream>
+
+
+// Enable to output socket send/receive on standard output
+#define DEBUG_SOCKET_IN_OUT 0
+
+
+
+// testSocket
+
+void testSocket::connect(const vmime::string& address, const vmime::port_t port) {
+
+ m_address = address;
+ m_port = port;
+ m_connected = true;
+
+ onConnected();
+}
+
+
+void testSocket::disconnect() {
+
+ m_address.clear();
+ m_port = 0;
+ m_connected = false;
+}
+
+
+bool testSocket::isConnected() const {
+
+ return m_connected;
+}
+
+
+vmime::size_t testSocket::getBlockSize() const {
+
+ return 16384;
+}
+
+
+unsigned int testSocket::getStatus() const {
+
+ return 0;
+}
+
+
+const vmime::string testSocket::getPeerName() const {
+
+ return "test.vmime.org";
+}
+
+
+const vmime::string testSocket::getPeerAddress() const {
+
+ return "127.0.0.1";
+}
+
+
+vmime::shared_ptr <vmime::net::timeoutHandler> testSocket::getTimeoutHandler() {
+
+ return vmime::null;
+}
+
+
+void testSocket::setTracer(const vmime::shared_ptr <vmime::net::tracer>& /* tracer */) {
+
+}
+
+
+vmime::shared_ptr <vmime::net::tracer> testSocket::getTracer() {
+
+ return vmime::null;
+}
+
+
+bool testSocket::waitForRead(const int /* msecs */) {
+
+ return true;
+}
+
+
+bool testSocket::waitForWrite(const int /* msecs */) {
+
+ return true;
+}
+
+
+void testSocket::receive(vmime::string& buffer) {
+
+ buffer = m_inBuffer;
+ m_inBuffer.clear();
+}
+
+
+void testSocket::send(const vmime::string& buffer) {
+
+ m_outBuffer += buffer;
+
+ onDataReceived();
+}
+
+
+void testSocket::send(const char* str) {
+
+ sendRaw(reinterpret_cast <const vmime::byte_t*>(str), strlen(str));
+}
+
+
+vmime::size_t testSocket::receiveRaw(vmime::byte_t* buffer, const size_t count) {
+
+ const size_t n = std::min(count, static_cast <size_t>(m_inBuffer.size()));
+
+ std::copy(m_inBuffer.begin(), m_inBuffer.begin() + n, buffer);
+ m_inBuffer.erase(m_inBuffer.begin(), m_inBuffer.begin() + n);
+
+ return n;
+}
+
+
+void testSocket::sendRaw(const vmime::byte_t* buffer, const size_t count) {
+
+ send(vmime::utility::stringUtils::makeStringFromBytes(buffer, count));
+}
+
+
+vmime::size_t testSocket::sendRawNonBlocking(const vmime::byte_t* buffer, const size_t count) {
+
+ sendRaw(buffer, count);
+ return count;
+}
+
+
+void testSocket::localSend(const vmime::string& buffer) {
+
+ m_inBuffer += buffer;
+
+#if DEBUG_SOCKET_IN_OUT
+ std::cout << "> " << vmime::utility::stringUtils::trim(buffer) << std::endl;
+#endif // DEBUG_SOCKET_IN_OUT
+
+}
+
+
+void testSocket::localReceive(vmime::string& buffer) {
+
+ buffer = m_outBuffer;
+ m_outBuffer.clear();
+}
+
+
+bool testSocket::localReceiveLine(vmime::string& line) {
+
+ vmime::size_t eol;
+
+ if ((eol = m_outBuffer.find('\n')) != vmime::string::npos) {
+
+ line = vmime::string(m_outBuffer.begin(), m_outBuffer.begin() + eol);
+
+ if (!line.empty() && line[line.length() - 1] == '\r') {
+ line.erase(line.end() - 1, line.end());
+ }
+
+ m_outBuffer.erase(m_outBuffer.begin(), m_outBuffer.begin() + eol + 1);
+
+ return true;
+ }
+
+ return false;
+}
+
+
+vmime::size_t testSocket::localReceiveRaw(vmime::byte_t* buffer, const size_t count) {
+
+ const size_t received = std::min(count, static_cast <size_t>(m_outBuffer.size()));
+
+ if (received != 0) {
+
+ if (buffer) {
+ std::copy(m_outBuffer.begin(), m_outBuffer.begin() + received, buffer);
+ }
+
+ m_outBuffer.erase(m_outBuffer.begin(), m_outBuffer.begin() + received);
+ }
+
+ return received;
+}
+
+
+void testSocket::onDataReceived() {
+
+ // Override
+}
+
+
+void testSocket::onConnected() {
+
+ // Override
+}
+
+
+// lineBasedTestSocket
+
+void lineBasedTestSocket::onDataReceived() {
+
+ vmime::string chunk;
+ localReceive(chunk);
+
+ m_buffer += chunk;
+
+ vmime::size_t eol;
+
+ while ((eol = m_buffer.find('\n')) != vmime::string::npos) {
+
+ vmime::string line(std::string(m_buffer.begin(), m_buffer.begin() + eol));
+
+ if (!line.empty() && line[line.length() - 1] == '\r') {
+ line.erase(line.end() - 1, line.end());
+ }
+
+#if DEBUG_SOCKET_IN_OUT
+ std::cout << "< " << vmime::utility::stringUtils::trim(line) << std::endl;
+#endif // DEBUG_SOCKET_IN_OUT
+
+ m_lines.push_back(line);
+ m_buffer.erase(m_buffer.begin(), m_buffer.begin() + eol + 1);
+ }
+
+ while (!m_lines.empty()) {
+ processCommand();
+ }
+}
+
+
+const vmime::string lineBasedTestSocket::getNextLine() {
+
+ const vmime::string line = m_lines.front();
+ m_lines.erase(m_lines.begin(), m_lines.begin() + 1);
+ return line;
+}
+
+
+bool lineBasedTestSocket::haveMoreLines() const {
+
+ return !m_lines.empty();
+}
+
+
+// testTimeoutHandler
+
+testTimeoutHandler::testTimeoutHandler(const unsigned long delay)
+ : m_delay(delay),
+ m_start(0) {
+
+}
+
+
+bool testTimeoutHandler::isTimeOut() {
+
+ return (vmime::platform::getHandler()->getUnixTime() - m_start) >= m_delay;
+}
+
+
+void testTimeoutHandler::resetTimeOut() {
+
+ m_start = vmime::platform::getHandler()->getUnixTime();
+}
+
+
+bool testTimeoutHandler::handleTimeOut() {
+
+ return false;
+}
+
+
+// testTimeoutHandlerFactory : public vmime::net::timeoutHandlerFactory
+
+vmime::shared_ptr <vmime::net::timeoutHandler> testTimeoutHandlerFactory::create() {
+
+ return vmime::make_shared <testTimeoutHandler>();
+}
+
+
+
+// Exception helper
+std::ostream& operator<<(std::ostream& os, const vmime::exception& e) {
+
+ os << "* vmime::exceptions::" << e.name() << std::endl;
+ os << " what = " << e.what() << std::endl;
+
+ // More information for special exceptions
+ if (dynamic_cast <const vmime::exceptions::command_error*>(&e)) {
+
+ const vmime::exceptions::command_error& cee =
+ dynamic_cast <const vmime::exceptions::command_error&>(e);
+
+ os << " command = " << cee.command() << std::endl;
+ os << " response = " << cee.response() << std::endl;
+ }
+
+ if (dynamic_cast <const vmime::exceptions::invalid_response*>(&e)) {
+
+ const vmime::exceptions::invalid_response& ir =
+ dynamic_cast <const vmime::exceptions::invalid_response&>(e);
+
+ os << " response = " << ir.response() << std::endl;
+ }
+
+ if (dynamic_cast <const vmime::exceptions::connection_greeting_error*>(&e)) {
+
+ const vmime::exceptions::connection_greeting_error& cgee =
+ dynamic_cast <const vmime::exceptions::connection_greeting_error&>(e);
+
+ os << " response = " << cgee.response() << std::endl;
+ }
+
+ if (dynamic_cast <const vmime::exceptions::authentication_error*>(&e)) {
+
+ const vmime::exceptions::authentication_error& aee =
+ dynamic_cast <const vmime::exceptions::authentication_error&>(e);
+
+ os << " response = " << aee.response() << std::endl;
+ }
+
+ if (dynamic_cast <const vmime::exceptions::filesystem_exception*>(&e)) {
+
+ const vmime::exceptions::filesystem_exception& fse =
+ dynamic_cast <const vmime::exceptions::filesystem_exception&>(e);
+
+ os << " path = " << vmime::platform::getHandler()->
+ getFileSystemFactory()->pathToString(fse.path()) << std::endl;
+ }
+
+ if (e.other()) {
+ os << *e.other();
+ }
+
+ return os;
+}
+
+
+const vmime::string toHex(const vmime::string str) {
+
+ static const char hexChars[] = "0123456789abcdef";
+
+ vmime::string res = "\n";
+
+ for (size_t i = 0 ; i < str.length() ; i += 16) {
+
+ size_t r = std::min(static_cast <size_t>(16), str.length() - i);
+
+ vmime::string hex;
+ vmime::string chr;
+
+ for (size_t j = 0 ; j < r ; ++j) {
+
+ const unsigned char c = str[i + j];
+
+ hex += hexChars[c / 16];
+ hex += hexChars[c % 16];
+ hex += " ";
+
+ if (c >= 32 && c <= 127)
+ chr += c;
+ else
+ chr += '.';
+ }
+
+ for (size_t j = r ; j < 16 ; ++j) {
+ hex += " ";
+ }
+
+ res += hex + " " + chr + "\n";
+ }
+
+ return res;
+}
diff --git a/vmime-master/tests/testUtils.hpp b/vmime-master/tests/testUtils.hpp
new file mode 100644
index 0000000..e6bf1ee
--- /dev/null
+++ b/vmime-master/tests/testUtils.hpp
@@ -0,0 +1,407 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include <ostream>
+#include <iostream>
+#include <sstream>
+#include <vector>
+#include <string>
+
+
+// VMime
+#include "vmime/vmime.hpp"
+
+
+// CppUnit
+#pragma GCC diagnostic ignored "-Wold-style-cast"
+#include <cppunit/TestAssert.h>
+#include <cppunit/extensions/HelperMacros.h>
+#pragma GCC diagnostic warning "-Wold-style-cast"
+
+#define VASSERT(msg, cond) \
+ CPPUNIT_ASSERT_MESSAGE(std::string(msg), cond)
+
+#define VASSERT_TRUE(msg, cond) \
+ VASSERT(msg, cond)
+#define VASSERT_FALSE(msg, cond) \
+ VASSERT(msg, !(cond))
+
+#define VASSERT_NOT_NULL(msg, cond) \
+ VASSERT(msg, cond != NULL)
+#define VASSERT_NULL(msg, cond) \
+ VASSERT(msg, cond == NULL)
+
+#define VASSERT_EQ(msg, expected, actual) \
+ CPPUNIT_ASSERT_EQUAL_MESSAGE(std::string(msg), expected, actual)
+#define VASSERT_NEQ(msg, expected, actual) \
+ CPPUNIT_ASSERT_MESSAGE(std::string(msg), (expected) != (actual))
+
+#define VASSERT_THROW(msg, expression, exceptionType) \
+ CPPUNIT_ASSERT_THROW(expression, exceptionType)
+#define VASSERT_NO_THROW(msg, expression) \
+ CPPUNIT_ASSERT_NO_THROW(expression)
+
+#define VMIME_TEST_SUITE_BEGIN(testSuiteName) \
+ class testSuiteName; \
+ typedef testSuiteName VMIME_TEST_SUITE; \
+ class testSuiteName : public CppUnit::TestFixture { public:
+#define VMIME_TEST_SUITE_END \
+ }; \
+ \
+ /*static CppUnit::AutoRegisterSuite <VMIME_TEST_SUITE>(autoRegisterRegistry1);*/ \
+ /*static CppUnit::AutoRegisterSuite <VMIME_TEST_SUITE>(autoRegisterRegistry2)(VMIME_TEST_SUITE_MODULE);*/ \
+ extern void registerTestModule(const char* name); \
+ extern const char* getTestModuleNameFromSourceFile(const char *path); \
+ template <typename T> \
+ struct AutoRegisterModule { \
+ AutoRegisterModule() { \
+ static const char* moduleName = getTestModuleNameFromSourceFile(__FILE__); \
+ static CppUnit::AutoRegisterSuite <VMIME_TEST_SUITE>(autoRegisterRegistry1); \
+ static CppUnit::AutoRegisterSuite <VMIME_TEST_SUITE>(autoRegisterRegistry2)(moduleName); \
+ registerTestModule(moduleName); \
+ } \
+ }; \
+ static AutoRegisterModule <VMIME_TEST_SUITE> autoRegisterModule;
+
+#define VMIME_TEST_LIST_BEGIN CPPUNIT_TEST_SUITE(VMIME_TEST_SUITE);
+#define VMIME_TEST_LIST_END CPPUNIT_TEST_SUITE_END(); public:
+#define VMIME_TEST(name) CPPUNIT_TEST(name);
+
+
+namespace CppUnit {
+
+ // Work-around for comparing 'std::string' against 'char*'
+ inline void assertEquals(
+ const char* expected,
+ const std::string actual,
+ SourceLine sourceLine,
+ const std::string &message
+ ) {
+
+ assertEquals(std::string(expected), actual, sourceLine, message);
+ }
+
+ template <typename X, typename Y>
+ void assertEquals(
+ const X expected,
+ const Y actual,
+ SourceLine sourceLine,
+ const std::string &message
+ ) {
+
+ assertEquals(static_cast <Y>(expected), actual, sourceLine, message);
+ }
+}
+
+
+namespace std {
+
+
+inline std::ostream& operator<<(std::ostream& os, const vmime::charset& ch) {
+
+ os << "[charset: " << ch.getName() << "]";
+ return os;
+}
+
+
+inline std::ostream& operator<<(std::ostream& os, const vmime::word& w) {
+
+ os << "[word: charset=" << w.getCharset().getName()
+ << ", buffer=" << w.getBuffer();
+
+ if (!w.getLanguage().empty()) {
+ os << ", lang=" << w.getLanguage();
+ }
+
+ os << "]";
+
+ return os;
+}
+
+
+inline std::ostream& operator<<(std::ostream& os, const vmime::text& txt) {
+
+ os << "[text: [";
+
+ for (size_t i = 0 ; i < txt.getWordCount() ; ++i) {
+
+ const vmime::word& w = *txt.getWordAt(i);
+
+ if (i != 0) {
+ os << ",";
+ }
+
+ os << w;
+ }
+
+ os << "]]";
+
+ return os;
+}
+
+
+inline std::ostream& operator<<(std::ostream& os, const vmime::emailAddress& email) {
+
+ os << email.generate();
+
+ return os;
+}
+
+
+inline std::ostream& operator<<(std::ostream& os, const vmime::mailbox& mbox) {
+
+ os << "[mailbox: name=" << mbox.getName() << ", email=" << mbox.getEmail() << "]";
+
+ return os;
+}
+
+
+inline std::ostream& operator<<(std::ostream& os, const vmime::mailboxGroup& group) {
+
+ os << "[mailbox-group: name=" << group.getName() << ", list=[";
+
+ for (size_t i = 0 ; i < group.getMailboxCount() ; ++i) {
+
+ if (i != 0) {
+ os << ",";
+ }
+
+ os << *group.getMailboxAt(i);
+ }
+
+ os << "]]";
+
+ return os;
+}
+
+
+inline std::ostream& operator<<(std::ostream& os, const vmime::addressList& list) {
+
+ os << "[address-list: [";
+
+ for (size_t i = 0 ; i < list.getAddressCount() ; ++i) {
+
+ const vmime::address& addr = *list.getAddressAt(i);
+
+ if (i != 0) {
+ os << ",";
+ }
+
+ if (addr.isGroup()) {
+
+ const vmime::mailboxGroup& group =
+ dynamic_cast <const vmime::mailboxGroup&>(addr);
+
+ os << group;
+
+ } else {
+
+ const vmime::mailbox& mbox =
+ dynamic_cast <const vmime::mailbox&>(addr);
+
+ os << mbox;
+ }
+ }
+
+ os << "]]";
+
+ return os;
+}
+
+
+inline std::ostream& operator<<(std::ostream& os, const vmime::datetime& d) {
+
+ os << "[datetime: " << d.getYear() << "/" << d.getMonth() << "/" << d.getDay();
+ os << " " << d.getHour() << ":" << d.getMinute() << ":" << d.getSecond();
+ os << " #" << d.getZone() << "]";
+
+ return os;
+}
+
+
+inline std::ostream& operator<<(std::ostream& os, const vmime::encoding& enc) {
+
+ os << enc.generate();
+
+ return os;
+}
+
+
+}
+
+
+
+// Used to test network features.
+//
+// This works like a local pipe: client reads and writes data using receive()
+// and send(). Server reads incoming data with localReceive() and sends data
+// to client with localSend().
+
+class testSocket : public vmime::net::socket {
+
+public:
+
+ void connect(const vmime::string& address, const vmime::port_t port);
+ void disconnect();
+
+ bool isConnected() const;
+
+ bool waitForWrite(const int msecs = 30000);
+ bool waitForRead(const int msecs = 30000);
+
+ void receive(vmime::string& buffer);
+ void send(const vmime::string& buffer);
+ void send(const char* str);
+
+ size_t receiveRaw(vmime::byte_t* buffer, const size_t count);
+ void sendRaw(const vmime::byte_t* buffer, const size_t count);
+ size_t sendRawNonBlocking(const vmime::byte_t* buffer, const size_t count);
+
+ size_t getBlockSize() const;
+
+ unsigned int getStatus() const;
+
+ const vmime::string getPeerName() const;
+ const vmime::string getPeerAddress() const;
+
+ vmime::shared_ptr <vmime::net::timeoutHandler> getTimeoutHandler();
+
+ void setTracer(const vmime::shared_ptr <vmime::net::tracer>& tracer);
+ vmime::shared_ptr <vmime::net::tracer> getTracer();
+
+ /** Send data to client.
+ *
+ * @param buffer data to send
+ */
+ void localSend(const vmime::string& buffer);
+
+ /** Receive data from client.
+ *
+ * @param buffer buffer in which to store received data
+ */
+ void localReceive(vmime::string& buffer);
+
+ /** Receive a line from client.
+ *
+ * @param buffer buffer in which to store received line
+ * @return true if a line has been read, or false otherwise
+ */
+ bool localReceiveLine(vmime::string& buffer);
+
+ /** Receive data from client.
+ *
+ * @param buffer buffer in which to store received data
+ * @param count number of bytes to receive
+ * @return number of bytes received
+ */
+ vmime::size_t localReceiveRaw(vmime::byte_t* buffer, const size_t count);
+
+protected:
+
+ /** Called when the client has sent some data.
+ */
+ virtual void onDataReceived();
+
+ /** Called when the client has connected.
+ */
+ virtual void onConnected();
+
+private:
+
+ vmime::string m_address;
+ vmime::port_t m_port;
+ bool m_connected;
+
+ vmime::string m_inBuffer;
+ vmime::string m_outBuffer;
+};
+
+
+template <typename T>
+class testSocketFactory : public vmime::net::socketFactory {
+
+public:
+
+ vmime::shared_ptr <vmime::net::socket> create() {
+
+ return vmime::make_shared <T>();
+ }
+
+ vmime::shared_ptr <vmime::net::socket> create(
+ const vmime::shared_ptr <vmime::net::timeoutHandler>& /* th */
+ ) {
+
+ return vmime::make_shared <T>();
+ }
+};
+
+
+class lineBasedTestSocket : public testSocket {
+
+public:
+
+ void onDataReceived();
+
+ const vmime::string getNextLine();
+ bool haveMoreLines() const;
+
+ virtual void processCommand() = 0;
+
+private:
+
+ std::vector <vmime::string> m_lines;
+ std::string m_buffer;
+};
+
+
+class testTimeoutHandler : public vmime::net::timeoutHandler {
+
+public:
+
+ testTimeoutHandler(const unsigned long delay = 3);
+
+ bool isTimeOut();
+ void resetTimeOut();
+ bool handleTimeOut();
+
+private:
+
+ unsigned long m_delay;
+ unsigned long m_start;
+};
+
+
+class testTimeoutHandlerFactory : public vmime::net::timeoutHandlerFactory {
+
+public:
+
+ vmime::shared_ptr <vmime::net::timeoutHandler> create();
+};
+
+
+// Exception helper
+std::ostream& operator<<(std::ostream& os, const vmime::exception& e);
+
+
+// Conversion to hexadecimal for easier debugging
+const vmime::string toHex(const vmime::string str);
diff --git a/vmime-master/tests/utility/datetimeUtilsTest.cpp b/vmime-master/tests/utility/datetimeUtilsTest.cpp
new file mode 100644
index 0000000..77ce242
--- /dev/null
+++ b/vmime-master/tests/utility/datetimeUtilsTest.cpp
@@ -0,0 +1,157 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/dateTime.hpp"
+#include "vmime/utility/datetimeUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(datetimeUtilsTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testIsLeapYear)
+ VMIME_TEST(testGetDaysInMonth)
+ VMIME_TEST(testGetDaysInMonthLeapYear)
+ VMIME_TEST(testToUniversalTime)
+ VMIME_TEST(testToLocalTime)
+ VMIME_TEST(testGetDayOfWeek)
+ VMIME_TEST(testGetWeekOfYear)
+ VMIME_TEST_LIST_END
+
+
+ typedef vmime::utility::datetimeUtils datetimeUtils;
+
+
+ void testIsLeapYear() {
+
+ VASSERT_EQ("1", false, datetimeUtils::isLeapYear(1999));
+ VASSERT_EQ("2", false, datetimeUtils::isLeapYear(1800));
+ VASSERT_EQ("3", false, datetimeUtils::isLeapYear(1900));
+ VASSERT_EQ("4", false, datetimeUtils::isLeapYear(2100));
+ VASSERT_EQ("5", false, datetimeUtils::isLeapYear(2200));
+
+ VASSERT_EQ("6", true, datetimeUtils::isLeapYear(1996));
+ VASSERT_EQ("7", true, datetimeUtils::isLeapYear(2000));
+ }
+
+ void testGetDaysInMonth() {
+
+ VASSERT_EQ("1", 31, datetimeUtils::getDaysInMonth(2006, 1));
+ VASSERT_EQ("2", 28, datetimeUtils::getDaysInMonth(2006, 2));
+ VASSERT_EQ("3", 31, datetimeUtils::getDaysInMonth(2006, 3));
+ VASSERT_EQ("4", 30, datetimeUtils::getDaysInMonth(2006, 4));
+ VASSERT_EQ("5", 31, datetimeUtils::getDaysInMonth(2006, 5));
+ VASSERT_EQ("6", 30, datetimeUtils::getDaysInMonth(2006, 6));
+ VASSERT_EQ("7", 31, datetimeUtils::getDaysInMonth(2006, 7));
+ VASSERT_EQ("8", 31, datetimeUtils::getDaysInMonth(2006, 8));
+ VASSERT_EQ("9", 30, datetimeUtils::getDaysInMonth(2006, 9));
+ VASSERT_EQ("10", 31, datetimeUtils::getDaysInMonth(2006, 10));
+ VASSERT_EQ("11", 30, datetimeUtils::getDaysInMonth(2006, 11));
+ VASSERT_EQ("12", 31, datetimeUtils::getDaysInMonth(2006, 12));
+ }
+
+ void testGetDaysInMonthLeapYear() {
+
+ VASSERT_EQ("1", 31, datetimeUtils::getDaysInMonth(2004, 1));
+ VASSERT_EQ("2", 29, datetimeUtils::getDaysInMonth(2004, 2));
+ VASSERT_EQ("3", 31, datetimeUtils::getDaysInMonth(2004, 3));
+ VASSERT_EQ("4", 30, datetimeUtils::getDaysInMonth(2004, 4));
+ VASSERT_EQ("5", 31, datetimeUtils::getDaysInMonth(2004, 5));
+ VASSERT_EQ("6", 30, datetimeUtils::getDaysInMonth(2004, 6));
+ VASSERT_EQ("7", 31, datetimeUtils::getDaysInMonth(2004, 7));
+ VASSERT_EQ("8", 31, datetimeUtils::getDaysInMonth(2004, 8));
+ VASSERT_EQ("9", 30, datetimeUtils::getDaysInMonth(2004, 9));
+ VASSERT_EQ("10", 31, datetimeUtils::getDaysInMonth(2004, 10));
+ VASSERT_EQ("11", 30, datetimeUtils::getDaysInMonth(2004, 11));
+ VASSERT_EQ("12", 31, datetimeUtils::getDaysInMonth(2004, 12));
+ }
+
+ void testToUniversalTime() {
+
+ const vmime::datetime local(2005, 12, 2, 12, 34, 56, -789);
+
+ const vmime::datetime gmt = datetimeUtils::toUniversalTime(local);
+
+ // 789 is 13 hours, 9 minutes later
+ VASSERT_EQ("1", 2005, gmt.getYear());
+ VASSERT_EQ("2", 12, gmt.getMonth());
+ VASSERT_EQ("3", 3, gmt.getDay());
+ VASSERT_EQ("4", 1, gmt.getHour());
+ VASSERT_EQ("5", 43, gmt.getMinute());
+ VASSERT_EQ("6", 56, gmt.getSecond());
+ VASSERT_EQ("7", 0, gmt.getZone());
+ }
+
+ void testToLocalTime() {
+
+ const vmime::datetime date(2005, 12, 2, 12, 34, 56, -120); // GMT-2
+
+ const vmime::datetime local = datetimeUtils::toLocalTime(date, 120); // GMT+2
+
+ VASSERT_EQ("1", 2005, local.getYear());
+ VASSERT_EQ("2", 12, local.getMonth());
+ VASSERT_EQ("3", 2, local.getDay());
+ VASSERT_EQ("4", 16, local.getHour());
+ VASSERT_EQ("5", 34, local.getMinute());
+ VASSERT_EQ("6", 56, local.getSecond());
+ VASSERT_EQ("7", 120, local.getZone());
+ }
+
+ void testGetDayOfWeek() {
+
+ VASSERT_EQ("1", vmime::datetime::WEDNESDAY, datetimeUtils::getDayOfWeek(1969, 12, 31));
+ VASSERT_EQ("2", vmime::datetime::FRIDAY, datetimeUtils::getDayOfWeek(1976, 4, 9));
+ VASSERT_EQ("3", vmime::datetime::TUESDAY, datetimeUtils::getDayOfWeek(1987, 6, 23));
+ VASSERT_EQ("4", vmime::datetime::SATURDAY, datetimeUtils::getDayOfWeek(1990, 1, 13));
+ VASSERT_EQ("5", vmime::datetime::MONDAY, datetimeUtils::getDayOfWeek(1999, 9, 20));
+ VASSERT_EQ("6", vmime::datetime::THURSDAY, datetimeUtils::getDayOfWeek(2003, 2, 27));
+ VASSERT_EQ("7", vmime::datetime::SATURDAY, datetimeUtils::getDayOfWeek(2005, 11, 19));
+ VASSERT_EQ("8", vmime::datetime::WEDNESDAY, datetimeUtils::getDayOfWeek(2012, 5, 16));
+ VASSERT_EQ("9", vmime::datetime::FRIDAY, datetimeUtils::getDayOfWeek(2027, 3, 12));
+ }
+
+ void testGetWeekOfYear() {
+
+ VASSERT_EQ("1.1", 52, datetimeUtils::getWeekOfYear(2003, 12, 27));
+ VASSERT_EQ("1.2", 52, datetimeUtils::getWeekOfYear(2003, 12, 28));
+ VASSERT_EQ("1.3", 1, datetimeUtils::getWeekOfYear(2003, 12, 29, true));
+ VASSERT_EQ("1.4", 53, datetimeUtils::getWeekOfYear(2003, 12, 29, false));
+ VASSERT_EQ("1.5", 1, datetimeUtils::getWeekOfYear(2004, 1, 4));
+ VASSERT_EQ("1.6", 2, datetimeUtils::getWeekOfYear(2004, 1, 5));
+ VASSERT_EQ("1.7", 2, datetimeUtils::getWeekOfYear(2004, 1, 11));
+
+ VASSERT_EQ("2.1", 52, datetimeUtils::getWeekOfYear(2004, 12, 26));
+ VASSERT_EQ("2.2", 53, datetimeUtils::getWeekOfYear(2004, 12, 27));
+ VASSERT_EQ("2.3", 53, datetimeUtils::getWeekOfYear(2005, 1, 2));
+ VASSERT_EQ("2.4", 1, datetimeUtils::getWeekOfYear(2005, 1, 3));
+ VASSERT_EQ("2.5", 1, datetimeUtils::getWeekOfYear(2005, 1, 4));
+ VASSERT_EQ("2.6", 2, datetimeUtils::getWeekOfYear(2005, 1, 11));
+
+ VASSERT_EQ("3.1", 9, datetimeUtils::getWeekOfYear(2027, 3, 7));
+ VASSERT_EQ("3.2", 10, datetimeUtils::getWeekOfYear(2027, 3, 8));
+ VASSERT_EQ("3.3", 10, datetimeUtils::getWeekOfYear(2027, 3, 14));
+ VASSERT_EQ("3.4", 11, datetimeUtils::getWeekOfYear(2027, 3, 15));
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/utility/encoder/b64EncoderTest.cpp b/vmime-master/tests/utility/encoder/b64EncoderTest.cpp
new file mode 100644
index 0000000..36fa61a
--- /dev/null
+++ b/vmime-master/tests/utility/encoder/b64EncoderTest.cpp
@@ -0,0 +1,168 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "encoderTestUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(b64EncoderTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testBase64)
+ VMIME_TEST_LIST_END
+
+
+ void testBase64() {
+
+ static const vmime::string testSuites[] = {
+
+ // Test 1
+ "",
+
+ "",
+
+ // Test 2
+ "A",
+
+ "QQ==",
+
+ // Test 3
+ "AB",
+
+ "QUI=",
+
+ // Test 4
+ "ABC",
+
+ "QUJD",
+
+ // Test 5
+ "foo",
+
+ "Zm9v",
+
+ // Test 6
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789",
+
+ "QUJDREVGR0hJSktMTU5PUFFSU1RVVldYWVphYmNkZWZnaGlqa2xtbm9wcXJzdHV2d3h5ejAx"
+ "MjM0NTY3ODk=",
+
+ // Test 7
+ vmime::string(
+ "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
+ "\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f"
+ "\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f"
+ "\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f"
+ "\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f"
+ "\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f"
+ "\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f"
+ "\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f"
+ "\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f"
+ "\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f"
+ "\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf"
+ "\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf"
+ "\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf"
+ "\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf"
+ "\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef"
+ "\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff",
+ 256),
+
+ "AAECAwQFBgcICQoLDA0ODxAREhMUFRYXGBkaGxwdHh8gISIjJCUmJygpKissLS4vMDEyMzQ1"
+ "Njc4OTo7PD0+P0BBQkNERUZHSElKS0xNTk9QUVJTVFVWV1hZWltcXV5fYGFiY2RlZmdoaWpr"
+ "bG1ub3BxcnN0dXZ3eHl6e3x9fn+AgYKDhIWGh4iJiouMjY6PkJGSk5SVlpeYmZqbnJ2en6Ch"
+ "oqOkpaanqKmqq6ytrq+wsbKztLW2t7i5uru8vb6/wMHCw8TFxsfIycrLzM3Oz9DR0tPU1dbX"
+ "2Nna29zd3t/g4eLj5OXm5+jp6uvs7e7v8PHy8/T19vf4+fr7/P3+/w=="
+ };
+
+
+ for (unsigned int i = 0 ; i < sizeof(testSuites) / sizeof(testSuites[0]) / 2 ; ++i) {
+
+ const vmime::string decoded = testSuites[i * 2];
+ const vmime::string encoded = testSuites[i * 2 + 1];
+
+ std::ostringstream oss;
+ oss << "[Base64] Test " << (i + 1) << ": ";
+
+ // Encoding
+ VASSERT_EQ(oss.str() + "encoding", encoded, encode("base64", decoded));
+
+ // Decoding
+ VASSERT_EQ(oss.str() + "decoding", decoded, decode("base64", encoded));
+
+ // Multiple and successive encoding/decoding
+ VASSERT_EQ(
+ oss.str() + "multiple1",
+ decoded,
+ decode("base64",
+ encode("base64", decoded))
+ );
+
+ VASSERT_EQ(
+ oss.str() + "multiple2",
+ decoded,
+ decode("base64",
+ decode("base64",
+ encode("base64",
+ encode("base64", decoded))))
+ );
+
+ VASSERT_EQ(
+ oss.str() + "multiple3",
+ decoded,
+ decode("base64",
+ decode("base64",
+ decode("base64",
+ encode("base64",
+ encode("base64",
+ encode("base64", decoded))))))
+ );
+
+ VASSERT_EQ(
+ oss.str() + "multiple4",
+ decoded,
+ decode("base64",
+ decode("base64",
+ decode("base64",
+ decode("base64",
+ encode("base64",
+ encode("base64",
+ encode("base64",
+ encode("base64", decoded))))))))
+ );
+
+ VASSERT(
+ oss.str() + "encoded size",
+ getEncoder("base64")->getEncodedSize(decoded.length())
+ >= encode("base64", decoded).length()
+ );
+
+ VASSERT(
+ oss.str() + "decoded size",
+ getEncoder("base64")->getDecodedSize(encoded.length())
+ >= decode("base64", encoded).length()
+ );
+ }
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/utility/encoder/encoderFactoryTest.cpp b/vmime-master/tests/utility/encoder/encoderFactoryTest.cpp
new file mode 100644
index 0000000..916706c
--- /dev/null
+++ b/vmime-master/tests/utility/encoder/encoderFactoryTest.cpp
@@ -0,0 +1,63 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/utility/encoder/noopEncoder.hpp"
+
+
+
+VMIME_TEST_SUITE_BEGIN(encoderFactoryTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testNoDefaultEncoder)
+ VMIME_TEST(testDefaultEncoder)
+ VMIME_TEST_LIST_END
+
+
+ void testNoDefaultEncoder() {
+
+ vmime::shared_ptr <vmime::utility::encoder::encoderFactory> ef =
+ vmime::utility::encoder::encoderFactory::getInstance();
+
+ VASSERT_THROW(
+ "no default encoder",
+ ef->create("non-existing-encoding"),
+ vmime::exceptions::no_encoder_available
+ );
+ }
+
+ void testDefaultEncoder() {
+
+ vmime::shared_ptr <vmime::utility::encoder::encoderFactory> ef =
+ vmime::utility::encoder::encoderFactory::getInstance();
+
+ ef->setDefaultEncoder(vmime::make_shared <vmime::utility::encoder::noopEncoder>());
+
+ VASSERT_NO_THROW(
+ "default encoder",
+ ef->create("non-existing-encoding")
+ );
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/utility/encoder/encoderTestUtils.hpp b/vmime-master/tests/utility/encoder/encoderTestUtils.hpp
new file mode 100644
index 0000000..cc1141c
--- /dev/null
+++ b/vmime-master/tests/utility/encoder/encoderTestUtils.hpp
@@ -0,0 +1,82 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+
+// Helper function to obtain an encoder given its name
+static vmime::shared_ptr <vmime::utility::encoder::encoder> getEncoder(
+ const vmime::string& name,
+ int maxLineLength = 0,
+ const vmime::propertySet props = vmime::propertySet()
+) {
+
+ vmime::shared_ptr <vmime::utility::encoder::encoder> enc =
+ vmime::utility::encoder::encoderFactory::getInstance()->create(name);
+
+ enc->getProperties() = props;
+
+ if (maxLineLength != 0) {
+ enc->getProperties()["maxlinelength"] = maxLineLength;
+ }
+
+ return enc;
+}
+
+
+// Encoding helper function
+static const vmime::string encode(
+ const vmime::string& name, const vmime::string& in,
+ int maxLineLength = 0,
+ const vmime::propertySet props = vmime::propertySet()
+) {
+
+ vmime::shared_ptr <vmime::utility::encoder::encoder> enc = getEncoder(name, maxLineLength, props);
+
+ vmime::utility::inputStreamStringAdapter vin(in);
+
+ std::ostringstream out;
+ vmime::utility::outputStreamAdapter vout(out);
+
+ enc->encode(vin, vout);
+
+ return (out.str());
+}
+
+
+// Decoding helper function
+static const vmime::string decode(
+ const vmime::string& name,
+ const vmime::string& in,
+ int maxLineLength = 0
+) {
+
+ vmime::shared_ptr <vmime::utility::encoder::encoder> enc = getEncoder(name, maxLineLength);
+
+ vmime::utility::inputStreamStringAdapter vin(in);
+
+ std::ostringstream out;
+ vmime::utility::outputStreamAdapter vout(out);
+
+ enc->decode(vin, vout);
+
+ return (out.str());
+}
diff --git a/vmime-master/tests/utility/encoder/qpEncoderTest.cpp b/vmime-master/tests/utility/encoder/qpEncoderTest.cpp
new file mode 100644
index 0000000..e476947
--- /dev/null
+++ b/vmime-master/tests/utility/encoder/qpEncoderTest.cpp
@@ -0,0 +1,275 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "encoderTestUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(qpEncoderTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testQuotedPrintable)
+ VMIME_TEST(testQuotedPrintable_SoftLineBreaks)
+ VMIME_TEST(testQuotedPrintable_HardLineBreakEncode)
+ VMIME_TEST(testQuotedPrintable_HardLineBreakDecode)
+ VMIME_TEST(testQuotedPrintable_CRLF)
+ VMIME_TEST(testQuotedPrintable_RFC2047)
+ VMIME_TEST_LIST_END
+
+
+ void testQuotedPrintable() {
+
+ static const vmime::string testSuites[] = {
+
+ // Test 1
+ "",
+
+ "",
+
+ // Test 2
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
+
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ",
+
+ // Test 3
+ "0123456789012345678901234567890123456789012345678901234567890123456789012"
+ "3456789012345678901234567890123456789012345678901234567890123456789012345"
+ "6789",
+
+ "0123456789012345678901234567890123456789012345678901234567890123456789012=\r\n"
+ "3456789012345678901234567890123456789012345678901234567890123456789012345=\r\n"
+ "6789",
+
+ // Test 4
+ vmime::string(
+ "\x89\xe8\x24\x04\x2f\xe8\xff\xfb\xeb\xff\x90\xd7\x74\x8d\x00\x26\x89\x55"
+ "\x83\xe5\x08\xec\x04\xc7\xa0\x24\x05\xa2\xe8\x08\x43\xee\x00\x00\xc0\x85"
+ "\x0a\x74\xec\x89\xc3\x5d\xb6\x8d\x00\x00\x00\x00\x04\xc7\xa8\x24\x05\xa2"
+ "\xe8\x08\x43\xd4\x00\x00\xe8\xeb\xf6\x89\x89\x55\x81\xe5\xa8\xec\x00\x00"
+ "\x89\x00\xfc\x75\x75\x8b\x89\x08\xf8\x5d\xb9\xe8\xff\xff\x83\xff\x14\xfe"
+ "\x47\x74\xc0\x31\x9d\x8d\xff\x68\xff\xff\x85\x89\xff\x68\xff\xff\x85\x8d"
+ "\xff\x6c\xff\xff\x04\x89\xe8\x24\xfa\x50\xff\xff\x45\xc7\x00\xec\x00\x00"
+ "\x31\x00\x89\xc0\x24\x44\x89\x08\x24\x5c\x89\x04\x24\x34\x87\xe8\xff\xf6"
+ "\x89\xff\x24\x34\x2f\xe8\xff\xf9\x8b\xff\xf8\x5d\x75\x8b\x89\xfc\x5d\xec"
+ "\xbe\xc3\x00\x13\x00\x00\xe7\xeb\xb6\x8d\x00\x00\x00\x00\x89\x55\x57\xe5"
+ "\x53\x56\xec\x81\x01\xdc\x00\x00\x45\xbb\x05\x5c\x8b\x08\x0c\x55\xe4\x83"
+ "\x8b\xf0\x89\x02\x24\x5c\xc7\x04\x24\x04\x00\x06\x00\x00\xec\xa3\x05\xa9"
+ "\xe8\x08\xf7\x2a\xff\xff\x04\xc7\x46\x24\x05\x5c\xb9\x08\x5c\x50\x08\x05"
+ "\x4c\x89\x04\x24\xf5\xe8\xff\xf7\xc7\xff\x24\x04\x5c\x46\x08\x05\xe9\xe8"
+ "\xff\xf8\xc7\xff\x24\x04\x1d\x70\x08\x05\x55\xe8\x00\xbb\xb8\x00\x00\x01"
+ "\x00\x00\xd2\x31\x08\xa3\x05\xa7\xb8\x08\x00\x01\x00\x00\x0c\xa3\x05\xa7",
+ 18 * 16),
+
+ "=89=E8$=04/=E8=FF=FB=EB=FF=90=D7t=8D=00&=89U=83=E5=08=EC=04=C7=A0$=05=A2=E8=\r\n"
+ "=08C=EE=00=00=C0=85=0At=EC=89=C3]=B6=8D=00=00=00=00=04=C7=A8$=05=A2=E8=08=\r\n"
+ "C=D4=00=00=E8=EB=F6=89=89U=81=E5=A8=EC=00=00=89=00=FCuu=8B=89=08=F8]=B9=E8=\r\n"
+ "=FF=FF=83=FF=14=FEGt=C01=9D=8D=FFh=FF=FF=85=89=FFh=FF=FF=85=8D=FFl=FF=FF=04=\r\n"
+ "=89=E8$=FAP=FF=FFE=C7=00=EC=00=001=00=89=C0$D=89=08$\\=89=04$4=87=E8=FF=F6=\r\n"
+ "=89=FF$4/=E8=FF=F9=8B=FF=F8]u=8B=89=FC]=EC=BE=C3=00=13=00=00=E7=EB=B6=8D=00=\r\n"
+ "=00=00=00=89UW=E5SV=EC=81=01=DC=00=00E=BB=05\\=8B=08=0CU=E4=83=8B=F0=89=02=\r\n"
+ "$\\=C7=04$=04=00=06=00=00=EC=A3=05=A9=E8=08=F7*=FF=FF=04=C7F$=05\\=B9=08\\P=08=\r\n"
+ "=05L=89=04$=F5=E8=FF=F7=C7=FF$=04\\F=08=05=E9=E8=FF=F8=C7=FF$=04=1Dp=08=05=\r\n"
+ "U=E8=00=BB=B8=00=00=01=00=00=D21=08=A3=05=A7=B8=08=00=01=00=00=0C=A3=05=A7=\r\n"
+ };
+
+
+ for (unsigned int i = 0 ; i < sizeof(testSuites) / sizeof(testSuites[0]) / 2 ; ++i) {
+
+ const vmime::string decoded = testSuites[i * 2];
+ const vmime::string encoded = testSuites[i * 2 + 1];
+
+ std::ostringstream oss;
+ oss << "[QP] Test " << (i + 1) << ": ";
+
+ // Encoding
+ VASSERT_EQ(oss.str() + "encoding", encoded, encode("quoted-printable", decoded, 74));
+
+ // Decoding
+ VASSERT_EQ(oss.str() + "decoding", decoded, decode("quoted-printable", encoded, 74));
+
+ // Multiple and successive encoding/decoding
+ VASSERT_EQ(
+ oss.str() + "multiple1",
+ decoded,
+ decode("quoted-printable",
+ encode("quoted-printable", decoded))
+ );
+
+ VASSERT_EQ(
+ oss.str() + "multiple2",
+ decoded,
+ decode("quoted-printable",
+ decode("quoted-printable",
+ encode("quoted-printable",
+ encode("quoted-printable", decoded))))
+ );
+
+ VASSERT_EQ(
+ oss.str() + "multiple3",
+ decoded,
+ decode("quoted-printable",
+ decode("quoted-printable",
+ decode("quoted-printable",
+ encode("quoted-printable",
+ encode("quoted-printable",
+ encode("quoted-printable", decoded))))))
+ );
+
+ VASSERT_EQ(
+ oss.str() + "multiple4",
+ decoded,
+ decode("quoted-printable",
+ decode("quoted-printable",
+ decode("quoted-printable",
+ decode("quoted-printable",
+ encode("quoted-printable",
+ encode("quoted-printable",
+ encode("quoted-printable",
+ encode("quoted-printable", decoded))))))))
+ );
+
+ VASSERT(
+ oss.str() + "encoded size",
+ getEncoder("quoted-printable")->getEncodedSize(decoded.length())
+ >= encode("quoted-printable", decoded).length()
+ );
+
+ VASSERT(
+ oss.str() + "decoded size",
+ getEncoder("quoted-printable")->getDecodedSize(encoded.length())
+ >= decode("quoted-printable", encoded).length()
+ );
+ }
+ }
+
+ /** Tests Soft Line Breaks (RFC-2047/6.7(5). */
+ void testQuotedPrintable_SoftLineBreaks() {
+
+ VASSERT_EQ(
+ "1",
+ "Now's the time=\r\n"
+ " for all folk =\r\n"
+ "to come to the=\r\n"
+ " aid of their =\r\n"
+ "country.",
+ encode(
+ "quoted-printable",
+ "Now's the time for all folk "
+ "to come to the aid of their country.",
+ 15
+ )
+ );
+ }
+
+ void testQuotedPrintable_HardLineBreakEncode() {
+
+ const std::string data =
+ "If you believe that truth=beauty,"
+ " then surely mathematics\r\nis the most"
+ " beautiful branch of philosophy.";
+
+ const std::string expected =
+ "If you believe that truth=3Dbeauty=\r\n"
+ ", then surely mathematics\r\n"
+ "is the most beautiful branch of ph=\r\n"
+ "ilosophy.";
+
+ vmime::propertySet encProps;
+ encProps["text"] = true;
+
+ VASSERT_EQ("1", expected, encode("quoted-printable", data, 35, encProps));
+ }
+
+ void testQuotedPrintable_HardLineBreakDecode() {
+
+ const std::string expected =
+ "If you believe that truth=beauty,"
+ " then surely mathematics\r\nis the most"
+ " beautiful branch of philosophy.";
+
+ const std::string data =
+ "If you believe that truth=3Dbeauty=\r\n"
+ ", then surely mathematics\r\n"
+ "is the most beautiful branch of ph=\r\n"
+ "ilosophy.";
+
+ VASSERT_EQ("1", expected, decode("quoted-printable", data, 35));
+ }
+
+
+ /** In text mode, ensure line breaks in QP-encoded text are represented
+ * by a CRLF sequence, as per RFC-2047/6.7(4). */
+ void testQuotedPrintable_CRLF() {
+
+ vmime::propertySet encProps;
+
+ // in "text" mode
+ encProps["text"] = true;
+ VASSERT_EQ(
+ "text",
+ "line1\r\nline2",
+ encode("quoted-printable", "line1\r\nline2", 80, encProps)
+ );
+
+ // in "binary" mode
+ encProps["text"] = false;
+ VASSERT_EQ(
+ "binary",
+ "line1=0D=0Aline2",
+ encode("quoted-printable", "line1\r\nline2", 80, encProps)
+ );
+ }
+
+ void testQuotedPrintable_RFC2047() {
+
+ /*
+ * The RFC (http://tools.ietf.org/html/rfc2047#section-5) says:
+ *
+ * In this case the set of characters that may be used in a "Q"-encoded
+ * 'encoded-word' is restricted to: <upper and lower case ASCII
+ * letters, decimal digits, "!", "*", "+", "-", "/", "=", and "_"
+ * (underscore, ASCII 95.)>. An 'encoded-word' that appears within a
+ * 'phrase' MUST be separated from any adjacent 'word', 'text' or
+ * 'special' by 'linear-white-space'.
+ */
+
+ vmime::propertySet encProps;
+ encProps["rfc2047"] = true;
+
+ // Ensure 'especials' are encoded
+ VASSERT_EQ("especials.1", "=2C", encode("quoted-printable", ",", 10, encProps));
+ VASSERT_EQ("especials.2", "=3B", encode("quoted-printable", ";", 10, encProps));
+ VASSERT_EQ("especials.3", "=3A", encode("quoted-printable", ":", 10, encProps));
+ VASSERT_EQ("especials.4", "=5F", encode("quoted-printable", "_", 10, encProps));
+ VASSERT_EQ("especials.5", "=40", encode("quoted-printable", "@", 10, encProps));
+ VASSERT_EQ("especials.6", "=28", encode("quoted-printable", "(", 10, encProps));
+ VASSERT_EQ("especials.7", "=29", encode("quoted-printable", ")", 10, encProps));
+ VASSERT_EQ("especials.8", "=3C", encode("quoted-printable", "<", 10, encProps));
+ VASSERT_EQ("especials.9", "=3E", encode("quoted-printable", ">", 10, encProps));
+ VASSERT_EQ("especials.10", "=5B", encode("quoted-printable", "[", 10, encProps));
+ VASSERT_EQ("especials.11", "=5D", encode("quoted-printable", "]", 10, encProps));
+ VASSERT_EQ("especials.12", "=22", encode("quoted-printable", "\"", 10, encProps));
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/utility/filteredStreamTest.cpp b/vmime-master/tests/utility/filteredStreamTest.cpp
new file mode 100644
index 0000000..ff3fb6a
--- /dev/null
+++ b/vmime-master/tests/utility/filteredStreamTest.cpp
@@ -0,0 +1,341 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/utility/filteredStream.hpp"
+#include "vmime/utility/stringUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(filteredStreamTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testDotFilteredInputStream)
+ VMIME_TEST(testDotFilteredOutputStream)
+ VMIME_TEST(testCRLFToLFFilteredOutputStream)
+ VMIME_TEST(testStopSequenceFilteredInputStream1)
+ VMIME_TEST(testStopSequenceFilteredInputStreamN_2)
+ VMIME_TEST(testStopSequenceFilteredInputStreamN_3)
+ VMIME_TEST(testLFToCRLFFilteredOutputStream_Global)
+ VMIME_TEST(testLFToCRLFFilteredOutputStream_Edge)
+ VMIME_TEST_LIST_END
+
+
+ class chunkInputStream : public vmime::utility::inputStream {
+
+ private:
+
+ std::vector <std::string> m_chunks;
+ size_t m_index;
+
+ public:
+
+ chunkInputStream() : m_index(0) { }
+
+ void addChunk(const std::string& chunk) { m_chunks.push_back(chunk); }
+
+ bool eof() const { return (m_index >= m_chunks.size()); }
+ void reset() { m_index = 0; }
+
+ vmime::size_t read(vmime::byte_t* const data, const vmime::size_t /* count */) {
+
+ if (eof()) {
+ return 0;
+ }
+
+ const std::string chunk = m_chunks[m_index];
+
+ // Warning: 'count' should be larger than chunk length.
+ // This is OK for our tests.
+ std::copy(chunk.begin(), chunk.end(), data);
+
+ ++m_index;
+
+ return chunk.length();
+ }
+
+ vmime::size_t skip(const vmime::size_t /* count */) {
+
+ // Not supported
+ return 0;
+ }
+ };
+
+
+ const std::string readWhole(vmime::utility::inputStream& is) {
+
+ vmime::byte_t buffer[256];
+ std::string whole;
+
+ while (!is.eof()) {
+
+ const vmime::size_t read = is.read(buffer, sizeof(buffer));
+
+ whole += vmime::utility::stringUtils::makeStringFromBytes(buffer, read);
+ }
+
+ return whole;
+ }
+
+
+ // dotFilteredInputStream
+
+ void testDotFilteredInputStreamHelper(
+ const std::string& number,
+ const std::string& expected,
+ const std::string& c1,
+ const std::string& c2 = "",
+ const std::string& c3 = "",
+ const std::string& c4 = ""
+ ) {
+
+ chunkInputStream cis;
+ cis.addChunk(c1);
+ if (!c2.empty()) cis.addChunk(c2);
+ if (!c3.empty()) cis.addChunk(c3);
+ if (!c4.empty()) cis.addChunk(c4);
+
+ vmime::utility::dotFilteredInputStream is(cis);
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter os(oss);
+
+ vmime::utility::bufferedStreamCopy(is, os);
+
+ VASSERT_EQ(number, expected, oss.str());
+ }
+
+ void testDotFilteredInputStream() {
+
+ testDotFilteredInputStreamHelper("1", "foo\n.bar", "foo\n..bar");
+ testDotFilteredInputStreamHelper("2", "foo\n.bar", "foo\n", "..bar");
+ testDotFilteredInputStreamHelper("3", "foo\n.bar", "foo\n.", ".bar");
+ testDotFilteredInputStreamHelper("4", "foo\n.bar", "foo\n..", "bar");
+ testDotFilteredInputStreamHelper("5", "foo\n.bar", "foo\n", ".", ".bar");
+ testDotFilteredInputStreamHelper("6", "foo\n.bar", "foo\n", ".", ".", "bar");
+
+ testDotFilteredInputStreamHelper("7", "\x0d\x0a.", "\x0d\x0a..");
+ testDotFilteredInputStreamHelper("8", "\x0d\x0a.\x0d\x0a", "\x0d\x0a..\x0d\x0a");
+ testDotFilteredInputStreamHelper("9", "\x0d\x0a.\x0d\x0a.", "\x0d\x0a..\x0d\x0a.");
+ testDotFilteredInputStreamHelper("10", "\x0d\x0a.\x0d\x0a.\x0d\x0ax", "\x0d\x0a..\x0d\x0a.\x0d\x0ax");
+ testDotFilteredInputStreamHelper("11", "this is the first line\x0d\x0a.\x0d\x0aone dot\x0d\x0a..\x0d\x0atwo dots\x0d\x0a...\x0d\x0athree... \x0d\x0a.\x0d\x0a.\x0d\x0a", "this is the first line\x0d\x0a..\x0d\x0aone dot\x0d\x0a...\x0d\x0atwo dots\x0d\x0a....\x0d\x0athree... \x0d\x0a..\x0d\x0a.\x0d\x0a");
+ }
+
+ // dotFilteredOutputStream
+ // CRLFToLFFilteredOutputStream
+
+ template <typename FILTER>
+ void testFilteredOutputStreamHelper(
+ const std::string& number,
+ const std::string& expected,
+ const std::string& c1,
+ const std::string& c2 = "",
+ const std::string& c3 = "",
+ const std::string& c4 = ""
+ ) {
+
+ std::ostringstream oss;
+ vmime::utility::outputStreamAdapter os(oss);
+
+ FILTER fos(os);
+
+ fos.write(c1.data(), c1.length());
+ if (!c2.empty()) fos.write(c2.data(), c2.length());
+ if (!c3.empty()) fos.write(c3.data(), c3.length());
+ if (!c4.empty()) fos.write(c4.data(), c4.length());
+
+ VASSERT_EQ(number, expected, oss.str());
+ }
+
+ void testDotFilteredOutputStream() {
+
+ typedef vmime::utility::dotFilteredOutputStream FILTER;
+
+ testFilteredOutputStreamHelper<FILTER>("1", "foo\n..bar", "foo\n.bar");
+ testFilteredOutputStreamHelper<FILTER>("2", "foo\n..bar", "foo\n", ".bar");
+ testFilteredOutputStreamHelper<FILTER>("3", "foo\n..bar", "foo", "\n.bar");
+ testFilteredOutputStreamHelper<FILTER>("4", "foo\n..bar", "foo", "\n", ".bar");
+ testFilteredOutputStreamHelper<FILTER>("5", "foo\n..bar", "foo", "\n", ".", "bar");
+
+ testFilteredOutputStreamHelper<FILTER>("6", "..\nfoobar", ".\nfoobar");
+ testFilteredOutputStreamHelper<FILTER>("7", "..\r\nfoobar", ".\r\nfoobar");
+ testFilteredOutputStreamHelper<FILTER>("8", "..\r\nfoobar", ".\r", "\nfoobar");
+ testFilteredOutputStreamHelper<FILTER>("9", ".foobar", ".foobar");
+ testFilteredOutputStreamHelper<FILTER>("10", ".foobar", ".", "foobar");
+
+ testFilteredOutputStreamHelper<FILTER>("11", "this is the first line\x0d\x0a...\x0d\x0aone dot\x0d\x0a....\x0d\x0atwo dots\x0d\x0a.....\x0d\x0athree... \x0d\x0a...\x0d\x0a..\x0d\x0a", "this is the first line\x0d\x0a..\x0d\x0aone dot\x0d\x0a...\x0d\x0atwo dots\x0d\x0a....\x0d\x0athree... \x0d\x0a..\x0d\x0a.\x0d\x0a");
+ }
+
+ void testCRLFToLFFilteredOutputStream() {
+
+ typedef vmime::utility::CRLFToLFFilteredOutputStream FILTER;
+
+ testFilteredOutputStreamHelper<FILTER>("1", "foo\nbar", "foo\r\nbar");
+ testFilteredOutputStreamHelper<FILTER>("2", "foo\nbar", "foo\r\n", "bar");
+ testFilteredOutputStreamHelper<FILTER>("3", "foo\nbar", "foo\r", "\nbar");
+ testFilteredOutputStreamHelper<FILTER>("4", "foo\nbar", "foo", "\r\nbar");
+ testFilteredOutputStreamHelper<FILTER>("5", "foo\nbar", "foo", "\r", "\nbar");
+ testFilteredOutputStreamHelper<FILTER>("6", "foo\nbar", "foo", "\r", "\n", "bar");
+ testFilteredOutputStreamHelper<FILTER>("7", "foo\nba\nr", "foo\r", "\nba\r\nr");
+ }
+
+ // stopSequenceFilteredInputStream
+
+ template <int N>
+ void testStopSequenceFISHelper(
+ const std::string& number,
+ const std::string& sequence,
+ const std::string& expected,
+ const std::string& c1,
+ const std::string& c2 = "",
+ const std::string& c3 = "",
+ const std::string& c4 = "",
+ const std::string& c5 = ""
+ ) {
+
+ chunkInputStream cis;
+ cis.addChunk(c1);
+ if (!c2.empty()) cis.addChunk(c2);
+ if (!c3.empty()) cis.addChunk(c3);
+ if (!c4.empty()) cis.addChunk(c4);
+ if (!c5.empty()) cis.addChunk(c5);
+
+ vmime::utility::stopSequenceFilteredInputStream <N> is(cis, sequence.data());
+
+ VASSERT_EQ(number, expected, readWhole(is));
+ }
+
+ void testStopSequenceFilteredInputStream1() {
+
+ testStopSequenceFISHelper <1>("1", "x", "foo", "fooxbar");
+ testStopSequenceFISHelper <1>("2", "x", "foo", "foox", "bar");
+ testStopSequenceFISHelper <1>("3", "x", "foo", "foo", "x", "bar");
+ testStopSequenceFISHelper <1>("4", "x", "foo", "fo", "o", "x", "bar");
+ testStopSequenceFISHelper <1>("5", "x", "foo", "fo", "o", "x", "b", "ar");
+
+ testStopSequenceFISHelper <1>("6", "x", "foobar", "fo", "o", "b", "ar");
+ testStopSequenceFISHelper <1>("7", "x", "foobar", "foo", "bar");
+ testStopSequenceFISHelper <1>("8", "x", "foobar", "foo", "b", "ar");
+
+ testStopSequenceFISHelper <1>("9", "x", "foobar", "foobar");
+ testStopSequenceFISHelper <1>("10", "x", "foobar", "foobarx");
+
+ testStopSequenceFISHelper <1>("11", "x", "", "");
+ testStopSequenceFISHelper <1>("12", "x", "", "x");
+ testStopSequenceFISHelper <1>("13", "x", "", "", "x");
+ }
+
+ void testStopSequenceFilteredInputStreamN_2() {
+
+ testStopSequenceFISHelper <2>("1", "xy", "foo", "fooxybar");
+ testStopSequenceFISHelper <2>("2", "xy", "foo", "foox", "ybar");
+ testStopSequenceFISHelper <2>("3", "xy", "foo", "foox", "y", "bar");
+ testStopSequenceFISHelper <2>("4", "xy", "foo", "foo", "x", "ybar");
+ testStopSequenceFISHelper <2>("5", "xy", "foo", "foo", "xy", "bar");
+ testStopSequenceFISHelper <2>("6", "xy", "foo", "foo", "x", "y", "bar");
+
+ testStopSequenceFISHelper <2>("7", "xy", "fooxbar", "foox", "bar");
+ testStopSequenceFISHelper <2>("8", "xy", "fooxbar", "foo", "xbar");
+ testStopSequenceFISHelper <2>("9", "xy", "fooxbar", "foo", "x", "bar");
+ testStopSequenceFISHelper <2>("10", "xy", "foobarx", "foo", "barx");
+
+ testStopSequenceFISHelper <2>("11", "xy", "foobar", "foobarxy");
+ testStopSequenceFISHelper <2>("12", "xy", "foobar", "foo", "barxy");
+ testStopSequenceFISHelper <2>("13", "xy", "foobar", "foo", "bar", "xy");
+
+ testStopSequenceFISHelper <2>("14", "xy", "", "");
+ testStopSequenceFISHelper <2>("15", "xy", "x", "x");
+ testStopSequenceFISHelper <2>("16", "xy", "", "xy");
+ testStopSequenceFISHelper <2>("17", "xy", "", "x", "y");
+ }
+
+ void testStopSequenceFilteredInputStreamN_3() {
+
+ testStopSequenceFISHelper <3>("1", "xyz", "foo", "fooxyzbar");
+ testStopSequenceFISHelper <3>("2", "xyz", "foo", "foox", "yzbar");
+ testStopSequenceFISHelper <3>("3", "xyz", "foo", "foox", "y", "zbar");
+ testStopSequenceFISHelper <3>("4", "xyz", "foo", "foox", "yz", "bar");
+ testStopSequenceFISHelper <3>("5", "xyz", "foo", "foo", "xyz", "bar");
+ testStopSequenceFISHelper <3>("6", "xyz", "foo", "foo", "xy", "zbar");
+ testStopSequenceFISHelper <3>("7", "xyz", "foo", "foo", "x", "y", "zbar");
+ testStopSequenceFISHelper <3>("8", "xyz", "foo", "foo", "x", "y", "z", "bar");
+ testStopSequenceFISHelper <3>("9", "xyz", "foo", "fooxy", "z", "bar");
+
+ testStopSequenceFISHelper <3>("10", "xyz", "fooxybar", "foox", "y", "bar");
+ testStopSequenceFISHelper <3>("11", "xyz", "fooxybar", "fooxy", "bar");
+ testStopSequenceFISHelper <3>("12", "xyz", "fooxybar", "fo", "ox", "y", "bar");
+ testStopSequenceFISHelper <3>("13", "xyz", "fooxybar", "fo", "o", "x", "y", "bar");
+ testStopSequenceFISHelper <3>("14", "xyz", "fooxybar", "foo", "x", "ybar");
+ testStopSequenceFISHelper <3>("15", "xyz", "fooxybar", "foo", "xybar");
+
+ testStopSequenceFISHelper <3>("16", "xyz", "xfoxoxybxar", "xfoxo", "xybxar");
+ testStopSequenceFISHelper <3>("17", "xyz", "xfoxoxybxarx", "xfoxo", "xybxarx");
+ testStopSequenceFISHelper <3>("18", "xyz", "xfoxoxybxarxy", "xfoxo", "xybxarxy");
+
+ testStopSequenceFISHelper <3>("19", "xyz", "", "");
+ testStopSequenceFISHelper <3>("20", "xyz", "x", "x");
+ testStopSequenceFISHelper <3>("21", "xyz", "xy", "xy");
+ testStopSequenceFISHelper <3>("22", "xyz", "", "xyz");
+ testStopSequenceFISHelper <3>("23", "xyz", "", "x", "yz");
+ testStopSequenceFISHelper <3>("24", "xyz", "", "x", "y", "z");
+ }
+
+
+ // LFToCRLFFilteredOutputStream
+
+ void testLFToCRLFFilteredOutputStream_Global() {
+
+ typedef vmime::utility::LFToCRLFFilteredOutputStream FILTER;
+
+ testFilteredOutputStreamHelper<FILTER>("1", "ABC\r\nDEF", "ABC\nDEF");
+ testFilteredOutputStreamHelper<FILTER>("2", "ABC\r\nDEF", "ABC\rDEF");
+ testFilteredOutputStreamHelper<FILTER>("3", "\r\n\r\nAB\r\n\r\nA\r\nB\r\n", "\n\nAB\n\nA\nB\n");
+ testFilteredOutputStreamHelper<FILTER>("4", "ABCDE\r\nF", "ABCDE\nF");
+ testFilteredOutputStreamHelper<FILTER>("5", "ABCDE\r\nF", "ABCDE\r\nF");
+ testFilteredOutputStreamHelper<FILTER>("6", "\r\n\r\n\r\n", "\n\n\n");
+ testFilteredOutputStreamHelper<FILTER>("7", "\r\n\r\n\r\n", "\r\r\n\n");
+ testFilteredOutputStreamHelper<FILTER>("8", "\r\n\r\n\r\n\r\n", "\r\r\r\r");
+ testFilteredOutputStreamHelper<FILTER>("9", "\r\n\r\n\r\n\r\n", "\n\n\n\n");
+ testFilteredOutputStreamHelper<FILTER>("10", "\r\n\r\n\r\n", "\r\n\n\n");
+ testFilteredOutputStreamHelper<FILTER>("11", "\r\n\r\n\r\n\r\n", "\n\n\n\r\n");
+ }
+
+ void testLFToCRLFFilteredOutputStream_Edge() {
+
+ typedef vmime::utility::LFToCRLFFilteredOutputStream FILTER;
+
+ testFilteredOutputStreamHelper<FILTER>("1", "\r\n\r\n", "\r", "\r");
+ testFilteredOutputStreamHelper<FILTER>("2", "\r\n\r\n", "\r", "\n\r");
+ testFilteredOutputStreamHelper<FILTER>("3", "ABC\r\n\r\n", "ABC\r", "\n\r");
+ testFilteredOutputStreamHelper<FILTER>("4", "ABC\r\n\r\n\r\n", "ABC\r", "\n\r", "\n\n");
+ testFilteredOutputStreamHelper<FILTER>("5", "\r\n\r\n", "\n", "\n");
+ testFilteredOutputStreamHelper<FILTER>("6", "\r\n\r\n", "\r\n\r\n");
+ testFilteredOutputStreamHelper<FILTER>("7", "\r\n\r\n", "\r\n\r", "\n");
+
+ testFilteredOutputStreamHelper<FILTER>("8", "A\r\nB\r\nC\r\nD", "A\rB", "\nC\r\nD");
+ testFilteredOutputStreamHelper<FILTER>("9", "\r\nA\r\nB\r\nC\r\nD", "\rA\r", "B\nC\r\nD");
+ testFilteredOutputStreamHelper<FILTER>("10", "\r\nA\r\nB\r\nC\r\nD", "\nA\r", "B\nC\r\nD");
+ testFilteredOutputStreamHelper<FILTER>("11", "\r\nA\r\nB\r\nC\r\nD\r\n", "\nA\rB", "\nC\r\nD\r");
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/utility/outputStreamByteArrayAdapterTest.cpp b/vmime-master/tests/utility/outputStreamByteArrayAdapterTest.cpp
new file mode 100644
index 0000000..07a0f4b
--- /dev/null
+++ b/vmime-master/tests/utility/outputStreamByteArrayAdapterTest.cpp
@@ -0,0 +1,82 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/utility/outputStreamByteArrayAdapter.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(outputStreamByteArrayAdapterTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testWrite)
+ VMIME_TEST(testWriteBinary)
+ VMIME_TEST(testWriteCRLF)
+ VMIME_TEST_LIST_END
+
+
+ void testWrite() {
+
+ vmime::byteArray bytes;
+
+ vmime::utility::outputStreamByteArrayAdapter stream(bytes);
+ stream << "some data";
+ stream.flush();
+
+ VASSERT_EQ("Write 1", 0, memcmp("some data", &bytes[0], 9));
+
+ stream.write("more data", 9);
+
+ VASSERT_EQ("Write 2", 0, memcmp("some datamore data", &bytes[0], 18));
+ }
+
+ void testWriteBinary() {
+
+ const char binaryData[] =
+ "\xc5\x9a\xc3\xb8\xc9\xb1\xc9\x9b\x20\xc9\x93\xc9\xa8\xc9\xb2\xc9"
+ "\x91\xc5\x95\xc9\xa3\x20\xc9\x96\xc9\x90\xca\x88\xc9\x92";
+
+ vmime::byteArray bytes;
+
+ vmime::utility::outputStreamByteArrayAdapter stream(bytes);
+ stream.write(binaryData, sizeof(binaryData));
+ stream.flush();
+
+ VASSERT_EQ("Write", 0, memcmp(binaryData, &bytes[0], sizeof(binaryData)));
+ }
+
+ void testWriteCRLF() {
+
+ vmime::byteArray bytes;
+
+ vmime::utility::outputStreamByteArrayAdapter stream(bytes);
+ stream << "some data";
+ stream.flush();
+
+ stream << "\nmore\r\ndata\r";
+ stream.flush();
+
+ VASSERT_EQ("Write", 0, memcmp("some data\nmore\r\ndata\r", &bytes[0], 21));
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/utility/outputStreamSocketAdapterTest.cpp b/vmime-master/tests/utility/outputStreamSocketAdapterTest.cpp
new file mode 100644
index 0000000..a869ed7
--- /dev/null
+++ b/vmime-master/tests/utility/outputStreamSocketAdapterTest.cpp
@@ -0,0 +1,87 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/utility/outputStreamSocketAdapter.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(outputStreamSocketAdapterTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testWrite)
+ VMIME_TEST(testWriteBinary)
+ VMIME_TEST(testWriteCRLF)
+ VMIME_TEST_LIST_END
+
+
+ void testWrite() {
+
+ vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
+
+ vmime::utility::outputStreamSocketAdapter stream(*socket);
+ stream << "some data";
+ stream.flush();
+
+ vmime::string buffer;
+ socket->localReceive(buffer);
+
+ VASSERT_EQ("Write", "some data", buffer);
+ }
+
+ void testWriteBinary() {
+
+ const char binaryData[] =
+ "\xc5\x9a\xc3\xb8\xc9\xb1\xc9\x9b\x20\xc9\x93\xc9\xa8\xc9\xb2\xc9"
+ "\x91\xc5\x95\xc9\xa3\x20\xc9\x96\xc9\x90\xca\x88\xc9\x92";
+
+ vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
+
+ vmime::utility::outputStreamSocketAdapter stream(*socket);
+ stream.write(binaryData, sizeof(binaryData));
+ stream.flush();
+
+ vmime::string buffer;
+ socket->localReceive(buffer);
+
+ VASSERT_EQ("Write", 0, memcmp(binaryData, buffer.data(), sizeof(binaryData)));
+ }
+
+ void testWriteCRLF() {
+
+ vmime::shared_ptr <testSocket> socket = vmime::make_shared <testSocket>();
+
+ vmime::utility::outputStreamSocketAdapter stream(*socket);
+ stream << "some data";
+ stream.flush();
+
+ stream << "\nmore\r\ndata\r";
+ stream.flush();
+
+ vmime::string buffer;
+ socket->localReceive(buffer);
+
+ VASSERT_EQ("Write", "some data\nmore\r\ndata\r", buffer);
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/utility/outputStreamStringAdapterTest.cpp b/vmime-master/tests/utility/outputStreamStringAdapterTest.cpp
new file mode 100644
index 0000000..3de8f8b
--- /dev/null
+++ b/vmime-master/tests/utility/outputStreamStringAdapterTest.cpp
@@ -0,0 +1,84 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/utility/outputStreamStringAdapter.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(outputStreamStringAdapterTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testWrite)
+ VMIME_TEST(testWriteBinary)
+ VMIME_TEST(testWriteCRLF)
+ VMIME_TEST_LIST_END
+
+
+ void testWrite() {
+
+ vmime::string str("initial data");
+
+ vmime::utility::outputStreamStringAdapter stream(str);
+ stream << "additional data";
+ stream.flush();
+
+ VASSERT_EQ("Write 1 len", 27, str.length());
+ VASSERT_EQ("Write 1 data", "initial dataadditional data", str);
+
+ stream.write("more data");
+
+ VASSERT_EQ("Write 2 len", 36, str.length());
+ VASSERT_EQ("Write 2 data", "initial dataadditional datamore data", str);
+ }
+
+ void testWriteBinary() {
+
+ const vmime::byte_t binaryData[] =
+ "\xc5\x9a\xc3\xb8\xc9\xb1\xc9\x9b\x20\xc9\x93\xc9\xa8\xc9\xb2\xc9"
+ "\x91\xc5\x95\xc9\xa3\x20\xc9\x96\xc9\x90\xca\x88\xc9\x92";
+
+ vmime::string str;
+
+ vmime::utility::outputStreamStringAdapter stream(str);
+ stream.write(binaryData, sizeof(binaryData));
+ stream.flush();
+
+ VASSERT_EQ("Write", 0, memcmp(binaryData, str.data(), sizeof(binaryData)));
+ }
+
+ void testWriteCRLF() {
+
+ vmime::string str;
+
+ vmime::utility::outputStreamStringAdapter stream(str);
+ stream << "some data";
+ stream.flush();
+
+ stream << "\nmore\r\ndata\r";
+ stream.flush();
+
+ VASSERT_EQ("Write", "some data\nmore\r\ndata\r", str);
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/utility/parserInputStreamAdapterTest.cpp b/vmime-master/tests/utility/parserInputStreamAdapterTest.cpp
new file mode 100644
index 0000000..4bc310c
--- /dev/null
+++ b/vmime-master/tests/utility/parserInputStreamAdapterTest.cpp
@@ -0,0 +1,51 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/utility/parserInputStreamAdapter.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(parserInputStreamAdapterTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testEndlessLoopBufferSize)
+ VMIME_TEST_LIST_END
+
+
+ void testEndlessLoopBufferSize() {
+
+ static const unsigned int BUFFER_SIZE = 4096; // same as in parserInputStreamAdapter::findNext()
+
+ vmime::string str(BUFFER_SIZE, 'X');
+
+ vmime::shared_ptr <vmime::utility::inputStreamStringAdapter> iss =
+ vmime::make_shared <vmime::utility::inputStreamStringAdapter>(str);
+
+ vmime::shared_ptr <vmime::utility::parserInputStreamAdapter> parser =
+ vmime::make_shared <vmime::utility::parserInputStreamAdapter>(iss);
+
+ VASSERT_EQ("Not found", vmime::string::npos, parser->findNext("token"));
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/utility/pathTest.cpp b/vmime-master/tests/utility/pathTest.cpp
new file mode 100644
index 0000000..e6227f3
--- /dev/null
+++ b/vmime-master/tests/utility/pathTest.cpp
@@ -0,0 +1,356 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/utility/path.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(utilityPathTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testConstruct1)
+ VMIME_TEST(testConstruct2)
+ VMIME_TEST(testConstruct3)
+ VMIME_TEST(testConstruct4)
+
+ VMIME_TEST(testAppendComponent)
+
+ VMIME_TEST(testOperatorDiv1)
+ VMIME_TEST(testOperatorDiv2)
+
+ VMIME_TEST(testOperatorDivEqual1)
+ VMIME_TEST(testOperatorDivEqual2)
+
+ VMIME_TEST(testGetParent)
+
+ VMIME_TEST(testComparison)
+
+ VMIME_TEST(testGetLastComponent)
+
+ VMIME_TEST(testIsDirectParentOf)
+ VMIME_TEST(testIsParentOf)
+ VMIME_TEST(testIsParentOf_EquivalentCharset)
+
+ VMIME_TEST(testRenameParent)
+
+ VMIME_TEST(testFromString)
+ VMIME_TEST(testFromString_IgnoreLeadingOrTrailingSep)
+ VMIME_TEST(testToString)
+ VMIME_TEST_LIST_END
+
+
+ typedef vmime::utility::path path;
+ typedef vmime::utility::path::component comp;
+
+
+ void testConstruct1() {
+
+ VASSERT_EQ("1", true, path().isEmpty());
+ VASSERT_EQ("2", 0, path().getSize());
+ }
+
+ void testConstruct2() {
+
+ path p(comp("foo"));
+
+ VASSERT_EQ("1", false, p.isEmpty());
+ VASSERT_EQ("2", 1, p.getSize());
+ VASSERT_EQ("3", "foo", p.getComponentAt(0).getBuffer());
+ }
+
+ void testAppendComponent() {
+
+ path p;
+
+ VASSERT_EQ("1", 0, p.getSize());
+
+ comp c("foo");
+ p.appendComponent(c);
+
+ VASSERT_EQ("2", 1, p.getSize());
+ VASSERT_EQ("3", c.getBuffer(), p.getComponentAt(0).getBuffer());
+ }
+
+ void testConstruct3() {
+
+ path p1;
+ p1.appendComponent(comp("foo"));
+ p1.appendComponent(comp("bar"));
+
+ path p2(p1);
+
+ VASSERT_EQ("1", 2, p2.getSize());
+ VASSERT_EQ("2", "foo", p2.getComponentAt(0).getBuffer());
+ VASSERT_EQ("3", "bar", p2.getComponentAt(1).getBuffer());
+ }
+
+ void testConstruct4() {
+
+ // Same as path::path(const component&)
+ path p("foo");
+
+ VASSERT_EQ("1", false, p.isEmpty());
+ VASSERT_EQ("2", 1, p.getSize());
+ VASSERT_EQ("3", "foo", p.getComponentAt(0).getBuffer());
+ }
+
+ void testOperatorDiv1() {
+
+ path p1;
+ p1.appendComponent(comp("foo"));
+ p1.appendComponent(comp("bar"));
+
+ path p2;
+ p2.appendComponent(comp("baz"));
+
+ path p3 = p1 / p2;
+
+ VASSERT_EQ("1", 3, p3.getSize());
+ VASSERT_EQ("2", p1.getComponentAt(0).getBuffer(), p3.getComponentAt(0).getBuffer());
+ VASSERT_EQ("3", p1.getComponentAt(1).getBuffer(), p3.getComponentAt(1).getBuffer());
+ VASSERT_EQ("4", p2.getComponentAt(0).getBuffer(), p3.getComponentAt(2).getBuffer());
+ }
+
+ void testOperatorDiv2() {
+
+ path p1;
+ p1.appendComponent(comp("foo"));
+ p1.appendComponent(comp("bar"));
+
+ comp c("baz");
+
+ path p2 = p1 / c;
+
+ VASSERT_EQ("1", 3, p2.getSize());
+ VASSERT_EQ("2", p1.getComponentAt(0).getBuffer(), p2.getComponentAt(0).getBuffer());
+ VASSERT_EQ("3", p1.getComponentAt(1).getBuffer(), p2.getComponentAt(1).getBuffer());
+ VASSERT_EQ("4", c.getBuffer(), p2.getComponentAt(2).getBuffer());
+ }
+
+ void testOperatorDivEqual1() {
+
+ path p1;
+ p1.appendComponent(comp("foo"));
+ p1.appendComponent(comp("bar"));
+
+ path p2;
+ p2.appendComponent(comp("baz"));
+
+ path p3(p1);
+ p3 /= p2;
+
+ VASSERT_EQ("1", 3, p3.getSize());
+ VASSERT_EQ("2", p1.getComponentAt(0).getBuffer(), p3.getComponentAt(0).getBuffer());
+ VASSERT_EQ("3", p1.getComponentAt(1).getBuffer(), p3.getComponentAt(1).getBuffer());
+ VASSERT_EQ("4", p2.getComponentAt(0).getBuffer(), p3.getComponentAt(2).getBuffer());
+ }
+
+ void testOperatorDivEqual2() {
+
+ path p1;
+ p1.appendComponent(comp("foo"));
+ p1.appendComponent(comp("bar"));
+
+ comp c("baz");
+
+ path p2(p1);
+ p2 /= c;
+
+ VASSERT_EQ("1", 3, p2.getSize());
+ VASSERT_EQ("2", p1.getComponentAt(0).getBuffer(), p2.getComponentAt(0).getBuffer());
+ VASSERT_EQ("3", p1.getComponentAt(1).getBuffer(), p2.getComponentAt(1).getBuffer());
+ VASSERT_EQ("4", c.getBuffer(), p2.getComponentAt(2).getBuffer());
+ }
+
+ void testGetParent() {
+
+ path p1;
+ path p1p = p1.getParent();
+
+ VASSERT_EQ("1", true, p1p.isEmpty());
+
+ path p2;
+ p2.appendComponent(comp("foo"));
+ p2.appendComponent(comp("bar"));
+
+ path p2p = p2.getParent();
+
+ VASSERT_EQ("2", 1, p2p.getSize());
+ VASSERT_EQ("3", p2.getComponentAt(0).getBuffer(), p2p.getComponentAt(0).getBuffer());
+ }
+
+ void testComparison() {
+
+ path p1;
+ p1.appendComponent(comp("foo"));
+ p1.appendComponent(comp("bar"));
+
+ path p2;
+ p2.appendComponent(comp("foo"));
+ p2.appendComponent(comp("bar"));
+
+ path p3;
+ p3.appendComponent(comp("foo"));
+ p3.appendComponent(comp("bar"));
+ p3.appendComponent(comp("baz"));
+
+ VASSERT_EQ("1", true, p1 == p2);
+ VASSERT_EQ("2", false, p1 == p3);
+
+ VASSERT_EQ("3", false, p1 != p2);
+ VASSERT_EQ("4", true, p1 != p3);
+
+ VASSERT_EQ("5", true, p3.getParent() == p1);
+ }
+
+ void testGetLastComponent() {
+
+ path p1;
+ p1.appendComponent(comp("foo"));
+ p1.appendComponent(comp("bar"));
+ p1.appendComponent(comp("baz"));
+
+ VASSERT_EQ("1", "baz", p1.getLastComponent().getBuffer());
+ VASSERT_EQ("2", "bar", p1.getParent().getLastComponent().getBuffer());
+ VASSERT_EQ("3", "foo", p1.getParent().getParent().getLastComponent().getBuffer());
+ }
+
+ void testIsDirectParentOf() {
+
+ path p1;
+ p1.appendComponent(comp("foo"));
+
+ path p2;
+ p2.appendComponent(comp("foo"));
+ p2.appendComponent(comp("bar"));
+
+ path p3;
+ p3.appendComponent(comp("foo"));
+ p3.appendComponent(comp("bar"));
+ p3.appendComponent(comp("baz"));
+
+ VASSERT_EQ("1", true, p1.isDirectParentOf(p2));
+ VASSERT_EQ("2", true, p2.isDirectParentOf(p3));
+ VASSERT_EQ("3", false, p1.isDirectParentOf(p3));
+ VASSERT_EQ("4", false, p2.isDirectParentOf(p1));
+ }
+
+ void testIsParentOf() {
+
+ path p1;
+ p1.appendComponent(comp("foo"));
+
+ path p2;
+ p2.appendComponent(comp("foo"));
+ p2.appendComponent(comp("bar"));
+
+ path p3;
+ p3.appendComponent(comp("foo"));
+ p3.appendComponent(comp("bar"));
+ p3.appendComponent(comp("baz"));
+
+ VASSERT_EQ("1", true, p1.isParentOf(p2));
+ VASSERT_EQ("2", true, p2.isParentOf(p3));
+ VASSERT_EQ("3", true, p1.isParentOf(p3));
+ VASSERT_EQ("4", false, p2.isParentOf(p1));
+ }
+
+ void testIsParentOf_EquivalentCharset() {
+
+ path p1;
+ p1.appendComponent(comp("foo", "us-ascii"));
+
+ path p2;
+ p2.appendComponent(comp("foo", "utf-8"));
+ p2.appendComponent(comp("bar"));
+ p2.appendComponent(comp("baz"));
+
+ VASSERT_EQ("1", true, p1.isParentOf(p2));
+ }
+
+ void testRenameParent() {
+
+ path p1;
+ p1.appendComponent(comp("a"));
+ p1.appendComponent(comp("b"));
+ p1.appendComponent(comp("c"));
+ p1.appendComponent(comp("d"));
+
+ path p2;
+ p2.appendComponent(comp("a"));
+ p2.appendComponent(comp("b"));
+
+ path p3;
+ p3.appendComponent(comp("x"));
+ p3.appendComponent(comp("y"));
+ p3.appendComponent(comp("z"));
+
+ path p(p1);
+ p.renameParent(p2, p3);
+
+ VASSERT_EQ("1", 5, p.getSize());
+ VASSERT_EQ("2", "x", p.getComponentAt(0).getBuffer());
+ VASSERT_EQ("3", "y", p.getComponentAt(1).getBuffer());
+ VASSERT_EQ("4", "z", p.getComponentAt(2).getBuffer());
+ VASSERT_EQ("5", "c", p.getComponentAt(3).getBuffer());
+ VASSERT_EQ("6", "d", p.getComponentAt(4).getBuffer());
+ }
+
+ void testFromString() {
+
+ path p = path::fromString("ab/cde/f", "/", vmime::charset("my-charset"));
+
+ VASSERT_EQ("count", 3, p.getSize());
+ VASSERT_EQ("buffer1", "ab", p.getComponentAt(0).getBuffer());
+ VASSERT_EQ("charset1", "my-charset", p.getComponentAt(0).getCharset().getName());
+ VASSERT_EQ("buffer2", "cde", p.getComponentAt(1).getBuffer());
+ VASSERT_EQ("charset2", "my-charset", p.getComponentAt(1).getCharset().getName());
+ VASSERT_EQ("buffer3", "f", p.getComponentAt(2).getBuffer());
+ VASSERT_EQ("charset3", "my-charset", p.getComponentAt(2).getCharset().getName());
+ }
+
+ void testFromString_IgnoreLeadingOrTrailingSep() {
+
+ path p = path::fromString("//ab/cde/f////", "/", vmime::charset("my-charset"));
+
+ VASSERT_EQ("count", 3, p.getSize());
+ VASSERT_EQ("buffer1", "ab", p.getComponentAt(0).getBuffer());
+ VASSERT_EQ("charset1", "my-charset", p.getComponentAt(0).getCharset().getName());
+ VASSERT_EQ("buffer2", "cde", p.getComponentAt(1).getBuffer());
+ VASSERT_EQ("charset2", "my-charset", p.getComponentAt(1).getCharset().getName());
+ VASSERT_EQ("buffer3", "f", p.getComponentAt(2).getBuffer());
+ VASSERT_EQ("charset3", "my-charset", p.getComponentAt(2).getCharset().getName());
+ }
+
+ void testToString() {
+
+ path p;
+ p.appendComponent(comp("ab"));
+ p.appendComponent(comp("cde"));
+ p.appendComponent(comp("f"));
+
+ VASSERT_EQ("string", "ab/cde/f", p.toString("/", vmime::charset("us-ascii")));
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/utility/seekableInputStreamRegionAdapterTest.cpp b/vmime-master/tests/utility/seekableInputStreamRegionAdapterTest.cpp
new file mode 100644
index 0000000..b099cd7
--- /dev/null
+++ b/vmime-master/tests/utility/seekableInputStreamRegionAdapterTest.cpp
@@ -0,0 +1,176 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/utility/inputStreamStringAdapter.hpp"
+#include "vmime/utility/seekableInputStreamRegionAdapter.hpp"
+#include "vmime/utility/stringUtils.hpp"
+
+
+using namespace vmime::utility;
+
+
+VMIME_TEST_SUITE_BEGIN(seekableInputStreamRegionAdapterTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testInitialPosition)
+ VMIME_TEST(testSeekAndGetPosition)
+ VMIME_TEST(testRead)
+ VMIME_TEST(testSkip)
+ VMIME_TEST(testReset)
+ VMIME_TEST(testOwnPosition)
+ VMIME_TEST_LIST_END
+
+
+ vmime::shared_ptr <seekableInputStreamRegionAdapter> createStream(
+ vmime::shared_ptr <seekableInputStream>* underlyingStream = NULL
+ ) {
+
+ vmime::string buffer("THIS IS A TEST BUFFER");
+
+ vmime::shared_ptr <seekableInputStream> strStream =
+ vmime::make_shared <inputStreamStringAdapter>(buffer);
+
+ vmime::shared_ptr <seekableInputStreamRegionAdapter> rgnStream =
+ vmime::make_shared <seekableInputStreamRegionAdapter>(strStream, 10, 11);
+
+ if (underlyingStream) {
+ *underlyingStream = strStream;
+ }
+
+ return rgnStream;
+ }
+
+ void testInitialPosition() {
+
+ vmime::shared_ptr <seekableInputStreamRegionAdapter> stream = createStream();
+
+ VASSERT_EQ("Pos", 0, stream->getPosition());
+ VASSERT_FALSE("EOF", stream->eof());
+ }
+
+ void testSeekAndGetPosition() {
+
+ vmime::shared_ptr <seekableInputStreamRegionAdapter> stream = createStream();
+
+ stream->seek(5);
+
+ VASSERT_EQ("Pos 1", 5, stream->getPosition());
+ VASSERT_FALSE("EOF 1", stream->eof());
+
+ stream->seek(20);
+
+ VASSERT_EQ("Pos 2", 11, stream->getPosition());
+ VASSERT_TRUE("EOF 2", stream->eof());
+ }
+
+ void testRead() {
+
+ vmime::shared_ptr <seekableInputStreamRegionAdapter> stream = createStream();
+
+ stream->seek(5);
+
+ vmime::byte_t buffer[100];
+ std::fill(vmime::begin(buffer), vmime::end(buffer), 0);
+ vmime::size_t read = stream->read(buffer, 6);
+
+ VASSERT_EQ("Pos", 11, stream->getPosition());
+ VASSERT_EQ("Read", 6, read);
+ VASSERT_TRUE("EOF", stream->eof());
+ VASSERT_EQ("Buffer", "BUFFER", vmime::utility::stringUtils::makeStringFromBytes(buffer, 6));
+ }
+
+ void testSkip() {
+
+ vmime::shared_ptr <seekableInputStreamRegionAdapter> stream = createStream();
+
+ stream->skip(5);
+
+ VASSERT_EQ("Pos 1", 5, stream->getPosition());
+ VASSERT_FALSE("EOF 1", stream->eof());
+
+ vmime::byte_t buffer[100];
+ std::fill(vmime::begin(buffer), vmime::end(buffer), 0);
+ vmime::size_t read = stream->read(buffer, 3);
+
+ VASSERT_EQ("Pos 2", 8, stream->getPosition());
+ VASSERT_EQ("Read", 3, read);
+ VASSERT_FALSE("EOF 2", stream->eof());
+ VASSERT_EQ("Buffer", "BUF", vmime::utility::stringUtils::makeStringFromBytes(buffer, 3));
+
+ stream->skip(50);
+
+ VASSERT_EQ("Pos 3", 11, stream->getPosition());
+ VASSERT_TRUE("EOF 3", stream->eof());
+ }
+
+ void testReset() {
+
+ vmime::shared_ptr <seekableInputStreamRegionAdapter> stream = createStream();
+
+ stream->skip(100);
+ stream->reset();
+
+ VASSERT_EQ("Pos", 0, stream->getPosition());
+ VASSERT_FALSE("EOF", stream->eof());
+ }
+
+ void testOwnPosition() {
+
+ // seekableInputStreamRegionAdapter should keep track of its own position
+ // in the underlying stream, and not be affected by possible seek/read
+ // operations on it...
+ vmime::shared_ptr <seekableInputStream> ustream;
+ vmime::shared_ptr <seekableInputStreamRegionAdapter> stream = createStream(&ustream);
+
+ stream->seek(5);
+
+ vmime::byte_t buffer1[100];
+ std::fill(vmime::begin(buffer1), vmime::end(buffer1), 0);
+
+ VASSERT_EQ("Read 1", 7, ustream->read(buffer1, 7));
+
+ vmime::byte_t buffer2[100];
+ std::fill(vmime::begin(buffer2), vmime::end(buffer2), 0);
+
+ VASSERT_EQ("Read 2", 6, stream->read(buffer2, 6));
+
+ VASSERT_EQ(
+ "Buffer 1",
+ "THIS IS",
+ vmime::utility::stringUtils::makeStringFromBytes(buffer1, 7)
+ );
+
+ VASSERT_EQ(
+ "Buffer 2",
+ "BUFFER",
+ vmime::utility::stringUtils::makeStringFromBytes(buffer2, 6)
+ );
+
+ // ...but the underlying stream position is affected by read operations
+ // from the region adapter (FIXME?)
+ VASSERT_EQ("Pos", 21, ustream->getPosition());
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/utility/stringUtilsTest.cpp b/vmime-master/tests/utility/stringUtilsTest.cpp
new file mode 100644
index 0000000..6c2e18f
--- /dev/null
+++ b/vmime-master/tests/utility/stringUtilsTest.cpp
@@ -0,0 +1,214 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/utility/stringUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(stringUtilsTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testMakeStringFromBytes)
+ VMIME_TEST(testAppendBytesToString)
+
+ VMIME_TEST(testIsStringEqualNoCase1)
+ VMIME_TEST(testIsStringEqualNoCase2)
+ VMIME_TEST(testIsStringEqualNoCase3)
+
+ VMIME_TEST(testToLower)
+
+ VMIME_TEST(testTrim)
+
+ VMIME_TEST(testCountASCIIChars)
+
+ VMIME_TEST(testUnquote)
+
+ VMIME_TEST(testIsValidHostname)
+ VMIME_TEST(testIsValidFQDN)
+ VMIME_TEST_LIST_END
+
+
+ typedef vmime::utility::stringUtils stringUtils;
+
+
+ void testMakeStringFromBytes() {
+
+ vmime::byte_t bytes[] = { 0x12, 0x34, 0x56, 0x78 };
+ vmime::string str = vmime::utility::stringUtils::makeStringFromBytes(bytes, 3);
+
+ VASSERT_EQ("length", 3, str.length());
+ VASSERT_EQ("byte1", '\x12', str[0]);
+ VASSERT_EQ("byte2", '\x34', str[1]);
+ VASSERT_EQ("byte3", '\x56', str[2]);
+ }
+
+ void testAppendBytesToString() {
+
+ vmime::byte_t bytes[] = { 0x42, 0x56, 0x12, 0x00, 'f', 'o', 'o' };
+
+ vmime::string str = "test";
+ vmime::utility::stringUtils::appendBytesToString(str, bytes, 7);
+
+ VASSERT_EQ("length", 4 + 7, str.length());
+ VASSERT_EQ("byte1", 't', str[0]);
+ VASSERT_EQ("byte2", 'e', str[1]);
+ VASSERT_EQ("byte3", 's', str[2]);
+ VASSERT_EQ("byte4", 't', str[3]);
+ VASSERT_EQ("byte5", '\x42', str[4]);
+ VASSERT_EQ("byte6", '\x56', str[5]);
+ VASSERT_EQ("byte7", '\x12', str[6]);
+ VASSERT_EQ("byte8", '\0', str[7]);
+ VASSERT_EQ("byte9", 'f', str[8]);
+ VASSERT_EQ("byte10", 'o', str[9]);
+ VASSERT_EQ("byte11", 'o', str[10]);
+ }
+
+ void testIsStringEqualNoCase1() {
+
+ VASSERT_EQ("1", true, stringUtils::isStringEqualNoCase(vmime::string("foo"), "foo", 3));
+ VASSERT_EQ("2", true, stringUtils::isStringEqualNoCase(vmime::string("FOo"), "foo", 3));
+
+ VASSERT_EQ("3", false, stringUtils::isStringEqualNoCase(vmime::string("foo"), "FOo", 3));
+ VASSERT_EQ("4", false, stringUtils::isStringEqualNoCase(vmime::string("foo"), "bar", 3));
+
+ VASSERT_EQ("5", false, stringUtils::isStringEqualNoCase(vmime::string("foO"), "bar", 3));
+ VASSERT_EQ("6", false, stringUtils::isStringEqualNoCase(vmime::string("foOO"), "barO", 4));
+ VASSERT_EQ("7", false, stringUtils::isStringEqualNoCase(vmime::string("foOO"), "ba", 2));
+
+ VASSERT_EQ("8", true, stringUtils::isStringEqualNoCase(vmime::string("FOoooo"), "foo", 3));
+ }
+
+ void testIsStringEqualNoCase2() {
+
+ VASSERT_EQ("1", true, stringUtils::isStringEqualNoCase(vmime::string("foo"), vmime::string("foo")));
+ VASSERT_EQ("2", true, stringUtils::isStringEqualNoCase(vmime::string("FOo"), vmime::string("foo")));
+ VASSERT_EQ("3", true, stringUtils::isStringEqualNoCase(vmime::string("foO"), vmime::string("FOo")));
+
+ VASSERT_EQ("4", false, stringUtils::isStringEqualNoCase(vmime::string("foO"), vmime::string("bar")));
+ VASSERT_EQ("5", false, stringUtils::isStringEqualNoCase(vmime::string("foOO"), vmime::string("barO")));
+ }
+
+ void testIsStringEqualNoCase3() {
+
+ vmime::string str1("FooBar");
+
+ VASSERT_EQ("1", true, stringUtils::isStringEqualNoCase(str1.begin(), str1.end(), "foobar", 6));
+ VASSERT_EQ("2", false, stringUtils::isStringEqualNoCase(str1.begin(), str1.end(), "FooBar", 6));
+ VASSERT_EQ("3", true, stringUtils::isStringEqualNoCase(str1.begin(), str1.end(), "fooBar", 3));
+ VASSERT_EQ("4", false, stringUtils::isStringEqualNoCase(str1.begin(), str1.begin() + 3, "fooBar", 6));
+ VASSERT_EQ("5", false, stringUtils::isStringEqualNoCase(str1.begin(), str1.begin() + 3, "bar", 3));
+ VASSERT_EQ("6", false, stringUtils::isStringEqualNoCase(str1.begin(), str1.begin() + 6, "barbar", 6));
+ }
+
+ void testToLower() {
+
+ VASSERT_EQ("1", "foo", stringUtils::toLower("FOO"));
+ VASSERT_EQ("2", "foo", stringUtils::toLower("foO"));
+ VASSERT_EQ("3", "foo", stringUtils::toLower("foo"));
+ }
+
+ void testTrim() {
+
+ VASSERT_EQ("1", "foo", stringUtils::trim(" foo"));
+ VASSERT_EQ("2", "foo", stringUtils::trim("\t\tfoo"));
+ VASSERT_EQ("3", "foo", stringUtils::trim(" \t \tfoo"));
+ VASSERT_EQ("4", "foo", stringUtils::trim(" \r\n\tfoo"));
+
+ VASSERT_EQ("5", "foo", stringUtils::trim("foo "));
+ VASSERT_EQ("6", "foo", stringUtils::trim("foo\t\t"));
+ VASSERT_EQ("7", "foo", stringUtils::trim("foo \t \t"));
+ VASSERT_EQ("8", "foo", stringUtils::trim("foo \r\n\t"));
+
+ VASSERT_EQ( "9", "foo", stringUtils::trim("foo "));
+ VASSERT_EQ("10", "foo", stringUtils::trim(" foo "));
+ VASSERT_EQ("11", "foo", stringUtils::trim(" foo\t\t"));
+ VASSERT_EQ("12", "foo", stringUtils::trim("\tfoo \r \t"));
+ VASSERT_EQ("13", "foo", stringUtils::trim("\r \tfoo \n\t"));
+ }
+
+ void testCountASCIIChars() {
+
+ vmime::string str1("foo");
+ VASSERT_EQ(
+ "1",
+ static_cast <vmime::size_t>(3),
+ stringUtils::countASCIIchars(str1.begin(), str1.end())
+ );
+
+ vmime::string str2("f=?oo");
+ VASSERT_EQ(
+ "2",
+ static_cast <vmime::size_t>(3 + 1),
+ stringUtils::countASCIIchars(str2.begin(), str2.end())
+ );
+
+ vmime::string str3("foo\x7f");
+ VASSERT_EQ(
+ "3",
+ static_cast <vmime::size_t>(4),
+ stringUtils::countASCIIchars(str3.begin(), str3.end())
+ );
+
+ vmime::string str4("foo\x80");
+ VASSERT_EQ(
+ "4",
+ static_cast <vmime::size_t>(3),
+ stringUtils::countASCIIchars(str4.begin(), str4.end())
+ );
+ }
+
+ void testUnquote() {
+
+ VASSERT_EQ("1", "quoted", stringUtils::unquote("\"quoted\"")); // "quoted"
+ VASSERT_EQ("2", "\"not quoted", stringUtils::unquote("\"not quoted")); // "not quoted
+ VASSERT_EQ("3", "not quoted\"", stringUtils::unquote("not quoted\"")); // not quoted"
+ VASSERT_EQ("4", "quoted with \"escape\"", stringUtils::unquote("\"quoted with \\\"escape\\\"\"")); // "quoted with \"escape\""
+ }
+
+ void testIsValidHostname() {
+
+ VASSERT_TRUE ("1", stringUtils::isValidHostname("localhost"));
+ VASSERT_TRUE ("2", stringUtils::isValidHostname("localhost.localdomain"));
+ VASSERT_TRUE ("3", stringUtils::isValidHostname("example.com"));
+ VASSERT_TRUE ("4", stringUtils::isValidHostname("host.example.com"));
+ VASSERT_FALSE("5", stringUtils::isValidHostname(".example.com"));
+ VASSERT_FALSE("6", stringUtils::isValidHostname(".-example.com"));
+ VASSERT_FALSE("7", stringUtils::isValidHostname(".example-.com"));
+ VASSERT_FALSE("8", stringUtils::isValidHostname(".exa--mple.com"));
+ VASSERT_FALSE("9", stringUtils::isValidHostname("-example.com"));
+ }
+
+ void testIsValidFQDN() {
+
+ VASSERT_FALSE("1", stringUtils::isValidFQDN("localhost"));
+ VASSERT_FALSE("2", stringUtils::isValidFQDN("localhost.localdomain"));
+ VASSERT_FALSE("3", stringUtils::isValidFQDN("example.com"));
+ VASSERT_TRUE ("4", stringUtils::isValidFQDN("host.example.com"));
+ VASSERT_FALSE("5", stringUtils::isValidFQDN(".example.com"));
+ VASSERT_FALSE("6", stringUtils::isValidFQDN(".-example.com"));
+ VASSERT_FALSE("7", stringUtils::isValidFQDN(".example-.com"));
+ VASSERT_FALSE("8", stringUtils::isValidFQDN(".exa--mple.com"));
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/tests/utility/urlTest.cpp b/vmime-master/tests/utility/urlTest.cpp
new file mode 100644
index 0000000..36820a6
--- /dev/null
+++ b/vmime-master/tests/utility/urlTest.cpp
@@ -0,0 +1,312 @@
+//
+// VMime library (http://www.vmime.org)
+// Copyright (C) 2002 Vincent Richard <vincent@vmime.org>
+//
+// This program is free software; you can redistribute it and/or
+// modify it under the terms of the GNU General Public License as
+// published by the Free Software Foundation; either version 3 of
+// the License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License along
+// with this program; if not, write to the Free Software Foundation, Inc.,
+// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Linking this library statically or dynamically with other modules is making
+// a combined work based on this library. Thus, the terms and conditions of
+// the GNU General Public License cover the whole combination.
+//
+
+#include "tests/testUtils.hpp"
+
+#include "vmime/utility/url.hpp"
+#include "vmime/utility/urlUtils.hpp"
+
+
+VMIME_TEST_SUITE_BEGIN(urlTest)
+
+ VMIME_TEST_LIST_BEGIN
+ VMIME_TEST(testParse1)
+ VMIME_TEST(testParse2)
+ VMIME_TEST(testParse3)
+ VMIME_TEST(testParse4)
+ VMIME_TEST(testParse5)
+ VMIME_TEST(testGenerate)
+ VMIME_TEST(testUtilsEncode)
+ VMIME_TEST(testUtilsDecode)
+ VMIME_TEST(testUtilsDecodeSpecialCases)
+ VMIME_TEST(testUtilsEncodeReservedChars)
+ VMIME_TEST(testUtilsEncodeUnsafeChars)
+ VMIME_TEST_LIST_END
+
+
+ static bool parseHelper(vmime::utility::url& u, const vmime::string& str) {
+
+ try {
+
+ u = vmime::utility::url(str);
+
+ } catch (vmime::exceptions::malformed_url) {
+
+ return false;
+ }
+
+ return true;
+ }
+
+
+ void testParse1() {
+
+ // Test some valid constructions
+ vmime::utility::url u1("", "");
+
+ VASSERT_EQ("1.1", true, parseHelper(u1, "protocol://user:password@host:12345/path/"));
+ VASSERT_EQ("1.2", "protocol", u1.getProtocol());
+ VASSERT_EQ("1.3", "user", u1.getUsername());
+ VASSERT_EQ("1.4", "password", u1.getPassword());
+ VASSERT_EQ("1.5", "host", u1.getHost());
+ VASSERT_EQ("1.6", 12345, u1.getPort());
+ VASSERT_EQ("1.7", "/path/", u1.getPath());
+
+ vmime::utility::url u2("", "");
+
+ VASSERT_EQ("2.1", true, parseHelper(u2, "protocol://user@host:12345/path/"));
+ VASSERT_EQ("2.2", "protocol", u2.getProtocol());
+ VASSERT_EQ("2.3", "user", u2.getUsername());
+ VASSERT_EQ("2.4", "", u2.getPassword());
+ VASSERT_EQ("2.5", "host", u2.getHost());
+ VASSERT_EQ("2.6", 12345, u2.getPort());
+ VASSERT_EQ("2.7", "/path/", u2.getPath());
+
+ vmime::utility::url u3("", "");
+
+ VASSERT_EQ("3.1", true, parseHelper(u3, "protocol://host:12345/path/"));
+ VASSERT_EQ("3.2", "protocol", u3.getProtocol());
+ VASSERT_EQ("3.3", "", u3.getUsername());
+ VASSERT_EQ("3.4", "", u3.getPassword());
+ VASSERT_EQ("3.5", "host", u3.getHost());
+ VASSERT_EQ("3.6", 12345, u3.getPort());
+ VASSERT_EQ("3.7", "/path/", u3.getPath());
+
+ vmime::utility::url u4("", "");
+
+ VASSERT_EQ("4.1", true, parseHelper(u4, "protocol://host/path/"));
+ VASSERT_EQ("4.2", "protocol", u4.getProtocol());
+ VASSERT_EQ("4.3", "", u4.getUsername());
+ VASSERT_EQ("4.4", "", u4.getPassword());
+ VASSERT_EQ("4.5", "host", u4.getHost());
+ VASSERT_EQ("4.6", vmime::utility::url::UNSPECIFIED_PORT, u4.getPort());
+ VASSERT_EQ("4.7", "/path/", u4.getPath());
+
+ vmime::utility::url u5("", "");
+
+ VASSERT_EQ("5.1", true, parseHelper(u5, "protocol://host/"));
+ VASSERT_EQ("5.2", "protocol", u5.getProtocol());
+ VASSERT_EQ("5.3", "", u5.getUsername());
+ VASSERT_EQ("5.4", "", u5.getPassword());
+ VASSERT_EQ("5.5", "host", u5.getHost());
+ VASSERT_EQ("5.6", vmime::utility::url::UNSPECIFIED_PORT, u4.getPort());
+ VASSERT_EQ("5.7", "", u5.getPath());
+
+ vmime::utility::url u6("", "");
+
+ VASSERT_EQ("6.1", true, parseHelper(u4, "protocol://host/path/file"));
+ VASSERT_EQ("6.2", "protocol", u4.getProtocol());
+ VASSERT_EQ("6.3", "", u4.getUsername());
+ VASSERT_EQ("6.4", "", u4.getPassword());
+ VASSERT_EQ("6.5", "host", u4.getHost());
+ VASSERT_EQ("6.6", vmime::utility::url::UNSPECIFIED_PORT, u4.getPort());
+ VASSERT_EQ("6.7", "/path/file", u4.getPath());
+ }
+
+ void testParse2() {
+
+ // Now, test some ill-formed URLs
+
+ // -- missing protocol
+ vmime::utility::url u1("", "");
+ VASSERT_EQ("1", false, parseHelper(u1, "://host"));
+
+ // -- port can contain only digits
+ vmime::utility::url u2("", "");
+ VASSERT_EQ("2", false, parseHelper(u2, "proto://host:abc123"));
+
+ // -- no host specified
+ vmime::utility::url u3("", "");
+ VASSERT_EQ("3", false, parseHelper(u3, "proto:///path"));
+
+ // -- no protocol separator (://)
+ vmime::utility::url u4("", "");
+ VASSERT_EQ("4", false, parseHelper(u4, "protohost/path"));
+ }
+
+ void testParse3() {
+
+ // Test decoding
+ vmime::utility::url u1("", "");
+
+ VASSERT_EQ("1.1", true, parseHelper(u1, "pro%12to://user%34:pass%56word@ho%78st:12345/pa%abth/"));
+ VASSERT_EQ("1.2", "pro%12to", u1.getProtocol()); // protocol should not be decoded
+ VASSERT_EQ("1.3", "user\x34", u1.getUsername());
+ VASSERT_EQ("1.4", "pass\x56word", u1.getPassword());
+ VASSERT_EQ("1.5", "ho\x78st", u1.getHost());
+ VASSERT_EQ("1.6", 12345, u1.getPort());
+ VASSERT_EQ("1.7", "/pa\xabth/", u1.getPath());
+ }
+
+ void testParse4() {
+
+ // Test parameters
+ vmime::utility::url u1("", "");
+
+ VASSERT_EQ("1.1", true, parseHelper(u1, "proto://host/path?p1=v1&p2=v2"));
+ VASSERT_EQ("1.2", "v1", u1.getParams()["p1"]);
+ VASSERT_EQ("1.3", "v2", u1.getParams()["p2"]);
+ VASSERT_EQ("1.4", "/path", u1.getPath());
+
+ vmime::utility::url u2("", "");
+
+ VASSERT_EQ("2.1", true, parseHelper(u2, "proto://host/path?p1=v1&p2"));
+ VASSERT_EQ("2.2", "v1", u2.getParams()["p1"]);
+ VASSERT_EQ("2.3", "p2", u2.getParams()["p2"]);
+ VASSERT_EQ("2.4", "/path", u2.getPath());
+
+ vmime::utility::url u3("", "");
+
+ VASSERT_EQ("3.1", true, parseHelper(u3, "proto://host/?p1=v1&p2=v2"));
+ VASSERT_EQ("3.2", "v1", u3.getParams()["p1"]);
+ VASSERT_EQ("3.3", "v2", u3.getParams()["p2"]);
+ VASSERT_EQ("3.4", "", u3.getPath());
+
+ vmime::utility::url u4("", "");
+
+ VASSERT_EQ("4.1", true, parseHelper(u4, "proto://host/path?p1=%3D&%3D=v2"));
+ VASSERT_EQ("4.2", "=", u4.getParams()["p1"]);
+ VASSERT_EQ("4.3", "v2", u4.getParams()["="]);
+ VASSERT_EQ("4.4", "/path", u4.getPath());
+ }
+
+ // '@' symbol in the username part
+ void testParse5() {
+
+ vmime::utility::url u1("", "");
+
+ VASSERT_EQ("1", true, parseHelper(u1, "imap://account@myserver.com:password@myserver.com"));
+ VASSERT_EQ("2", "account@myserver.com", u1.getUsername());
+ VASSERT_EQ("3", "password", u1.getPassword());
+ VASSERT_EQ("4", "myserver.com", u1.getHost());
+ }
+
+ void testGenerate() {
+
+ vmime::utility::url u1("proto", "host", 12345, "path", "user", "password");
+ VASSERT_EQ(
+ "1",
+ "proto://user:password@host:12345/path",
+ static_cast <vmime::string>(u1)
+ );
+
+ vmime::utility::url u2("proto", "host");
+ VASSERT_EQ("2", "proto://host", static_cast <vmime::string>(u2));
+
+ vmime::utility::url u3("proto", "host");
+ u3.getParams()["p1"] = "v1";
+ VASSERT_EQ(
+ "3.1",
+ "proto://host/?p1=v1",
+ static_cast <vmime::string>(u3)
+ );
+ u3.getParams()["p2"] = "v2";
+ VASSERT_EQ(
+ "3.2",
+ "proto://host/?p1=v1&p2=v2",
+ static_cast <vmime::string>(u3)
+ );
+
+ // Test special characters
+ u3.getParams().clear();
+ u3.getParams()["&"] = "=";
+ VASSERT_EQ(
+ "3.3",
+ "proto://host/?%26=%3D",
+ static_cast <vmime::string>(u3)
+ );
+ }
+
+ void testUtilsEncode() {
+
+ VASSERT_EQ("1", "%01", vmime::utility::urlUtils::encode("\x01"));
+ VASSERT_EQ("2", "%20", vmime::utility::urlUtils::encode(" "));
+ VASSERT_EQ("3", "%FF", vmime::utility::urlUtils::encode("\xff"));
+ VASSERT_EQ("4", "a", vmime::utility::urlUtils::encode("a"));
+ }
+
+ void testUtilsDecode() {
+
+ for (int i = 0 ; i < 255 ; ++i) {
+
+ std::ostringstream ossTest;
+ ossTest << "%" << "0123456789ABCDEF"[i / 16]
+ << "0123456789ABCDEF"[i % 16];
+
+ std::ostringstream ossNum;
+ ossNum << i;
+
+ vmime::string res;
+ res += static_cast <unsigned char>(i);
+
+ VASSERT_EQ(
+ ossNum.str(),
+ res,
+ vmime::utility::urlUtils::decode(ossTest.str())
+ );
+ }
+
+ }
+
+ void testUtilsDecodeSpecialCases() {
+
+ // Bug #1656547: segfault with '%' at the end of the string
+ VASSERT_EQ("1.1", "sadfsda%", vmime::utility::urlUtils::decode("sadfsda%"));
+ VASSERT_EQ("1.2", "sadfsda\x05", vmime::utility::urlUtils::decode("sadfsda%5"));
+ VASSERT_EQ("1.3", "sadfsda\x42", vmime::utility::urlUtils::decode("sadfsda%42"));
+ }
+
+ void testUtilsEncodeReservedChars() {
+
+ VASSERT_EQ("1", "%24", vmime::utility::urlUtils::encode("$"));
+ VASSERT_EQ("2", "%26", vmime::utility::urlUtils::encode("&"));
+ VASSERT_EQ("3", "%2B", vmime::utility::urlUtils::encode("+"));
+ VASSERT_EQ("4", "%2C", vmime::utility::urlUtils::encode(","));
+ VASSERT_EQ("5", "%2F", vmime::utility::urlUtils::encode("/"));
+ VASSERT_EQ("6", "%3A", vmime::utility::urlUtils::encode(":"));
+ VASSERT_EQ("7", "%3B", vmime::utility::urlUtils::encode(";"));
+ VASSERT_EQ("8", "%3D", vmime::utility::urlUtils::encode("="));
+ VASSERT_EQ("9", "%3F", vmime::utility::urlUtils::encode("?"));
+ VASSERT_EQ("10", "%40", vmime::utility::urlUtils::encode("@"));
+ }
+
+ void testUtilsEncodeUnsafeChars() {
+
+ VASSERT_EQ("1", "%20", vmime::utility::urlUtils::encode(" "));
+ VASSERT_EQ("2", "%22", vmime::utility::urlUtils::encode("\""));
+ VASSERT_EQ("3", "%3C", vmime::utility::urlUtils::encode("<"));
+ VASSERT_EQ("4", "%3E", vmime::utility::urlUtils::encode(">"));
+ VASSERT_EQ("5", "%23", vmime::utility::urlUtils::encode("#"));
+ VASSERT_EQ("6", "%25", vmime::utility::urlUtils::encode("%"));
+ VASSERT_EQ("7", "%7B", vmime::utility::urlUtils::encode("{"));
+ VASSERT_EQ("8", "%7D", vmime::utility::urlUtils::encode("}"));
+ VASSERT_EQ("9", "%7C", vmime::utility::urlUtils::encode("|"));
+ VASSERT_EQ("10", "%5C", vmime::utility::urlUtils::encode("\\"));
+ VASSERT_EQ("11", "%5E", vmime::utility::urlUtils::encode("^"));
+ VASSERT_EQ("12", "%7E", vmime::utility::urlUtils::encode("~"));
+ VASSERT_EQ("13", "%5B", vmime::utility::urlUtils::encode("["));
+ VASSERT_EQ("14", "%5D", vmime::utility::urlUtils::encode("]"));
+ VASSERT_EQ("15", "%60", vmime::utility::urlUtils::encode("`"));
+ }
+
+VMIME_TEST_SUITE_END
diff --git a/vmime-master/vmime.pc.in b/vmime-master/vmime.pc.in
new file mode 100644
index 0000000..fc1103e
--- /dev/null
+++ b/vmime-master/vmime.pc.in
@@ -0,0 +1,13 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: @VMIME_PACKAGE_NAME@
+Description: @VMIME_PACKAGE_DESCRIPTION@
+Version: @VMIME_PACKAGE_VERSION@
+Requires.private: @VMIME_PKGCONFIG_REQUIRES@
+Libs: -L${libdir} -l@VMIME_LIBRARY_NAME@
+Libs.private: @VMIME_PKGCONFIG_LIBS@
+Cflags: -I${includedir}/ @VMIME_PKGCONFIG_CFLAGS@
+