From aa4d426b4d3527d7e166df1a05058c9a4a0f6683 Mon Sep 17 00:00:00 2001 From: Wojtek Kosior Date: Fri, 30 Apr 2021 00:33:56 +0200 Subject: initial/final commit --- vmime-master/.gitignore | 41 + vmime-master/.travis.yml | 37 + vmime-master/AUTHORS | 38 + vmime-master/CMakeLists.txt | 1038 ++++ vmime-master/COPYING | 674 +++ vmime-master/COPYING.OpenSSL | 26 + vmime-master/Doxyfile.in | 1043 ++++ vmime-master/HACKING | 360 ++ vmime-master/NEWS | 0 vmime-master/README | 30 + vmime-master/README.autotools | 13 + vmime-master/build_for_losedows.sh | 23 + vmime-master/cmake/FindCppUnit.cmake | 34 + vmime-master/cmake/FindGSasl.cmake | 51 + vmime-master/cmake/FindICU.cmake | 314 ++ vmime-master/cmake/FindIconv.cmake | 61 + vmime-master/cmake/Utils.cmake | 13 + vmime-master/cmake/config.hpp.cmake | 97 + vmime-master/config_header/config.hpp | 97 + vmime-master/contrib/punycode/punycode.c | 264 ++ vmime-master/contrib/punycode/punycode.h | 84 + vmime-master/contrib/utf8/utf8.h | 34 + vmime-master/contrib/utf8/utf8/checked.h | 327 ++ vmime-master/contrib/utf8/utf8/core.h | 326 ++ vmime-master/contrib/utf8/utf8/unchecked.h | 228 + vmime-master/doc/book/.gitignore | 17 + vmime-master/doc/book/basics.tex | 823 ++++ vmime-master/doc/book/book.tex | 118 + vmime-master/doc/book/building.tex | 175 + .../book/images/address-mailbox-mailboxgroup.svg | 355 ++ .../doc/book/images/message-body-header.svg | 716 +++ .../doc/book/images/messaging-services.svg | 617 +++ vmime-master/doc/book/intro.tex | 90 + vmime-master/doc/book/msg.tex | 430 ++ vmime-master/doc/book/net.tex | 1203 +++++ vmime-master/doc/book/start.tex | 111 + vmime-master/examples/CMakeLists.txt | 38 + vmime-master/examples/example1.cpp | 107 + vmime-master/examples/example2.cpp | 121 + vmime-master/examples/example3.cpp | 153 + vmime-master/examples/example4.cpp | 108 + vmime-master/examples/example5.cpp | 85 + vmime-master/examples/example6.cpp | 938 ++++ vmime-master/examples/example6_authenticator.hpp | 112 + .../examples/example6_certificateVerifier.hpp | 64 + vmime-master/examples/example6_timeoutHandler.hpp | 60 + vmime-master/examples/example6_tracer.hpp | 59 + vmime-master/examples/example7.cpp | 118 + vmime-master/examples/viewer/CMakeLists.txt | 31 + vmime-master/examples/viewer/viewer.cpp | 294 ++ vmime-master/mingw_cross_toolchain.cmake | 14 + vmime-master/src/vmime/address.cpp | 236 + vmime-master/src/vmime/address.hpp | 89 + vmime-master/src/vmime/addressList.cpp | 328 ++ vmime-master/src/vmime/addressList.hpp | 198 + vmime-master/src/vmime/attachment.hpp | 116 + vmime-master/src/vmime/attachmentHelper.cpp | 339 ++ vmime-master/src/vmime/attachmentHelper.hpp | 137 + vmime-master/src/vmime/base.cpp | 158 + vmime-master/src/vmime/base.hpp | 258 + vmime-master/src/vmime/body.cpp | 1111 +++++ vmime-master/src/vmime/body.hpp | 365 ++ vmime-master/src/vmime/bodyPart.cpp | 198 + vmime-master/src/vmime/bodyPart.hpp | 155 + vmime-master/src/vmime/bodyPartAttachment.cpp | 147 + vmime-master/src/vmime/bodyPartAttachment.hpp | 76 + vmime-master/src/vmime/charset.cpp | 268 ++ vmime-master/src/vmime/charset.hpp | 176 + vmime-master/src/vmime/charsetConverter.cpp | 53 + vmime-master/src/vmime/charsetConverter.hpp | 162 + vmime-master/src/vmime/charsetConverterOptions.cpp | 37 + vmime-master/src/vmime/charsetConverterOptions.hpp | 59 + vmime-master/src/vmime/charsetConverter_iconv.cpp | 537 +++ vmime-master/src/vmime/charsetConverter_iconv.hpp | 145 + vmime-master/src/vmime/charsetConverter_icu.cpp | 572 +++ vmime-master/src/vmime/charsetConverter_icu.hpp | 137 + vmime-master/src/vmime/charsetConverter_idna.cpp | 208 + vmime-master/src/vmime/charsetConverter_idna.hpp | 74 + vmime-master/src/vmime/charsetConverter_win.cpp | 227 + vmime-master/src/vmime/charsetConverter_win.hpp | 91 + vmime-master/src/vmime/component.cpp | 275 ++ vmime-master/src/vmime/component.hpp | 265 ++ vmime-master/src/vmime/constants.cpp | 251 + vmime-master/src/vmime/constants.hpp | 272 ++ vmime-master/src/vmime/contentDisposition.cpp | 144 + vmime-master/src/vmime/contentDisposition.hpp | 99 + vmime-master/src/vmime/contentDispositionField.cpp | 162 + vmime-master/src/vmime/contentDispositionField.hpp | 146 + vmime-master/src/vmime/contentHandler.cpp | 39 + vmime-master/src/vmime/contentHandler.hpp | 147 + vmime-master/src/vmime/contentTypeField.cpp | 114 + vmime-master/src/vmime/contentTypeField.hpp | 113 + vmime-master/src/vmime/context.cpp | 86 + vmime-master/src/vmime/context.hpp | 120 + vmime-master/src/vmime/dateTime.cpp | 925 ++++ vmime-master/src/vmime/dateTime.hpp | 275 ++ vmime-master/src/vmime/defaultAttachment.cpp | 164 + vmime-master/src/vmime/defaultAttachment.hpp | 99 + vmime-master/src/vmime/disposition.cpp | 351 ++ vmime-master/src/vmime/disposition.hpp | 163 + vmime-master/src/vmime/emailAddress.cpp | 708 +++ vmime-master/src/vmime/emailAddress.hpp | 135 + vmime-master/src/vmime/emptyContentHandler.cpp | 126 + vmime-master/src/vmime/emptyContentHandler.hpp | 80 + vmime-master/src/vmime/encoding.cpp | 331 ++ vmime-master/src/vmime/encoding.hpp | 180 + vmime-master/src/vmime/exception.cpp | 735 +++ vmime-master/src/vmime/exception.hpp | 865 ++++ vmime-master/src/vmime/export.hpp | 36 + vmime-master/src/vmime/fileAttachment.cpp | 253 + vmime-master/src/vmime/fileAttachment.hpp | 226 + vmime-master/src/vmime/fileContentHandler.cpp | 94 + vmime-master/src/vmime/fileContentHandler.hpp | 102 + .../src/vmime/generatedMessageAttachment.cpp | 108 + .../src/vmime/generatedMessageAttachment.hpp | 77 + vmime-master/src/vmime/generationContext.cpp | 139 + vmime-master/src/vmime/generationContext.hpp | 171 + vmime-master/src/vmime/header.cpp | 417 ++ vmime-master/src/vmime/header.hpp | 362 ++ vmime-master/src/vmime/headerField.cpp | 374 ++ vmime-master/src/vmime/headerField.hpp | 191 + vmime-master/src/vmime/headerFieldFactory.cpp | 158 + vmime-master/src/vmime/headerFieldFactory.hpp | 159 + vmime-master/src/vmime/headerFieldValue.cpp | 43 + vmime-master/src/vmime/headerFieldValue.hpp | 49 + vmime-master/src/vmime/htmlTextPart.cpp | 568 +++ vmime-master/src/vmime/htmlTextPart.hpp | 268 ++ vmime-master/src/vmime/mailbox.cpp | 476 ++ vmime-master/src/vmime/mailbox.hpp | 123 + vmime-master/src/vmime/mailboxField.cpp | 96 + vmime-master/src/vmime/mailboxField.hpp | 69 + vmime-master/src/vmime/mailboxGroup.cpp | 406 ++ vmime-master/src/vmime/mailboxGroup.hpp | 206 + vmime-master/src/vmime/mailboxList.cpp | 252 + vmime-master/src/vmime/mailboxList.hpp | 184 + vmime-master/src/vmime/mdn/MDNHelper.cpp | 362 ++ vmime-master/src/vmime/mdn/MDNHelper.hpp | 142 + vmime-master/src/vmime/mdn/MDNInfos.cpp | 38 + vmime-master/src/vmime/mdn/MDNInfos.hpp | 57 + vmime-master/src/vmime/mdn/receivedMDNInfos.cpp | 140 + vmime-master/src/vmime/mdn/receivedMDNInfos.hpp | 93 + vmime-master/src/vmime/mdn/sendableMDNInfos.cpp | 72 + vmime-master/src/vmime/mdn/sendableMDNInfos.hpp | 72 + vmime-master/src/vmime/mediaType.cpp | 207 + vmime-master/src/vmime/mediaType.hpp | 119 + vmime-master/src/vmime/message.cpp | 49 + vmime-master/src/vmime/message.hpp | 60 + vmime-master/src/vmime/messageAttachment.hpp | 52 + vmime-master/src/vmime/messageBuilder.cpp | 333 ++ vmime-master/src/vmime/messageBuilder.hpp | 221 + vmime-master/src/vmime/messageId.cpp | 329 ++ vmime-master/src/vmime/messageId.hpp | 144 + vmime-master/src/vmime/messageIdSequence.cpp | 277 ++ vmime-master/src/vmime/messageIdSequence.hpp | 175 + vmime-master/src/vmime/messageParser.cpp | 328 ++ vmime-master/src/vmime/messageParser.hpp | 164 + vmime-master/src/vmime/misc/importanceHelper.cpp | 163 + vmime-master/src/vmime/misc/importanceHelper.hpp | 103 + vmime-master/src/vmime/net/builtinServices.inl | 76 + vmime-master/src/vmime/net/connectionInfos.hpp | 68 + .../src/vmime/net/defaultConnectionInfos.cpp | 60 + .../src/vmime/net/defaultConnectionInfos.hpp | 66 + .../src/vmime/net/defaultTimeoutHandler.cpp | 78 + .../src/vmime/net/defaultTimeoutHandler.hpp | 80 + vmime-master/src/vmime/net/dsnAttributes.cpp | 71 + vmime-master/src/vmime/net/dsnAttributes.hpp | 114 + vmime-master/src/vmime/net/events.cpp | 180 + vmime-master/src/vmime/net/events.hpp | 276 ++ vmime-master/src/vmime/net/fetchAttributes.cpp | 98 + vmime-master/src/vmime/net/fetchAttributes.hpp | 140 + vmime-master/src/vmime/net/folder.cpp | 134 + vmime-master/src/vmime/net/folder.hpp | 440 ++ vmime-master/src/vmime/net/folderAttributes.cpp | 122 + vmime-master/src/vmime/net/folderAttributes.hpp | 177 + vmime-master/src/vmime/net/folderStatus.hpp | 73 + vmime-master/src/vmime/net/imap/IMAPCommand.cpp | 437 ++ vmime-master/src/vmime/net/imap/IMAPCommand.hpp | 124 + vmime-master/src/vmime/net/imap/IMAPConnection.cpp | 886 ++++ vmime-master/src/vmime/net/imap/IMAPConnection.hpp | 172 + vmime-master/src/vmime/net/imap/IMAPFolder.cpp | 1622 +++++++ vmime-master/src/vmime/net/imap/IMAPFolder.hpp | 230 + .../src/vmime/net/imap/IMAPFolderStatus.cpp | 292 ++ .../src/vmime/net/imap/IMAPFolderStatus.hpp | 123 + vmime-master/src/vmime/net/imap/IMAPMessage.cpp | 760 +++ vmime-master/src/vmime/net/imap/IMAPMessage.hpp | 200 + .../src/vmime/net/imap/IMAPMessagePart.cpp | 225 + .../src/vmime/net/imap/IMAPMessagePart.hpp | 108 + .../net/imap/IMAPMessagePartContentHandler.cpp | 227 + .../net/imap/IMAPMessagePartContentHandler.hpp | 95 + .../src/vmime/net/imap/IMAPMessageStructure.cpp | 94 + .../src/vmime/net/imap/IMAPMessageStructure.hpp | 75 + vmime-master/src/vmime/net/imap/IMAPParser.hpp | 4986 ++++++++++++++++++++ vmime-master/src/vmime/net/imap/IMAPSStore.cpp | 82 + vmime-master/src/vmime/net/imap/IMAPSStore.hpp | 70 + .../src/vmime/net/imap/IMAPServiceInfos.cpp | 135 + .../src/vmime/net/imap/IMAPServiceInfos.hpp | 89 + vmime-master/src/vmime/net/imap/IMAPStore.cpp | 287 ++ vmime-master/src/vmime/net/imap/IMAPStore.hpp | 124 + vmime-master/src/vmime/net/imap/IMAPTag.cpp | 148 + vmime-master/src/vmime/net/imap/IMAPTag.hpp | 85 + vmime-master/src/vmime/net/imap/IMAPUtils.cpp | 854 ++++ vmime-master/src/vmime/net/imap/IMAPUtils.hpp | 144 + vmime-master/src/vmime/net/imap/imap.hpp | 35 + .../net/maildir/format/courierMaildirFormat.cpp | 569 +++ .../net/maildir/format/courierMaildirFormat.hpp | 127 + .../net/maildir/format/kmailMaildirFormat.cpp | 337 ++ .../net/maildir/format/kmailMaildirFormat.hpp | 115 + vmime-master/src/vmime/net/maildir/maildir.hpp | 34 + .../src/vmime/net/maildir/maildirFolder.cpp | 1365 ++++++ .../src/vmime/net/maildir/maildirFolder.hpp | 211 + .../src/vmime/net/maildir/maildirFolderStatus.cpp | 88 + .../src/vmime/net/maildir/maildirFolderStatus.hpp | 75 + .../src/vmime/net/maildir/maildirFormat.cpp | 104 + .../src/vmime/net/maildir/maildirFormat.hpp | 192 + .../src/vmime/net/maildir/maildirMessage.cpp | 410 ++ .../src/vmime/net/maildir/maildirMessage.hpp | 137 + .../src/vmime/net/maildir/maildirMessagePart.cpp | 178 + .../src/vmime/net/maildir/maildirMessagePart.hpp | 106 + .../vmime/net/maildir/maildirMessageStructure.cpp | 104 + .../vmime/net/maildir/maildirMessageStructure.hpp | 82 + .../src/vmime/net/maildir/maildirServiceInfos.cpp | 76 + .../src/vmime/net/maildir/maildirServiceInfos.hpp | 69 + .../src/vmime/net/maildir/maildirStore.cpp | 294 ++ .../src/vmime/net/maildir/maildirStore.hpp | 123 + .../src/vmime/net/maildir/maildirUtils.cpp | 288 ++ .../src/vmime/net/maildir/maildirUtils.hpp | 160 + vmime-master/src/vmime/net/message.cpp | 155 + vmime-master/src/vmime/net/message.hpp | 369 ++ vmime-master/src/vmime/net/messageSet.cpp | 430 ++ vmime-master/src/vmime/net/messageSet.hpp | 358 ++ vmime-master/src/vmime/net/pop3/POP3Command.cpp | 267 ++ vmime-master/src/vmime/net/pop3/POP3Command.hpp | 123 + vmime-master/src/vmime/net/pop3/POP3Connection.cpp | 737 +++ vmime-master/src/vmime/net/pop3/POP3Connection.hpp | 132 + vmime-master/src/vmime/net/pop3/POP3Folder.cpp | 822 ++++ vmime-master/src/vmime/net/pop3/POP3Folder.hpp | 179 + .../src/vmime/net/pop3/POP3FolderStatus.cpp | 88 + .../src/vmime/net/pop3/POP3FolderStatus.hpp | 75 + vmime-master/src/vmime/net/pop3/POP3Message.cpp | 283 ++ vmime-master/src/vmime/net/pop3/POP3Message.hpp | 124 + vmime-master/src/vmime/net/pop3/POP3Response.cpp | 504 ++ vmime-master/src/vmime/net/pop3/POP3Response.hpp | 194 + vmime-master/src/vmime/net/pop3/POP3SStore.cpp | 82 + vmime-master/src/vmime/net/pop3/POP3SStore.hpp | 74 + .../src/vmime/net/pop3/POP3ServiceInfos.cpp | 142 + .../src/vmime/net/pop3/POP3ServiceInfos.hpp | 91 + vmime-master/src/vmime/net/pop3/POP3Store.cpp | 262 + vmime-master/src/vmime/net/pop3/POP3Store.hpp | 120 + vmime-master/src/vmime/net/pop3/POP3Utils.cpp | 135 + vmime-master/src/vmime/net/pop3/POP3Utils.hpp | 92 + vmime-master/src/vmime/net/pop3/pop3.hpp | 35 + .../src/vmime/net/securedConnectionInfos.hpp | 55 + vmime-master/src/vmime/net/sendmail/sendmail.hpp | 31 + .../vmime/net/sendmail/sendmailServiceInfos.cpp | 77 + .../vmime/net/sendmail/sendmailServiceInfos.hpp | 69 + .../src/vmime/net/sendmail/sendmailTransport.cpp | 244 + .../src/vmime/net/sendmail/sendmailTransport.hpp | 112 + vmime-master/src/vmime/net/service.cpp | 170 + vmime-master/src/vmime/net/service.hpp | 239 + vmime-master/src/vmime/net/serviceFactory.cpp | 157 + vmime-master/src/vmime/net/serviceFactory.hpp | 168 + vmime-master/src/vmime/net/serviceInfos.cpp | 198 + vmime-master/src/vmime/net/serviceInfos.hpp | 263 ++ vmime-master/src/vmime/net/serviceRegistration.inl | 105 + vmime-master/src/vmime/net/session.cpp | 188 + vmime-master/src/vmime/net/session.hpp | 206 + .../net/smtp/SMTPChunkingOutputStreamAdapter.cpp | 180 + .../net/smtp/SMTPChunkingOutputStreamAdapter.hpp | 94 + vmime-master/src/vmime/net/smtp/SMTPCommand.cpp | 258 + vmime-master/src/vmime/net/smtp/SMTPCommand.hpp | 125 + vmime-master/src/vmime/net/smtp/SMTPCommandSet.cpp | 160 + vmime-master/src/vmime/net/smtp/SMTPCommandSet.hpp | 106 + vmime-master/src/vmime/net/smtp/SMTPConnection.cpp | 714 +++ vmime-master/src/vmime/net/smtp/SMTPConnection.hpp | 136 + vmime-master/src/vmime/net/smtp/SMTPExceptions.cpp | 212 + vmime-master/src/vmime/net/smtp/SMTPExceptions.hpp | 159 + vmime-master/src/vmime/net/smtp/SMTPResponse.cpp | 366 ++ vmime-master/src/vmime/net/smtp/SMTPResponse.hpp | 200 + vmime-master/src/vmime/net/smtp/SMTPSTransport.cpp | 82 + vmime-master/src/vmime/net/smtp/SMTPSTransport.hpp | 74 + .../src/vmime/net/smtp/SMTPServiceInfos.cpp | 144 + .../src/vmime/net/smtp/SMTPServiceInfos.hpp | 93 + vmime-master/src/vmime/net/smtp/SMTPTransport.cpp | 502 ++ vmime-master/src/vmime/net/smtp/SMTPTransport.hpp | 144 + vmime-master/src/vmime/net/smtp/smtp.hpp | 33 + vmime-master/src/vmime/net/socket.hpp | 223 + vmime-master/src/vmime/net/store.cpp | 57 + vmime-master/src/vmime/net/store.hpp | 115 + vmime-master/src/vmime/net/timeoutHandler.hpp | 89 + vmime-master/src/vmime/net/tls/TLSProperties.cpp | 44 + vmime-master/src/vmime/net/tls/TLSProperties.hpp | 105 + .../vmime/net/tls/TLSSecuredConnectionInfos.cpp | 77 + .../vmime/net/tls/TLSSecuredConnectionInfos.hpp | 88 + vmime-master/src/vmime/net/tls/TLSSession.cpp | 48 + vmime-master/src/vmime/net/tls/TLSSession.hpp | 96 + vmime-master/src/vmime/net/tls/TLSSocket.cpp | 44 + vmime-master/src/vmime/net/tls/TLSSocket.hpp | 88 + .../vmime/net/tls/gnutls/TLSProperties_GnuTLS.cpp | 113 + .../vmime/net/tls/gnutls/TLSProperties_GnuTLS.hpp | 68 + .../src/vmime/net/tls/gnutls/TLSSession_GnuTLS.cpp | 313 ++ .../src/vmime/net/tls/gnutls/TLSSession_GnuTLS.hpp | 95 + .../src/vmime/net/tls/gnutls/TLSSocket_GnuTLS.cpp | 548 +++ .../src/vmime/net/tls/gnutls/TLSSocket_GnuTLS.hpp | 129 + .../vmime/net/tls/openssl/OpenSSLInitializer.cpp | 169 + .../vmime/net/tls/openssl/OpenSSLInitializer.hpp | 90 + .../net/tls/openssl/TLSProperties_OpenSSL.cpp | 112 + .../net/tls/openssl/TLSProperties_OpenSSL.hpp | 68 + .../vmime/net/tls/openssl/TLSSession_OpenSSL.cpp | 147 + .../vmime/net/tls/openssl/TLSSession_OpenSSL.hpp | 109 + .../vmime/net/tls/openssl/TLSSocket_OpenSSL.cpp | 761 +++ .../vmime/net/tls/openssl/TLSSocket_OpenSSL.hpp | 142 + vmime-master/src/vmime/net/tracer.cpp | 74 + vmime-master/src/vmime/net/tracer.hpp | 110 + vmime-master/src/vmime/net/transport.cpp | 265 ++ vmime-master/src/vmime/net/transport.hpp | 152 + vmime-master/src/vmime/object.cpp | 52 + vmime-master/src/vmime/object.hpp | 52 + vmime-master/src/vmime/parameter.cpp | 665 +++ vmime-master/src/vmime/parameter.hpp | 176 + .../src/vmime/parameterizedHeaderField.cpp | 634 +++ .../src/vmime/parameterizedHeaderField.hpp | 222 + vmime-master/src/vmime/parsedMessageAttachment.cpp | 114 + vmime-master/src/vmime/parsedMessageAttachment.hpp | 76 + vmime-master/src/vmime/parserHelpers.hpp | 140 + vmime-master/src/vmime/parsingContext.cpp | 64 + vmime-master/src/vmime/parsingContext.hpp | 82 + vmime-master/src/vmime/path.cpp | 206 + vmime-master/src/vmime/path.hpp | 106 + vmime-master/src/vmime/plainTextPart.cpp | 121 + vmime-master/src/vmime/plainTextPart.hpp | 74 + vmime-master/src/vmime/platform.cpp | 77 + vmime-master/src/vmime/platform.hpp | 158 + .../vmime/platforms/posix/posixChildProcess.cpp | 410 ++ .../vmime/platforms/posix/posixChildProcess.hpp | 92 + .../vmime/platforms/posix/posixCriticalSection.cpp | 67 + .../vmime/platforms/posix/posixCriticalSection.hpp | 69 + .../src/vmime/platforms/posix/posixFile.cpp | 715 +++ .../src/vmime/platforms/posix/posixFile.hpp | 224 + .../src/vmime/platforms/posix/posixHandler.cpp | 292 ++ .../src/vmime/platforms/posix/posixHandler.hpp | 103 + .../src/vmime/platforms/posix/posixSocket.cpp | 969 ++++ .../src/vmime/platforms/posix/posixSocket.hpp | 118 + .../vmime/platforms/windows/windowsCodepages.hpp | 197 + .../platforms/windows/windowsCriticalSection.cpp | 67 + .../platforms/windows/windowsCriticalSection.hpp | 68 + .../src/vmime/platforms/windows/windowsFile.cpp | 712 +++ .../src/vmime/platforms/windows/windowsFile.hpp | 225 + .../src/vmime/platforms/windows/windowsHandler.cpp | 315 ++ .../src/vmime/platforms/windows/windowsHandler.hpp | 101 + .../src/vmime/platforms/windows/windowsSocket.cpp | 547 +++ .../src/vmime/platforms/windows/windowsSocket.hpp | 117 + vmime-master/src/vmime/propertySet.cpp | 399 ++ vmime-master/src/vmime/propertySet.hpp | 461 ++ vmime-master/src/vmime/relay.cpp | 363 ++ vmime-master/src/vmime/relay.hpp | 108 + vmime-master/src/vmime/security/authenticator.hpp | 136 + .../src/vmime/security/cert/X509Certificate.cpp | 72 + .../src/vmime/security/cert/X509Certificate.hpp | 197 + .../src/vmime/security/cert/certificate.hpp | 84 + .../src/vmime/security/cert/certificateChain.cpp | 53 + .../src/vmime/security/cert/certificateChain.hpp | 79 + .../vmime/security/cert/certificateException.cpp | 84 + .../vmime/security/cert/certificateException.hpp | 95 + .../security/cert/certificateExpiredException.cpp | 55 + .../security/cert/certificateExpiredException.hpp | 65 + .../certificateIssuerVerificationException.cpp | 55 + .../certificateIssuerVerificationException.hpp | 65 + .../cert/certificateNotTrustedException.cpp | 55 + .../cert/certificateNotTrustedException.hpp | 65 + .../cert/certificateNotYetValidException.cpp | 55 + .../cert/certificateNotYetValidException.hpp | 65 + .../vmime/security/cert/certificateVerifier.hpp | 76 + .../security/cert/defaultCertificateVerifier.cpp | 191 + .../security/cert/defaultCertificateVerifier.hpp | 98 + .../cert/gnutls/X509Certificate_GnuTLS.cpp | 395 ++ .../cert/gnutls/X509Certificate_GnuTLS.hpp | 96 + .../cert/openssl/X509Certificate_OpenSSL.cpp | 655 +++ .../cert/openssl/X509Certificate_OpenSSL.hpp | 119 + .../security/cert/serverIdentityException.cpp | 55 + .../security/cert/serverIdentityException.hpp | 65 + .../cert/unsupportedCertificateTypeException.cpp | 61 + .../cert/unsupportedCertificateTypeException.hpp | 72 + .../src/vmime/security/defaultAuthenticator.cpp | 130 + .../src/vmime/security/defaultAuthenticator.hpp | 73 + .../vmime/security/digest/md5/md5MessageDigest.cpp | 349 ++ .../vmime/security/digest/md5/md5MessageDigest.hpp | 85 + .../src/vmime/security/digest/messageDigest.cpp | 56 + .../src/vmime/security/digest/messageDigest.hpp | 142 + .../vmime/security/digest/messageDigestFactory.cpp | 81 + .../vmime/security/digest/messageDigestFactory.hpp | 110 + .../security/digest/sha1/sha1MessageDigest.cpp | 276 ++ .../security/digest/sha1/sha1MessageDigest.hpp | 79 + .../src/vmime/security/sasl/SASLAuthenticator.hpp | 96 + .../src/vmime/security/sasl/SASLContext.cpp | 221 + .../src/vmime/security/sasl/SASLContext.hpp | 136 + .../src/vmime/security/sasl/SASLMechanism.hpp | 153 + .../vmime/security/sasl/SASLMechanismFactory.cpp | 149 + .../vmime/security/sasl/SASLMechanismFactory.hpp | 155 + .../src/vmime/security/sasl/SASLSession.cpp | 221 + .../src/vmime/security/sasl/SASLSession.hpp | 180 + .../src/vmime/security/sasl/SASLSocket.cpp | 273 ++ .../src/vmime/security/sasl/SASLSocket.hpp | 108 + .../security/sasl/XOAuth2SASLAuthenticator.cpp | 99 + .../security/sasl/XOAuth2SASLAuthenticator.hpp | 77 + .../vmime/security/sasl/XOAuth2SASLMechanism.cpp | 155 + .../vmime/security/sasl/XOAuth2SASLMechanism.hpp | 102 + .../vmime/security/sasl/builtinSASLMechanism.cpp | 221 + .../vmime/security/sasl/builtinSASLMechanism.hpp | 105 + .../security/sasl/defaultSASLAuthenticator.cpp | 159 + .../security/sasl/defaultSASLAuthenticator.hpp | 91 + vmime-master/src/vmime/streamContentHandler.cpp | 257 + vmime-master/src/vmime/streamContentHandler.hpp | 126 + vmime-master/src/vmime/stringContentHandler.cpp | 228 + vmime-master/src/vmime/stringContentHandler.hpp | 107 + vmime-master/src/vmime/text.cpp | 536 +++ vmime-master/src/vmime/text.hpp | 291 ++ vmime-master/src/vmime/textPart.hpp | 117 + vmime-master/src/vmime/textPartFactory.cpp | 68 + vmime-master/src/vmime/textPartFactory.hpp | 77 + vmime-master/src/vmime/types.hpp | 87 + vmime-master/src/vmime/utility/childProcess.hpp | 103 + vmime-master/src/vmime/utility/datetimeUtils.cpp | 317 ++ vmime-master/src/vmime/utility/datetimeUtils.hpp | 98 + .../src/vmime/utility/encoder/b64Encoder.cpp | 350 ++ .../src/vmime/utility/encoder/b64Encoder.hpp | 73 + .../src/vmime/utility/encoder/binaryEncoder.cpp | 39 + .../src/vmime/utility/encoder/binaryEncoder.hpp | 51 + .../src/vmime/utility/encoder/eightBitEncoder.cpp | 39 + .../src/vmime/utility/encoder/eightBitEncoder.hpp | 51 + vmime-master/src/vmime/utility/encoder/encoder.cpp | 76 + vmime-master/src/vmime/utility/encoder/encoder.hpp | 135 + .../src/vmime/utility/encoder/encoderFactory.cpp | 149 + .../src/vmime/utility/encoder/encoderFactory.hpp | 164 + .../src/vmime/utility/encoder/noopEncoder.cpp | 94 + .../src/vmime/utility/encoder/noopEncoder.hpp | 66 + .../src/vmime/utility/encoder/qpEncoder.cpp | 568 +++ .../src/vmime/utility/encoder/qpEncoder.hpp | 77 + .../src/vmime/utility/encoder/sevenBitEncoder.cpp | 39 + .../src/vmime/utility/encoder/sevenBitEncoder.hpp | 51 + .../src/vmime/utility/encoder/uuEncoder.cpp | 358 ++ .../src/vmime/utility/encoder/uuEncoder.hpp | 68 + vmime-master/src/vmime/utility/file.hpp | 264 ++ vmime-master/src/vmime/utility/filteredStream.cpp | 402 ++ vmime-master/src/vmime/utility/filteredStream.hpp | 405 ++ vmime-master/src/vmime/utility/inputStream.cpp | 33 + vmime-master/src/vmime/utility/inputStream.hpp | 75 + .../src/vmime/utility/inputStreamAdapter.cpp | 84 + .../src/vmime/utility/inputStreamAdapter.hpp | 65 + .../vmime/utility/inputStreamByteBufferAdapter.cpp | 104 + .../vmime/utility/inputStreamByteBufferAdapter.hpp | 63 + .../vmime/utility/inputStreamPointerAdapter.cpp | 48 + .../vmime/utility/inputStreamPointerAdapter.hpp | 61 + .../src/vmime/utility/inputStreamSocketAdapter.cpp | 79 + .../src/vmime/utility/inputStreamSocketAdapter.hpp | 75 + .../src/vmime/utility/inputStreamStringAdapter.cpp | 119 + .../src/vmime/utility/inputStreamStringAdapter.hpp | 66 + vmime-master/src/vmime/utility/outputStream.cpp | 44 + vmime-master/src/vmime/utility/outputStream.hpp | 133 + .../src/vmime/utility/outputStreamAdapter.cpp | 52 + .../src/vmime/utility/outputStreamAdapter.hpp | 63 + .../vmime/utility/outputStreamByteArrayAdapter.cpp | 50 + .../vmime/utility/outputStreamByteArrayAdapter.hpp | 59 + .../vmime/utility/outputStreamSocketAdapter.cpp | 65 + .../vmime/utility/outputStreamSocketAdapter.hpp | 76 + .../vmime/utility/outputStreamStringAdapter.cpp | 52 + .../vmime/utility/outputStreamStringAdapter.hpp | 59 + .../src/vmime/utility/parserInputStreamAdapter.cpp | 175 + .../src/vmime/utility/parserInputStreamAdapter.hpp | 172 + vmime-master/src/vmime/utility/path.cpp | 324 ++ vmime-master/src/vmime/utility/path.hpp | 189 + .../src/vmime/utility/progressListener.cpp | 78 + .../src/vmime/utility/progressListener.hpp | 99 + vmime-master/src/vmime/utility/random.cpp | 90 + vmime-master/src/vmime/utility/random.hpp | 78 + .../src/vmime/utility/seekableInputStream.hpp | 62 + .../utility/seekableInputStreamRegionAdapter.cpp | 111 + .../utility/seekableInputStreamRegionAdapter.hpp | 73 + vmime-master/src/vmime/utility/stream.cpp | 39 + vmime-master/src/vmime/utility/stream.hpp | 60 + vmime-master/src/vmime/utility/streamUtils.cpp | 130 + vmime-master/src/vmime/utility/streamUtils.hpp | 83 + vmime-master/src/vmime/utility/stringUtils.cpp | 337 ++ vmime-master/src/vmime/utility/stringUtils.hpp | 271 ++ vmime-master/src/vmime/utility/sync/autoLock.hpp | 65 + .../src/vmime/utility/sync/criticalSection.cpp | 44 + .../src/vmime/utility/sync/criticalSection.hpp | 64 + vmime-master/src/vmime/utility/url.cpp | 431 ++ vmime-master/src/vmime/utility/url.hpp | 213 + vmime-master/src/vmime/utility/urlUtils.cpp | 133 + vmime-master/src/vmime/utility/urlUtils.hpp | 57 + vmime-master/src/vmime/vmime.hpp | 160 + vmime-master/src/vmime/word.cpp | 939 ++++ vmime-master/src/vmime/word.hpp | 272 ++ vmime-master/src/vmime/wordEncoder.cpp | 320 ++ vmime-master/src/vmime/wordEncoder.hpp | 118 + vmime-master/test-outsourced-build.sh | 12 + vmime-master/tests/misc/importanceHelperTest.cpp | 191 + vmime-master/tests/net/folderAttributesTest.cpp | 137 + vmime-master/tests/net/imap/IMAPCommandTest.cpp | 495 ++ vmime-master/tests/net/imap/IMAPParserTest.cpp | 374 ++ vmime-master/tests/net/imap/IMAPTagTest.cpp | 90 + vmime-master/tests/net/imap/IMAPUtilsTest.cpp | 283 ++ .../tests/net/maildir/maildirStoreTest.cpp | 584 +++ .../tests/net/maildir/maildirUtilsTest.cpp | 54 + vmime-master/tests/net/messageSetTest.cpp | 229 + vmime-master/tests/net/pop3/POP3CommandTest.cpp | 241 + vmime-master/tests/net/pop3/POP3ResponseTest.cpp | 244 + vmime-master/tests/net/pop3/POP3StoreTest.cpp | 67 + vmime-master/tests/net/pop3/POP3TestUtils.hpp | 69 + vmime-master/tests/net/pop3/POP3UtilsTest.cpp | 88 + vmime-master/tests/net/smtp/SMTPCommandSetTest.cpp | 181 + vmime-master/tests/net/smtp/SMTPCommandTest.cpp | 252 + vmime-master/tests/net/smtp/SMTPResponseTest.cpp | 238 + vmime-master/tests/net/smtp/SMTPTransportTest.cpp | 324 ++ .../tests/net/smtp/SMTPTransportTestUtils.hpp | 792 ++++ vmime-master/tests/parser/attachmentHelperTest.cpp | 335 ++ vmime-master/tests/parser/bodyPartTest.cpp | 414 ++ vmime-master/tests/parser/bodyTest.cpp | 79 + .../parser/charsetFilteredOutputStreamTest.cpp | 213 + vmime-master/tests/parser/charsetTest.cpp | 252 + vmime-master/tests/parser/charsetTestSuites.hpp | 102 + vmime-master/tests/parser/datetimeTest.cpp | 123 + vmime-master/tests/parser/dispositionTest.cpp | 150 + vmime-master/tests/parser/emailAddressTest.cpp | 281 ++ .../tests/parser/emptyContentHandlerTest.cpp | 99 + .../tests/parser/fileContentHandlerTest.cpp | 134 + vmime-master/tests/parser/headerFieldTest.cpp | 112 + vmime-master/tests/parser/headerTest.cpp | 375 ++ vmime-master/tests/parser/htmlTextPartTest.cpp | 241 + vmime-master/tests/parser/mailboxGroupTest.cpp | 107 + vmime-master/tests/parser/mailboxListTest.cpp | 47 + vmime-master/tests/parser/mailboxTest.cpp | 187 + vmime-master/tests/parser/mediaTypeTest.cpp | 100 + .../tests/parser/messageIdSequenceTest.cpp | 78 + vmime-master/tests/parser/messageIdTest.cpp | 77 + vmime-master/tests/parser/messageTest.cpp | 64 + vmime-master/tests/parser/parameterTest.cpp | 722 +++ vmime-master/tests/parser/pathTest.cpp | 102 + .../tests/parser/streamContentHandlerTest.cpp | 194 + .../tests/parser/stringContentHandlerTest.cpp | 165 + vmime-master/tests/parser/textTest.cpp | 918 ++++ vmime-master/tests/parser/wordEncoderTest.cpp | 174 + vmime-master/tests/security/digest/md5Test.cpp | 228 + vmime-master/tests/security/digest/sha1Test.cpp | 119 + vmime-master/tests/testRunner.cpp | 305 ++ vmime-master/tests/testUtils.cpp | 404 ++ vmime-master/tests/testUtils.hpp | 407 ++ vmime-master/tests/utility/datetimeUtilsTest.cpp | 157 + .../tests/utility/encoder/b64EncoderTest.cpp | 168 + .../tests/utility/encoder/encoderFactoryTest.cpp | 63 + .../tests/utility/encoder/encoderTestUtils.hpp | 82 + .../tests/utility/encoder/qpEncoderTest.cpp | 275 ++ vmime-master/tests/utility/filteredStreamTest.cpp | 341 ++ .../utility/outputStreamByteArrayAdapterTest.cpp | 82 + .../utility/outputStreamSocketAdapterTest.cpp | 87 + .../utility/outputStreamStringAdapterTest.cpp | 84 + .../tests/utility/parserInputStreamAdapterTest.cpp | 51 + vmime-master/tests/utility/pathTest.cpp | 356 ++ .../seekableInputStreamRegionAdapterTest.cpp | 176 + vmime-master/tests/utility/stringUtilsTest.cpp | 214 + vmime-master/tests/utility/urlTest.cpp | 312 ++ vmime-master/vmime.pc.in | 13 + 562 files changed, 116586 insertions(+) create mode 100644 vmime-master/.gitignore create mode 100644 vmime-master/.travis.yml create mode 100644 vmime-master/AUTHORS create mode 100644 vmime-master/CMakeLists.txt create mode 100644 vmime-master/COPYING create mode 100644 vmime-master/COPYING.OpenSSL create mode 100644 vmime-master/Doxyfile.in create mode 100644 vmime-master/HACKING create mode 100644 vmime-master/NEWS create mode 100644 vmime-master/README create mode 100644 vmime-master/README.autotools create mode 100755 vmime-master/build_for_losedows.sh create mode 100644 vmime-master/cmake/FindCppUnit.cmake create mode 100644 vmime-master/cmake/FindGSasl.cmake create mode 100644 vmime-master/cmake/FindICU.cmake create mode 100644 vmime-master/cmake/FindIconv.cmake create mode 100644 vmime-master/cmake/Utils.cmake create mode 100644 vmime-master/cmake/config.hpp.cmake create mode 100644 vmime-master/config_header/config.hpp create mode 100644 vmime-master/contrib/punycode/punycode.c create mode 100644 vmime-master/contrib/punycode/punycode.h create mode 100644 vmime-master/contrib/utf8/utf8.h create mode 100644 vmime-master/contrib/utf8/utf8/checked.h create mode 100644 vmime-master/contrib/utf8/utf8/core.h create mode 100644 vmime-master/contrib/utf8/utf8/unchecked.h create mode 100644 vmime-master/doc/book/.gitignore create mode 100644 vmime-master/doc/book/basics.tex create mode 100644 vmime-master/doc/book/book.tex create mode 100644 vmime-master/doc/book/building.tex create mode 100644 vmime-master/doc/book/images/address-mailbox-mailboxgroup.svg create mode 100644 vmime-master/doc/book/images/message-body-header.svg create mode 100644 vmime-master/doc/book/images/messaging-services.svg create mode 100644 vmime-master/doc/book/intro.tex create mode 100644 vmime-master/doc/book/msg.tex create mode 100644 vmime-master/doc/book/net.tex create mode 100644 vmime-master/doc/book/start.tex create mode 100644 vmime-master/examples/CMakeLists.txt create mode 100644 vmime-master/examples/example1.cpp create mode 100644 vmime-master/examples/example2.cpp create mode 100644 vmime-master/examples/example3.cpp create mode 100644 vmime-master/examples/example4.cpp create mode 100644 vmime-master/examples/example5.cpp create mode 100644 vmime-master/examples/example6.cpp create mode 100644 vmime-master/examples/example6_authenticator.hpp create mode 100644 vmime-master/examples/example6_certificateVerifier.hpp create mode 100644 vmime-master/examples/example6_timeoutHandler.hpp create mode 100644 vmime-master/examples/example6_tracer.hpp create mode 100644 vmime-master/examples/example7.cpp create mode 100644 vmime-master/examples/viewer/CMakeLists.txt create mode 100644 vmime-master/examples/viewer/viewer.cpp create mode 100644 vmime-master/mingw_cross_toolchain.cmake create mode 100644 vmime-master/src/vmime/address.cpp create mode 100644 vmime-master/src/vmime/address.hpp create mode 100644 vmime-master/src/vmime/addressList.cpp create mode 100644 vmime-master/src/vmime/addressList.hpp create mode 100644 vmime-master/src/vmime/attachment.hpp create mode 100644 vmime-master/src/vmime/attachmentHelper.cpp create mode 100644 vmime-master/src/vmime/attachmentHelper.hpp create mode 100644 vmime-master/src/vmime/base.cpp create mode 100644 vmime-master/src/vmime/base.hpp create mode 100644 vmime-master/src/vmime/body.cpp create mode 100644 vmime-master/src/vmime/body.hpp create mode 100644 vmime-master/src/vmime/bodyPart.cpp create mode 100644 vmime-master/src/vmime/bodyPart.hpp create mode 100644 vmime-master/src/vmime/bodyPartAttachment.cpp create mode 100644 vmime-master/src/vmime/bodyPartAttachment.hpp create mode 100644 vmime-master/src/vmime/charset.cpp create mode 100644 vmime-master/src/vmime/charset.hpp create mode 100644 vmime-master/src/vmime/charsetConverter.cpp create mode 100644 vmime-master/src/vmime/charsetConverter.hpp create mode 100644 vmime-master/src/vmime/charsetConverterOptions.cpp create mode 100644 vmime-master/src/vmime/charsetConverterOptions.hpp create mode 100644 vmime-master/src/vmime/charsetConverter_iconv.cpp create mode 100644 vmime-master/src/vmime/charsetConverter_iconv.hpp create mode 100644 vmime-master/src/vmime/charsetConverter_icu.cpp create mode 100644 vmime-master/src/vmime/charsetConverter_icu.hpp create mode 100644 vmime-master/src/vmime/charsetConverter_idna.cpp create mode 100644 vmime-master/src/vmime/charsetConverter_idna.hpp create mode 100644 vmime-master/src/vmime/charsetConverter_win.cpp create mode 100644 vmime-master/src/vmime/charsetConverter_win.hpp create mode 100644 vmime-master/src/vmime/component.cpp create mode 100644 vmime-master/src/vmime/component.hpp create mode 100644 vmime-master/src/vmime/constants.cpp create mode 100644 vmime-master/src/vmime/constants.hpp create mode 100644 vmime-master/src/vmime/contentDisposition.cpp create mode 100644 vmime-master/src/vmime/contentDisposition.hpp create mode 100644 vmime-master/src/vmime/contentDispositionField.cpp create mode 100644 vmime-master/src/vmime/contentDispositionField.hpp create mode 100644 vmime-master/src/vmime/contentHandler.cpp create mode 100644 vmime-master/src/vmime/contentHandler.hpp create mode 100644 vmime-master/src/vmime/contentTypeField.cpp create mode 100644 vmime-master/src/vmime/contentTypeField.hpp create mode 100644 vmime-master/src/vmime/context.cpp create mode 100644 vmime-master/src/vmime/context.hpp create mode 100644 vmime-master/src/vmime/dateTime.cpp create mode 100644 vmime-master/src/vmime/dateTime.hpp create mode 100644 vmime-master/src/vmime/defaultAttachment.cpp create mode 100644 vmime-master/src/vmime/defaultAttachment.hpp create mode 100644 vmime-master/src/vmime/disposition.cpp create mode 100644 vmime-master/src/vmime/disposition.hpp create mode 100644 vmime-master/src/vmime/emailAddress.cpp create mode 100644 vmime-master/src/vmime/emailAddress.hpp create mode 100644 vmime-master/src/vmime/emptyContentHandler.cpp create mode 100644 vmime-master/src/vmime/emptyContentHandler.hpp create mode 100644 vmime-master/src/vmime/encoding.cpp create mode 100644 vmime-master/src/vmime/encoding.hpp create mode 100644 vmime-master/src/vmime/exception.cpp create mode 100644 vmime-master/src/vmime/exception.hpp create mode 100644 vmime-master/src/vmime/export.hpp create mode 100644 vmime-master/src/vmime/fileAttachment.cpp create mode 100644 vmime-master/src/vmime/fileAttachment.hpp create mode 100644 vmime-master/src/vmime/fileContentHandler.cpp create mode 100644 vmime-master/src/vmime/fileContentHandler.hpp create mode 100644 vmime-master/src/vmime/generatedMessageAttachment.cpp create mode 100644 vmime-master/src/vmime/generatedMessageAttachment.hpp create mode 100644 vmime-master/src/vmime/generationContext.cpp create mode 100644 vmime-master/src/vmime/generationContext.hpp create mode 100644 vmime-master/src/vmime/header.cpp create mode 100644 vmime-master/src/vmime/header.hpp create mode 100644 vmime-master/src/vmime/headerField.cpp create mode 100644 vmime-master/src/vmime/headerField.hpp create mode 100644 vmime-master/src/vmime/headerFieldFactory.cpp create mode 100644 vmime-master/src/vmime/headerFieldFactory.hpp create mode 100644 vmime-master/src/vmime/headerFieldValue.cpp create mode 100644 vmime-master/src/vmime/headerFieldValue.hpp create mode 100644 vmime-master/src/vmime/htmlTextPart.cpp create mode 100644 vmime-master/src/vmime/htmlTextPart.hpp create mode 100644 vmime-master/src/vmime/mailbox.cpp create mode 100644 vmime-master/src/vmime/mailbox.hpp create mode 100644 vmime-master/src/vmime/mailboxField.cpp create mode 100644 vmime-master/src/vmime/mailboxField.hpp create mode 100644 vmime-master/src/vmime/mailboxGroup.cpp create mode 100644 vmime-master/src/vmime/mailboxGroup.hpp create mode 100644 vmime-master/src/vmime/mailboxList.cpp create mode 100644 vmime-master/src/vmime/mailboxList.hpp create mode 100644 vmime-master/src/vmime/mdn/MDNHelper.cpp create mode 100644 vmime-master/src/vmime/mdn/MDNHelper.hpp create mode 100644 vmime-master/src/vmime/mdn/MDNInfos.cpp create mode 100644 vmime-master/src/vmime/mdn/MDNInfos.hpp create mode 100644 vmime-master/src/vmime/mdn/receivedMDNInfos.cpp create mode 100644 vmime-master/src/vmime/mdn/receivedMDNInfos.hpp create mode 100644 vmime-master/src/vmime/mdn/sendableMDNInfos.cpp create mode 100644 vmime-master/src/vmime/mdn/sendableMDNInfos.hpp create mode 100644 vmime-master/src/vmime/mediaType.cpp create mode 100644 vmime-master/src/vmime/mediaType.hpp create mode 100644 vmime-master/src/vmime/message.cpp create mode 100644 vmime-master/src/vmime/message.hpp create mode 100644 vmime-master/src/vmime/messageAttachment.hpp create mode 100644 vmime-master/src/vmime/messageBuilder.cpp create mode 100644 vmime-master/src/vmime/messageBuilder.hpp create mode 100644 vmime-master/src/vmime/messageId.cpp create mode 100644 vmime-master/src/vmime/messageId.hpp create mode 100644 vmime-master/src/vmime/messageIdSequence.cpp create mode 100644 vmime-master/src/vmime/messageIdSequence.hpp create mode 100644 vmime-master/src/vmime/messageParser.cpp create mode 100644 vmime-master/src/vmime/messageParser.hpp create mode 100644 vmime-master/src/vmime/misc/importanceHelper.cpp create mode 100644 vmime-master/src/vmime/misc/importanceHelper.hpp create mode 100644 vmime-master/src/vmime/net/builtinServices.inl create mode 100644 vmime-master/src/vmime/net/connectionInfos.hpp create mode 100644 vmime-master/src/vmime/net/defaultConnectionInfos.cpp create mode 100644 vmime-master/src/vmime/net/defaultConnectionInfos.hpp create mode 100644 vmime-master/src/vmime/net/defaultTimeoutHandler.cpp create mode 100644 vmime-master/src/vmime/net/defaultTimeoutHandler.hpp create mode 100644 vmime-master/src/vmime/net/dsnAttributes.cpp create mode 100644 vmime-master/src/vmime/net/dsnAttributes.hpp create mode 100644 vmime-master/src/vmime/net/events.cpp create mode 100644 vmime-master/src/vmime/net/events.hpp create mode 100644 vmime-master/src/vmime/net/fetchAttributes.cpp create mode 100644 vmime-master/src/vmime/net/fetchAttributes.hpp create mode 100644 vmime-master/src/vmime/net/folder.cpp create mode 100644 vmime-master/src/vmime/net/folder.hpp create mode 100644 vmime-master/src/vmime/net/folderAttributes.cpp create mode 100644 vmime-master/src/vmime/net/folderAttributes.hpp create mode 100644 vmime-master/src/vmime/net/folderStatus.hpp create mode 100644 vmime-master/src/vmime/net/imap/IMAPCommand.cpp create mode 100644 vmime-master/src/vmime/net/imap/IMAPCommand.hpp create mode 100644 vmime-master/src/vmime/net/imap/IMAPConnection.cpp create mode 100644 vmime-master/src/vmime/net/imap/IMAPConnection.hpp create mode 100644 vmime-master/src/vmime/net/imap/IMAPFolder.cpp create mode 100644 vmime-master/src/vmime/net/imap/IMAPFolder.hpp create mode 100644 vmime-master/src/vmime/net/imap/IMAPFolderStatus.cpp create mode 100644 vmime-master/src/vmime/net/imap/IMAPFolderStatus.hpp create mode 100644 vmime-master/src/vmime/net/imap/IMAPMessage.cpp create mode 100644 vmime-master/src/vmime/net/imap/IMAPMessage.hpp create mode 100644 vmime-master/src/vmime/net/imap/IMAPMessagePart.cpp create mode 100644 vmime-master/src/vmime/net/imap/IMAPMessagePart.hpp create mode 100644 vmime-master/src/vmime/net/imap/IMAPMessagePartContentHandler.cpp create mode 100644 vmime-master/src/vmime/net/imap/IMAPMessagePartContentHandler.hpp create mode 100644 vmime-master/src/vmime/net/imap/IMAPMessageStructure.cpp create mode 100644 vmime-master/src/vmime/net/imap/IMAPMessageStructure.hpp create mode 100644 vmime-master/src/vmime/net/imap/IMAPParser.hpp create mode 100644 vmime-master/src/vmime/net/imap/IMAPSStore.cpp create mode 100644 vmime-master/src/vmime/net/imap/IMAPSStore.hpp create mode 100644 vmime-master/src/vmime/net/imap/IMAPServiceInfos.cpp create mode 100644 vmime-master/src/vmime/net/imap/IMAPServiceInfos.hpp create mode 100644 vmime-master/src/vmime/net/imap/IMAPStore.cpp create mode 100644 vmime-master/src/vmime/net/imap/IMAPStore.hpp create mode 100644 vmime-master/src/vmime/net/imap/IMAPTag.cpp create mode 100644 vmime-master/src/vmime/net/imap/IMAPTag.hpp create mode 100644 vmime-master/src/vmime/net/imap/IMAPUtils.cpp create mode 100644 vmime-master/src/vmime/net/imap/IMAPUtils.hpp create mode 100644 vmime-master/src/vmime/net/imap/imap.hpp create mode 100644 vmime-master/src/vmime/net/maildir/format/courierMaildirFormat.cpp create mode 100644 vmime-master/src/vmime/net/maildir/format/courierMaildirFormat.hpp create mode 100644 vmime-master/src/vmime/net/maildir/format/kmailMaildirFormat.cpp create mode 100644 vmime-master/src/vmime/net/maildir/format/kmailMaildirFormat.hpp create mode 100644 vmime-master/src/vmime/net/maildir/maildir.hpp create mode 100644 vmime-master/src/vmime/net/maildir/maildirFolder.cpp create mode 100644 vmime-master/src/vmime/net/maildir/maildirFolder.hpp create mode 100644 vmime-master/src/vmime/net/maildir/maildirFolderStatus.cpp create mode 100644 vmime-master/src/vmime/net/maildir/maildirFolderStatus.hpp create mode 100644 vmime-master/src/vmime/net/maildir/maildirFormat.cpp create mode 100644 vmime-master/src/vmime/net/maildir/maildirFormat.hpp create mode 100644 vmime-master/src/vmime/net/maildir/maildirMessage.cpp create mode 100644 vmime-master/src/vmime/net/maildir/maildirMessage.hpp create mode 100644 vmime-master/src/vmime/net/maildir/maildirMessagePart.cpp create mode 100644 vmime-master/src/vmime/net/maildir/maildirMessagePart.hpp create mode 100644 vmime-master/src/vmime/net/maildir/maildirMessageStructure.cpp create mode 100644 vmime-master/src/vmime/net/maildir/maildirMessageStructure.hpp create mode 100644 vmime-master/src/vmime/net/maildir/maildirServiceInfos.cpp create mode 100644 vmime-master/src/vmime/net/maildir/maildirServiceInfos.hpp create mode 100644 vmime-master/src/vmime/net/maildir/maildirStore.cpp create mode 100644 vmime-master/src/vmime/net/maildir/maildirStore.hpp create mode 100644 vmime-master/src/vmime/net/maildir/maildirUtils.cpp create mode 100644 vmime-master/src/vmime/net/maildir/maildirUtils.hpp create mode 100644 vmime-master/src/vmime/net/message.cpp create mode 100644 vmime-master/src/vmime/net/message.hpp create mode 100644 vmime-master/src/vmime/net/messageSet.cpp create mode 100644 vmime-master/src/vmime/net/messageSet.hpp create mode 100644 vmime-master/src/vmime/net/pop3/POP3Command.cpp create mode 100644 vmime-master/src/vmime/net/pop3/POP3Command.hpp create mode 100644 vmime-master/src/vmime/net/pop3/POP3Connection.cpp create mode 100644 vmime-master/src/vmime/net/pop3/POP3Connection.hpp create mode 100644 vmime-master/src/vmime/net/pop3/POP3Folder.cpp create mode 100644 vmime-master/src/vmime/net/pop3/POP3Folder.hpp create mode 100644 vmime-master/src/vmime/net/pop3/POP3FolderStatus.cpp create mode 100644 vmime-master/src/vmime/net/pop3/POP3FolderStatus.hpp create mode 100644 vmime-master/src/vmime/net/pop3/POP3Message.cpp create mode 100644 vmime-master/src/vmime/net/pop3/POP3Message.hpp create mode 100644 vmime-master/src/vmime/net/pop3/POP3Response.cpp create mode 100644 vmime-master/src/vmime/net/pop3/POP3Response.hpp create mode 100644 vmime-master/src/vmime/net/pop3/POP3SStore.cpp create mode 100644 vmime-master/src/vmime/net/pop3/POP3SStore.hpp create mode 100644 vmime-master/src/vmime/net/pop3/POP3ServiceInfos.cpp create mode 100644 vmime-master/src/vmime/net/pop3/POP3ServiceInfos.hpp create mode 100644 vmime-master/src/vmime/net/pop3/POP3Store.cpp create mode 100644 vmime-master/src/vmime/net/pop3/POP3Store.hpp create mode 100644 vmime-master/src/vmime/net/pop3/POP3Utils.cpp create mode 100644 vmime-master/src/vmime/net/pop3/POP3Utils.hpp create mode 100644 vmime-master/src/vmime/net/pop3/pop3.hpp create mode 100644 vmime-master/src/vmime/net/securedConnectionInfos.hpp create mode 100644 vmime-master/src/vmime/net/sendmail/sendmail.hpp create mode 100644 vmime-master/src/vmime/net/sendmail/sendmailServiceInfos.cpp create mode 100644 vmime-master/src/vmime/net/sendmail/sendmailServiceInfos.hpp create mode 100644 vmime-master/src/vmime/net/sendmail/sendmailTransport.cpp create mode 100644 vmime-master/src/vmime/net/sendmail/sendmailTransport.hpp create mode 100644 vmime-master/src/vmime/net/service.cpp create mode 100644 vmime-master/src/vmime/net/service.hpp create mode 100644 vmime-master/src/vmime/net/serviceFactory.cpp create mode 100644 vmime-master/src/vmime/net/serviceFactory.hpp create mode 100644 vmime-master/src/vmime/net/serviceInfos.cpp create mode 100644 vmime-master/src/vmime/net/serviceInfos.hpp create mode 100644 vmime-master/src/vmime/net/serviceRegistration.inl create mode 100644 vmime-master/src/vmime/net/session.cpp create mode 100644 vmime-master/src/vmime/net/session.hpp create mode 100644 vmime-master/src/vmime/net/smtp/SMTPChunkingOutputStreamAdapter.cpp create mode 100644 vmime-master/src/vmime/net/smtp/SMTPChunkingOutputStreamAdapter.hpp create mode 100644 vmime-master/src/vmime/net/smtp/SMTPCommand.cpp create mode 100644 vmime-master/src/vmime/net/smtp/SMTPCommand.hpp create mode 100644 vmime-master/src/vmime/net/smtp/SMTPCommandSet.cpp create mode 100644 vmime-master/src/vmime/net/smtp/SMTPCommandSet.hpp create mode 100644 vmime-master/src/vmime/net/smtp/SMTPConnection.cpp create mode 100644 vmime-master/src/vmime/net/smtp/SMTPConnection.hpp create mode 100644 vmime-master/src/vmime/net/smtp/SMTPExceptions.cpp create mode 100644 vmime-master/src/vmime/net/smtp/SMTPExceptions.hpp create mode 100644 vmime-master/src/vmime/net/smtp/SMTPResponse.cpp create mode 100644 vmime-master/src/vmime/net/smtp/SMTPResponse.hpp create mode 100644 vmime-master/src/vmime/net/smtp/SMTPSTransport.cpp create mode 100644 vmime-master/src/vmime/net/smtp/SMTPSTransport.hpp create mode 100644 vmime-master/src/vmime/net/smtp/SMTPServiceInfos.cpp create mode 100644 vmime-master/src/vmime/net/smtp/SMTPServiceInfos.hpp create mode 100644 vmime-master/src/vmime/net/smtp/SMTPTransport.cpp create mode 100644 vmime-master/src/vmime/net/smtp/SMTPTransport.hpp create mode 100644 vmime-master/src/vmime/net/smtp/smtp.hpp create mode 100644 vmime-master/src/vmime/net/socket.hpp create mode 100644 vmime-master/src/vmime/net/store.cpp create mode 100644 vmime-master/src/vmime/net/store.hpp create mode 100644 vmime-master/src/vmime/net/timeoutHandler.hpp create mode 100644 vmime-master/src/vmime/net/tls/TLSProperties.cpp create mode 100644 vmime-master/src/vmime/net/tls/TLSProperties.hpp create mode 100644 vmime-master/src/vmime/net/tls/TLSSecuredConnectionInfos.cpp create mode 100644 vmime-master/src/vmime/net/tls/TLSSecuredConnectionInfos.hpp create mode 100644 vmime-master/src/vmime/net/tls/TLSSession.cpp create mode 100644 vmime-master/src/vmime/net/tls/TLSSession.hpp create mode 100644 vmime-master/src/vmime/net/tls/TLSSocket.cpp create mode 100644 vmime-master/src/vmime/net/tls/TLSSocket.hpp create mode 100644 vmime-master/src/vmime/net/tls/gnutls/TLSProperties_GnuTLS.cpp create mode 100644 vmime-master/src/vmime/net/tls/gnutls/TLSProperties_GnuTLS.hpp create mode 100644 vmime-master/src/vmime/net/tls/gnutls/TLSSession_GnuTLS.cpp create mode 100644 vmime-master/src/vmime/net/tls/gnutls/TLSSession_GnuTLS.hpp create mode 100644 vmime-master/src/vmime/net/tls/gnutls/TLSSocket_GnuTLS.cpp create mode 100644 vmime-master/src/vmime/net/tls/gnutls/TLSSocket_GnuTLS.hpp create mode 100644 vmime-master/src/vmime/net/tls/openssl/OpenSSLInitializer.cpp create mode 100644 vmime-master/src/vmime/net/tls/openssl/OpenSSLInitializer.hpp create mode 100644 vmime-master/src/vmime/net/tls/openssl/TLSProperties_OpenSSL.cpp create mode 100644 vmime-master/src/vmime/net/tls/openssl/TLSProperties_OpenSSL.hpp create mode 100644 vmime-master/src/vmime/net/tls/openssl/TLSSession_OpenSSL.cpp create mode 100644 vmime-master/src/vmime/net/tls/openssl/TLSSession_OpenSSL.hpp create mode 100644 vmime-master/src/vmime/net/tls/openssl/TLSSocket_OpenSSL.cpp create mode 100644 vmime-master/src/vmime/net/tls/openssl/TLSSocket_OpenSSL.hpp create mode 100644 vmime-master/src/vmime/net/tracer.cpp create mode 100644 vmime-master/src/vmime/net/tracer.hpp create mode 100644 vmime-master/src/vmime/net/transport.cpp create mode 100644 vmime-master/src/vmime/net/transport.hpp create mode 100644 vmime-master/src/vmime/object.cpp create mode 100644 vmime-master/src/vmime/object.hpp create mode 100644 vmime-master/src/vmime/parameter.cpp create mode 100644 vmime-master/src/vmime/parameter.hpp create mode 100644 vmime-master/src/vmime/parameterizedHeaderField.cpp create mode 100644 vmime-master/src/vmime/parameterizedHeaderField.hpp create mode 100644 vmime-master/src/vmime/parsedMessageAttachment.cpp create mode 100644 vmime-master/src/vmime/parsedMessageAttachment.hpp create mode 100644 vmime-master/src/vmime/parserHelpers.hpp create mode 100644 vmime-master/src/vmime/parsingContext.cpp create mode 100644 vmime-master/src/vmime/parsingContext.hpp create mode 100644 vmime-master/src/vmime/path.cpp create mode 100644 vmime-master/src/vmime/path.hpp create mode 100644 vmime-master/src/vmime/plainTextPart.cpp create mode 100644 vmime-master/src/vmime/plainTextPart.hpp create mode 100644 vmime-master/src/vmime/platform.cpp create mode 100644 vmime-master/src/vmime/platform.hpp create mode 100644 vmime-master/src/vmime/platforms/posix/posixChildProcess.cpp create mode 100644 vmime-master/src/vmime/platforms/posix/posixChildProcess.hpp create mode 100644 vmime-master/src/vmime/platforms/posix/posixCriticalSection.cpp create mode 100644 vmime-master/src/vmime/platforms/posix/posixCriticalSection.hpp create mode 100644 vmime-master/src/vmime/platforms/posix/posixFile.cpp create mode 100644 vmime-master/src/vmime/platforms/posix/posixFile.hpp create mode 100644 vmime-master/src/vmime/platforms/posix/posixHandler.cpp create mode 100644 vmime-master/src/vmime/platforms/posix/posixHandler.hpp create mode 100644 vmime-master/src/vmime/platforms/posix/posixSocket.cpp create mode 100644 vmime-master/src/vmime/platforms/posix/posixSocket.hpp create mode 100644 vmime-master/src/vmime/platforms/windows/windowsCodepages.hpp create mode 100644 vmime-master/src/vmime/platforms/windows/windowsCriticalSection.cpp create mode 100644 vmime-master/src/vmime/platforms/windows/windowsCriticalSection.hpp create mode 100644 vmime-master/src/vmime/platforms/windows/windowsFile.cpp create mode 100644 vmime-master/src/vmime/platforms/windows/windowsFile.hpp create mode 100644 vmime-master/src/vmime/platforms/windows/windowsHandler.cpp create mode 100644 vmime-master/src/vmime/platforms/windows/windowsHandler.hpp create mode 100644 vmime-master/src/vmime/platforms/windows/windowsSocket.cpp create mode 100644 vmime-master/src/vmime/platforms/windows/windowsSocket.hpp create mode 100644 vmime-master/src/vmime/propertySet.cpp create mode 100644 vmime-master/src/vmime/propertySet.hpp create mode 100644 vmime-master/src/vmime/relay.cpp create mode 100644 vmime-master/src/vmime/relay.hpp create mode 100644 vmime-master/src/vmime/security/authenticator.hpp create mode 100644 vmime-master/src/vmime/security/cert/X509Certificate.cpp create mode 100644 vmime-master/src/vmime/security/cert/X509Certificate.hpp create mode 100644 vmime-master/src/vmime/security/cert/certificate.hpp create mode 100644 vmime-master/src/vmime/security/cert/certificateChain.cpp create mode 100644 vmime-master/src/vmime/security/cert/certificateChain.hpp create mode 100644 vmime-master/src/vmime/security/cert/certificateException.cpp create mode 100644 vmime-master/src/vmime/security/cert/certificateException.hpp create mode 100644 vmime-master/src/vmime/security/cert/certificateExpiredException.cpp create mode 100644 vmime-master/src/vmime/security/cert/certificateExpiredException.hpp create mode 100644 vmime-master/src/vmime/security/cert/certificateIssuerVerificationException.cpp create mode 100644 vmime-master/src/vmime/security/cert/certificateIssuerVerificationException.hpp create mode 100644 vmime-master/src/vmime/security/cert/certificateNotTrustedException.cpp create mode 100644 vmime-master/src/vmime/security/cert/certificateNotTrustedException.hpp create mode 100644 vmime-master/src/vmime/security/cert/certificateNotYetValidException.cpp create mode 100644 vmime-master/src/vmime/security/cert/certificateNotYetValidException.hpp create mode 100644 vmime-master/src/vmime/security/cert/certificateVerifier.hpp create mode 100644 vmime-master/src/vmime/security/cert/defaultCertificateVerifier.cpp create mode 100644 vmime-master/src/vmime/security/cert/defaultCertificateVerifier.hpp create mode 100644 vmime-master/src/vmime/security/cert/gnutls/X509Certificate_GnuTLS.cpp create mode 100644 vmime-master/src/vmime/security/cert/gnutls/X509Certificate_GnuTLS.hpp create mode 100644 vmime-master/src/vmime/security/cert/openssl/X509Certificate_OpenSSL.cpp create mode 100644 vmime-master/src/vmime/security/cert/openssl/X509Certificate_OpenSSL.hpp create mode 100644 vmime-master/src/vmime/security/cert/serverIdentityException.cpp create mode 100644 vmime-master/src/vmime/security/cert/serverIdentityException.hpp create mode 100644 vmime-master/src/vmime/security/cert/unsupportedCertificateTypeException.cpp create mode 100644 vmime-master/src/vmime/security/cert/unsupportedCertificateTypeException.hpp create mode 100644 vmime-master/src/vmime/security/defaultAuthenticator.cpp create mode 100644 vmime-master/src/vmime/security/defaultAuthenticator.hpp create mode 100644 vmime-master/src/vmime/security/digest/md5/md5MessageDigest.cpp create mode 100644 vmime-master/src/vmime/security/digest/md5/md5MessageDigest.hpp create mode 100644 vmime-master/src/vmime/security/digest/messageDigest.cpp create mode 100644 vmime-master/src/vmime/security/digest/messageDigest.hpp create mode 100644 vmime-master/src/vmime/security/digest/messageDigestFactory.cpp create mode 100644 vmime-master/src/vmime/security/digest/messageDigestFactory.hpp create mode 100644 vmime-master/src/vmime/security/digest/sha1/sha1MessageDigest.cpp create mode 100644 vmime-master/src/vmime/security/digest/sha1/sha1MessageDigest.hpp create mode 100644 vmime-master/src/vmime/security/sasl/SASLAuthenticator.hpp create mode 100644 vmime-master/src/vmime/security/sasl/SASLContext.cpp create mode 100644 vmime-master/src/vmime/security/sasl/SASLContext.hpp create mode 100644 vmime-master/src/vmime/security/sasl/SASLMechanism.hpp create mode 100644 vmime-master/src/vmime/security/sasl/SASLMechanismFactory.cpp create mode 100644 vmime-master/src/vmime/security/sasl/SASLMechanismFactory.hpp create mode 100644 vmime-master/src/vmime/security/sasl/SASLSession.cpp create mode 100644 vmime-master/src/vmime/security/sasl/SASLSession.hpp create mode 100644 vmime-master/src/vmime/security/sasl/SASLSocket.cpp create mode 100644 vmime-master/src/vmime/security/sasl/SASLSocket.hpp create mode 100644 vmime-master/src/vmime/security/sasl/XOAuth2SASLAuthenticator.cpp create mode 100644 vmime-master/src/vmime/security/sasl/XOAuth2SASLAuthenticator.hpp create mode 100644 vmime-master/src/vmime/security/sasl/XOAuth2SASLMechanism.cpp create mode 100644 vmime-master/src/vmime/security/sasl/XOAuth2SASLMechanism.hpp create mode 100644 vmime-master/src/vmime/security/sasl/builtinSASLMechanism.cpp create mode 100644 vmime-master/src/vmime/security/sasl/builtinSASLMechanism.hpp create mode 100644 vmime-master/src/vmime/security/sasl/defaultSASLAuthenticator.cpp create mode 100644 vmime-master/src/vmime/security/sasl/defaultSASLAuthenticator.hpp create mode 100644 vmime-master/src/vmime/streamContentHandler.cpp create mode 100644 vmime-master/src/vmime/streamContentHandler.hpp create mode 100644 vmime-master/src/vmime/stringContentHandler.cpp create mode 100644 vmime-master/src/vmime/stringContentHandler.hpp create mode 100644 vmime-master/src/vmime/text.cpp create mode 100644 vmime-master/src/vmime/text.hpp create mode 100644 vmime-master/src/vmime/textPart.hpp create mode 100644 vmime-master/src/vmime/textPartFactory.cpp create mode 100644 vmime-master/src/vmime/textPartFactory.hpp create mode 100644 vmime-master/src/vmime/types.hpp create mode 100644 vmime-master/src/vmime/utility/childProcess.hpp create mode 100644 vmime-master/src/vmime/utility/datetimeUtils.cpp create mode 100644 vmime-master/src/vmime/utility/datetimeUtils.hpp create mode 100644 vmime-master/src/vmime/utility/encoder/b64Encoder.cpp create mode 100644 vmime-master/src/vmime/utility/encoder/b64Encoder.hpp create mode 100644 vmime-master/src/vmime/utility/encoder/binaryEncoder.cpp create mode 100644 vmime-master/src/vmime/utility/encoder/binaryEncoder.hpp create mode 100644 vmime-master/src/vmime/utility/encoder/eightBitEncoder.cpp create mode 100644 vmime-master/src/vmime/utility/encoder/eightBitEncoder.hpp create mode 100644 vmime-master/src/vmime/utility/encoder/encoder.cpp create mode 100644 vmime-master/src/vmime/utility/encoder/encoder.hpp create mode 100644 vmime-master/src/vmime/utility/encoder/encoderFactory.cpp create mode 100644 vmime-master/src/vmime/utility/encoder/encoderFactory.hpp create mode 100644 vmime-master/src/vmime/utility/encoder/noopEncoder.cpp create mode 100644 vmime-master/src/vmime/utility/encoder/noopEncoder.hpp create mode 100644 vmime-master/src/vmime/utility/encoder/qpEncoder.cpp create mode 100644 vmime-master/src/vmime/utility/encoder/qpEncoder.hpp create mode 100644 vmime-master/src/vmime/utility/encoder/sevenBitEncoder.cpp create mode 100644 vmime-master/src/vmime/utility/encoder/sevenBitEncoder.hpp create mode 100644 vmime-master/src/vmime/utility/encoder/uuEncoder.cpp create mode 100644 vmime-master/src/vmime/utility/encoder/uuEncoder.hpp create mode 100644 vmime-master/src/vmime/utility/file.hpp create mode 100644 vmime-master/src/vmime/utility/filteredStream.cpp create mode 100644 vmime-master/src/vmime/utility/filteredStream.hpp create mode 100644 vmime-master/src/vmime/utility/inputStream.cpp create mode 100644 vmime-master/src/vmime/utility/inputStream.hpp create mode 100644 vmime-master/src/vmime/utility/inputStreamAdapter.cpp create mode 100644 vmime-master/src/vmime/utility/inputStreamAdapter.hpp create mode 100644 vmime-master/src/vmime/utility/inputStreamByteBufferAdapter.cpp create mode 100644 vmime-master/src/vmime/utility/inputStreamByteBufferAdapter.hpp create mode 100644 vmime-master/src/vmime/utility/inputStreamPointerAdapter.cpp create mode 100644 vmime-master/src/vmime/utility/inputStreamPointerAdapter.hpp create mode 100644 vmime-master/src/vmime/utility/inputStreamSocketAdapter.cpp create mode 100644 vmime-master/src/vmime/utility/inputStreamSocketAdapter.hpp create mode 100644 vmime-master/src/vmime/utility/inputStreamStringAdapter.cpp create mode 100644 vmime-master/src/vmime/utility/inputStreamStringAdapter.hpp create mode 100644 vmime-master/src/vmime/utility/outputStream.cpp create mode 100644 vmime-master/src/vmime/utility/outputStream.hpp create mode 100644 vmime-master/src/vmime/utility/outputStreamAdapter.cpp create mode 100644 vmime-master/src/vmime/utility/outputStreamAdapter.hpp create mode 100644 vmime-master/src/vmime/utility/outputStreamByteArrayAdapter.cpp create mode 100644 vmime-master/src/vmime/utility/outputStreamByteArrayAdapter.hpp create mode 100644 vmime-master/src/vmime/utility/outputStreamSocketAdapter.cpp create mode 100644 vmime-master/src/vmime/utility/outputStreamSocketAdapter.hpp create mode 100644 vmime-master/src/vmime/utility/outputStreamStringAdapter.cpp create mode 100644 vmime-master/src/vmime/utility/outputStreamStringAdapter.hpp create mode 100644 vmime-master/src/vmime/utility/parserInputStreamAdapter.cpp create mode 100644 vmime-master/src/vmime/utility/parserInputStreamAdapter.hpp create mode 100644 vmime-master/src/vmime/utility/path.cpp create mode 100644 vmime-master/src/vmime/utility/path.hpp create mode 100644 vmime-master/src/vmime/utility/progressListener.cpp create mode 100644 vmime-master/src/vmime/utility/progressListener.hpp create mode 100644 vmime-master/src/vmime/utility/random.cpp create mode 100644 vmime-master/src/vmime/utility/random.hpp create mode 100644 vmime-master/src/vmime/utility/seekableInputStream.hpp create mode 100644 vmime-master/src/vmime/utility/seekableInputStreamRegionAdapter.cpp create mode 100644 vmime-master/src/vmime/utility/seekableInputStreamRegionAdapter.hpp create mode 100644 vmime-master/src/vmime/utility/stream.cpp create mode 100644 vmime-master/src/vmime/utility/stream.hpp create mode 100644 vmime-master/src/vmime/utility/streamUtils.cpp create mode 100644 vmime-master/src/vmime/utility/streamUtils.hpp create mode 100644 vmime-master/src/vmime/utility/stringUtils.cpp create mode 100644 vmime-master/src/vmime/utility/stringUtils.hpp create mode 100644 vmime-master/src/vmime/utility/sync/autoLock.hpp create mode 100644 vmime-master/src/vmime/utility/sync/criticalSection.cpp create mode 100644 vmime-master/src/vmime/utility/sync/criticalSection.hpp create mode 100644 vmime-master/src/vmime/utility/url.cpp create mode 100644 vmime-master/src/vmime/utility/url.hpp create mode 100644 vmime-master/src/vmime/utility/urlUtils.cpp create mode 100644 vmime-master/src/vmime/utility/urlUtils.hpp create mode 100644 vmime-master/src/vmime/vmime.hpp create mode 100644 vmime-master/src/vmime/word.cpp create mode 100644 vmime-master/src/vmime/word.hpp create mode 100644 vmime-master/src/vmime/wordEncoder.cpp create mode 100644 vmime-master/src/vmime/wordEncoder.hpp create mode 100755 vmime-master/test-outsourced-build.sh create mode 100644 vmime-master/tests/misc/importanceHelperTest.cpp create mode 100644 vmime-master/tests/net/folderAttributesTest.cpp create mode 100644 vmime-master/tests/net/imap/IMAPCommandTest.cpp create mode 100644 vmime-master/tests/net/imap/IMAPParserTest.cpp create mode 100644 vmime-master/tests/net/imap/IMAPTagTest.cpp create mode 100644 vmime-master/tests/net/imap/IMAPUtilsTest.cpp create mode 100644 vmime-master/tests/net/maildir/maildirStoreTest.cpp create mode 100644 vmime-master/tests/net/maildir/maildirUtilsTest.cpp create mode 100644 vmime-master/tests/net/messageSetTest.cpp create mode 100644 vmime-master/tests/net/pop3/POP3CommandTest.cpp create mode 100644 vmime-master/tests/net/pop3/POP3ResponseTest.cpp create mode 100644 vmime-master/tests/net/pop3/POP3StoreTest.cpp create mode 100644 vmime-master/tests/net/pop3/POP3TestUtils.hpp create mode 100644 vmime-master/tests/net/pop3/POP3UtilsTest.cpp create mode 100644 vmime-master/tests/net/smtp/SMTPCommandSetTest.cpp create mode 100644 vmime-master/tests/net/smtp/SMTPCommandTest.cpp create mode 100644 vmime-master/tests/net/smtp/SMTPResponseTest.cpp create mode 100644 vmime-master/tests/net/smtp/SMTPTransportTest.cpp create mode 100644 vmime-master/tests/net/smtp/SMTPTransportTestUtils.hpp create mode 100644 vmime-master/tests/parser/attachmentHelperTest.cpp create mode 100644 vmime-master/tests/parser/bodyPartTest.cpp create mode 100644 vmime-master/tests/parser/bodyTest.cpp create mode 100644 vmime-master/tests/parser/charsetFilteredOutputStreamTest.cpp create mode 100644 vmime-master/tests/parser/charsetTest.cpp create mode 100644 vmime-master/tests/parser/charsetTestSuites.hpp create mode 100644 vmime-master/tests/parser/datetimeTest.cpp create mode 100644 vmime-master/tests/parser/dispositionTest.cpp create mode 100644 vmime-master/tests/parser/emailAddressTest.cpp create mode 100644 vmime-master/tests/parser/emptyContentHandlerTest.cpp create mode 100644 vmime-master/tests/parser/fileContentHandlerTest.cpp create mode 100644 vmime-master/tests/parser/headerFieldTest.cpp create mode 100644 vmime-master/tests/parser/headerTest.cpp create mode 100644 vmime-master/tests/parser/htmlTextPartTest.cpp create mode 100644 vmime-master/tests/parser/mailboxGroupTest.cpp create mode 100644 vmime-master/tests/parser/mailboxListTest.cpp create mode 100644 vmime-master/tests/parser/mailboxTest.cpp create mode 100644 vmime-master/tests/parser/mediaTypeTest.cpp create mode 100644 vmime-master/tests/parser/messageIdSequenceTest.cpp create mode 100644 vmime-master/tests/parser/messageIdTest.cpp create mode 100644 vmime-master/tests/parser/messageTest.cpp create mode 100644 vmime-master/tests/parser/parameterTest.cpp create mode 100644 vmime-master/tests/parser/pathTest.cpp create mode 100644 vmime-master/tests/parser/streamContentHandlerTest.cpp create mode 100644 vmime-master/tests/parser/stringContentHandlerTest.cpp create mode 100644 vmime-master/tests/parser/textTest.cpp create mode 100644 vmime-master/tests/parser/wordEncoderTest.cpp create mode 100644 vmime-master/tests/security/digest/md5Test.cpp create mode 100644 vmime-master/tests/security/digest/sha1Test.cpp create mode 100644 vmime-master/tests/testRunner.cpp create mode 100644 vmime-master/tests/testUtils.cpp create mode 100644 vmime-master/tests/testUtils.hpp create mode 100644 vmime-master/tests/utility/datetimeUtilsTest.cpp create mode 100644 vmime-master/tests/utility/encoder/b64EncoderTest.cpp create mode 100644 vmime-master/tests/utility/encoder/encoderFactoryTest.cpp create mode 100644 vmime-master/tests/utility/encoder/encoderTestUtils.hpp create mode 100644 vmime-master/tests/utility/encoder/qpEncoderTest.cpp create mode 100644 vmime-master/tests/utility/filteredStreamTest.cpp create mode 100644 vmime-master/tests/utility/outputStreamByteArrayAdapterTest.cpp create mode 100644 vmime-master/tests/utility/outputStreamSocketAdapterTest.cpp create mode 100644 vmime-master/tests/utility/outputStreamStringAdapterTest.cpp create mode 100644 vmime-master/tests/utility/parserInputStreamAdapterTest.cpp create mode 100644 vmime-master/tests/utility/pathTest.cpp create mode 100644 vmime-master/tests/utility/seekableInputStreamRegionAdapterTest.cpp create mode 100644 vmime-master/tests/utility/stringUtilsTest.cpp create mode 100644 vmime-master/tests/utility/urlTest.cpp create mode 100644 vmime-master/vmime.pc.in (limited to 'vmime-master') 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 +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 + - Rafael Fernandez + - Xin Li + - Benjamin Biron + - Bertrand Benoit + - Tim Teulings + - Georg Sauthoff + - Pierre Thierry (patches for STL algorithms) + - Zarafa + - Bartek Szurgot + - Achim Brandt + - Mehmet Bozkurt (OpenSSL support, ICU support) + - Anthony Dervish + +Please apologize if I have forgotten someone here. ;) Send me an email +to 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 ' 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 + $ + ) + + 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 + $ + ) + + 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 ") +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. + 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. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU 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 . + +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: + + Copyright (C) + 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 +. + + 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 +. 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 + +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 , where +# is the value of the INPUT_FILTER tag, and 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 & 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 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, +# +# Changes are Copyright 2009, Michele Caini, +# +# 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__FOUND : were 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= +# - 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} = ") + 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 ) +# ... +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) + ########## ########## + 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}") + ########## ########## + + # 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 + 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 +#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 +#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 + +/*** 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 */ + /* state to , 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 + +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 + +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 + 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(cp); + else if (cp < 0x800) { // two octets + *(result++) = static_cast((cp >> 6) | 0xc0); + *(result++) = static_cast((cp & 0x3f) | 0x80); + } + else if (cp < 0x10000) { // three octets + *(result++) = static_cast((cp >> 12) | 0xe0); + *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); + *(result++) = static_cast((cp & 0x3f) | 0x80); + } + else { // four octets + *(result++) = static_cast((cp >> 18) | 0xf0); + *(result++) = static_cast(((cp >> 12) & 0x3f) | 0x80); + *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); + *(result++) = static_cast((cp & 0x3f) | 0x80); + } + return result; + } + + template + 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 + 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 + 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 + uint32_t peek_next(octet_iterator it, octet_iterator end) + { + return utf8::next(it, end); + } + + template + 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 + 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 + 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 std::iterator_traits::difference_type + distance (octet_iterator first, octet_iterator last) + { + typename std::iterator_traits::difference_type dist; + for (dist = 0; first < last; ++dist) + utf8::next(first, last); + return dist; + } + + template + 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(trail_surrogate)); + } + else + throw invalid_utf16(static_cast(cp)); + + } + // Lone trail surrogate + else if (utf8::internal::is_trail_surrogate(cp)) + throw invalid_utf16(static_cast(cp)); + + result = utf8::append(cp, result); + } + return result; + } + + template + 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((cp >> 10) + internal::LEAD_OFFSET); + *result++ = static_cast((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN); + } + else + *result++ = static_cast(cp); + } + return result; + } + + template + octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result) + { + while (start != end) + result = utf8::append(*(start++), result); + + return result; + } + + template + 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 + class iterator : public std::iterator { + 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 + +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 + inline uint8_t mask8(octet_type oc) + { + return static_cast(0xff & oc); + } + template + inline uint16_t mask16(u16_type oc) + { + return static_cast(0xffff & oc); + } + template + inline bool is_trail(octet_type oc) + { + return ((utf8::internal::mask8(oc) >> 6) == 0x2); + } + + template + inline bool is_lead_surrogate(u16 cp) + { + return (cp >= LEAD_SURROGATE_MIN && cp <= LEAD_SURROGATE_MAX); + } + + template + inline bool is_trail_surrogate(u16 cp) + { + return (cp >= TRAIL_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX); + } + + template + inline bool is_surrogate(u16 cp) + { + return (cp >= LEAD_SURROGATE_MIN && cp <= TRAIL_SURROGATE_MAX); + } + + template + inline bool is_code_point_valid(u32 cp) + { + return (cp <= CODE_POINT_MAX && !utf8::internal::is_surrogate(cp)); + } + + template + inline typename std::iterator_traits::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 + 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 + 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 + 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 + 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 + 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 + 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 + 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::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 + 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 + 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 + inline bool is_valid(octet_iterator start, octet_iterator end) + { + return (utf8::find_invalid(start, end) == end); + } + + template + 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 + 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 + octet_iterator append(uint32_t cp, octet_iterator result) + { + if (cp < 0x80) // one octet + *(result++) = static_cast(cp); + else if (cp < 0x800) { // two octets + *(result++) = static_cast((cp >> 6) | 0xc0); + *(result++) = static_cast((cp & 0x3f) | 0x80); + } + else if (cp < 0x10000) { // three octets + *(result++) = static_cast((cp >> 12) | 0xe0); + *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); + *(result++) = static_cast((cp & 0x3f) | 0x80); + } + else { // four octets + *(result++) = static_cast((cp >> 18) | 0xf0); + *(result++) = static_cast(((cp >> 12) & 0x3f)| 0x80); + *(result++) = static_cast(((cp >> 6) & 0x3f) | 0x80); + *(result++) = static_cast((cp & 0x3f) | 0x80); + } + return result; + } + + template + uint32_t next(octet_iterator& it) + { + uint32_t cp = utf8::internal::mask8(*it); + typename std::iterator_traits::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 + uint32_t peek_next(octet_iterator it) + { + return utf8::unchecked::next(it); + } + + template + 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 + inline uint32_t previous(octet_iterator& it) + { + return utf8::unchecked::prior(it); + } + + template + void advance (octet_iterator& it, distance_type n) + { + for (distance_type i = 0; i < n; ++i) + utf8::unchecked::next(it); + } + + template + typename std::iterator_traits::difference_type + distance (octet_iterator first, octet_iterator last) + { + typename std::iterator_traits::difference_type dist; + for (dist = 0; first < last; ++dist) + utf8::unchecked::next(first); + return dist; + } + + template + 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 + 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((cp >> 10) + internal::LEAD_OFFSET); + *result++ = static_cast((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN); + } + else + *result++ = static_cast(cp); + } + return result; + } + + template + octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result) + { + while (start != end) + result = utf8::unchecked::append(*(start++), result); + + return result; + } + + template + 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 + class iterator : public std::iterator { + 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 obj = + vmime::make_shared ("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 obj = vmime::make_shared (); + +// Implicit downcast +vmime::shared_ptr base = obj; + +// Explicit upcast +vmime::shared_ptr obj2 = vmime::dynamicCast (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 c) { + + m_child = c; + } + +private: + + vmime::shared_ptr m_child; +}; + +class child : public vmime::object { + +public: + + child(vmime::shared_ptr p) + : m_parent(p) { + + } + +private: + + vmime::shared_ptr m_parent; +}; + +int main() { + + vmime::shared_ptr p = vmime::make_shared (); + vmime::shared_ptr c = vmime::make_shared (); + + 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 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 mbox1 = vmime::make_shared + (/* name */ vmime::text("John Doe"), /* email */ "john.doe@acme.com"); +vmime::shared_ptr mbox2 = vmime::make_shared + (/* no name, email only */ "bill@acme.com"); + +vmime::shared_ptr grp = vmime::make_shared (); +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 field = + header->findField ("X-Field-That-Contains-Parameters"); + +// Use setValue() to convert from a basic type to 'text' +vmime::shared_ptr 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 (); +\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 field = + header->getField (vmime::fields::CONTENT_TYPE); + +// 1. First solution: the "hard" way +vmime::shared_ptr prm = field->findParameter("charset"); +const charset ch1 = prm->getValueAs (); + +// 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 msg; + +// Obtains a reference to the body contents +vmime::shared_ptr body = msg->getBody(); +vmime::shared_ptr 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 part; // suppose we have a body part + +// Create a new content handler from a string +vmime::shared_ptr cth = + vmime::make_shared ("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 dataStream = + vmime::make_shared (fileStream); + + // NOTE: 'fileStream' will be automatically deleted + // when 'dataStream' is deleted + +// Create a new content handler +vmime::shared_ptr data = + vmime::make_shared (dataStream, 0); + +// Now create the attachment +ref att = vmime::make_shared ( + /* 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 msg; // we have a message + +// Obtain the content handler first +vmime::shared_ptr body = msg->getBody(); +vmime::shared_ptr 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: +// . "Linux dans un " +// . "téléphone " +// . "mobile" + +vmime::shared_ptr 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 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 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 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 + enc = ef->getEncoderAt(i); + + std::cout << " * " << enc->getName() << std::endl; + + // Create an instance of the encoder to get its properties + vmime::shared_ptr e = enc->create(); + + std::vector props = e->getAvailableProperties(); + std::vector ::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 @@ + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + isEmpty() : boolisGroup() : bool + address + + + getName() : stringsetName(n : string) : voidappendMailbox(m : ref <mailbox>)getMailboxCount() : intgetMailboxAt(i : int) : ref <mailbox>... + mailboxGroup + + + getName() : textsetName(n : text) : voidgetEmail() : stringsetEmail(e : string) : void + mailbox + + + 0..n + mailboxes + 0 + + + + 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 @@ + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + parse(buf : string) : voidgenerate(out : outputStream) : voidclone() : ref <component>copyFrom(src : component) : voidgetChildComponents() : vectorgetParsedOffset() : intgetParsedLength() : int + component + + + getBody() : ref <body>getHeader() : ref <header>getParentPart() : ref <bodyPart> + bodyPart + + + + + + + + + body + + hasField(name : string) : boolfindField(name : string) : ref <headerField>findAllFields(name : string) : vectorgetField(name : string) : ref <headerField>appendField(f : ref <headerField>) : void...getFieldAt(pos : int) : ref <headerField>getFieldCount() : int + header + + + getName() : stringgetValue() : componentsetValue(val : component) + headerField + + + + 0..n + fields + 0 + + + getContents() : ref <ch>getCharset() : charsetgetEncoding() : encoding + body + + + + + + + + + + + + + + + + + header + + extract(out : outputStream) : voidgetLength() : intgetEncoding() : encodingisEmpty() : bool + contentHandler + + contents + + 0..n + sub-parts + 0 + + + message + + + + + + 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 @@ + + + + + + + + + + + + + + + + + + + + + + + + + image/svg+xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + connect() : voiddisconnect() : voidisConnected() : boolnoop() : void + service + + + getTransport(url : url) : ref <transport>getStore(url : url) : ref <store>getProperties() : propertySet + session + + + getDefaultFolder() : ref <folder>getRootFolder() : ref <folder> + store + + + send(msg : ref <message>) : void + transport + + + + + + + + + + session + <instanciates> + + create(protocol : string) : ref <service> + serviceFactory + + <uses> + + getName() : stringopen() : voidclose() : voidgetMessages(int from, int to) : vector... + folder + + <instanciates> + + getNumber() : intgetFlags() : intgetHeader() : intgetStructure() : structureextract(out : outputStream) : void... + message + + <instanciates> + + + + 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 +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 msg = vmime::make_shared (); +msg->parse(data); + +vmime::shared_ptr hdr = msg->getHeader(); +vmime::shared_ptr 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 ()->getConvertedText(ch) + << std::endl + << "It was sent by: " + << hdr->From()->getValue ()->getName().getConvertedText(ch) + << " (email: " << hdr->From()->getValue ()->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 msg = vmime::make_shared (); +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 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 tp = mp.getTextPartAt(i); + + // text/html + if (tp->getType().getSubType() == vmime::mediaTypes::TEXT_HTML) { + + vmime::shared_ptr htp = + vmime::dynamicCast (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 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 msg = vmime::make_shared (); + +vmime::shared_ptr hdr = msg->getHeader(); +vmime::shared_ptr bdy = msg->getBody(); + +vmime::shared_ptr hfFactory = + vmime::headerFieldFactory::getInstance(); + +// Append a 'Date:' field +vmime::shared_ptr dateField = + hfFactory->create(vmime::fields::DATE); + +dateField->setValue(vmime::datetime::now()); +hdr->appendField(dateField); + +// Append a 'Subject:' field +vmime::shared_ptr subjectField = + hfFactory->create(vmime::fields::SUBJECT); + +subjectField->setValue(vmime::text("Message subject")); +hdr->appendField(subjectField); + +// Append a 'From:' field +vmime::shared_ptr fromField = + hfFactory->create(vmime::fields::FROM); + +fromField->setValue(vmime::make_shared ("me@vmime.org")); +hdr->appendField(fromField); + +// Append a 'To:' field +vmime::shared_ptr toField = + hfFactory->create(vmime::fields::TO); + +vmime::shared_ptr recipients = + vmime::make_shared (); + +recipients->appendMailbox + (vmime::make_shared ("you@vmime.org")); + +toField->setValue(recipients); +hdr->appendField(toField); + +// Set the body contents +bdy->setContents( + vmime::make_shared ( + "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 ("you@vmime.org") + ); + + mb.getTextPart()->setCharset(vmime::charsets::ISO8859_15); + mb.getTextPart()->setText( + vmime::make_shared ( + "This is the text of your message..." + ) + ); + + // Message construction + vmime::shared_ptr 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 att = + vmime::make_shared ( + /* 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 ("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 textPart = + vmime::dynamicCast (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 ( + "This is the HTML text, and the image:
" + "" + ) +); + +textPart->setPlainText( + vmime::make_shared ( + "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 imageFile = + fs->create(fs->stringToPath("/path/to/image.jpg")); + +vmime::shared_ptr imageCts = + vmime::make_shared ( + 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 part; // suppose we have a body part + +if (vmime::attachmentHelper::isBodyPartAnAttachment(part)) { + + // The body part contains an attachment, get it + vmime::shared_ptr 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 msg; // suppose we have a message + +const std::vector > 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 msg; // suppose we have a message + +// Create an attachment +vmime::shared_ptr att = + vmime::make_shared ( + /* 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 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 st = sess->getStore(url); +\end{lstlisting} + +and for transport services: + +\begin{lstlisting} +vmime::utility:url url("smtp://smtp.example.com"); +vmime::shared_ptr 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 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 sess = vmime::net::session::create(); + +// Next, initialize a service which will use our authenticator +vmime::shared_ptr st = sess->getStore( + vmime::utility::url("imap://imap.example.com"), + /* use our authenticator */ vmime::make_shared () +); +\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 > getAcceptableMechanisms( + const std::vector >& available, + const vmime::shared_ptr & 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 & 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 sess = vmime::net::session::create(); + +// Create an instance of the transport service +vmime::shared_ptr 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 ("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 sess = vmime::net::session::create(); + +// Create an instance of the transport service +vmime::shared_ptr 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 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 > 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 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 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 folder = store->getDefaultFolder(); +vmime::shared_ptr 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 folder = store->getDefaultFolder(); + +folder->deleteMessages(vmime::net::messageSet::byNumber(/* from */ 2, /* to */ 3)); + +// This is equivalent +std::vector 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 create() { + + return vmime::make_shared (); + } +}; +\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 ()); +\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 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 + 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 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 vrf = + vmime::make_shared (); + +// Load root CAs (such as Verisign or Thawte) +std::vector > 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 > 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 & certs) { + + // Obtain the subject's certificate + vmime::shared_ptr 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 ()); +\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 sess = /* ... */; + +vmime::shared_ptr tlsProps = + vmime::make_shared (); + +// 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 create( + const vmime::shared_ptr & serv, + const int connectionId + ) { + + return vmime::make_shared ( + 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 store = + session->getStore("imaps://user:password@imap.myserver.com"); + +// Enable tracing communication between client and server +store->setTracerFactory(vmime::make_shared ()); +\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 +\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 +#include + +int main() { + + vmime::platform:: + setHandler (); + + // 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 (); +\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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +#include +#include + +#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 ("you@elsewhere.com")); + + mb.setRecipients(to); + + vmime::addressList bcc; + bcc.appendAddress(vmime::make_shared ("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 ( + "I'm writing this short text to test message construction " \ + "using the vmime::messageBuilder component." + ) + ); + + // Construction + vmime::shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +#include +#include + +#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 ("you@elsewhere.com")); + + mb.setRecipients(to); + + vmime::addressList bcc; + bcc.appendAddress(vmime::make_shared ("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 ( + "I'm writing this short text to test message construction " \ + "with attachment, using the vmime::messageBuilder component." + ) + ); + + // Adding an attachment + vmime::shared_ptr a = + vmime::make_shared ( + __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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +#include +#include + +#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 ("you@elsewhere.com")); + + mb.setRecipients(to); + + vmime::addressList bcc; + bcc.appendAddress(vmime::make_shared ("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 (mb.getTextPart()); + + // -- embed an image (the returned "CID" (content identifier) is used to reference + // -- the image into HTML content). + vmime::shared_ptr fs = + vmime::platform::getHandler()->getFileSystemFactory(); + + vmime::shared_ptr imageFile = + fs->create(fs->stringToPath("/path/to/image.jpg")); + + vmime::shared_ptr fileReader = + imageFile->getFileReader(); + + vmime::shared_ptr imageCts = + vmime::make_shared ( + fileReader->getInputStream(), + imageFile->getLength() + ); + + vmime::shared_ptr obj = + textPart.addObject( + imageCts, + vmime::mediaType( + vmime::mediaTypes::IMAGE, + vmime::mediaTypes::IMAGE_JPEG + ) + ); + + // -- message text + textPart.setText( + vmime::make_shared ( + vmime::string("This is the HTML text.
" + "getReferenceId() + vmime::string("\"/>") + ) + ); + + textPart.setPlainText( + vmime::make_shared ( + "This is the plain text (without HTML formatting)." + ) + ); + + // Construction + vmime::shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +#include +#include + +#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(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(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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +#include +#include + +#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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include +#include +#include +#include +#include +#include + +#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 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 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 (&e)) { + + const vmime::exceptions::command_error& cee = + dynamic_cast (e); + + os << " command = " << cee.command() << std::endl; + os << " response = " << cee.response() << std::endl; + } + + if (dynamic_cast (&e)) { + + const vmime::exceptions::invalid_response& ir = + dynamic_cast (e); + + os << " response = " << ir.response() << std::endl; + } + + if (dynamic_cast (&e)) { + + const vmime::exceptions::connection_greeting_error& cgee = + dynamic_cast (e); + + os << " response = " << cgee.response() << std::endl; + } + + if (dynamic_cast (&e)) { + + const vmime::exceptions::authentication_error& aee = + dynamic_cast (e); + + os << " response = " << aee.response() << std::endl; + } + + if (dynamic_cast (&e)) { + + const vmime::exceptions::filesystem_exception& fse = + dynamic_cast (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 s, + const int level = 0 +) { + + for (size_t i = 0 ; i < s->getPartCount() ; ++i) { + + vmime::shared_ptr 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 f) { + + const vmime::string n = f->getName().getBuffer(); + + if (n.empty()) { // root folder + + return "/"; + + } else { + + vmime::shared_ptr 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 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 > 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 & 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 tr; + + if (url.getUsername().empty() || url.getPassword().empty()) { + tr = g_session->getTransport(url, vmime::make_shared ()); + } 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 ()); + + // Set the object responsible for verifying certificates, in the + // case a secured connection is used (TLS/SSL) + tr->setCertificateVerifier( + vmime::make_shared () + ); + +#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 traceStream = vmime::make_shared (); + tr->setTracerFactory(vmime::make_shared (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 (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 st; + + if (url.getUsername().empty() || url.getPassword().empty()) { + st = g_session->getStore(url, vmime::make_shared ()); + } 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 ()); + + // Set the object responsible for verifying certificates, in the + // case a secured connection is used (TLS/SSL) + st->setCertificateVerifier( + vmime::make_shared () + ); + +#endif // VMIME_HAVE_TLS_SUPPORT + + // Trace communication between client and server + vmime::shared_ptr traceStream = vmime::make_shared (); + st->setTracerFactory(vmime::make_shared (traceStream)); + + // Connect to the mail store + st->connect(); + + // Display some information about the connection + vmime::shared_ptr 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 f = st->getDefaultFolder(); +// vmime::shared_ptr 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 > MessageList; + MessageList msgList; + + try { + + std::vector 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 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 parsedMsg = msg->getParsedMessage(); + + std::vector > attchs = + vmime::attachmentHelper::findAttachmentsInMessage(parsedMsg); + + if (attchs.size() > 0) { + + std::cout << attchs.size() << " attachments found." << std::endl; + + for (std::vector >::iterator + it = attchs.begin() ; it != attchs.end() ; ++it) { + + vmime::shared_ptr 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 fsf + = vmime::platform::getHandler()->getFileSystemFactory(); + + vmime::shared_ptr 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 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 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 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 ("you@elsewhere.com")); + mb.setRecipients(to); + + mb.setSubject(vmime::text("Test message from VMime example6")); + mb.getTextPart()->setText( + vmime::make_shared ( + "Body of test message from VMime example6." + ) + ); + + vmime::shared_ptr 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 (range).getFirst(); + + std::cout << "Message has successfully been added, " + << "its UID is '" << uid << "'." << std::endl; + + } else { + + const vmime::size_t number = + dynamic_cast (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 (range).getFirst(); + + std::cout << "Message has successfully been copied, " + << "its UID is '" << uid << "'." << std::endl; + + } else { + + const vmime::size_t number = + dynamic_cast (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 f = st->getFolder(vmime::net::folder::path("c")); + f->rename(vmime::net::folder::path("c2")); + + vmime::shared_ptr 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 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 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 > + getAcceptableMechanisms( + const std::vector >& available, + const vmime::shared_ptr & 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 & 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 & 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 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 (cert) + ); + + setX509TrustedCerts(m_trustedCerts); + defaultCertificateVerifier::verify(chain, hostname); + } + + return; + } + + throw vmime::security::cert::certificateException("User did not accept the certificate."); + } + } + +private: + + static std::vector > m_trustedCerts; +}; + + +std::vector > + 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 + + +/** 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 create() { + + return vmime::make_shared (); + } +}; 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 & stream, + const vmime::shared_ptr & 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 m_stream; + vmime::shared_ptr m_service; + const int m_connectionId; +}; + + +class myTracerFactory : public vmime::net::tracerFactory { + +public: + + myTracerFactory(const vmime::shared_ptr & stream) + : m_stream(stream) { + + } + + vmime::shared_ptr create( + const vmime::shared_ptr & serv, + const int connectionId + ) { + + return vmime::make_shared (m_stream, serv, connectionId); + } + +private: + + vmime::shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +#include +#include + +#include "vmime/vmime.hpp" +#include "vmime/platforms/posix/posixHandler.hpp" + + +int main() { + + // Enumerate encoders + vmime::shared_ptr ef = + vmime::utility::encoder::encoderFactory::getInstance(); + + std::cout << "Available encoders:" << std::endl; + + for (size_t i = 0 ; i < ef->getEncoderCount() ; ++i) { + + vmime::shared_ptr + enc = ef->getEncoderAt(i); + + std::cout << " * " << enc->getName() << std::endl; + + vmime::shared_ptr e = + vmime::utility::encoder::encoderFactory::getInstance()->create(enc->getName()); + + std::vector props = e->getAvailableProperties(); + + for (std::vector ::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 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 props = + serv.getInfos().getAvailableProperties(); + + for (std::vector ::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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +#include +#include +#include + +#include + +#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 currentMessage; + + + +void insertRowInModel( + GtkTreeStore* model, + vmime::shared_ptr 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 > 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 msg = vmime::make_shared (); + 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...", "O", NULL, G_CALLBACK(onFileOpen) }, + { "FileExit", GTK_STOCK_QUIT, "_Exit", "Q", NULL, G_CALLBACK(gtk_main_quit) } +}; + +static const char* uiDefinition = + "" \ + " " \ + " " \ + " " \ + " " \ + " " \ + " " \ + ""; + + +int main(int argc, char* argv[]) { + + // VMime initialization + vmime::platform::setHandler(); + + // 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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::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
parsedAddress; + + if (isGroup) { + parsedAddress = make_shared (); + } else { + parsedAddress = make_shared (); + } + + 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 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
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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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
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 >::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 (other); + + removeAllAddresses(); + + for (std::vector >::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
(other.getMailboxAt(i)->clone())); + } + + return *this; +} + + +shared_ptr addressList::clone() const { + + return make_shared (*this); +} + + +void addressList::appendAddress(const shared_ptr
&addr) { + + m_list.push_back(addr); +} + + +void addressList::insertAddressBefore(const shared_ptr
& beforeAddress, const shared_ptr
& addr) { + + const std::vector >::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
& 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
& afterAddress, + const shared_ptr
& addr +) { + + const std::vector >::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
& 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
& addr) { + + const std::vector >::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 >::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
addressList::getAddressAt(const size_t pos) { + + return m_list[pos]; +} + + +const shared_ptr addressList::getAddressAt(const size_t pos) const { + + return m_list[pos]; +} + + +const std::vector > addressList::getAddressList() const { + + std::vector > list; + + list.reserve(m_list.size()); + + for (std::vector >::const_iterator it = m_list.begin() ; + it != m_list.end() ; ++it) { + + list.push_back(*it); + } + + return list; +} + + +const std::vector > addressList::getAddressList() { + + return m_list; +} + + +const std::vector > addressList::getChildComponents() { + + std::vector > list; + + copy_vector(m_list, list); + + return list; +} + + +shared_ptr addressList::toMailboxList() const { + + shared_ptr res = make_shared (); + + for (std::vector >::const_iterator it = m_list.begin() ; + it != m_list.end() ; ++it) { + + shared_ptr addr = *it; + + if (addr->isGroup()) { + + const std::vector > mailboxes = + dynamicCast (addr)->getMailboxList(); + + for (std::vector >::const_iterator jt = mailboxes.begin() ; + jt != mailboxes.end() ; ++jt) { + + res->appendMailbox(vmime::clone(*jt)); + } + + } else { + + res->appendMailbox(dynamicCast (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 clone() const; + void copyFrom(const component& other); + addressList& operator=(const addressList& other); + addressList& operator=(const mailboxList& other); + + const std::vector > getChildComponents(); + + + /** Add a address at the end of the list. + * + * @param addr address to append + */ + void appendAddress(const shared_ptr
& 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
& beforeAddress, + const shared_ptr
& 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
& 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
& afterAddress, + const shared_ptr
& 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
& 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
& 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
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 getAddressAt(const size_t pos) const; + + /** Return the address list. + * + * @return list of addresses + */ + const std::vector > getAddressList() const; + + /** Return the address list. + * + * @return list of addresses + */ + const std::vector > 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 toMailboxList() const; + +private: + + std::vector > 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 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 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 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 & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 + + +namespace vmime { + + +// static +bool attachmentHelper::isBodyPartAnAttachment( + const shared_ptr & part, + const unsigned int options +) { + + // First, try with "Content-Disposition" field. + // If not present, we will try with "Content-Type" field. + shared_ptr cdf = + part->getHeader()->findField (fields::CONTENT_DISPOSITION); + + if (cdf) { + + const contentDisposition disp = *cdf->getValue (); + + 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 ctf = + part->getHeader()->findField (fields::CONTENT_TYPE); + + if (ctf) { + + type = *ctf->getValue (); + + 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 attachmentHelper::getBodyPartAttachment( + const shared_ptr & part, + const unsigned int options +) { + + if (!isBodyPartAnAttachment(part, options)) { + return null; + } + + mediaType type; + + shared_ptr ctf = + part->getHeader()->findField (fields::CONTENT_TYPE); + + if (ctf) { + + type = *ctf->getValue (); + + } 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 (part); + + } else { + + return make_shared (part); + } +} + + +// static +const std::vector > + attachmentHelper::findAttachmentsInMessage( + const shared_ptr & msg, + const unsigned int options + ) { + + return findAttachmentsInBodyPart(msg, options); +} + + +// static +const std::vector > + attachmentHelper::findAttachmentsInBodyPart( + const shared_ptr & part, + const unsigned int options + ) { + + std::vector > atts; + + // Test this part + if (isBodyPartAnAttachment(part, options)) { + + atts.push_back(getBodyPartAttachment(part, options)); + + // Find in sub-parts + } else { + + shared_ptr bdy = part->getBody(); + + for (size_t i = 0 ; i < bdy->getPartCount() ; ++i) { + + std::vector > 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 & msg, const shared_ptr & 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 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 container = make_shared (); + + 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 > 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 child = make_shared (); + + 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 ()); + + 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 attachmentHelper::findBodyPart( + const shared_ptr & part, + const mediaType& type +) { + + if (part->getBody()->getContentType() == type) { + return part; + } + + // Try in sub-parts + shared_ptr bdy = part->getBody(); + + for (size_t i = 0 ; i < bdy->getPartCount() ; ++i) { + + shared_ptr found = findBodyPart(bdy->getPartAt(i), type); + + if (found) { + return found; + } + } + + return null; +} + + +// static +void attachmentHelper::addAttachment(const shared_ptr & msg, const shared_ptr & amsg) { + + shared_ptr att = make_shared (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & 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 getBodyPartAttachment( + const shared_ptr & 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 > + findAttachmentsInBodyPart( + const shared_ptr & 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 > + findAttachmentsInMessage( + const shared_ptr & 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 & msg, + const shared_ptr & 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 & msg, + const shared_ptr & amsg + ); + +protected: + + static shared_ptr findBodyPart( + const shared_ptr & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 ::max(); +} + + +const size_t npos = std::numeric_limits ::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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +#include +#include +#include +#include +#include + +#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 + operator shared_ptr () { return shared_ptr (); } + }; + + 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 + inline T const* cbegin(T const (&array)[N]) { + + return array; + } + + template + inline T const* cend(T const (&array)[N]) { + + return array + N; + } + + template + inline T* begin(T (&array)[N]) { + + return array; + } + + template + inline T* end(T (&array)[N]) { + + return array + N; + } + + template + inline size_t count(T const (&/* array */)[N]) { + + return N; + } + + + // Copy one vector to another, with type conversion + + template + 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 (obj->clone()). + */ + template + shared_ptr clone(const shared_ptr & obj) { + + return dynamic_pointer_cast (obj->clone()); + } + + /** Clone helper (using a const shared_ptr). + * This is an alias for dynamic_pointer_cast (obj->clone()). + */ + template + shared_ptr clone(const shared_ptr & obj) { + + return dynamic_pointer_cast (obj->clone()); + } + + /** Clone helper (using a const reference). + * This is an alias for dynamic_pointer_cast (obj.clone()). + */ + template + shared_ptr clone(const T& obj) { + + return dynamic_pointer_cast (obj.clone()); + } + + /** Downcast helper. + * Usage: vmime::dynamicCast (obj), where 'obj' is of + * type Type, and DerivedType is derived from Type. + */ + template + shared_ptr dynamicCast(const shared_ptr & obj) { + + return dynamic_pointer_cast (obj); + } + + /** Const cast helper. + */ + template + shared_ptr constCast(const shared_ptr & obj) { + + return const_pointer_cast (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 ()) { + +} + + +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 & 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 & 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 ctf = + m_part->getHeader()->findField (fields::CONTENT_TYPE); + + if (ctf) { + + const mediaType type = *ctf->getValue (); + + 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 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 (); + + // Last part was not found: recover from missing boundary + if (!lastPart && pos == npos) { + + shared_ptr 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 cef = + m_part->getHeader()->findField(fields::CONTENT_TRANSFER_ENCODING); + + if (cef) { + + enc = *cef->getValue (); + + } else { + + // Defaults to "7bit" (RFC-1521) + enc = vmime::encoding(encodingTypes::SEVEN_BIT); + } + + // Extract the (encoded) contents + const size_t length = end - position; + + shared_ptr contentStream = + make_shared ( + parser->getUnderlyingStream(), position, length + ); + + m_contents = make_shared (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 ctf = + m_part->getHeader()->findField (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 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 srcEncoder = m_contents->getEncoding().getEncoder(); + shared_ptr 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 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 (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 (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 ctf = + dynamicCast (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 ctf = + m_part->getHeader()->findField (fields::CONTENT_TYPE); + + if (ctf) { + + return *ctf->getValue (); + + } else { + + // Defaults to "text/plain" (RFC-1521) + return mediaType(mediaTypes::TEXT, mediaTypes::TEXT_PLAIN); + } +} + + +void body::setCharset(const charset& chset) { + + shared_ptr ctf = + m_part->getHeader()->findField (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 ctf = + m_part->getHeader()->findField (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 cef = + m_part->getHeader()->findField(fields::CONTENT_TRANSFER_ENCODING); + + if (cef) { + + return *cef->getValue (); + + } 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 >::iterator it = m_parts.begin() ; + it != m_parts.end() ; ++it) { + + shared_ptr childPart = *it; + parent->importChildPart(childPart); + } +} + + +bool body::isRootPart() const { + + return !m_part || !m_part->getParentPart(); +} + + +shared_ptr body::clone() const { + + shared_ptr bdy = make_shared (); + + bdy->copyFrom(*this); + + return bdy; +} + + +void body::copyFrom(const component& other) { + + const body& bdy = dynamic_cast (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 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 body::getContents() const { + + return m_contents; +} + + +void body::setContents(const shared_ptr & contents) { + + m_contents = contents; +} + + +void body::setContents( + const shared_ptr & contents, + const mediaType& type +) { + + m_contents = contents; + + setContentType(type); +} + + +void body::setContents( + const shared_ptr & contents, + const mediaType& type, + const charset& chset +) { + + m_contents = contents; + + setContentType(type, chset); +} + + +void body::setContents( + const shared_ptr & contents, + const mediaType& type, + const charset& chset, + const encoding& enc +) { + + m_contents = contents; + + setContentType(type, chset); + setEncoding(enc); +} + + +void body::initNewPart(const shared_ptr & 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
hdr = m_part->getHeader(); + + // Check whether we have a boundary string + shared_ptr ctf = + hdr->findField (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 ()->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 (fields::CONTENT_TYPE); + + ctf->setValue(mediaType(mediaTypes::MULTIPART, mediaTypes::MULTIPART_MIXED)); + ctf->setBoundary(generateRandomBoundaryString()); + } + } +} + + +void body::appendPart(const shared_ptr & part) { + + initNewPart(part); + + m_parts.push_back(part); +} + + +void body::insertPartBefore( + const shared_ptr & beforePart, + const shared_ptr & part +) { + + initNewPart(part); + + const std::vector >::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 & part +) { + + initNewPart(part); + + m_parts.insert(m_parts.begin() + pos, part); +} + + +void body::insertPartAfter( + const shared_ptr & afterPart, + const shared_ptr & part +) { + + initNewPart(part); + + const std::vector >::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 & part) { + + initNewPart(part); + + m_parts.insert(m_parts.begin() + pos + 1, part); +} + + +void body::removePart(const shared_ptr & part) { + + const std::vector >::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 body::getPartAt(const size_t pos) { + + return m_parts[pos]; +} + + +const shared_ptr body::getPartAt(const size_t pos) const { + + return m_parts[pos]; +} + + +const std::vector > body::getPartList() const { + + std::vector > list; + + list.reserve(m_parts.size()); + + for (std::vector >::const_iterator it = m_parts.begin() ; + it != m_parts.end() ; ++it) { + + list.push_back(*it); + } + + return list; +} + + +const std::vector > body::getPartList() { + + return m_parts; +} + + +const std::vector > body::getChildComponents() { + + std::vector > 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & 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 & beforePart, + const shared_ptr & 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 & 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 & afterPart, + const shared_ptr & 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 & 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 & 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 getPartAt(const size_t pos); + + /** Return the part at the specified position. + * + * @param pos position + * @return part at position 'pos' + */ + const shared_ptr getPartAt(const size_t pos) const; + + /** Return the part list. + * + * @return list of parts + */ + const std::vector > getPartList() const; + + /** Return the part list. + * + * @return list of parts + */ + const std::vector > 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 getContents() const; + + /** Set the body contents. + * + * @param contents new body contents + */ + void setContents(const shared_ptr & contents); + + /** Set the body contents and type. + * + * @param contents new body contents + * @param type type of contents + */ + void setContents( + const shared_ptr & 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 & 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 & 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 clone() const; + void copyFrom(const component& other); + body& operator=(const body& other); + + const std::vector > 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 m_contents; + + bodyPart* m_part; + + std::vector > m_parts; + + bool isRootPart() const; + + void initNewPart(const shared_ptr & 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 & 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 & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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
()), + m_body(make_shared ()), + m_parent() { + + m_body->setParentPart(this); +} + + +void bodyPart::parseImpl( + const parsingContext& ctx, + const shared_ptr & 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 bodyPart::clone() const { + + shared_ptr p = make_shared (); + + 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 (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 bodyPart::getHeader() const { + + return m_header; +} + + +shared_ptr
bodyPart::getHeader() { + + return m_header; +} + + +void bodyPart::setHeader(const shared_ptr
& h) { + + m_header = h; +} + + +const shared_ptr bodyPart::getBody() const { + + return m_body; +} + + +shared_ptr bodyPart::getBody() { + + return m_body; +} + + +void bodyPart::setBody(const shared_ptr & 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 ()); + } +} + + +bodyPart* bodyPart::getParentPart() { + + return m_parent; +} + + +const bodyPart* bodyPart::getParentPart() const { + + return m_parent; +} + + +shared_ptr bodyPart::createChildPart() { + + shared_ptr part = make_shared (); + part->m_parent = this; + + return part; +} + + +void bodyPart::importChildPart(const shared_ptr & part) { + + part->m_parent = this; +} + + +const std::vector > bodyPart::getChildComponents() { + + std::vector > 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 getHeader() const; + + /** Return the header section of this part. + * + * @return header section + */ + shared_ptr
getHeader(); + + /** Replaces the header section of this part. + * + * @param header the new header of this part + */ + void setHeader(const shared_ptr
& header); + + /** Return the body section of this part. + * + * @return body section + */ + const shared_ptr getBody() const; + + /** Return the body section of this part. + * + * @return body section + */ + shared_ptr getBody(); + + /** Replaces the body section of this part. + * + * @param body new body section + */ + void setBody(const shared_ptr & 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 clone() const; + void copyFrom(const component& other); + bodyPart& operator=(const bodyPart& other); + + const std::vector > getChildComponents(); + + size_t getGeneratedSize(const generationContext& ctx); + +private: + + shared_ptr
m_header; + mutable shared_ptr 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 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 & part); + + // Component parsing & assembling + void parseImpl( + const parsingContext& ctx, + const shared_ptr & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 & part) + : m_part(part) { + +} + + +const mediaType bodyPartAttachment::getType() const { + + shared_ptr ctf = getContentType(); + + if (ctf) { + + return *ctf->getValue (); + + } 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 cdf = getContentDisposition(); + + if (cdf && cdf->hasFilename()) { + + name = cdf->getFilename(); + + // Try the 'name' parameter of 'Content-Type' field + } else { + + shared_ptr ctf = getContentType(); + + if (ctf) { + + shared_ptr prm = ctf->findParameter("name"); + + if (prm) { + name = prm->getValue(); + } + } + } + + return name; +} + + +const text bodyPartAttachment::getDescription() const { + + text description; + + shared_ptr cd = + getHeader()->findField(fields::CONTENT_DESCRIPTION); + + if (cd) { + + description = *cd->getValue (); + + } else { + + // No description available. + } + + return description; +} + + +const encoding bodyPartAttachment::getEncoding() const { + + return m_part->getBody()->getEncoding(); +} + + +const shared_ptr bodyPartAttachment::getData() const { + + return m_part->getBody()->getContents(); +} + + +shared_ptr bodyPartAttachment::getPart() const { + + return m_part; +} + + +shared_ptr bodyPartAttachment::getHeader() const { + + return m_part->getHeader(); +} + + +shared_ptr bodyPartAttachment::getContentDisposition() const { + + return getHeader()->findField (fields::CONTENT_DISPOSITION); +} + + +shared_ptr bodyPartAttachment::getContentType() const { + + return getHeader()->findField (fields::CONTENT_TYPE); +} + + +void bodyPartAttachment::generateIn(const shared_ptr & /* 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & part); + + const mediaType getType() const; + const word getName() const; + const text getDescription() const; + const encoding getEncoding() const; + + const shared_ptr getData() const; + + shared_ptr getPart() const; + shared_ptr getHeader() const; + +private: + + void generateIn(const shared_ptr & parent) const; + + shared_ptr getContentDisposition() const; + shared_ptr getContentType() const; + + + shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 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 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 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 charset::clone() const { + + return make_shared (m_name); +} + + +const string& charset::getName() const { + + return m_name; +} + + +void charset::copyFrom(const component& other) { + + m_name = dynamic_cast (other).m_name; +} + + +const std::vector > charset::getChildComponents() { + + return std::vector >(); +} + + + +// 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 > 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 platformHandler::getLocalCharset() + * 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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::create( + const charset& source, + const charset& dest, + const charsetConverterOptions& opts +) { + + if (source == "idna" || dest == "idna") { + return make_shared (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 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 + getFilteredOutputStream( + utility::outputStream& os, + const charsetConverterOptions& opts = charsetConverterOptions() + ) = 0; + +private: + + static shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 + #include + + // 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 (ptr)) { } + + operator const char**() { return m_ptr; } + operator char**() { return const_cast (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 (ptr)) { } + + operator char**() { return m_ptr; } + + private: + + char** m_ptr; + }; + +#endif // VMIME_BUILDING_DOC +} + + + +// Output replacement char when an invalid sequence is encountered +template +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 (-1)) { + + out.write(invalidCharOutBuffer, 16 - invalidCharOutLen); + } +} + + + +namespace vmime { + + +// static +shared_ptr charsetConverter::createGenericConverter( + const charset& source, + const charset& dest, + const charsetConverterOptions& opts +) { + + return make_shared (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 (-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 (m_desc)); + + delete static_cast (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 (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 (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 (-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 (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 (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 + charsetConverter_iconv::getFilteredOutputStream( + utility::outputStream& os, + const charsetConverterOptions& opts + ) { + + return make_shared (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 (-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 (m_desc)); + + delete static_cast (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 (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 (-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 (-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 (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 (-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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 + #include + +#endif // VMIME_BUILDING_DOC + + +#include + + +namespace vmime { + + +// static +shared_ptr charsetConverter::createGenericConverter( + const charset& source, + const charset& dest, + const charsetConverterOptions& opts +) { + + return make_shared (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 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 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 (&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 (&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 + charsetConverter_icu::getFilteredOutputStream( + utility::outputStream& os, + const charsetConverterOptions& opts + ) { + + return make_shared (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 uniBuffer(uniSize); + + // Conversion loop + UErrorCode toErr = U_ZERO_ERROR; + + const char* uniSource = reinterpret_cast (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 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 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 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 (unichars.size()); + + std::vector output(inUTF8.length() * 2); + punycode_uint outputLen = static_cast (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 (in.length() - 4); + + std::vector output(in.length() - 4); + punycode_uint outputLen = static_cast (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 outUTF8Bytes(outputLen * 4); + char* p = &outUTF8Bytes[0]; + + for (std::vector ::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 + 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +#include + + +#if (_WIN32 || _WIN64 || WIN32 || WIN64) + #include + #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::createGenericConverter( + const charset& source, + const charset& dest, + const charsetConverterOptions& opts +) { + + return make_shared (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 unicodeBuffer; + const WCHAR* unicodePtr = NULL; + size_t unicodeLen = 0; + + if (sourceCodePage == CP_UNICODE) { + + unicodePtr = reinterpret_cast (in.c_str()); + unicodeLen = in.length() / 2; + + } else { + + const size_t bufferSize = MultiByteToWideChar( + sourceCodePage, 0, in.c_str(), static_cast (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 (&unicodeBuffer[0]); + unicodeLen = MultiByteToWideChar( + sourceCodePage, 0, in.c_str(), static_cast (in.length()), + reinterpret_cast (&unicodeBuffer[0]), static_cast (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 (unicodePtr), unicodeLen * 2); + + } else { + + const size_t bufferSize = WideCharToMultiByte( + destCodePage, 0, unicodePtr, static_cast (unicodeLen), + NULL, 0, 0, NULL + ); // in multibyte characters + + std::vector buffer; + buffer.resize(bufferSize); + + const size_t len = WideCharToMultiByte( + destCodePage, 0, unicodePtr, static_cast (unicodeLen), + &buffer[0], static_cast (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 + 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 + + +namespace vmime { + + +component::component() + : m_parsedOffset(0), m_parsedLength(0) { + +} + + +component::~component() { + +} + + +void component::parse( + const shared_ptr & inputStream, + const size_t length +) { + + parse(inputStream, 0, length, NULL); +} + + +void component::parse( + const shared_ptr & 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 & inputStream, + const size_t position, + const size_t end, + size_t* newPosition +) { + + m_parsedOffset = m_parsedLength = 0; + + shared_ptr seekableStream = + dynamicCast (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 parser = + make_shared (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 > 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 & 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 stream = + make_shared (buffer); + + shared_ptr parser = + make_shared (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 > children = getChildComponents(); + size_t totalSize = 0; + + for (std::vector >::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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & 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 & 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 & 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 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 > 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 & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free SOFTWARE; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software FOUNDATION; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A 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 + +#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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 contentDisposition::clone() const { + + return make_shared (*this); +} + + +void contentDisposition::copyFrom(const component& other) { + + const contentDisposition& d = dynamic_cast (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 > contentDisposition::getChildComponents() { + + return std::vector >(); +} + + +} // 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 clone() const; + void copyFrom(const component& other); + contentDisposition& operator=(const contentDisposition& other); + + const std::vector > 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 param = findParameter("creation-date"); + + if (param) { + return param->getValueAs (); + } 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 param = findParameter("modification-date"); + + if (param) { + return param->getValueAs (); + } 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 param = findParameter("read-date"); + + if (param) { + return param->getValueAs (); + } 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 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 + +#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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 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 param = findParameter("charset"); + + if (param) { + return param->getValueAs (); + } 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 + 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include + +#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 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 (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 datetime::clone() const { + + return make_shared (*this); +} + + +const std::vector > datetime::getChildComponents() { + + return std::vector >(); +} + + +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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 + + +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 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 > 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 & 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 & 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 & parent) const { + + // Create and append a new part for this attachment + shared_ptr part = make_shared (); + parent->getBody()->appendPart(part); + + generatePart(part); +} + + +void defaultAttachment::generatePart(const shared_ptr & 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 (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 defaultAttachment::getData() const { + + return m_data; +} + + +const encoding defaultAttachment::getEncoding() const { + + return m_encoding; +} + + +shared_ptr defaultAttachment::getPart() const { + + return null; +} + + +shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & data, + const encoding& enc, + const mediaType& type, + const text& desc = NULL_TEXT, + const word& name = NULL_WORD + ); + + defaultAttachment( + const shared_ptr & 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 getData() const; + const encoding getEncoding() const; + + shared_ptr getPart() const; + + shared_ptr getHeader() const; + +protected: + + mediaType m_type; /**< Media type (eg. "application/octet-stream") */ + text m_desc; /**< Description (eg. "The image you requested") */ + shared_ptr 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 & parent) const; + +protected: + + virtual void generatePart(const shared_ptr & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 disposition::clone() const { + + shared_ptr disp = make_shared (); + + 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 (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 > disposition::getChildComponents() { + + return std::vector >(); +} + + +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 ::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 ::const_iterator it = m_modifiers.begin() ; + it != m_modifiers.end() ; ++it) { + + if (*it == modifierLC) { + return true; + } + } + + return false; +} + + +const std::vector 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 ::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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 + + +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 clone() const; + void copyFrom(const component& other); + disposition& operator=(const disposition& other); + + const std::vector > 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 getModifierList() const; + +private: + + string m_actionMode; + string m_sendingMode; + string m_type; + + std::vector 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 (other); + + m_localName = source.m_localName; + m_domainName = source.m_domainName; +} + + +emailAddress& emailAddress::operator=(const emailAddress& other) { + + copyFrom(other); + return *this; +} + + +shared_ptr emailAddress::clone() const { + + return make_shared (*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 > emailAddress::getChildComponents() { + + return std::vector >(); +} + + +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 (m_localName)); + txt.appendWord(make_shared ("@", vmime::charsets::US_ASCII)); + txt.appendWord(make_shared (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 clone() const; + emailAddress& operator=(const emailAddress& other); + + const std::vector > 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 emptyContentHandler::clone() const { + + return make_shared (); +} + + +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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 + + +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 encoding::getEncoder() const { + + shared_ptr 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(), 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 & 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 & 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 encoding::clone() const { + + return make_shared (*this); +} + + +void encoding::copyFrom(const component& other) { + + const encoding& e = dynamic_cast (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 > encoding::getChildComponents() { + + return std::vector >(); +} + + +} // 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 > 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 & 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 & data, + const charset& chset, + const EncodingUsage usage = USAGE_BINARY_DATA + ); + + + shared_ptr 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 + +#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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +#include + +#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 & 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 & 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 & 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 fsf = platform::getHandler()->getFileSystemFactory(); + utility::file::path path = fsf->stringToPath(filepath); + + shared_ptr file = fsf->create(path); + + if (!file->isFile()) { + throw exceptions::open_file_error(); + } + + m_data = make_shared ( + file->getFileReader()->getInputStream(), file->getLength() + ); + + m_fileInfo.setFilename(path.getLastComponent()); + m_fileInfo.setSize(file->getLength()); +} + + +void fileAttachment::setData(const shared_ptr & cts) { + + m_data = cts; + + m_fileInfo.setSize(cts->getLength()); +} + + +void fileAttachment::generatePart(const shared_ptr & part) const { + + defaultAttachment::generatePart(part); + + shared_ptr cdf = + dynamicCast (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & cts, + const word& filename, + const mediaType& type + ); + + fileAttachment( + const shared_ptr & cts, + const word& filename, + const mediaType& type, + const text& desc + ); + + fileAttachment( + const shared_ptr & 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 & cts); + + fileInfo m_fileInfo; + + void generatePart(const shared_ptr & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 & 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 fileContentHandler::clone() const { + + return make_shared (*this); +} + + +void fileContentHandler::setData( + const shared_ptr & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & file, + const vmime::encoding& enc = NO_ENCODING + ); + + ~fileContentHandler(); + + fileContentHandler(const fileContentHandler& cts); + fileContentHandler& operator=(const fileContentHandler& cts); + + shared_ptr 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 & 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 & part +) + : m_bpa(make_shared (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 generatedMessageAttachment::getData() const { + + return m_bpa->getData(); +} + + +const encoding generatedMessageAttachment::getEncoding() const { + + return m_bpa->getEncoding(); +} + + +shared_ptr generatedMessageAttachment::getPart() const { + + return m_bpa->getPart(); +} + + +shared_ptr generatedMessageAttachment::getHeader() const { + + return m_bpa->getHeader(); +} + + +shared_ptr generatedMessageAttachment::getMessage() const { + + if (!m_msg) { + + // Extract data + std::ostringstream oss; + utility::outputStreamAdapter os(oss); + + getData()->extract(os); + + // Parse message + m_msg = make_shared (); + m_msg->parse(oss.str()); + } + + return m_msg; +} + + +void generatedMessageAttachment::generateIn(const shared_ptr & /* 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & part); + + const mediaType getType() const; + const text getDescription() const; + const word getName() const; + + const shared_ptr getData() const; + + const encoding getEncoding() const; + + shared_ptr getPart() const; + + shared_ptr getHeader() const; + + shared_ptr getMessage() const; + +protected: + + void generateIn(const shared_ptr & parent) const; + +private: + + shared_ptr m_bpa; + mutable shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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: + * + * to + * + * Message-Id: + * + * + * @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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +#include + + +namespace vmime { + + +header::header() { + +} + + +header::~header() { + + removeAllFields(); +} + + +/* + + RFC #822: + 3.2. HEADER FIELD DEFINITIONS + +field = field-name ":" [ field-body ] CRLF + +field-name = 1* + +field-body = field-body-contents + [CRLF LWSP-char field-body] + +field-body-contents = + +*/ + +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 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 >::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 header::clone() const { + + shared_ptr
hdr = make_shared
(); + + hdr->m_fields.reserve(m_fields.size()); + + for (std::vector >::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 (other); + + std::vector > fields; + + fields.reserve(h.m_fields.size()); + + for (std::vector >::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 >::const_iterator pos = + std::find_if( + m_fields.begin(), m_fields.end(), + fieldHasName(utility::stringUtils::toLower(fieldName)) + ); + + return pos != m_fields.end(); +} + + +shared_ptr header::findField(const string& fieldName) const { + + // Find the first field that matches the specified name + std::vector >::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 > header::findAllFields(const string& fieldName) { + + std::vector > result; + std::back_insert_iterator > > back(result); + + std::remove_copy_if( + m_fields.begin(), m_fields.end(), back, + fieldHasNotName(utility::stringUtils::toLower(fieldName)) + ); + + return result; +} + + +shared_ptr header::getField(const string& fieldName) { + + const string name = utility::stringUtils::toLower(fieldName); + + // Find the first field that matches the specified name + std::vector >::const_iterator pos = m_fields.begin(); + const std::vector >::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 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 & field) { + + m_fields.push_back(field); +} + + +void header::insertFieldBefore( + const shared_ptr & beforeField, + const shared_ptr & field +) { + + const std::vector >::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 & field) { + + m_fields.insert(m_fields.begin() + pos, field); +} + + +void header::insertFieldAfter( + const shared_ptr & afterField, + const shared_ptr & field +) { + + const std::vector >::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 & field) { + + m_fields.insert(m_fields.begin() + pos + 1, field); +} + + +void header::removeField(const shared_ptr & field) { + + const std::vector >::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 >::iterator it = m_fields.begin() + pos; + + m_fields.erase(it); +} + + +void header::replaceField( + const shared_ptr & field, + const shared_ptr & newField +) { + + insertFieldBefore(field, newField); + removeField(field); +} + + +void header::removeAllFields() { + + m_fields.clear(); +} + + +void header::removeAllFields(const string& fieldName) { + + std::vector > 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 header::getFieldAt(const size_t pos) { + + return m_fields[pos]; +} + + +const shared_ptr header::getFieldAt(const size_t pos) const { + + return m_fields[pos]; +} + + +const std::vector > header::getFieldList() const { + + std::vector > list; + + list.reserve(m_fields.size()); + + for (std::vector >::const_iterator it = m_fields.begin() ; + it != m_fields.end() ; ++it) { + + list.push_back(*it); + } + + return list; +} + + +const std::vector > header::getFieldList() { + + return m_fields; +} + + +const std::vector > header::getChildComponents() { + + std::vector > 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 & 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 & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 methodName() { return getField(fields::fieldName); } \ + shared_ptr 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 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 + shared_ptr findField(const string& fieldName) const { + + return dynamicCast (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 + shared_ptr findFieldValue(const string& fieldName) const { + + shared_ptr field = findField(fieldName); + + if (field) { + return dynamicCast (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 > 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 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 + shared_ptr getField(const string& fieldName) { + + return dynamicCast (getField(fieldName)); + } + + /** Add a field at the end of the list. + * + * @param field field to append + */ + void appendField(const shared_ptr & 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 & beforeField, + const shared_ptr & 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 & 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 & afterField, + const shared_ptr & 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 & 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 & 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 & field, + const shared_ptr & 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 getFieldAt(const size_t pos); + + /** Return the field at the specified position. + * + * @param pos position + * @return field at position 'pos' + */ + const shared_ptr getFieldAt(const size_t pos) const; + + /** Return the field list. + * + * @return list of fields + */ + const std::vector > getFieldList() const; + + /** Return the field list. + * + * @return list of fields + */ + const std::vector > getFieldList(); + + shared_ptr clone() const; + void copyFrom(const component& other); + header& operator=(const header& other); + + const std::vector > getChildComponents(); + + size_t getGeneratedSize(const generationContext& ctx); + +private: + + std::vector > m_fields; + + + class fieldHasName { + + public: + + fieldHasName(const string& name); + bool operator() (const shared_ptr & field); + + private: + + string m_name; + }; + + class fieldHasNotName { + + public: + + fieldHasNotName(const string& name); + bool operator() (const shared_ptr & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 headerField::clone() const { + + shared_ptr field = headerFieldFactory::getInstance()->create(m_name); + + field->copyFrom(*this); + + return field; +} + + +void headerField::copyFrom(const component& other) { + + const headerField& hf = dynamic_cast (other); + + m_value->copyFrom(*hf.m_value); +} + + +headerField& headerField::operator=(const headerField& other) { + + copyFrom(other); + return *this; +} + + +shared_ptr 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 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 > headerField::getChildComponents() { + + std::vector > list; + + if (m_value) { + list.push_back(m_value); + } + + return list; +} + + +shared_ptr headerField::getValue() const { + + return m_value; +} + + +shared_ptr headerField::getValue() { + + return m_value; +} + + +void headerField::setValue(const shared_ptr & 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 & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 clone() const; + void copyFrom(const component& other); + headerField& operator=(const headerField& other); + + const std::vector > 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 getValue() const; + + /** Return the read-only value object attached to this field, + * casted to the specified type. + * + * @return value object + */ + template + shared_ptr getValue() const { + + return dynamicCast (m_value); + } + + /** Return the value object attached to this field. + * + * @return value object + */ + virtual shared_ptr getValue(); + + /** Return the value object attached to this field, + * casted to the specified type. + * + * @return value object + */ + template + shared_ptr getValue() { + + return dynamicCast (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 & 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 & 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 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 (vmime::fields::CONTENT_TYPE); + registerField (vmime::fields::CONTENT_TRANSFER_ENCODING); + registerField (vmime::fields::CONTENT_DISPOSITION); + + registerField (vmime::fields::FROM); + registerField (vmime::fields::SENDER); + registerField (vmime::fields::REPLY_TO); + registerField (vmime::fields::DELIVERED_TO); + + // Register standard field values + registerFieldValue (vmime::fields::FROM); + registerFieldValue (vmime::fields::TO); + registerFieldValue (vmime::fields::CC); + registerFieldValue (vmime::fields::BCC); + registerFieldValue (vmime::fields::SENDER); + registerFieldValue (vmime::fields::DATE); + registerFieldValue (vmime::fields::RECEIVED); + registerFieldValue (vmime::fields::SUBJECT); + registerFieldValue (vmime::fields::REPLY_TO); + registerFieldValue (vmime::fields::DELIVERED_TO); + registerFieldValue (vmime::fields::ORGANIZATION); + registerFieldValue (vmime::fields::USER_AGENT); + registerFieldValue (vmime::fields::RETURN_PATH); + registerFieldValue (vmime::fields::CONTENT_TYPE); + registerFieldValue (vmime::fields::CONTENT_TRANSFER_ENCODING); + registerFieldValue (vmime::fields::CONTENT_DESCRIPTION); + registerFieldValue (vmime::fields::MIME_VERSION); + registerFieldValue (vmime::fields::CONTENT_DISPOSITION); + registerFieldValue (vmime::fields::CONTENT_ID); + registerFieldValue (vmime::fields::MESSAGE_ID); + registerFieldValue (vmime::fields::CONTENT_LOCATION); + registerFieldValue (vmime::fields::IN_REPLY_TO); + registerFieldValue (vmime::fields::REFERENCES); + + registerFieldValue (vmime::fields::ORIGINAL_MESSAGE_ID); + registerFieldValue (vmime::fields::DISPOSITION); + registerFieldValue (vmime::fields::DISPOSITION_NOTIFICATION_TO); +} + + +headerFieldFactory::~headerFieldFactory() { + +} + + +shared_ptr headerFieldFactory::getInstance() { + + static headerFieldFactory instance; + return shared_ptr (&instance, noop_shared_ptr_deleter ()); +} + + +shared_ptr headerFieldFactory::create( + const string& name, + const string& body +) { + + NameMap::const_iterator pos = m_nameMap.find(utility::stringUtils::toLower(name)); + shared_ptr field; + + if (pos != m_nameMap.end()) { + field = ((*pos).second)(); + } else { + field = registerer ::creator(); + } + + field->setName(name); + field->setValue(createValue(name)); + + if (body != NULL_STRING) { + field->parse(body); + } + + return field; +} + + +shared_ptr headerFieldFactory::createValue(const string& fieldName) { + + ValueMap::const_iterator pos = m_valueMap.find( + utility::stringUtils::toLower(fieldName) + ); + + shared_ptr value; + + if (pos != m_valueMap.end()) { + value = ((*pos).second.allocFunc)(); + } else { + value = registerer ::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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 (*AllocFunc)(void); + typedef std::map NameMap; + + NameMap m_nameMap; + + + struct ValueInfo { + + typedef shared_ptr (*ValueAllocFunc)(void); + typedef bool (*ValueTypeCheckFunc)(const object&); + + ValueAllocFunc allocFunc; + ValueTypeCheckFunc checkTypeFunc; + }; + + typedef std::map ValueMap; + + ValueMap m_valueMap; + +public: + + static shared_ptr getInstance(); + +#ifndef VMIME_BUILDING_DOC + + // TYPE must inherit from BASE_TYPE + template + class registerer { + + public: + + static bool checkType(const object& obj) { + + const TYPE* typedObj = dynamic_cast (&obj); + return typedObj != NULL; + } + + static shared_ptr creator() { + + // Allocate a new object + return shared_ptr (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 + void registerField(const string& name) { + + m_nameMap.insert( + NameMap::value_type( + utility::stringUtils::toLower(name), + ®isterer ::creator + ) + ); + } + + /** Register a field value type. + * + * @param T value class (must inherit from 'headerFieldValue') + * @param name field name + */ + template + void registerFieldValue(const string& name) { + + ValueInfo vi; + vi.allocFunc = ®isterer ::creator; + vi.checkTypeFunc = ®isterer ::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 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 ()), + m_text(make_shared ()) { + +} + + +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 & /* message */, + const shared_ptr & parent +) const { + + // Plain text + if (!m_plainText->isEmpty()) { + + // -- Create a new part + shared_ptr part = make_shared (); + 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 htmlPart = make_shared (); + + // -- 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 relPart = make_shared (); + 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 >::const_iterator it = m_objects.begin() ; + it != m_objects.end() ; ++it) { + + shared_ptr objPart = make_shared (); + 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 >& cidParts, + std::vector >& locParts +) { + + for (size_t i = 0 ; i < part.getBody()->getPartCount() ; ++i) { + + shared_ptr 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 ctf = + part.getHeader()->findField(fields::CONTENT_TYPE); + + if (ctf) { + + type = *ctf->getValue (); + + } else { + + // No "Content-type" field: assume "application/octet-stream". + } + + m_objects.push_back( + make_shared ( + vmime::clone(part.getBody()->getContents()), + part.getBody()->getEncoding(), + id, + type, + refType + ) + ); +} + + +void htmlTextPart::parse( + const shared_ptr & message, + const shared_ptr & parent, + const shared_ptr & textPart +) { + + // Search for possible embedded objects in the _whole_ message. + std::vector > cidParts; + std::vector > 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 ctf = + textPart->getHeader()->findField (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 >::const_iterator p = cidParts.begin() ; + p != cidParts.end() ; ++p) { + + const shared_ptr midField = + (*p)->getHeader()->findField(fields::CONTENT_ID); + + const messageId mid = *midField->getValue (); + + 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 >::const_iterator p = locParts.begin() ; + p != locParts.end() ; ++p) { + + const shared_ptr locField = + (*p)->getHeader()->findField(fields::CONTENT_LOCATION); + + const text loc = *locField->getValue (); + 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 (); + } +} + + +bool htmlTextPart::findPlainTextPart( + const bodyPart& part, + const bodyPart& parent, + const bodyPart& textPart +) { + + // We search for the nearest "multipart/alternative" part. + const shared_ptr ctf = + part.getHeader()->findField(fields::CONTENT_TYPE); + + if (ctf) { + + const mediaType type = *ctf->getValue (); + + if (type.getType() == mediaTypes::MULTIPART && + type.getSubType() == mediaTypes::MULTIPART_ALTERNATIVE) { + + shared_ptr foundPart; + + for (size_t i = 0 ; i < part.getBody()->getPartCount() ; ++i) { + + const shared_ptr 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 p = part.getBody()->getPartAt(i); + + const shared_ptr ctf = + p->getHeader()->findField(fields::CONTENT_TYPE); + + if (ctf) { + + const mediaType type = *ctf->getValue (); + + 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 htmlTextPart::getPlainText() const { + + return m_plainText; +} + + +void htmlTextPart::setPlainText(const shared_ptr & plainText) { + + m_plainText = plainText->clone(); +} + + +const shared_ptr htmlTextPart::getText() const { + + return m_text; +} + + +void htmlTextPart::setText(const shared_ptr & text) { + + m_text = text->clone(); +} + + +size_t htmlTextPart::getObjectCount() const { + + return m_objects.size(); +} + + +shared_ptr htmlTextPart::getObjectAt(const size_t pos) const { + + return m_objects[pos]; +} + + +shared_ptr htmlTextPart::findObject(const string& id) const +{ + for (std::vector >::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 >::const_iterator o = m_objects.begin() ; + o != m_objects.end() ; ++o) { + + if ((*o)->matchesId(id)) { + return true; + } + } + + return false; +} + + +shared_ptr htmlTextPart::addObject( + const shared_ptr & data, + const vmime::encoding& enc, + const mediaType& type +) { + + const messageId mid(messageId::generateId()); + + shared_ptr obj = make_shared ( + data, enc, mid.getId(), type, embeddedObject::REFERENCED_BY_ID + ); + + m_objects.push_back(obj); + + return obj; +} + + +shared_ptr htmlTextPart::addObject( + const shared_ptr & data, + const mediaType& type +) { + + return addObject(data, encoding::decide(data), type); +} + + +shared_ptr htmlTextPart::addObject( + const string& data, + const mediaType& type +) { + + shared_ptr cts = make_shared (data); + return addObject(cts, encoding::decide(cts), type); +} + + + +// +// htmlTextPart::embeddedObject +// + +htmlTextPart::embeddedObject::embeddedObject( + const shared_ptr & 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 getPlainText() const; + void setPlainText(const shared_ptr & plainText); + + const shared_ptr getText() const; + void setText(const shared_ptr & text); + + /** Embedded object (eg: image for <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 & 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 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 <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 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 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 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 <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 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 <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 addObject( + const shared_ptr & 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 <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 addObject( + const shared_ptr & data, + const encoding& enc, + const mediaType& type + ); + + + size_t getPartCount() const; + + void generateIn( + const shared_ptr & message, + const shared_ptr & parent + ) const; + + void parse( + const shared_ptr & message, + const shared_ptr & parent, + const shared_ptr & textPart + ); + +private: + + shared_ptr m_plainText; + shared_ptr m_text; + charset m_charset; + + std::vector > m_objects; + + void findEmbeddedParts( + const bodyPart& part, + std::vector >& cidParts, + std::vector >& 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 (other); + + m_name = source.m_name; + m_email = source.m_email; +} + + +mailbox& mailbox::operator=(const mailbox& other) { + + copyFrom(other); + return *this; +} + + +shared_ptr mailbox::clone() const { + + return make_shared (*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 > mailbox::getChildComponents() { + + return std::vector >(); +} + + +} // 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 clone() const; + mailbox& operator=(const mailbox& other); + + bool isEmpty() const; + + void clear(); + + const std::vector > 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 mbox = make_shared (); + + // 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
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 group = dynamicCast (parsedAddress); + + if (!group->isEmpty()) { + mbox = group->getMailboxAt(0); + } + + } else { + + // Parse only if it is a mailbox + mbox = dynamicCast (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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
parsedAddress = + address::parseNext(ctx, buffer, pos, end, &pos, &isLastAddressOfGroup); + + if (parsedAddress) { + + if (parsedAddress->isGroup()) { + + shared_ptr group = dynamicCast (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 (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 >::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 (other); + + m_name = source.m_name; + + removeAllMailboxes(); + + for (std::vector >::const_iterator it = source.m_list.begin() ; + it != source.m_list.end() ; ++it) { + + m_list.push_back(vmime::clone(*it)); + } +} + + +shared_ptr mailboxGroup::clone() const { + + return make_shared (*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 & mbox) { + + m_list.push_back(mbox); +} + + +void mailboxGroup::insertMailboxBefore( + const shared_ptr & beforeMailbox, + const shared_ptr & mbox +) { + + const std::vector >::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 & 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 & afterMailbox, + const shared_ptr & mbox +) { + + const std::vector >::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 & 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 & mbox) { + + const std::vector >::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 >::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 mailboxGroup::getMailboxAt(const size_t pos) { + + return m_list[pos]; +} + + +const shared_ptr mailboxGroup::getMailboxAt(const size_t pos) const { + + return m_list[pos]; +} + + +const std::vector > mailboxGroup::getMailboxList() const { + + std::vector > list; + + list.reserve(m_list.size()); + + for (std::vector >::const_iterator it = m_list.begin() ; + it != m_list.end() ; ++it) { + + list.push_back(*it); + } + + return list; +} + + +const std::vector > mailboxGroup::getMailboxList() { + + return m_list; +} + + +const std::vector > mailboxGroup::getChildComponents() { + + std::vector > 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 clone() const; + mailboxGroup& operator=(const component& other); + + const std::vector > 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 & 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 & beforeMailbox, + const shared_ptr & 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 & 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 & afterMailbox, + const shared_ptr & 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 & 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 & 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 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 getMailboxAt(const size_t pos) const; + + /** Return the mailbox list. + * + * @return list of mailboxes + */ + const std::vector > getMailboxList() const; + + /** Return the mailbox list. + * + * @return list of mailboxes + */ + const std::vector > getMailboxList(); + + bool isGroup() const; + +private: + + text m_name; + std::vector > 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 & mbox) { + + m_list.appendAddress(mbox); +} + + +void mailboxList::insertMailboxBefore( + const shared_ptr & beforeMailbox, + const shared_ptr & mbox +) { + + m_list.insertAddressBefore(beforeMailbox, mbox); +} + + +void mailboxList::insertMailboxBefore( + const size_t pos, + const shared_ptr & mbox +) { + + m_list.insertAddressBefore(pos, mbox); +} + + +void mailboxList::insertMailboxAfter( + const shared_ptr & afterMailbox, + const shared_ptr & mbox +) { + + m_list.insertAddressAfter(afterMailbox, mbox); +} + + +void mailboxList::insertMailboxAfter( + const size_t pos, + const shared_ptr & mbox +) { + + m_list.insertAddressAfter(pos, mbox); +} + + +void mailboxList::removeMailbox(const shared_ptr & 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 mailboxList::getMailboxAt(const size_t pos) { + + return dynamicCast (m_list.getAddressAt(pos)); +} + + +const shared_ptr mailboxList::getMailboxAt(const size_t pos) const { + + return dynamicCast (m_list.getAddressAt(pos)); +} + + +const std::vector > mailboxList::getMailboxList() const { + + const std::vector > addrList = m_list.getAddressList(); + std::vector > res; + + for (std::vector >::const_iterator it = addrList.begin() ; + it != addrList.end() ; ++it) { + + const shared_ptr mbox = dynamicCast (*it); + + if (mbox) { + res.push_back(mbox); + } + } + + return res; +} + + +const std::vector > mailboxList::getMailboxList() { + + const std::vector > addrList = m_list.getAddressList(); + std::vector > res; + + for (std::vector >::const_iterator it = addrList.begin() ; + it != addrList.end() ; ++it) { + + const shared_ptr mbox = dynamicCast (*it); + + if (mbox) { + res.push_back(mbox); + } + } + + return res; +} + + +shared_ptr mailboxList::clone() const { + + return make_shared (*this); +} + + +void mailboxList::copyFrom(const component& other) { + + const mailboxList& mboxList = dynamic_cast (other); + + m_list = mboxList.m_list; +} + + +mailboxList& mailboxList::operator=(const mailboxList& other) { + + copyFrom(other); + return *this; +} + + +const std::vector > 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
parsedAddress = address::parseNext(ctx, buffer, pos, end, &pos, NULL); + + if (parsedAddress) { + + if (parsedAddress->isGroup()) { + + shared_ptr group = dynamicCast (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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 clone() const; + void copyFrom(const component& other); + mailboxList& operator=(const mailboxList& other); + + const std::vector > getChildComponents(); + + /** Add a mailbox at the end of the list. + * + * @param mbox mailbox to append + */ + void appendMailbox(const shared_ptr & 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 & beforeMailbox, const shared_ptr & 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 & 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 & afterMailbox, const shared_ptr & 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 & 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 & 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 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 getMailboxAt(const size_t pos) const; + + /** Return the mailbox list. + * + * @return list of mailboxes + */ + const std::vector > getMailboxList() const; + + /** Return the mailbox list. + * + * @return list of mailboxes + */ + const std::vector > getMailboxList(); + + /** Return a list of addresses. + * + * @return list of addresses + */ + shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 & msg, const mailboxList& mailboxes) { + + shared_ptr
hdr = msg->getHeader(); + + hdr->DispositionNotificationTo()->setValue(mailboxes); +} + + +void MDNHelper::attachMDNRequest(const shared_ptr & msg, const mailbox& mbox) { + + mailboxList mboxList; + mboxList.appendMailbox(vmime::clone(mbox)); + + attachMDNRequest(msg, mboxList); +} + + +const std::vector MDNHelper::getPossibleMDNs(const shared_ptr & msg) { + + std::vector result; + + const shared_ptr hdr = msg->getHeader(); + + if (hdr->hasField(fields::DISPOSITION_NOTIFICATION_TO)) { + + const mailboxList& dnto = + *hdr->DispositionNotificationTo()->getValue (); + + 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 & msg) +{ + const shared_ptr 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 (hdr->ContentType()); + + const mediaType type = *ctf.getValue (); + + 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 & msg) +{ + if (!isMDN(msg)) { + throw exceptions::invalid_argument(); + } + + return receivedMDNInfos(msg); +} + + +bool MDNHelper::needConfirmation(const shared_ptr & msg) +{ + shared_ptr 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 (); + + 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 (); + + if (mbox.getEmail() != rp.getLocalPart() + "@" + rp.getDomain()) { + return true; + } + } + + // User confirmation not needed + return false; +} + + +shared_ptr MDNHelper::buildMDN( + const sendableMDNInfos& mdnInfos, + const string& text, + const charset& ch, + const mailbox& expeditor, + const disposition& dispo, + const string& reportingUA, + const std::vector & reportingUAProducts, + const std::map & fields +) { + + // Create a new message + shared_ptr msg = make_shared (); + + // Fill-in header fields + shared_ptr
hdr = msg->getHeader(); + + hdr->ContentType()->setValue( + mediaType(vmime::mediaTypes::MULTIPART, vmime::mediaTypes::MULTIPART_REPORT) + ); + + dynamicCast (hdr->ContentType())->setReportType("disposition-notification"); + + hdr->Disposition()->setValue(dispo); + + addressList to; + to.appendAddress(make_shared (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 MDNHelper::createFirstMDNPart( + const sendableMDNInfos& /* mdnInfos */, + const string& text, + const charset& ch +) { + + shared_ptr part = make_shared (); + + // Header + shared_ptr
hdr = part->getHeader(); + + hdr->ContentType()->setValue( + mediaType(vmime::mediaTypes::TEXT, vmime::mediaTypes::TEXT_PLAIN) + ); + + dynamicCast (hdr->ContentType())->setCharset(ch); + + // Body + part->getBody()->setContents(make_shared (text)); + + return part; +} + + +shared_ptr MDNHelper::createSecondMDNPart( + const sendableMDNInfos& mdnInfos, + const disposition& dispo, + const string& reportingUA, + const std::vector & reportingUAProducts, + const std::map & additionalFields +) { + + shared_ptr part = make_shared (); + + // Header + shared_ptr
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 rua = headerFieldFactory::getInstance()-> + create(vmime::fields::REPORTING_UA); + + rua->setValue(ruaText); + + fields.appendField(rua); + } + + // -- Final-Recipient + shared_ptr 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 ::const_iterator it; + + if (additionalFields.size() > 0) { + + if ((it = additionalFields.find(vmime::fields::ERROR)) != additionalFields.end()) { + + shared_ptr 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 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 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 (oss.str())); + + return part; +} + + +shared_ptr MDNHelper::createThirdMDNPart(const sendableMDNInfos& mdnInfos) { + + shared_ptr part = make_shared (); + + // Header + shared_ptr
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 (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & 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 & 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 getPossibleMDNs(const shared_ptr & 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 & 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 & 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 & 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 buildMDN( + const sendableMDNInfos& mdnInfos, + const string& text, + const charset& ch, + const mailbox& expeditor, + const disposition& dispo, + const string& reportingUA = NULL_STRING, + const std::vector & reportingUAProducts = std::vector (), + const std::map & fields = std::map () + ); + +private: + + static shared_ptr createFirstMDNPart( + const sendableMDNInfos& mdnInfos, + const string& text, + const charset& ch + ); + + static shared_ptr createSecondMDNPart( + const sendableMDNInfos& mdnInfos, + const disposition& dispo, + const string& reportingUA, + const std::vector & reportingUAProducts, + const std::map & fields + ); + + static shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 & 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 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 bdy = m_msg->getBody(); + + for (size_t i = 0 ; i < bdy->getPartCount() ; ++i) { + + const shared_ptr part = bdy->getPartAt(i); + + if (!part->getHeader()->hasField(fields::CONTENT_TYPE)) { + continue; + } + + const mediaType& type = *part->getHeader()->ContentType()->getValue (); + + // 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 omid = + fields.findFieldValue (fields::ORIGINAL_MESSAGE_ID); + + if (omid) { + m_omid = *omid; + } + + shared_ptr disp = + fields.findFieldValue (fields::DISPOSITION); + + if (disp) { + m_disp = *disp; + } + + shared_ptr contentMIC = + fields.findFieldValue ("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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & msg); + receivedMDNInfos(const receivedMDNInfos& other); + + receivedMDNInfos& operator=(const receivedMDNInfos& other); + + + const shared_ptr 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 & 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & msg, const mailbox& mbox); + sendableMDNInfos(const sendableMDNInfos& other); + + sendableMDNInfos& operator=(const sendableMDNInfos& other); + + const shared_ptr 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 mediaType::clone() const { + + return make_shared (m_type, m_subType); +} + + +void mediaType::copyFrom(const component& other) { + + const mediaType& mt = dynamic_cast (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 > mediaType::getChildComponents() { + + return std::vector >(); +} + + +} // 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 clone() const; + void copyFrom(const component& other); + mediaType& operator=(const mediaType& other); + + const std::vector > 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 + + +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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 messageBuilder::construct() const { + + // Create a new message + shared_ptr msg = make_shared (); + + // 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 subPart = make_shared (); + 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 >::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 bodyCopy = vmime::clone(part.getBody()); + + // First, copy (and replace) the header fields + const std::vector > fields = part.getHeader()->getFieldList(); + + for (std::vector >::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 & attach) { + + appendAttachment(attach); +} + + +void messageBuilder::appendAttachment(const shared_ptr & attach) { + + m_attach.push_back(attach); +} + + +void messageBuilder::constructTextPart(const mediaType& type) { + + shared_ptr part; + + try { + part = textPartFactory::getInstance()->create(type); + } catch (exceptions::no_factory_available& e) { + throw; + } + + m_textPart = part; +} + + +shared_ptr 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 messageBuilder::getAttachmentAt(const size_t pos) const { + + return m_attach[pos]; +} + + +shared_ptr messageBuilder::getAttachmentAt(const size_t pos) { + + return m_attach[pos]; +} + + +size_t messageBuilder::getAttachmentCount() const { + + return m_attach.size(); +} + + +const std::vector > messageBuilder::getAttachmentList() const { + + std::vector > res; + + res.reserve(m_attach.size()); + + for (std::vector >::const_iterator it = m_attach.begin() ; + it != m_attach.end() ; ++it) { + + res.push_back(*it); + } + + return res; +} + + +const std::vector > 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & attach); + + /** Attach a new object to the message. + * + * @param attach new attachment + */ + void appendAttachment(const shared_ptr & 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 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 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 > getAttachmentList() const; + + /** Return the list of attachments. + * + * @return list of attachments + */ + const std::vector > 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 getTextPart(); + + /** Construct a new message based on the information specified + * in this object. + * + * @return a new message + */ + shared_ptr construct() const; + +private: + + mailbox m_from; + + addressList m_to; + addressList m_cc; + addressList m_bcc; + + text m_subject; + + shared_ptr m_textPart; + + std::vector > 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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::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 mid = make_shared (); + 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 messageId::clone() const { + + return make_shared (*this); +} + + +void messageId::copyFrom(const component& other) { + + const messageId& mid = dynamic_cast (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 > messageId::getChildComponents() { + + return std::vector >(); +} + + +} // 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 clone() const; + void copyFrom(const component& other); + messageId& operator=(const messageId& other); + + const std::vector > 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 + + +namespace vmime { + + +messageIdSequence::messageIdSequence() { + +} + + +messageIdSequence::~messageIdSequence() { + + removeAllMessageIds(); +} + + +messageIdSequence::messageIdSequence(const messageIdSequence& midSeq) + : headerFieldValue() { + + copyFrom(midSeq); +} + + +shared_ptr messageIdSequence::clone() const { + + return make_shared (*this); +} + + +void messageIdSequence::copyFrom(const component& other) { + + const messageIdSequence& midSeq = dynamic_cast (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 > messageIdSequence::getChildComponents() { + + std::vector > 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 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 >::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 & mid) { + + m_list.push_back(mid); +} + + +void messageIdSequence::insertMessageIdBefore( + const shared_ptr & beforeMid, + const shared_ptr & mid +) { + + const std::vector >::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 & mid +) { + + m_list.insert(m_list.begin() + pos, mid); +} + + +void messageIdSequence::insertMessageIdAfter( + const shared_ptr & afterMid, + const shared_ptr & mid +) { + + const std::vector >::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 & mid +) { + + m_list.insert(m_list.begin() + pos + 1, mid); +} + + +void messageIdSequence::removeMessageId(const shared_ptr & mid) +{ + const std::vector >::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 >::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 messageIdSequence::getMessageIdAt(const size_t pos) { + + return m_list[pos]; +} + + +const shared_ptr messageIdSequence::getMessageIdAt(const size_t pos) const { + + return m_list[pos]; +} + + +const std::vector > messageIdSequence::getMessageIdList() const { + + std::vector > list; + + list.reserve(m_list.size()); + + for (std::vector >::const_iterator it = m_list.begin() ; + it != m_list.end() ; ++it) { + + list.push_back(*it); + } + + return list; +} + + +const std::vector > 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 clone() const; + void copyFrom(const component& other); + messageIdSequence& operator=(const messageIdSequence& other); + + const std::vector > getChildComponents(); + + + /** Add a message-id at the end of the list. + * + * @param mid message-id to append + */ + void appendMessageId(const shared_ptr & 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 & beforeMid, const shared_ptr & 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 & 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 & afterMid, + const shared_ptr & 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 & 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 & 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 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 getMessageIdAt(const size_t pos) const; + + /** Return the message-id list. + * + * @return list of message-ids + */ + const std::vector > getMessageIdList() const; + + /** Return the message-id list. + * + * @return list of message-ids + */ + const std::vector > getMessageIdList(); + +private: + + std::vector > 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 msg = make_shared (); + msg->parse(buffer); + + parse(msg); +} + + +messageParser::messageParser(const shared_ptr & msg) { + + parse(msg); +} + + +messageParser::~messageParser() { + +} + + +void messageParser::parse(const shared_ptr & 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 fldValue = msg->getHeader()->findFieldValue (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 recv = msg->getHeader()->findField(fields::RECEIVED); + + if (recv) { + + m_date = recv->getValue ()->getDate(); + + } else { + + shared_ptr date = msg->getHeader()->findField(fields::DATE); + + if (date) { + m_date = *date->getValue (); + } else { + m_date = datetime::now(); + } + } + + // Attachments + findAttachments(msg); + + // Text parts + findTextParts(msg, msg); +} + + +void messageParser::findAttachments(const shared_ptr & msg) { + + m_attach = attachmentHelper::findAttachmentsInMessage(msg); +} + + +void messageParser::findTextParts( + const shared_ptr & msg, + const shared_ptr & 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 ctf = + msg->getHeader()->findField (fields::CONTENT_TYPE); + + if (ctf) { + + const mediaType ctfType = *ctf->getValue (); + + if (ctfType.getType() == mediaTypes::TEXT) { + + type = ctfType; + accept = true; + } + + } else { + + // No "Content-type" field: assume "text/plain". + accept = true; + } + + if (accept) { + + shared_ptr 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 & msg, + const shared_ptr & 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 > textParts; + + for (size_t i = 0 ; i < part->getBody()->getPartCount() ; ++i) { + + const shared_ptr p = part->getBody()->getPartAt(i); + + shared_ptr ctf = + p->getHeader()->findField (fields::CONTENT_TYPE); + + if (ctf) { + + const mediaType type = *ctf->getValue (); + contentDisposition disp; // default should be inline + + if (type.getType() == mediaTypes::TEXT) { + + shared_ptr cdf = p->getHeader()-> + findField (fields::CONTENT_DISPOSITION); + + if (cdf) { + + disp = *cdf->getValue (); + + } 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 >::const_iterator p = textParts.begin() ; + p != textParts.end() ; ++p) { + + const contentTypeField& ctf = + *(*p)->getHeader()->findField (fields::CONTENT_TYPE); + + const mediaType type = *ctf.getValue (); + + try { + + shared_ptr 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 > messageParser::getAttachmentList() const { + + return m_attach; +} + + +size_t messageParser::getAttachmentCount() const { + + return m_attach.size(); +} + + +const shared_ptr messageParser::getAttachmentAt(const size_t pos) const { + + return m_attach[pos]; +} + + +const std::vector > messageParser::getTextPartList() const { + + std::vector > res; + + res.reserve(m_textParts.size()); + + for (std::vector >::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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & 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 getAttachmentAt(const size_t pos) const; + + /** Return the attachments of the message. + * + * @return list of attachments in the message + */ + const std::vector > getAttachmentList() const; + + /** Return the text parts of the message. + * + * @return list of text parts in the message + */ + const std::vector > 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 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 > m_attach; + + std::vector > m_textParts; + + void parse(const shared_ptr & msg); + + void findAttachments(const shared_ptr & msg); + + void findTextParts( + const shared_ptr & msg, + const shared_ptr & part + ); + + bool findSubTextParts( + const shared_ptr & msg, + const shared_ptr & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 & msg) { + + resetImportanceHeader(msg->getHeader()); +} + + +void importanceHelper::resetImportanceHeader(const shared_ptr
& hdr) { + + shared_ptr 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 & msg) { + + return getImportanceHeader(msg->getHeader()); +} + + +importanceHelper::Importance importanceHelper::getImportanceHeader(const shared_ptr & hdr) { + + // Try "X-Priority" field + shared_ptr fld = hdr->findField("X-Priority"); + + if (fld) { + + const string value = fld->getValue ()->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 ()->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 & msg, const Importance i) { + + setImportanceHeader(msg->getHeader(), i); +} + + +void importanceHelper::setImportanceHeader(const shared_ptr
& hdr, const Importance i) { + + // "X-Priority:" Field + shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & 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
& 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 & 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 & 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 & 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
& 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 defaultTimeoutHandlerFactory::create() { + + return make_shared (); +} + + +} // 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 + + +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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 + +#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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 + + +namespace vmime { +namespace net { +namespace events { + + +// +// event +// + +event::event() { + +} + + +event::~event() { + +} + + +// +// messageCountEvent +// + +const char* messageCountEvent::EVENT_CLASS = "messageCountEvent"; + + +messageCountEvent::messageCountEvent( + const shared_ptr & folder, + const Types type, + const std::vector & nums +) + : m_folder(folder), + m_type(type) { + + m_nums.resize(nums.size()); + std::copy(nums.begin(), nums.end(), m_nums.begin()); +} + + +shared_ptr messageCountEvent::getFolder() const { return (m_folder); } +messageCountEvent::Types messageCountEvent::getType() const { return (m_type); } +const std::vector & messageCountEvent::getNumbers() const { return (m_nums); } + + +void messageCountEvent::dispatch(messageCountListener* listener) { + + if (m_type == TYPE_ADDED) { + listener->messagesAdded(dynamicCast (shared_from_this())); + } else { + listener->messagesRemoved(dynamicCast (shared_from_this())); + } +} + + +const char* messageCountEvent::getClass() const { + + return EVENT_CLASS; +} + + +// +// messageChangedEvent +// + +const char* messageChangedEvent::EVENT_CLASS = "messageChangedEvent"; + + +messageChangedEvent::messageChangedEvent( + const shared_ptr & folder, + const Types type, + const std::vector & nums +) + : m_folder(folder), + m_type(type) { + + m_nums.resize(nums.size()); + std::copy(nums.begin(), nums.end(), m_nums.begin()); +} + + +shared_ptr messageChangedEvent::getFolder() const { return (m_folder); } +messageChangedEvent::Types messageChangedEvent::getType() const { return (m_type); } +const std::vector & messageChangedEvent::getNumbers() const { return (m_nums); } + + +void messageChangedEvent::dispatch(messageChangedListener* listener) { + + listener->messageChanged(dynamicCast (shared_from_this())); +} + + +const char* messageChangedEvent::getClass() const { + + return EVENT_CLASS; +} + + +// +// folderEvent +// + +const char* folderEvent::EVENT_CLASS = "folderEvent"; + + +folderEvent::folderEvent( + const shared_ptr & 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 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 (shared_from_this())); break; + case TYPE_RENAMED: listener->folderRenamed(dynamicCast (shared_from_this())); break; + case TYPE_DELETED: listener->folderDeleted(dynamicCast (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 + +#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 { + +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, + const Types type, + const std::vector & nums + ); + + /** Return the folder in which messages have been added/removed. + * + * @return folder in which message count changed + */ + shared_ptr 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 & 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 m_folder; + const Types m_type; + std::vector 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 & event) = 0; + virtual void messagesRemoved(const shared_ptr & 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, + const Types type, + const std::vector & nums + ); + + /** Return the folder in which messages have changed. + * + * @return folder in which message count changed + */ + shared_ptr 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 & 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 m_folder; + const Types m_type; + std::vector m_nums; +}; + + +/** Listener for events occuring on a message. + */ +class VMIME_EXPORT messageChangedListener { + +protected: + + virtual ~messageChangedListener() { } + +public: + + virtual void messageChanged(const shared_ptr & 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, + 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 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 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 & event) = 0; + virtual void folderRenamed(const shared_ptr & event) = 0; + virtual void folderDeleted(const shared_ptr & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 + + +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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 + +#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 getHeaderFields() const; + +private: + + int m_predefinedAttribs; + std::vector 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 + + +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 & event) { + + for (std::list ::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 & event) { + + for (std::list ::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 & event) { + + for (std::list ::iterator + it = m_folderListeners.begin() ; it != m_folderListeners.end() ; ++it) { + + event->dispatch(*it); + } +} + + +void folder::notifyEvent(const shared_ptr & event) { + + if (event->getClass() == events::messageCountEvent::EVENT_CLASS) { + notifyMessageCount(dynamicCast (event)); + } else if (event->getClass() == events::messageChangedEvent::EVENT_CLASS) { + notifyMessageChanged(dynamicCast (event)); + } else if (event->getClass() == events::folderEvent::EVENT_CLASS) { + notifyFolder(dynamicCast (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 + +#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 { + +protected: + + folder(const folder&) : object(), enable_shared_from_this () { } + 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 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 > 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 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 > 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 & 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 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 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 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 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 >& 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 & 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 > 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 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 & event); + void notifyMessageCount(const shared_ptr & event); + void notifyFolder(const shared_ptr & event); + void notifyEvent(const shared_ptr & event); + +private: + + std::list m_messageChangedListeners; + std::list m_messageCountListeners; + std::list 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 + + +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 folderAttributes::getUserFlags() const { + + return m_userFlags; +} + + +void folderAttributes::setUserFlags(const std::vector & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 + +#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 getUserFlags() const; + + /** Set the user-defined flags of the folder. + * + * @param flags a list of user-defined flags + */ + void setUserFlags(const std::vector & 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 + + + +namespace vmime { +namespace net { +namespace imap { + + +IMAPCommand::IMAPCommand(const string& text, const string& traceText) + : m_text(text), + m_traceText(traceText) { + +} + + +// static +shared_ptr 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::AUTHENTICATE(const string& mechName) { + + std::ostringstream cmd; + cmd.imbue(std::locale::classic()); + cmd << "AUTHENTICATE " << mechName; + + return createCommand(cmd.str()); +} + + +// static +shared_ptr 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::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::SELECT( + const bool readOnly, + const string& mailboxName, + const std::vector & 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::STATUS( + const string& mailboxName, + const std::vector & 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::CREATE( + const string& mailboxName, + const std::vector & 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::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::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::FETCH( + const messageSet& msgs, + const std::vector & 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::STORE( + const messageSet& msgs, + const int mode, + const std::vector & 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::APPEND( + const string& mailboxName, + const std::vector & 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::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::SEARCH( + const std::vector & 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::STARTTLS() { + + return createCommand("STARTTLS"); +} + + +// static +shared_ptr IMAPCommand::CAPABILITY() { + + return createCommand("CAPABILITY"); +} + + +// static +shared_ptr IMAPCommand::NOOP() { + + return createCommand("NOOP"); +} + + +// static +shared_ptr IMAPCommand::EXPUNGE() { + + return createCommand("EXPUNGE"); +} + + +// static +shared_ptr IMAPCommand::CLOSE() { + + return createCommand("CLOSE"); +} + + +// static +shared_ptr IMAPCommand::LOGOUT() { + + return createCommand("LOGOUT"); +} + + +// static +shared_ptr IMAPCommand::createCommand( + const string& text, + const string& traceText +) { + + if (traceText.empty()) { + return shared_ptr (new IMAPCommand(text, text)); + } else { + return shared_ptr (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 & conn) { + + conn->sendCommand(dynamicCast (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 { + +public: + + static shared_ptr LOGIN(const string& username, const string& password); + static shared_ptr AUTHENTICATE(const string& mechName); + static shared_ptr AUTHENTICATE(const string& mechName, const string& initialResponse); + static shared_ptr LIST(const string& refName, const string& mailboxName); + static shared_ptr SELECT(const bool readOnly, const string& mailboxName, const std::vector & params); + static shared_ptr STATUS(const string& mailboxName, const std::vector & attribs); + static shared_ptr CREATE(const string& mailboxName, const std::vector & params); + static shared_ptr DELETE(const string& mailboxName); + static shared_ptr RENAME(const string& mailboxName, const string& newMailboxName); + static shared_ptr FETCH(const messageSet& msgs, const std::vector & params); + static shared_ptr STORE(const messageSet& msgs, const int mode, const std::vector & flags); + static shared_ptr APPEND(const string& mailboxName, const std::vector & flags, vmime::datetime* date, const size_t size); + static shared_ptr COPY(const messageSet& msgs, const string& mailboxName); + static shared_ptr SEARCH(const std::vector & keys, const vmime::charset* charset); + static shared_ptr STARTTLS(); + static shared_ptr CAPABILITY(); + static shared_ptr NOOP(); + static shared_ptr EXPUNGE(); + static shared_ptr CLOSE(); + static shared_ptr 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 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 & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 + + +// Helpers for service properties +#define GET_PROPERTY(type, prop) \ + (m_store.lock()->getInfos().getPropertyValue (getSession(), \ + dynamic_cast (m_store.lock()->getInfos()).getProperties().prop)) +#define HAS_PROPERTY(prop) \ + (m_store.lock()->getInfos().hasProperty(getSession(), \ + dynamic_cast (m_store.lock()->getInfos()).getProperties().prop)) + + +namespace vmime { +namespace net { +namespace imap { + + +IMAPConnection::IMAPConnection( + const shared_ptr & store, + const shared_ptr & 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 (); + + if (store->getTracerFactory()) { + m_tracer = store->getTracerFactory()->create(store, ++connectionId); + } + + m_parser = make_shared (); + 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 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 tlsSession = tls::TLSSession::create + (store->getCertificateVerifier(), + store->getSession()->getTLSProperties()); + + shared_ptr tlsSocket = + tlsSession->getSocket(m_socket); + + m_socket = tlsSocket; + + m_secured = true; + m_cntInfos = make_shared (address, port, tlsSession, tlsSocket); + + } else +#endif // VMIME_HAVE_TLS_SUPPORT + { + m_cntInfos = make_shared (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: + // --- S: * OK mydomain.org IMAP4rev1 v12.256 server ready + + scoped_ptr 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 conn = dynamicCast (shared_from_this()); + IMAPCommand::LOGIN(username, password)->send(conn); + + scoped_ptr 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 (getAuthenticator())) { + throw exceptions::authentication_error("No SASL authenticator available."); + } + + const std::vector capa = getCapabilities(); + std::vector 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 > mechList; + + shared_ptr 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 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 (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 mech = mechList[i]; + + shared_ptr saslSession = + saslContext->createSession("imap", getAuthenticator(), mech); + + saslSession->init(); + + shared_ptr 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 (shared_from_this())); + + for (bool cont = true ; cont ; ) { + + scoped_ptr 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 (shared_from_this())); + + scoped_ptr 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 tlsSession = tls::TLSSession::create( + m_store.lock()->getCertificateVerifier(), + m_store.lock()->getSession()->getTLSProperties() + ); + + shared_ptr tlsSocket = tlsSession->getSocket(m_socket); + + tlsSocket->handshake(); + + m_socket = tlsSocket; + m_parser->setSocket(m_socket); + + m_secured = true; + m_cntInfos = make_shared ( + 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 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 (shared_from_this())); + + scoped_ptr 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 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 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 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 (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 (shared_from_this())); + + scoped_ptr 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 & 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 IMAPConnection::getStore() const { + + return m_store.lock(); +} + + +shared_ptr IMAPConnection::getStore() { + + return m_store.lock(); +} + + +shared_ptr IMAPConnection::getSession() { + + return m_store.lock()->getSession(); +} + + +shared_ptr IMAPConnection::getSocket() const { + + return m_socket; +} + + +void IMAPConnection::setSocket(const shared_ptr & sok) { + + m_socket = sok; + m_parser->setSocket(sok); +} + + +shared_ptr IMAPConnection::getTracer() { + + return m_tracer; +} + + +shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 { + +public: + + IMAPConnection(const shared_ptr & store, const shared_ptr & 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 & cmd); + void sendRaw(const byte_t* buffer, const size_t count); + + IMAPParser::response* readResponse(IMAPParser::literalHandler* lh = NULL); + + + shared_ptr getStore() const; + shared_ptr getStore(); + + shared_ptr getSession(); + + void fetchCapabilities(); + void invalidateCapabilities(); + const std::vector getCapabilities(); + bool hasCapability(const string& capa); + bool hasCapability(const string& capa) const; + + shared_ptr getAuthenticator(); + + bool isSecuredConnection() const; + shared_ptr getConnectionInfos() const; + + shared_ptr getSocket() const; + void setSocket(const shared_ptr & sok); + + shared_ptr getTracer(); + + shared_ptr 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 m_store; + + shared_ptr m_auth; + + shared_ptr m_socket; + + shared_ptr m_parser; + + shared_ptr m_tag; + + char m_hierarchySeparator; + + ProtocolStates m_state; + + shared_ptr m_timeoutHandler; + + bool m_secured; + shared_ptr m_cntInfos; + + bool m_firstTag; + + std::vector m_capabilities; + bool m_capabilitiesFetched; + + bool m_noModSeq; + + shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +#include + + +namespace vmime { +namespace net { +namespace imap { + + +IMAPFolder::IMAPFolder( + const folder::path& path, + const shared_ptr & store, + const shared_ptr & 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 (); +} + + +IMAPFolder::~IMAPFolder() { + + try { + + shared_ptr 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 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 ::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 connection = + make_shared (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 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 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 (); + } + + 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 store = m_store.lock(); + + if (!store) { + throw exceptions::illegal_state("Store disconnected"); + } + + if (!isOpen()) { + throw exceptions::illegal_state("Folder not open"); + } + + shared_ptr 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 (); + + onClose(); +} + + +void IMAPFolder::onClose() { + + for (std::vector ::iterator it = m_messages.begin() ; + it != m_messages.end() ; ++it) { + + (*it)->onFolderClosed(); + } + + m_messages.clear(); +} + + +void IMAPFolder::create(const folderAttributes& attribs) { + + shared_ptr 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 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 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 event = + make_shared ( + dynamicCast (shared_from_this()), + events::folderEvent::TYPE_CREATED, + m_path, m_path + ); + + notifyFolder(event); +} + + +void IMAPFolder::destroy() { + + shared_ptr 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 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 event = + make_shared ( + dynamicCast (shared_from_this()), + events::folderEvent::TYPE_DELETED, + m_path, m_path + ); + + notifyFolder(event); +} + + +bool IMAPFolder::exists() { + + shared_ptr 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 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 (attribs); + + return m_attribs->getType(); +} + + +bool IMAPFolder::isOpen() const { + + return m_open; +} + + +shared_ptr 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 (dynamicCast (shared_from_this()), num); +} + + +std::vector > IMAPFolder::getMessages(const messageSet& msgs) { + + if (!isOpen()) { + throw exceptions::illegal_state("Folder not open"); + } + + if (msgs.isEmpty()) { + return std::vector >(); + } + + std::vector > 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 params; + params.push_back("UID"); + + IMAPCommand::FETCH(msgs, params)->send(m_connection); + + // Get the response + scoped_ptr 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 thisFolder = dynamicCast (shared_from_this()); + messages.push_back(make_shared (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 IMAPFolder::getFolder(const folder::path::component& name) { + + shared_ptr store = m_store.lock(); + + if (!store) { + throw exceptions::illegal_state("Store disconnected"); + } + + return make_shared (m_path / name, store, shared_ptr ()); +} + + +std::vector > IMAPFolder::getFolders(const bool recursive) { + + shared_ptr 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 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 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 > 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 attribs = make_shared (); + + IMAPUtils::mailboxFlagsToFolderAttributes( + m_connection, + path, + *mailboxData->mailbox_list->mailbox_flag_list, + *attribs + ); + + v.push_back(make_shared (path, store, attribs)); + } + } + + return v; +} + + +void IMAPFolder::fetchMessages( + std::vector >& msg, + const fetchAttributes& options, + utility::progressListener* progress +) { + + shared_ptr 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 list; + list.reserve(msg.size()); + + std::map > numberToMsg; + + for (std::vector >::iterator it = msg.begin() ; it != msg.end() ; ++it) { + + list.push_back((*it)->getNumber()); + numberToMsg[(*it)->getNumber()] = dynamicCast (*it); + } + + // Send the request + IMAPUtils::buildFetchCommand( + m_connection, messageSet::byNumber(list), options + )->send(m_connection); + + // Get the response + scoped_ptr 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 >::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 & msg, const fetchAttributes& options) { + + std::vector > msgs; + msgs.push_back(msg); + + fetchMessages(msgs, options, /* progress */ NULL); +} + + +std::vector > IMAPFolder::getAndFetchMessages( + const messageSet& msgs, + const fetchAttributes& attribs +) { + + shared_ptr 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 >(); + } + + // 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 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 > 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 thisFolder = dynamicCast (shared_from_this()); + shared_ptr msg = make_shared (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 IMAPFolder::getParent() { + + if (m_path.isEmpty()) { + + return null; + + } else { + + return make_shared ( + m_path.getParent(), m_store.lock(), shared_ptr () + ); + } +} + + +shared_ptr IMAPFolder::getStore() const { + + return m_store.lock(); +} + + +shared_ptr IMAPFolder::getStore() { + + return m_store.lock(); +} + + +void IMAPFolder::registerMessage(IMAPMessage* msg) { + + m_messages.push_back(msg); +} + + +void IMAPFolder::unregisterMessage(IMAPMessage* msg) { + + std::vector ::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 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 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 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 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 & 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 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 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 (m_connection->getSocket()->getBlockSize()) + ); + + std::vector 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 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 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 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 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 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 event = + make_shared ( + dynamicCast (shared_from_this()), + events::folderEvent::TYPE_RENAMED, + oldPath, + newPath + ); + + notifyFolder(event); + + // Notify sub-folders + for (std::list ::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 event = + make_shared ( + dynamicCast ((*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 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 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 status = getStatus(); + + count = status->getMessageCount(); + unseen = status->getUnseenCount(); +} + + +shared_ptr IMAPFolder::getStatus() { + + shared_ptr store = m_store.lock(); + + if (!store) { + throw exceptions::illegal_state("Store disconnected"); + } + + // Build the attributes list + std::vector 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 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 status = make_shared (); + 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 store = m_store.lock(); + + if (!store) { + throw exceptions::illegal_state("Store disconnected"); + } + + IMAPCommand::NOOP()->send(m_connection); + + scoped_ptr 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 IMAPFolder::getMessageNumbersStartingOnUID(const message::uid& uid) { + + // Send the request + std::ostringstream uidSearchKey; + uidSearchKey.imbue(std::locale::classic()); + uidSearchKey << "UID " << uid << ":*"; + + std::vector searchKeys; + searchKeys.push_back(uidSearchKey.str()); + + IMAPCommand::SEARCH(searchKeys, /* charset */ NULL)->send(m_connection); + + // Get the response + scoped_ptr 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 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 > events; + + shared_ptr 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 (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 ::iterator mit = + m_messages.begin() ; mit != m_messages.end() ; ++mit) { + + if ((*mit)->getNumber() == msgNumber) { + (*mit)->processFetchResponse(/* options */ 0, *msgData); + } + } + + events.push_back( + make_shared ( + dynamicCast (shared_from_this()), + events::messageChangedEvent::TYPE_FLAGS, + std::vector (1, msgNumber) + ) + ); + + } else if (msgData->type == IMAPParser::message_data::EXPUNGE) { + + // A message has been expunged, renumber messages + for (std::vector ::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 ( + dynamicCast (shared_from_this()), + events::messageCountEvent::TYPE_REMOVED, + std::vector (1, msgNumber) + ) + ); + + expungedMessageCount++; + } + } + } + + // New messages arrived + if (m_status->getMessageCount() > oldStatus->getMessageCount() - expungedMessageCount) { + + std::vector newMessageNumbers; + + for (size_t msgNumber = oldStatus->getMessageCount() - expungedMessageCount ; + msgNumber <= m_status->getMessageCount() ; ++msgNumber) { + + newMessageNumbers.push_back(msgNumber); + } + + events.push_back( + make_shared ( + dynamicCast (shared_from_this()), + events::messageCountEvent::TYPE_ADDED, + newMessageNumbers + ) + ); + } + + // Dispatch notifications + for (std::vector >::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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +#include + +#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 & store, + const shared_ptr & 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 getMessage(const size_t num); + std::vector > getMessages(const messageSet& msgs); + + std::vector getMessageNumbersStartingOnUID(const message::uid& uid); + + size_t getMessageCount(); + + shared_ptr getFolder(const folder::path::component& name); + std::vector > 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 & 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 getStatus(); + + void noop(); + + void expunge(); + + shared_ptr getParent(); + + shared_ptr getStore() const; + shared_ptr getStore(); + + + void fetchMessages( + std::vector >& msg, + const fetchAttributes& options, + utility::progressListener* progress = NULL + ); + + void fetchMessage(const shared_ptr & msg, const fetchAttributes& options); + + std::vector > 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 m_store; + shared_ptr m_connection; + + folder::path m_path; + folder::path::component m_name; + + int m_mode; + bool m_open; + + shared_ptr m_attribs; + + shared_ptr m_status; + + std::vector 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 IMAPFolderStatus::clone() const { + + return make_shared (*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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +#include +#include + + +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 (new targetStream(progress, os)); + } + + shared_ptr targetFor(const IMAPParser::component& comp, const int /* data */) { + + if (typeid(comp) == typeid(IMAPParser::msg_att_item)) { + + const int type = static_cast + (comp).type; + + if (type == IMAPParser::msg_att_item::BODY_SECTION || + type == IMAPParser::msg_att_item::RFC822_TEXT) { + + return m_target; + } + } + + return shared_ptr (); + } + + shared_ptr getTarget() { + + return m_target; + } + +private: + + shared_ptr m_target; +}; + +#endif // VMIME_BUILDING_DOC + + + +// +// IMAPMessage +// + + +IMAPMessage::IMAPMessage( + const shared_ptr & 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 & 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 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 IMAPMessage::getStructure() const { + + if (m_structure == NULL) { + throw exceptions::unfetched_object(); + } + + return m_structure; +} + + +shared_ptr IMAPMessage::getStructure() { + + if (m_structure == NULL) { + throw exceptions::unfetched_object(); + } + + return m_structure; +} + + +shared_ptr 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 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 & p, + utility::outputStream& os, + utility::progressListener* progress, + const size_t start, + const size_t length, + const bool peek +) const { + + shared_ptr 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 & p) { + + shared_ptr 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 (p)->getOrCreateHeader().parse(oss.str()); +} + + +void IMAPMessage::fetchPartHeaderForStructure(const shared_ptr & str) { + + for (size_t i = 0, n = str->getPartCount() ; i < n ; ++i) { + + shared_ptr 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 & p, + utility::outputStream& os, + utility::progressListener* progress, + const size_t start, + const size_t length, + const int extractFlags +) const { + + shared_ptr 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 currentPart = dynamicCast (p); + std::vector 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 ::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 (-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 (-1)) { + + if (length == static_cast (-1)) { + bodyDesc << "<" << start << "." << static_cast (-1) << ">"; + } else { + bodyDesc << "<" << start << "." << length << ">"; + } + } + + std::vector 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 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 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 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 (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 (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
IMAPMessage::getOrCreateHeader() { + + if (m_header != NULL) { + return m_header; + } else { + return m_header = make_shared
(); + } +} + + +void IMAPMessage::setFlags(const int flags, const int mode) { + + shared_ptr 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 & parentPart, + const shared_ptr & str, + int level +) { + + if (level == 0) { + + shared_ptr part = str->getPartAt(0); + + // Copy header + shared_ptr hdr = part->getHeader(); + parentPart->getHeader()->copyFrom(*hdr); + + // Initialize body + parentPart->getBody()->setContents( + make_shared ( + dynamicCast (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 part = str->getPartAt(i); + + shared_ptr childPart = make_shared (); + + // Copy header + shared_ptr hdr = part->getHeader(); + childPart->getHeader()->copyFrom(*hdr); + + // Initialize body + childPart->getBody()->setContents( + make_shared ( + dynamicCast (shared_from_this()), + part, childPart->getBody()->getEncoding() + ) + ); + + // Add child part + parentPart->getBody()->appendPart(childPart); + + // Construct sub parts + constructParsedMessage(childPart, part->getStructure(), ++level); + } + } +} + + +shared_ptr IMAPMessage::getParsedMessage() { + + // Fetch structure + shared_ptr structure; + + try { + + structure = getStructure(); + + } catch (exceptions::unfetched_object&) { + + std::vector > msgs; + msgs.push_back(dynamicCast (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 msg = make_shared (); + + 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & folder, const size_t num); + IMAPMessage(const shared_ptr & 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 getStructure() const; + shared_ptr getStructure(); + + shared_ptr 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 & 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 & p); + + shared_ptr 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 & 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 & parentPart, + const shared_ptr & str, + int level = 0 + ); + + + enum ExtractFlags + { + EXTRACT_HEADER = 0x1, + EXTRACT_BODY = 0x2, + EXTRACT_PEEK = 0x10 + }; + + size_t extractImpl( + const shared_ptr & p, + utility::outputStream& os, + utility::progressListener* progress, + const size_t start, + const size_t length, + const int extractFlags + ) const; + + + shared_ptr
getOrCreateHeader(); + + + void onFolderClosed(); + + weak_ptr 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
m_header; + shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 & 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 + 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 & 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 IMAPMessagePart::getStructure() const { + + if (m_structure) { + return m_structure; + } else { + return IMAPMessageStructure::emptyStructure(); + } +} + + +shared_ptr IMAPMessagePart::getStructure() { + + if (m_structure) { + return m_structure; + } else { + return IMAPMessageStructure::emptyStructure(); + } +} + + +shared_ptr 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 IMAPMessagePart::getHeader() const { + + if (!m_header) { + throw exceptions::unfetched_object(); + } else { + return m_header; + } +} + + +// static +shared_ptr IMAPMessagePart::create( + const shared_ptr & parent, + const size_t number, + const IMAPParser::body* body +) { + + if (body->body_type_mpart) { + + auto part = make_shared (parent, number, body->body_type_mpart.get()); + part->m_structure = make_shared (part, body->body_type_mpart->list); + + return part; + + } else { + + return make_shared (parent, number, body->body_type_1part.get()); + } +} + + +header& IMAPMessagePart::getOrCreateHeader() { + + if (m_header) { + return *m_header; + } else { + return *(m_header = make_shared
()); + } +} + + +} // 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & parent, + const size_t number, + const IMAPParser::body_type_mpart* mpart + ); + + IMAPMessagePart( + const shared_ptr & parent, + const size_t number, + const IMAPParser::body_type_1part* part + ); + + shared_ptr getStructure() const; + shared_ptr getStructure(); + + shared_ptr getParent() const; + + const mediaType& getType() const; + const contentDisposition &getDisposition() const; + size_t getSize() const; + size_t getNumber() const; + string getName() const; + + shared_ptr getHeader() const; + + + static shared_ptr create( + const shared_ptr & parent, + const size_t number, + const IMAPParser::body* body + ); + + + header& getOrCreateHeader(); + +private: + + shared_ptr m_structure; + weak_ptr m_parent; + shared_ptr
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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 & msg, + const shared_ptr & part, + const vmime::encoding& encoding +) + : m_message(msg), + m_part(part), + m_encoding(encoding) { + +} + + +shared_ptr IMAPMessagePartContentHandler::clone() const { + + return make_shared ( + 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 msg = m_message.lock(); + shared_ptr 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 theDecoder = m_encoding.getEncoder(); + theDecoder->decode(in, tmp2); + + // Reencode to output stream + string str = oss2.str(); + utility::inputStreamStringAdapter tempIn(str); + + shared_ptr 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 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 msg = m_message.lock(); + shared_ptr 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 theDecoder = m_encoding.getEncoder(); + theDecoder->decode(is, os, &plsa); + } +} + + +void IMAPMessagePartContentHandler::extractRaw( + utility::outputStream& os, + utility::progressListener* progress +) const { + + shared_ptr msg = m_message.lock(); + shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & msg, + const shared_ptr & part, + const vmime::encoding& encoding + ); + + shared_ptr 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 m_message; + weak_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 & parent, + const std::vector >& 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 IMAPMessageStructure::getPartAt(const size_t x) const { + + return m_parts[x]; +} + + +shared_ptr IMAPMessageStructure::getPartAt(const size_t x) { + + return m_parts[x]; +} + + +size_t IMAPMessageStructure::getPartCount() const { + + return m_parts.size(); +} + + +// static +shared_ptr IMAPMessageStructure::emptyStructure() { + + static shared_ptr emptyStructure = make_shared (); + 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & parent, const std::vector >& list); + + shared_ptr getPartAt(const size_t x) const; + shared_ptr getPartAt(const size_t x); + size_t getPartCount() const; + + static shared_ptr emptyStructure(); + +private: + + std::vector > 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +#include +#include + + +//#define DEBUG_RESPONSE 1 + + +#if DEBUG_RESPONSE +# include +#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 (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 (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 (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 (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 v; \ + try \ + { \ + v.reset(parser.get (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 (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 (line, &pos, arg)) + + + +namespace vmime { +namespace net { +namespace imap { + + +#if DEBUG_RESPONSE + static int IMAPParserDebugResponse_level = 0; + static std::vector 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 ::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 & sok) { + + m_socket = sok; + } + + /** Set the timeout handler currently used by this parser. + * + * @param toh timeout handler + */ + void setTimeoutHandler(const shared_ptr & toh) { + + m_timeoutHandler = toh; + } + + /** Set the tracer currently used by this parser. + * + * @param tr tracer + */ + void setTracer(const shared_ptr & 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 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 + 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 ::= + // + + 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 ::= + // LF ::= + // 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 ::= + // CTL ::= + // CHAR ::= + // ATOM_CHAR ::= + // atom_specials ::= "(" / ")" / "{" / SPACE / CTL / list_wildcards / quoted_specials + // list_wildcards ::= "%" / "*" + // quoted_specials ::= <"> / "\" + // + // tag ::= 1* (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 uniqueid1; + std::unique_ptr 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 uniqueid; + std::unique_ptr uid_range; + + std::unique_ptr next_uid_set; + }; + + + // + // text ::= 1*TEXT_CHAR + // + // CHAR ::= + // TEXT_CHAR ::= + // + + 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 + class text_except : public text { + + public: + + text_except() : text(false, C) { + + } + }; + + + template + class text8_except : public text { + + public: + + text8_except() : text(true, C) { + + } + }; + + + // + // QUOTED_CHAR ::= / "\" quoted_specials + // quoted_specials ::= <"> / "\" + // TEXT_CHAR ::= + // CHAR ::= + // + + DECLARE_COMPONENT(QUOTED_CHAR) + + bool parseImpl(IMAPParser& parser, string& line, size_t* currentPos) { + + size_t pos = *currentPos; + + const unsigned char c = static_cast (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 ::= / "\" quoted_specials + // quoted_specials ::= <"> / "\" + // TEXT_CHAR ::= + // CHAR ::= + // + + 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 ::= / "\" quoted_specials + // quoted_specials ::= <"> / "\" + // TEXT_CHAR ::= + // CHAR ::= + // literal ::= "{" number "}" CRLF *CHAR8 + // ;; Number represents the number of CHAR8 octets + // CHAR8 ::= + // + + 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 text; + VIMAP_PARSER_GET(quoted_text, text); + VIMAP_PARSER_CHECK(one_char <'"'>); + + if (parser.m_literalHandler != NULL) { + + shared_ptr 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]", ""); + + // literal ::= "{" number "}" CRLF *CHAR8 + } else { + + VIMAP_PARSER_CHECK(one_char <'{'>); + + shared_ptr 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 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]", ""); + } + } + + *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 str; + VIMAP_PARSER_TRY_GET(xstring, str); + + if (str) { + value = str->value; + } else { + std::unique_ptr at; + VIMAP_PARSER_GET(atom, at); + value = at->value; + } + + *currentPos = pos; + + return true; + } + + + string value; + }; + + + // + // atom ::= 1*ATOM_CHAR + // + // ATOM_CHAR ::= + // atom_specials ::= "(" / ")" / "{" / SPACE / CTL / list_wildcards / quoted_specials + // CHAR ::= + // CTL ::= + // list_wildcards ::= "%" / "*" + // quoted_specials ::= <"> / "\" + // SPACE ::= + // + + 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 ::= "=?" "?" "?" "?=" + // ;; 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 theCharset, theEncoding; + std::unique_ptr 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 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 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 first; + std::unique_ptr 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 number; + std::unique_ptr range; + std::unique_ptr 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 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 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 > 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 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 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 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 > 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 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 mailbox_flag_list; + std::unique_ptr 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 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 value; + + + const IMAPParser::number* value_as_number() const { + return dynamic_cast (value.get()); + } + + const IMAPParser::mod_sequence_value* value_as_mod_sequence_value() const { + return dynamic_cast (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 > 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 (value, &pos)); + + atom.reset(); + } + + *currentPos = pos; + + return true; + } + + + std::unique_ptr auth_type; + std::unique_ptr 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 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 > 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 nd; + VIMAP_PARSER_GET(number, nd); + + VIMAP_PARSER_CHECK(one_char <'-'> ); + + shared_ptr amo; + VIMAP_PARSER_GET(atom, amo); + + VIMAP_PARSER_CHECK(one_char <'-'> ); + + shared_ptr ny; + VIMAP_PARSER_GET(number, ny); + + VIMAP_PARSER_TRY_CHECK(SPACE); + + // 2digit ":" 2digit ":" 2digit + shared_ptr nh; + VIMAP_PARSER_GET(number, nh); + + VIMAP_PARSER_CHECK(one_char <':'> ); + + shared_ptr nmi; + VIMAP_PARSER_GET(number, nmi); + + VIMAP_PARSER_CHECK(one_char <':'> ); + + shared_ptr 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 nz; + VIMAP_PARSER_GET(number, nz); + + VIMAP_PARSER_CHECK(one_char <'"'> ); + + + m_datetime.setHour(static_cast (std::min(std::max(nh->value, 0ul), 23ul))); + m_datetime.setMinute(static_cast (std::min(std::max(nmi->value, 0ul), 59ul))); + m_datetime.setSecond(static_cast (std::min(std::max(ns->value, 0ul), 59ul))); + + const int zone = static_cast (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 (std::min(std::max(nd->value, 1ul), 31ul))); + m_datetime.setYear(static_cast (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 > 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 nstring; + std::unique_ptr number; + + std::vector > 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 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 num; + VIMAP_PARSER_GET(nz_number, num); + nz_numbers.push_back(static_cast (num->value)); + + while (VIMAP_PARSER_TRY_CHECK(one_char <'.'> )) { + + if (VIMAP_PARSER_TRY_GET(nz_number, num)) { + nz_numbers.push_back(static_cast (num->value)); + } else { + VIMAP_PARSER_GET(section_text, section_text2); + break; + } + } + } + + VIMAP_PARSER_CHECK(one_char <']'> ); + } + + *currentPos = pos; + + return true; + } + + + std::unique_ptr section_text1; + std::unique_ptr section_text2; + std::vector 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 addr_name; + std::unique_ptr addr_adl; + std::unique_ptr addr_mailbox; + std::unique_ptr 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 > 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 env_date; + std::unique_ptr env_subject; + std::unique_ptr env_from; + std::unique_ptr env_sender; + std::unique_ptr env_reply_to; + std::unique_ptr env_to; + std::unique_ptr env_cc; + std::unique_ptr env_bcc; + std::unique_ptr env_in_reply_to; + std::unique_ptr 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 instead of a here: + // eg. ... (CHARSET "X-UNKNOWN") ... + if (!VIMAP_PARSER_TRY_GET(xstring, string1)) { + + std::unique_ptr 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 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 string1; + std::unique_ptr 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 > 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 m_string; + std::unique_ptr 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 > 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 body_fld_param; + std::unique_ptr body_fld_id; + std::unique_ptr body_fld_desc; + std::unique_ptr body_fld_enc; + std::unique_ptr 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 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 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 media_type; + std::unique_ptr 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 body_fld_md5; + std::unique_ptr body_fld_dsp; + std::unique_ptr body_fld_lang; + + std::vector > 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 body_fld_param; + std::unique_ptr body_fld_dsp; + std::unique_ptr body_fld_lang; + + std::vector > 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 media_basic; + std::unique_ptr 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 media_message; + std::unique_ptr body_fields; + std::unique_ptr envelope; + std::unique_ptr body; + std::unique_ptr 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 media_text; + std::unique_ptr body_fields; + std::unique_ptr 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 body_type_basic; + std::unique_ptr body_type_msg; + std::unique_ptr body_type_text; + + std::unique_ptr 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 media_subtype; + std::unique_ptr body_ext_mpart; + + std::vector > 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 body_type_1part; + std::unique_ptr 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 (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 (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 date_time; + std::unique_ptr number; + std::unique_ptr envelope; + std::unique_ptr uniqueid; + std::unique_ptr nstring; + std::unique_ptr body; + std::unique_ptr flag_list; + std::unique_ptr section; + std::unique_ptr 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 (parser.get (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 > 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 num; + VIMAP_PARSER_GET(nz_number, num); + number = static_cast (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 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*] + // + // 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*] + } 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 nz_number; + std::unique_ptr atom; + std::unique_ptr flag_list; + std::unique_ptr text; + std::unique_ptr mod_sequence_value; + std::unique_ptr sequence_set; + std::unique_ptr capability_data; + std::unique_ptr uid_set; + std::unique_ptr 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 text1; + VIMAP_PARSER_TRY_GET(text_mime2, text1); + + if (text1.get()) { + + text = text1->value; + + } else { + + std::unique_ptr 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 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 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 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 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 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 number; + std::unique_ptr mailbox_flag_list; + std::unique_ptr mailbox_list; + std::unique_ptr mailbox; + std::unique_ptr text; + std::vector > search_nz_number_list; + std::unique_ptr 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 resp_cond_state; + std::unique_ptr resp_cond_bye; + std::unique_ptr mailbox_data; + std::unique_ptr message_data; + std::unique_ptr 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 continue_req; + std::unique_ptr 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 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 tag; + std::unique_ptr 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 response_tagged; + std::unique_ptr 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 (curLine, &pos))) { + + continue_req_or_response_data.push_back( + std::move( + std::unique_ptr (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 (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 > continue_req_or_response_data; + std::unique_ptr 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 resp_cond_auth; + std::unique_ptr 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 (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 (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 + TYPE* get(string& line, size_t* currentPos) { + + component* resp = new TYPE; + return internalGet (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 + TYPE* getWithArgs(string& line, size_t* currentPos, ARG1_TYPE arg1, ARG2_TYPE arg2) { + + component* resp = new TYPE(arg1, arg2); + return internalGet (resp, line, currentPos); + } + +private: + + template + 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 (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 + 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 + 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 m_socket; + shared_ptr m_tracer; + + utility::progressListener* m_progress; + + bool m_strict; + + literalHandler* m_literalHandler; + + weak_ptr m_timeoutHandler; + + + string m_buffer; + + string m_lastLine; + string m_errorResponseLine; + + std::map 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 toh = m_timeoutHandler.lock(); + shared_ptr 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 toh = m_timeoutHandler.lock(); + shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 & sess, + const shared_ptr & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & sess, const shared_ptr & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 IMAPServiceInfos::getAvailableProperties() const { + + std::vector 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 + + +namespace vmime { +namespace net { +namespace imap { + + +IMAPStore::IMAPStore( + const shared_ptr & sess, + const shared_ptr & 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 IMAPStore::getRootFolder() { + + if (!isConnected()) { + throw exceptions::illegal_state("Not connected"); + } + + return make_shared ( + folder::path(), + dynamicCast (shared_from_this()), + shared_ptr () + ); +} + + +shared_ptr IMAPStore::getDefaultFolder() { + + if (!isConnected()) { + throw exceptions::illegal_state("Not connected"); + } + + return make_shared ( + folder::path::component("INBOX"), + dynamicCast (shared_from_this()), + shared_ptr () + ); +} + + +shared_ptr IMAPStore::getFolder(const folder::path& path) { + + if (!isConnected()) { + throw exceptions::illegal_state("Not connected"); + } + + return make_shared ( + path, + dynamicCast (shared_from_this()), + shared_ptr () + ); +} + + +bool IMAPStore::isValidFolderName(const folder::path::component& /* name */) const { + + return true; +} + + +void IMAPStore::connect() { + + if (isConnected()) { + throw exceptions::already_connected(); + } + + m_connection = make_shared ( + dynamicCast (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 IMAPStore::getConnectionInfos() const { + + if (!m_connection) { + return null; + } + + return m_connection->getConnectionInfos(); +} + + +shared_ptr IMAPStore::getConnection() { + + return m_connection; +} + + +void IMAPStore::disconnect() { + + if (!isConnected()) { + throw exceptions::not_connected(); + } + + for (std::list ::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 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 ::iterator it = m_folders.begin() ; + it != m_folders.end() ; ++it) { + + if ((*it)->isOpen()) { + (*it)->noop(); + } + } +} + + +shared_ptr IMAPStore::connection() { + + return m_connection; +} + + +void IMAPStore::registerFolder(IMAPFolder* folder) { + + m_folders.push_back(folder); +} + + +void IMAPStore::unregisterFolder(IMAPFolder* folder) { + + std::list ::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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & sess, + const shared_ptr & auth, + const bool secured = false + ); + + ~IMAPStore(); + + const string getProtocolName() const; + + shared_ptr getDefaultFolder(); + shared_ptr getRootFolder(); + shared_ptr 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 getConnectionInfos() const; + shared_ptr getConnection(); + +protected: + + // Connection + shared_ptr m_connection; + + + + shared_ptr connection(); + + + void registerFolder(IMAPFolder* folder); + void unregisterFolder(IMAPFolder* folder); + + std::list 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 ('0' + (m_number % 1000) / 100); + m_tag[2] = static_cast ('0' + (m_number % 100) / 10); + m_tag[3] = static_cast ('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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +#include +#include + + +namespace vmime { +namespace net { +namespace imap { + + +// static +const string IMAPUtils::quoteString(const string& text) { + + // + // ATOM_CHAR ::= + // + // atom_specials ::= "(" / ")" / "{" / SPACE / CTL / + // list_wildcards / quoted_specials + // + // list_wildcards ::= "%" / "*" + // + // quoted_specials ::= <"> / "\" + // + // CHAR ::= + // + // CTL ::= + // + + 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 (static_cast (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 + + // 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 (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 & 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 IMAPUtils::messageFlagList(const int flags) { + + std::vector 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 IMAPUtils::buildFetchCommand( + const shared_ptr & 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 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 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 customHeaderFields = options.getHeaderFields(); + std::copy(customHeaderFields.begin(), customHeaderFields.end(), std::back_inserter(headerFields)); + + if (!headerFields.empty()) { + + string list; + + for (std::vector ::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 (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 & list() const { + + return m_list; + } + +public: + + std::vector 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 + + +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 & 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 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 buildFetchCommand( + const shared_ptr & 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 & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 & ctx) + : maildirFormat(ctx) { + +} + + +const string courierMaildirFormat::getName() const { + + return "courier"; +} + + +void courierMaildirFormat::createFolder(const folder::path& path) { + + shared_ptr fsf = platform::getHandler()->getFileSystemFactory(); + + if (!fsf->isValidPath(folderPathToFileSystemPath(path, ROOT_DIRECTORY))) { + throw exceptions::invalid_folder_name(); + } + + shared_ptr rootDir = fsf->create( + folderPathToFileSystemPath(path, ROOT_DIRECTORY) + ); + + shared_ptr newDir = fsf->create( + folderPathToFileSystemPath(path, NEW_DIRECTORY) + ); + shared_ptr tmpDir = fsf->create( + folderPathToFileSystemPath(path, TMP_DIRECTORY) + ); + shared_ptr curDir = fsf->create( + folderPathToFileSystemPath(path, CUR_DIRECTORY) + ); + + rootDir->createDirectory(true); + + newDir->createDirectory(false); + tmpDir->createDirectory(false); + curDir->createDirectory(false); + + shared_ptr maildirFile = fsf->create( + folderPathToFileSystemPath(path, ROOT_DIRECTORY) + / utility::file::path::component("maildirfolder") + ); + + maildirFile->createFile(); +} + + +void courierMaildirFormat::destroyFolder(const folder::path& path) { + + shared_ptr fsf = platform::getHandler()->getFileSystemFactory(); + + // Recursively delete directories of subfolders + const std::vector folders = listFolders(path, true); + + for (std::vector ::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 folders = listFolders(oldPath, true); + + for (std::vector ::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 fsf = platform::getHandler()->getFileSystemFactory(); + + const utility::file::path oldFSPath = + folderPathToFileSystemPath(oldPath, ROOT_DIRECTORY); + + const utility::file::path newFSPath = + folderPathToFileSystemPath(newPath, ROOT_DIRECTORY); + + shared_ptr rootDir = fsf->create(oldFSPath); + rootDir->rename(newFSPath); +} + + +bool courierMaildirFormat::folderExists(const folder::path& path) const { + + shared_ptr fsf = platform::getHandler()->getFileSystemFactory(); + + shared_ptr rootDir = fsf->create( + folderPathToFileSystemPath(path, ROOT_DIRECTORY) + ); + + shared_ptr newDir = fsf->create( + folderPathToFileSystemPath(path, NEW_DIRECTORY) + ); + shared_ptr tmpDir = fsf->create( + folderPathToFileSystemPath(path, TMP_DIRECTORY) + ); + shared_ptr curDir = fsf->create( + folderPathToFileSystemPath(path, CUR_DIRECTORY) + ); + + shared_ptr 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 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 courierMaildirFormat::listFolders( + const folder::path& root, + const bool recursive +) const { + + // First, list directories + std::vector dirs; + listDirectories(root, dirs, false); + + // Then, map directories to folders + std::vector folders; + + for (std::vector ::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 & dirs, + const bool onlyTestForExistence +) const { + + shared_ptr fsf = platform::getHandler()->getFileSystemFactory(); + + shared_ptr 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 it = rootDir->getFiles(); + + while (it->hasMoreElements()) { + + shared_ptr 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 fsf = platform::getHandler()->getFileSystemFactory(); + + shared_ptr 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 it = rootDir->getFiles(); + + while (it->hasMoreElements()) { + + shared_ptr file = it->nextElement(); + + if (isSubfolderDirectory(*file)) { + + shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & 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 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 & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 & ctx) + : maildirFormat(ctx) { + +} + + +const string kmailMaildirFormat::getName() const { + + return "kmail"; +} + + +void kmailMaildirFormat::createFolder(const folder::path& path) { + + shared_ptr fsf = platform::getHandler()->getFileSystemFactory(); + + if (!fsf->isValidPath(folderPathToFileSystemPath(path, ROOT_DIRECTORY))) { + throw exceptions::invalid_folder_name(); + } + + shared_ptr rootDir = fsf->create( + folderPathToFileSystemPath(path, ROOT_DIRECTORY) + ); + + shared_ptr newDir = fsf->create( + folderPathToFileSystemPath(path, NEW_DIRECTORY) + ); + shared_ptr tmpDir = fsf->create( + folderPathToFileSystemPath(path, TMP_DIRECTORY) + ); + shared_ptr 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 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 fsf = platform::getHandler()->getFileSystemFactory(); + + shared_ptr rootDir = fsf->create( + folderPathToFileSystemPath(path, ROOT_DIRECTORY) + ); + + shared_ptr newDir = fsf->create( + folderPathToFileSystemPath(path, NEW_DIRECTORY) + ); + shared_ptr tmpDir = fsf->create( + folderPathToFileSystemPath(path, TMP_DIRECTORY) + ); + shared_ptr 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 kmailMaildirFormat::listFolders( + const folder::path& root, + const bool recursive +) const { + + std::vector list; + listFoldersImpl(list, root, recursive); + + return list; +} + + +void kmailMaildirFormat::listFoldersImpl( + std::vector & list, + const folder::path& root, + const bool recursive +) const { + + shared_ptr fsf = platform::getHandler()->getFileSystemFactory(); + + shared_ptr rootDir = fsf->create( + folderPathToFileSystemPath(root, root.isEmpty() ? ROOT_DIRECTORY : CONTAINER_DIRECTORY) + ); + + if (rootDir->exists()) { + + shared_ptr it = rootDir->getFiles(); + + while (it->hasMoreElements()) { + + shared_ptr 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 fsf = platform::getHandler()->getFileSystemFactory(); + + shared_ptr rootDir = fsf->create( + folderPathToFileSystemPath(oldPath, ROOT_DIRECTORY) + ); + shared_ptr 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 fsf = platform::getHandler()->getFileSystemFactory(); + + shared_ptr rootDir = fsf->create( + folderPathToFileSystemPath(path, CONTAINER_DIRECTORY) + ); + + shared_ptr it = rootDir->getFiles(); + + while (it->hasMoreElements()) { + + shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & 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 listFolders( + const folder::path& root, + const bool recursive + ) const; + +protected: + + bool supports() const; + + + /** Recursive implementation of listFolders(). + */ + void listFoldersImpl( + std::vector & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 & 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 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 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 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 ::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 ::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 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 event = + make_shared ( + dynamicCast (shared_from_this()), + events::folderEvent::TYPE_CREATED, + m_path, m_path + ); + + notifyFolder(event); +} + + +void maildirFolder::destroy() { + + shared_ptr 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 event = + make_shared ( + dynamicCast (shared_from_this()), + events::folderEvent::TYPE_DELETED, + m_path, m_path + ); + + notifyFolder(event); +} + + +bool maildirFolder::exists() { + + shared_ptr store = m_store.lock(); + + return store->getFormat()->folderExists(m_path); +} + + +bool maildirFolder::isOpen() const { + + return m_open; +} + + +void maildirFolder::scanFolder() { + + shared_ptr store = m_store.lock(); + + try { + + m_messageCount = 0; + m_unreadMessageCount = 0; + + shared_ptr fsf = platform::getHandler()->getFileSystemFactory(); + + utility::file::path newDirPath = + store->getFormat()->folderPathToFileSystemPath(m_path, maildirFormat::NEW_DIRECTORY); + shared_ptr newDir = fsf->create(newDirPath); + + utility::file::path curDirPath = + store->getFormat()->folderPathToFileSystemPath(m_path, maildirFormat::CUR_DIRECTORY); + shared_ptr curDir = fsf->create(curDirPath); + + // New received messages (new/) + shared_ptr nit = newDir->getFiles(); + std::vector newMessageFilenames; + + while (nit->hasMoreElements()) { + + shared_ptr file = nit->nextElement(); + + if (maildirUtils::isMessageFile(*file)) { + newMessageFilenames.push_back(file->getFullPath().getLastComponent()); + } + } + + // Current messages (cur/) + shared_ptr cit = curDir->getFiles(); + std::vector curMessageFilenames; + + while (cit->hasMoreElements()) { + + shared_ptr 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 ::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 ::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 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 ::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 ::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 (m_messageInfos.size()); + + } catch (exceptions::filesystem_exception&) { + + // Should not happen... + } +} + + +shared_ptr 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 (dynamicCast (shared_from_this()), num); +} + + +std::vector > maildirFolder::getMessages(const messageSet& msgs) { + + if (!isOpen()) { + throw exceptions::illegal_state("Folder not open"); + } + + if (msgs.isNumberSet()) { + + const std::vector numbers = maildirUtils::messageSetToNumberList(msgs, m_messageCount); + + std::vector > messages; + shared_ptr thisFolder = dynamicCast (shared_from_this()); + + for (std::vector ::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 (thisFolder, *it)); + } + + return messages; + + } else { + + throw exceptions::operation_not_supported(); + } +} + + +size_t maildirFolder::getMessageCount() { + + return m_messageCount; +} + + +shared_ptr maildirFolder::getFolder(const folder::path::component& name) { + + shared_ptr store = m_store.lock(); + + if (!store) { + throw exceptions::illegal_state("Store disconnected"); + } + + return shared_ptr (new maildirFolder(m_path / name, store)); +} + + +std::vector > maildirFolder::getFolders(const bool recursive) { + + shared_ptr store = m_store.lock(); + + if (!isOpen() && !store) { + throw exceptions::illegal_state("Store disconnected"); + } + + std::vector > list; + + listFolders(list, recursive); + + return list; +} + + +void maildirFolder::listFolders(std::vector >& list, const bool recursive) { + + shared_ptr store = m_store.lock(); + + try { + + std::vector pathList = + store->getFormat()->listFolders(m_path, recursive); + + list.reserve(pathList.size()); + + for (std::vector ::size_type i = 0, n = pathList.size() ; i < n ; ++i) { + + shared_ptr 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 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 event = + make_shared ( + dynamicCast (shared_from_this()), + events::folderEvent::TYPE_RENAMED, + oldPath, newPath + ); + + notifyFolder(event); + + // Notify folders with the same path + for (std::list ::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 event = + make_shared ( + dynamicCast ((*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 event = + make_shared ( + dynamicCast ((*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 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 nums = maildirUtils::messageSetToNumberList(msgs, m_messageCount); + + // Change message flags + shared_ptr fsf = platform::getHandler()->getFileSystemFactory(); + + utility::file::path curDirPath = store->getFormat()-> + folderPathToFileSystemPath(m_path, maildirFormat::CUR_DIRECTORY); + + for (std::vector ::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 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 ::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 ::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 ::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 event = + make_shared ( + dynamicCast (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 & 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 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 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 tmpDir = fsf->create(tmpDirPath); + tmpDir->createDirectory(true); + } catch (exceptions::filesystem_exception&) { + // Don't throw now, it will fail later... + } + + try { + shared_ptr 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 nums; + nums.push_back(m_messageCount); + + shared_ptr event = + make_shared ( + dynamicCast (shared_from_this()), + events::messageCountEvent::TYPE_ADDED, + nums + ); + + notifyMessageCount(event); + + // Notify folders with the same path + for (std::list ::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 event = + make_shared ( + dynamicCast ((*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 fsf = platform::getHandler()->getFileSystemFactory(); + + shared_ptr file = fsf->create(tmpDirPath / filename); + + if (progress) { + progress->start(size); + } + + // First, write the message into 'tmp'... + try { + + file->createFile(); + + shared_ptr fw = file->getFileWriter(); + shared_ptr 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 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 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 store = m_store.lock(); + + if (!store) { + throw exceptions::illegal_state("Store disconnected"); + } else if (!isOpen()) { + throw exceptions::illegal_state("Folder not open"); + } + + shared_ptr 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 destTmpDir = fsf->create(destTmpDirPath); + destTmpDir->createDirectory(true); + + } catch (exceptions::filesystem_exception&) { + + // Don't throw now, it will fail later... + } + + try { + + shared_ptr destCurDir = fsf->create(destCurDirPath); + destCurDir->createDirectory(true); + + } catch (exceptions::filesystem_exception&) { + + // Don't throw now, it will fail later... + } + + // Copy messages + const std::vector nums = maildirUtils::messageSetToNumberList(msgs, m_messageCount); + + try { + + for (std::vector ::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 file = fsf->create(curDirPath / msg.path); + shared_ptr fr = file->getFileReader(); + shared_ptr 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 store = m_store.lock(); + + for (std::list ::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 status = getStatus(); + + count = status->getMessageCount(); + unseen = status->getUnseenCount(); + + m_messageCount = count; +} + + +shared_ptr maildirFolder::getStatus() { + + shared_ptr store = m_store.lock(); + + const size_t oldCount = m_messageCount; + + scanFolder(); + + shared_ptr status = make_shared (); + + status->setMessageCount(m_messageCount); + status->setUnseenCount(m_unreadMessageCount); + + // Notify message count changed (new messages) + if (m_messageCount > oldCount) { + + std::vector nums; + nums.reserve(m_messageCount - oldCount); + + for (size_t i = oldCount + 1, j = 0 ; i <= m_messageCount ; ++i, ++j) { + nums[j] = i; + } + + shared_ptr event = + make_shared ( + dynamicCast (shared_from_this()), + events::messageCountEvent::TYPE_ADDED, + nums + ); + + notifyMessageCount(event); + + // Notify folders with the same path + for (std::list ::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 event = + make_shared ( + dynamicCast ((*it)->shared_from_this()), + events::messageCountEvent::TYPE_ADDED, + nums + ); + + (*it)->notifyMessageCount(event); + } + } + } + + return status; +} + + +void maildirFolder::expunge() { + + shared_ptr 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 fsf = platform::getHandler()->getFileSystemFactory(); + + utility::file::path curDirPath = store->getFormat()-> + folderPathToFileSystemPath(m_path, maildirFormat::CUR_DIRECTORY); + + std::vector 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 ::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 file = fsf->create(curDirPath / infos.path); + file->remove(); + } catch (exceptions::filesystem_exception& e) { + // Ignore (not important) + } + } + } + + if (!nums.empty()) { + + for (std::vector ::size_type i = nums.size() ; i != 0 ; --i) { + m_messageInfos.erase(m_messageInfos.begin() + (i - 1)); + } + } + + m_messageCount -= static_cast (nums.size()); + m_unreadMessageCount -= unreadCount; + + // Notify message expunged + shared_ptr event = + make_shared ( + dynamicCast (shared_from_this()), + events::messageCountEvent::TYPE_REMOVED, + nums + ); + + notifyMessageCount(event); + + // Notify folders with the same path + for (std::list ::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 event = + make_shared ( + dynamicCast ((*it)->shared_from_this()), + events::messageCountEvent::TYPE_REMOVED, + nums + ); + + (*it)->notifyMessageCount(event); + } + } +} + + +shared_ptr maildirFolder::getParent() { + + if (m_path.isEmpty()) { + return null; + } else { + return shared_ptr (new maildirFolder(m_path.getParent(), m_store.lock())); + } +} + + +shared_ptr maildirFolder::getStore() const { + + return m_store.lock(); +} + + +shared_ptr maildirFolder::getStore() { + + return m_store.lock(); +} + + +void maildirFolder::fetchMessages( + std::vector >& msg, + const fetchAttributes& options, + utility::progressListener* progress +) { + + shared_ptr 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 thisFolder = dynamicCast (shared_from_this()); + + for (std::vector >::iterator it = msg.begin() ; + it != msg.end() ; ++it) { + + dynamicCast (*it)->fetch(thisFolder, options); + + if (progress) { + progress->progress(++current, total); + } + } + + if (progress) { + progress->stop(total); + } +} + + +void maildirFolder::fetchMessage( + const shared_ptr & msg, + const fetchAttributes& options +) { + + shared_ptr store = m_store.lock(); + + if (!store) { + throw exceptions::illegal_state("Store disconnected"); + } else if (!isOpen()) { + throw exceptions::illegal_state("Folder not open"); + } + + dynamicCast (msg)->fetch( + dynamicCast (shared_from_this()), + options + ); +} + + +std::vector > maildirFolder::getAndFetchMessages( + const messageSet& msgs, + const fetchAttributes& attribs +) { + + if (msgs.isEmpty()) { + return std::vector >(); + } + + std::vector > 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +#include + +#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 & 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 getMessage(const size_t num); + std::vector > getMessages(const messageSet& msgs); + + size_t getMessageCount(); + + shared_ptr getFolder(const folder::path::component& name); + std::vector > 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 & 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 getStatus(); + + void expunge(); + + shared_ptr getParent(); + + shared_ptr getStore() const; + shared_ptr getStore(); + + + void fetchMessages( + std::vector >& msg, + const fetchAttributes& options, + utility::progressListener* progress = NULL + ); + + void fetchMessage(const shared_ptr & msg, const fetchAttributes& options); + + std::vector > getAndFetchMessages( + const messageSet& msgs, + const fetchAttributes& attribs + ); + + int getFetchCapabilities() const; + + std::vector getMessageNumbersStartingOnUID(const message::uid& uid); + +private: + + void scanFolder(); + + void listFolders(std::vector >& 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 & nums); + void setMessageFlagsImpl(const std::vector & nums, const int flags, const int mode); + + void copyMessagesImpl(const folder::path& dest, const std::vector & 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 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 m_messageInfos; + + // Instanciated message objects + std::vector 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 maildirFolderStatus::clone() const { + + return make_shared (*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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 & store) + : m_store(store) { + +} + + +shared_ptr maildirFormat::context::getStore() { + + return m_store.lock(); +} + + +// +// maildirFormat +// + +maildirFormat::maildirFormat(const shared_ptr & ctx) + : m_context(ctx) { + +} + + +shared_ptr maildirFormat::getContext() const { + + return m_context; +} + + +// static +shared_ptr maildirFormat::detect(const shared_ptr & store) { + + shared_ptr ctx = make_shared (store); + + // Try Courier format + shared_ptr fmt = make_shared (ctx); + + if (fmt->supports()) { + return fmt; + } + + // Default is KMail format + return make_shared (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & store); + + shared_ptr getStore(); + + private: + + weak_ptr 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 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 detect(const shared_ptr & 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 & ctx); + + + /** Returns the current context. + * + * @return current context + */ + shared_ptr 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 & 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 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 (-1)) { + throw exceptions::unfetched_object(); + } + + return m_size; +} + + +bool maildirMessage::isExpunged() const { + + return m_expunged; +} + + +shared_ptr maildirMessage::getStructure() const { + + if (!m_structure) { + throw exceptions::unfetched_object(); + } + + return m_structure; +} + + +shared_ptr maildirMessage::getStructure() { + + if (!m_structure) { + throw exceptions::unfetched_object(); + } + + return m_structure; +} + + +shared_ptr 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 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 & p, + utility::outputStream& os, + utility::progressListener* progress, + const size_t start, + const size_t length, + const bool peek +) const { + + shared_ptr mp = dynamicCast (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 folder = m_folder.lock(); + + shared_ptr fsf = platform::getHandler()->getFileSystemFactory(); + + const utility::file::path path = folder->getMessageFSPath(m_num); + shared_ptr file = fsf->create(path); + + shared_ptr reader = file->getFileReader(); + shared_ptr is = reader->getInputStream(); + + is->skip(start + partialStart); + + byte_t buffer[8192]; + size_t remaining = + (partialLength == static_cast (-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 & p) { + + shared_ptr folder = m_folder.lock(); + + shared_ptr mp = dynamicCast (p); + + shared_ptr fsf = platform::getHandler()->getFileSystemFactory(); + + const utility::file::path path = folder->getMessageFSPath(m_num); + shared_ptr file = fsf->create(path); + + shared_ptr reader = file->getFileReader(); + shared_ptr 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 & msgFolder, const fetchAttributes& options) { + + shared_ptr folder = m_folder.lock(); + + if (folder != msgFolder) { + throw exceptions::folder_not_found(); + } + + shared_ptr fsf = platform::getHandler()->getFileSystemFactory(); + + const utility::file::path path = folder->getMessageFSPath(m_num); + shared_ptr 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 reader = file->getFileReader(); + shared_ptr 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 (shared_ptr (), 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
maildirMessage::getOrCreateHeader() { + + if (m_header) { + return m_header; + } else { + return (m_header = make_shared
()); + } +} + + +shared_ptr maildirMessage::getParsedMessage() { + + std::ostringstream oss; + utility::outputStreamAdapter os(oss); + + extract(os); + + shared_ptr msg = make_shared (); + 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & folder, const size_t num); + + ~maildirMessage(); + + + size_t getNumber() const; + + const uid getUID() const; + + size_t getSize() const; + + bool isExpunged() const; + + shared_ptr getStructure() const; + shared_ptr getStructure(); + + shared_ptr 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 & 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 & p); + + shared_ptr getParsedMessage(); + +private: + + void fetch(const shared_ptr & folder, const fetchAttributes& options); + + void onFolderClosed(); + + shared_ptr
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 m_folder; + + size_t m_num; + size_t m_size; + int m_flags; + bool m_expunged; + uid m_uid; + + shared_ptr
m_header; + shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 & 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 (*cdispField->getValue()); + } +} + + +maildirMessagePart::~maildirMessagePart() { + +} + + +void maildirMessagePart::initStructure(const bodyPart& part) { + + if (part.getBody()->getPartList().size() == 0) { + + m_structure = null; + + } else { + + m_structure = make_shared ( + dynamicCast (shared_from_this()), part.getBody()->getPartList() + ); + } +} + + +shared_ptr maildirMessagePart::getStructure() const { + + if (m_structure) { + return m_structure; + } else { + return maildirMessageStructure::emptyStructure(); + } +} + + +shared_ptr 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 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
()); + } +} + + +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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & parent, + const size_t number, + const bodyPart& part + ); + + ~maildirMessagePart(); + + + shared_ptr getStructure() const; + shared_ptr getStructure(); + + weak_ptr getParent() const { return (m_parent); } + + const mediaType& getType() const; + const contentDisposition &getDisposition() const; + size_t getSize() const; + size_t getNumber() const; + + shared_ptr 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 m_structure; + weak_ptr m_parent; + shared_ptr
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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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::m_emptyStructure = make_shared (); + + +maildirMessageStructure::maildirMessageStructure() +{ +} + + +maildirMessageStructure::maildirMessageStructure( + const shared_ptr & parent, + const bodyPart& part +) { + + shared_ptr mpart = make_shared (parent, 0, part); + mpart->initStructure(part); + + m_parts.push_back(mpart); +} + + +maildirMessageStructure::maildirMessageStructure( + const shared_ptr & parent, + const std::vector >& list +) { + + for (size_t i = 0 ; i < list.size() ; ++i) { + + shared_ptr mpart = make_shared (parent, i, *list[i]); + mpart->initStructure(*list[i]); + + m_parts.push_back(mpart); + } +} + + +shared_ptr maildirMessageStructure::getPartAt(const size_t x) const { + + return m_parts[x]; +} + + +shared_ptr maildirMessageStructure::getPartAt(const size_t x) { + + return m_parts[x]; +} + + +size_t maildirMessageStructure::getPartCount() const { + + return m_parts.size(); +} + + +// static +shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & parent, + const bodyPart& part + ); + maildirMessageStructure( + const shared_ptr & parent, + const std::vector >& list + ); + + + shared_ptr getPartAt(const size_t x) const; + shared_ptr getPartAt(const size_t x); + + size_t getPartCount() const; + + static shared_ptr emptyStructure(); + +private: + + static shared_ptr m_emptyStructure; + + std::vector > 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 maildirServiceInfos::getAvailableProperties() const { + + std::vector 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 (getSession(), \ + dynamic_cast (getInfos()).getProperties().prop)) +#define HAS_PROPERTY(prop) \ + (getInfos().hasProperty(getSession(), \ + dynamic_cast (getInfos()).getProperties().prop)) + + +namespace vmime { +namespace net { +namespace maildir { + + +maildirStore::maildirStore( + const shared_ptr & sess, + const shared_ptr & 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 maildirStore::getRootFolder() { + + if (!isConnected()) { + throw exceptions::illegal_state("Not connected"); + } + + return shared_ptr ( + new maildirFolder( + folder::path(), + dynamicCast (shared_from_this()) + ) + ); +} + + +shared_ptr maildirStore::getDefaultFolder() { + + if (!isConnected()) { + throw exceptions::illegal_state("Not connected"); + } + + return shared_ptr ( + new maildirFolder( + folder::path::component("inbox"), + dynamicCast (shared_from_this()) + ) + ); +} + + +shared_ptr maildirStore::getFolder(const folder::path& path) { + + if (!isConnected()) { + throw exceptions::illegal_state("Not connected"); + } + + return shared_ptr ( + new maildirFolder( + path, + dynamicCast (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 fsf = platform::getHandler()->getFileSystemFactory(); + + m_fsPath = fsf->stringToPath(GET_PROPERTY(string, PROPERTY_SERVER_ROOTPATH)); + + shared_ptr 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 (shared_from_this())); + + m_connected = true; +} + + +bool maildirStore::isConnected() const { + + return m_connected; +} + + +bool maildirStore::isSecuredConnection() const { + + return false; +} + + +shared_ptr maildirStore::getConnectionInfos() const { + + return make_shared ("localhost", static_cast (0)); +} + + +void maildirStore::disconnect() { + + for (std::list ::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 maildirStore::getFormat() { + + return m_format; +} + + +shared_ptr maildirStore::getFormat() const { + + return m_format; +} + + +void maildirStore::registerFolder(maildirFolder* folder) { + + m_folders.push_back(folder); +} + + +void maildirStore::unregisterFolder(maildirFolder* folder) { + + std::list ::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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 + + +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 & sess, + const shared_ptr & auth + ); + + ~maildirStore(); + + const string getProtocolName() const; + + shared_ptr getDefaultFolder(); + shared_ptr getRootFolder(); + shared_ptr 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 getConnectionInfos() const; + + shared_ptr getFormat(); + shared_ptr getFormat() const; + +private: + + void registerFolder(maildirFolder* folder); + void unregisterFolder(maildirFolder* folder); + + + std::list m_folders; + + shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 & dir) { + + shared_ptr files = dir->getFiles(); + + // First, delete files and subdirectories in this directory + while (files->hasMoreElements()) { + + shared_ptr 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 list; + +private: + + size_t m_msgCount; +}; + + +// static +const std::vector 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 + + +namespace vmime { +namespace net { + + +string messagePart::getName() const +{ + return {}; +} + +shared_ptr messagePart::getPartAt(const size_t pos) const { + + return getStructure()->getPartAt(pos); +} + + +shared_ptr 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 (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 { + +protected: + + messagePart() { } + messagePart(const messagePart&); + + virtual ~messagePart() { } + +public: + + /** Return the structure of this part. + * + * @return structure of the part + */ + virtual shared_ptr getStructure() const = 0; + + /** Return the structure of this part. + * + * @return structure of the part + */ + virtual shared_ptr 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 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 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 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 { + +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 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 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 { + +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 getStructure() const = 0; + + /** Return the MIME structure of the message (must fetch before). + * + * @return MIME structure of the message + */ + virtual shared_ptr getStructure() = 0; + + /** Return a reference to the header fields of the message (must fetch before). + * + * @return header section of the message + */ + virtual shared_ptr 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 & 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 & 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +#include +#include + + +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 (-1)) { + throw std::invalid_argument("first"); + } else if (last != static_cast (-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 & numbers) { + + // Sort a copy of the list + std::vector 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 (-1), rangeStart = static_cast (-1); + messageSet set; + + for (std::vector ::const_iterator it = sortedNumbers.begin() ; + it != sortedNumbers.end() ; ++it) { + + const size_t current = *it; + + if (current == previous) { + continue; // skip duplicates + } + + if (current == static_cast (-1)) { + throw std::invalid_argument("numbers"); + } + + if (previous == static_cast (-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 & uids) { + + std::vector 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 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 (-1), rangeStart = static_cast (-1); + messageSet set; + + for (std::vector ::const_iterator it = sortedUIDs.begin() ; + it != sortedUIDs.end() ; ++it) { + + const vmime_uint32 current = *it; + + if (current == previous) { + continue; // skip duplicates + } + + if (previous == static_cast (-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 (m_ranges[0]) != NULL; +} + + +bool messageSet::isUIDSet() const { + + return !isEmpty() && dynamic_cast (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & 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 & 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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::CAPA() { + + return createCommand("CAPA"); +} + + +// static +shared_ptr POP3Command::NOOP() { + + return createCommand("NOOP"); +} + + +// static +shared_ptr POP3Command::AUTH(const string& mechName) { + + std::ostringstream cmd; + cmd.imbue(std::locale::classic()); + cmd << "AUTH " << mechName; + + return createCommand(cmd.str()); +} + + +// static +shared_ptr 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::STLS() { + + return createCommand("STLS"); +} + + +// static +shared_ptr 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::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::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::STAT() { + + return createCommand("STAT"); +} + + +// static +shared_ptr POP3Command::LIST() { + + return createCommand("LIST"); +} + + +// static +shared_ptr 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::UIDL() { + + return createCommand("UIDL"); +} + + +// static +shared_ptr 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::DELE(const unsigned long msg) { + + std::ostringstream cmd; + cmd.imbue(std::locale::classic()); + cmd << "DELE " << msg; + + return createCommand(cmd.str()); +} + + +// static +shared_ptr 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::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::RSET() { + + return createCommand("RSET"); +} + + +// static +shared_ptr POP3Command::QUIT() { + + return createCommand("QUIT"); +} + + +// static +shared_ptr POP3Command::createCommand( + const string& text, + const string& traceText +) { + + if (traceText.empty()) { + return shared_ptr (new POP3Command(text, text)); + } else { + return shared_ptr (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 & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 CAPA(); + static shared_ptr NOOP(); + static shared_ptr AUTH(const string& mechName); + static shared_ptr AUTH(const string& mechName, const string& initialResponse); + static shared_ptr STLS(); + static shared_ptr APOP(const string& username, const string& digest); + static shared_ptr USER(const string& username); + static shared_ptr PASS(const string& password); + static shared_ptr STAT(); + static shared_ptr LIST(); + static shared_ptr LIST(const unsigned long msg); + static shared_ptr UIDL(); + static shared_ptr UIDL(const unsigned long msg); + static shared_ptr DELE(const unsigned long msg); + static shared_ptr RETR(const unsigned long msg); + static shared_ptr TOP(const unsigned long msg, const unsigned long lines); + static shared_ptr RSET(); + static shared_ptr 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 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 & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 (getSession(), \ + dynamic_cast (m_store.lock()->getInfos()).getProperties().prop)) +#define HAS_PROPERTY(prop) \ + (m_store.lock()->getInfos().hasProperty(getSession(), \ + dynamic_cast (m_store.lock()->getInfos()).getProperties().prop)) + + +namespace vmime { +namespace net { +namespace pop3 { + + + +POP3Connection::POP3Connection( + const shared_ptr & store, + const shared_ptr & 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 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 tlsSession = tls::TLSSession::create + (store->getCertificateVerifier(), + store->getSession()->getTLSProperties()); + + shared_ptr tlsSocket = + tlsSession->getSocket(m_socket); + + m_socket = tlsSocket; + + m_secured = true; + m_cntInfos = make_shared (address, port, tlsSession, tlsSocket); + } else +#endif // VMIME_HAVE_TLS_SUPPORT + { + m_cntInfos = make_shared (address, port); + } + + m_socket->connect(address, port); + + // Connection + // + // eg: C: + // --- S: +OK MailSite POP3 Server 5.3.4.0 Ready <36938848.1056800841.634@somewhere.com> + + shared_ptr response = POP3Response::readResponse( + dynamicCast (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 (shared_from_this())); + POP3Response::readResponse(dynamicCast (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 + // --- S: +OK vincent is a valid mailbox + + const string username = getAuthenticator()->getUsername(); + const string password = getAuthenticator()->getPassword(); + + shared_ptr conn = dynamicCast (shared_from_this()); + shared_ptr response; + + if (GET_PROPERTY(bool, PROPERTY_OPTIONS_APOP)) { + + if (randomMID.getLeft().length() != 0 && + randomMID.getRight().length() != 0) { + + // is the result of MD5 applied to "password" + shared_ptr 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 (getAuthenticator())) { + throw exceptions::authentication_error("No SASL authenticator available."); + } + + std::vector capa = getCapabilities(); + std::vector 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 > mechList; + + shared_ptr 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 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 (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 mech = mechList[i]; + + shared_ptr saslSession = + saslContext->createSession("pop3", getAuthenticator(), mech); + + saslSession->init(); + + shared_ptr 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 (shared_from_this())); + + for (bool cont = true ; cont ; ) { + + shared_ptr response = + POP3Response::readResponse(dynamicCast (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 (shared_from_this())); + + shared_ptr response = + POP3Response::readResponse(dynamicCast (shared_from_this())); + + if (!response->isSuccess()) { + throw exceptions::command_error("STLS", response->getFirstLine()); + } + + shared_ptr tlsSession = tls::TLSSession::create( + m_store.lock()->getCertificateVerifier(), + m_store.lock()->getSession()->getTLSProperties() + ); + + shared_ptr tlsSocket = tlsSession->getSocket(m_socket); + + tlsSocket->handshake(); + + m_socket = tlsSocket; + + m_secured = true; + m_cntInfos = make_shared ( + 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 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 (shared_from_this())); + + shared_ptr response = + POP3Response::readMultilineResponse(dynamicCast (shared_from_this())); + + std::vector 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 POP3Connection::getConnectionInfos() const { + + return m_cntInfos; +} + + +shared_ptr POP3Connection::getStore() { + + return m_store.lock(); +} + + +shared_ptr POP3Connection::getSession() { + + return m_store.lock()->getSession(); +} + + +shared_ptr POP3Connection::getSocket() { + + return m_socket; +} + + +shared_ptr POP3Connection::getTracer() { + + return m_tracer; +} + + +shared_ptr POP3Connection::getTimeoutHandler() { + + return m_timeoutHandler; +} + + +shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 { + +public: + + POP3Connection( + const shared_ptr & store, + const shared_ptr & auth + ); + + virtual ~POP3Connection(); + + + virtual void connect(); + virtual bool isConnected() const; + virtual void disconnect(); + + bool isSecuredConnection() const; + shared_ptr getConnectionInfos() const; + + virtual shared_ptr getStore(); + virtual shared_ptr getSocket(); + virtual shared_ptr getTimeoutHandler(); + virtual shared_ptr getAuthenticator(); + virtual shared_ptr getSession(); + virtual shared_ptr 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 getCapabilities(); + + void internalDisconnect(); + + + weak_ptr m_store; + + shared_ptr m_auth; + shared_ptr m_socket; + shared_ptr m_timeoutHandler; + shared_ptr m_tracer; + + bool m_authenticated; + bool m_secured; + + shared_ptr m_cntInfos; + + std::vector 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 & 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 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 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 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 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 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 POP3Folder::getMessage(const size_t num) { + + shared_ptr 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 (dynamicCast (shared_from_this()), num); +} + + +std::vector > POP3Folder::getMessages(const messageSet& msgs) { + + shared_ptr 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 numbers = POP3Utils::messageSetToNumberList(msgs, m_messageCount); + + std::vector > messages; + shared_ptr thisFolder(dynamicCast (shared_from_this())); + + for (std::vector ::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 (thisFolder, *it)); + } + + return messages; + + } else { + + throw exceptions::operation_not_supported(); + } +} + + +size_t POP3Folder::getMessageCount() { + + shared_ptr 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 POP3Folder::getFolder(const folder::path::component& name) { + + shared_ptr store = m_store.lock(); + + if (!store) { + throw exceptions::illegal_state("Store disconnected"); + } + + return shared_ptr (new POP3Folder(m_path / name, store)); +} + + +std::vector > POP3Folder::getFolders(const bool /* recursive */) { + + shared_ptr store = m_store.lock(); + + if (!store) { + throw exceptions::illegal_state("Store disconnected"); + } + + if (m_path.isEmpty()) { + + std::vector > v; + v.push_back(shared_ptr (new POP3Folder(folder::path::component("INBOX"), store))); + return v; + + } else { + + std::vector > v; + return v; + } +} + + +void POP3Folder::fetchMessages( + std::vector >& msg, + const fetchAttributes& options, + utility::progressListener* progress +) { + + shared_ptr 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 >::iterator it = msg.begin() ; + it != msg.end() ; ++it) { + + dynamicCast (*it)->fetch( + dynamicCast (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 response = + POP3Response::readMultilineResponse(store->getConnection()); + + if (response->isSuccess()) { + + // C: LIST + // S: +OK + // S: 1 47548 + // S: 2 12653 + // S: . + std::map result; + POP3Utils::parseMultiListOrUidlResponse(response, result); + + for (std::vector >::iterator it = msg.begin() ; + it != msg.end() ; ++it) { + + shared_ptr m = dynamicCast (*it); + + std::map ::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 response = + POP3Response::readMultilineResponse(store->getConnection()); + + if (response->isSuccess()) { + + // C: UIDL + // S: +OK + // S: 1 whqtswO00WBw418f9t5JxYwZ + // S: 2 QhdPYR:00WBw1Ph7x7 + // S: . + std::map result; + POP3Utils::parseMultiListOrUidlResponse(response, result); + + for (std::vector >::iterator it = msg.begin() ; + it != msg.end() ; ++it) { + + shared_ptr m = dynamicCast (*it); + + std::map ::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 & msg, const fetchAttributes& options) { + + shared_ptr store = m_store.lock(); + + if (!store) { + throw exceptions::illegal_state("Store disconnected"); + } else if (!isOpen()) { + throw exceptions::illegal_state("Folder not open"); + } + + dynamicCast (msg)->fetch( + dynamicCast (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 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 (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 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 (msg)->m_uid = string(it, responseText.end()); + } + } + } +} + + +std::vector > POP3Folder::getAndFetchMessages( + const messageSet& msgs, + const fetchAttributes& attribs +) { + + if (msgs.isEmpty()) { + return std::vector >(); + } + + std::vector > 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 POP3Folder::getParent() { + + if (m_path.isEmpty()) { + return null; + } else { + return shared_ptr (new POP3Folder(m_path.getParent(), m_store.lock())); + } +} + + +shared_ptr POP3Folder::getStore() const { + + return m_store.lock(); +} + + +shared_ptr 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 store = m_store.lock(); + + const std::vector 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 ::const_iterator + it = nums.begin() ; it != nums.end() ; ++it) { + + POP3Command::DELE(*it)->send(store->getConnection()); + + shared_ptr response = + POP3Response::readResponse(store->getConnection()); + + if (!response->isSuccess()) { + throw exceptions::command_error("DELE", response->getFirstLine()); + } + } + + // Sort message list + std::vector 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 ::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 event = + make_shared ( + dynamicCast (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 & /* 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 status = getStatus(); + + count = status->getMessageCount(); + unseen = status->getUnseenCount(); + + m_messageCount = count; +} + + +shared_ptr POP3Folder::getStatus() { + + shared_ptr store = m_store.lock(); + + if (!store) { + throw exceptions::illegal_state("Store disconnected"); + } + + POP3Command::STAT()->send(store->getConnection()); + + shared_ptr 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 status = make_shared (); + + 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 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 event = + make_shared ( + dynamicCast (shared_from_this()), + events::messageCountEvent::TYPE_ADDED, + nums + ); + + notifyMessageCount(event); + + // Notify folders with the same path + for (std::list ::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 event = + make_shared ( + dynamicCast ((*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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +#include + +#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 & 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 getMessage(const size_t num); + std::vector > getMessages(const messageSet& msgs); + + size_t getMessageCount(); + + shared_ptr getFolder(const folder::path::component& name); + std::vector > 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 & 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 getStatus(); + + void expunge(); + + shared_ptr getParent(); + + shared_ptr getStore() const; + shared_ptr getStore(); + + + void fetchMessages( + std::vector >& msg, + const fetchAttributes& options, + utility::progressListener* progress = NULL + ); + + void fetchMessage(const shared_ptr & msg, const fetchAttributes& options); + + std::vector > getAndFetchMessages( + const messageSet& msgs, + const fetchAttributes& attribs + ); + + int getFetchCapabilities() const; + + std::vector getMessageNumbersStartingOnUID(const message::uid& uid); + +private: + + void registerMessage(POP3Message* msg); + void unregisterMessage(POP3Message* msg); + + void onStoreDisconnected(); + + void onClose(); + + + weak_ptr m_store; + + folder::path m_path; + folder::path::component m_name; + + int m_mode; + bool m_open; + + size_t m_messageCount; + + typedef std::map 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 POP3FolderStatus::clone() const { + + return make_shared (*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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 + + +namespace vmime { +namespace net { +namespace pop3 { + + +POP3Message::POP3Message( + const shared_ptr & 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 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 (-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 POP3Message::getStructure() const { + + throw exceptions::operation_not_supported(); +} + + +shared_ptr POP3Message::getStructure() { + + throw exceptions::operation_not_supported(); +} + + +shared_ptr 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 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 (-1)) { + throw exceptions::partial_fetch_not_supported(); + } + + // Emit the "RETR" command + shared_ptr store = folder->m_store.lock(); + + POP3Command::RETR(m_num)->send(store->getConnection()); + + try { + + POP3Response::readLargeResponse( + store->getConnection(), os, progress, + m_size == static_cast (-1) ? 0 : m_size + ); + + } catch (exceptions::command_error& e) { + + throw exceptions::command_error("RETR", e.response()); + } +} + + +void POP3Message::extractPart( + const shared_ptr & /* 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 & /* p */) { + + throw exceptions::operation_not_supported(); +} + + +void POP3Message::fetch( + const shared_ptr & msgFolder, + const fetchAttributes& options +) { + + shared_ptr 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 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
(); + 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 POP3Message::getParsedMessage() { + + std::ostringstream oss; + utility::outputStreamAdapter os(oss); + + extract(os); + + shared_ptr msg = make_shared (); + 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & folder, const size_t num); + + ~POP3Message(); + + + size_t getNumber() const; + + const uid getUID() const; + + size_t getSize() const; + + bool isExpunged() const; + + shared_ptr getStructure() const; + shared_ptr getStructure(); + + shared_ptr 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 & 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 & p); + + shared_ptr getParsedMessage(); + +private: + + void fetch(const shared_ptr & folder, const fetchAttributes& options); + + void onFolderClosed(); + + weak_ptr m_folder; + size_t m_num; + uid m_uid; + size_t m_size; + + bool m_deleted; + + shared_ptr
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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 & sok, + const shared_ptr & toh, + const shared_ptr & tracer +) + : m_socket(sok), + m_timeoutHandler(toh), + m_tracer(tracer) { + +} + + +// static +shared_ptr POP3Response::readResponse( + const shared_ptr & conn +) { + + shared_ptr resp = shared_ptr ( + 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::readMultilineResponse( + const shared_ptr & conn +) { + + shared_ptr resp = shared_ptr ( + 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::readLargeResponse( + const shared_ptr & conn, + utility::outputStream& os, + utility::progressListener* progress, + const size_t predictedSize +) { + + shared_ptr resp = shared_ptr ( + 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 ((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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 readResponse(const shared_ptr & 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 readMultilineResponse(const shared_ptr & 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 readLargeResponse( + const shared_ptr & 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 & sok, + const shared_ptr & toh, + const shared_ptr & 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 m_socket; + shared_ptr m_timeoutHandler; + shared_ptr m_tracer; + + string m_firstLine; + ResponseCode m_code; + string m_text; + + std::vector 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 & sess, + const shared_ptr & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & sess, + const shared_ptr & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 POP3ServiceInfos::getAvailableProperties() const { + + std::vector 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 + + +namespace vmime { +namespace net { +namespace pop3 { + + +POP3Store::POP3Store( + const shared_ptr & sess, + const shared_ptr & 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 POP3Store::getDefaultFolder() { + + if (!isConnected()) { + throw exceptions::illegal_state("Not connected"); + } + + return shared_ptr ( + new POP3Folder( + folder::path(folder::path::component("INBOX")), + dynamicCast (shared_from_this()) + ) + ); +} + + +shared_ptr POP3Store::getRootFolder() { + + if (!isConnected()) { + throw exceptions::illegal_state("Not connected"); + } + + return shared_ptr ( + new POP3Folder( + folder::path(), + dynamicCast (shared_from_this()) + ) + ); +} + + +shared_ptr POP3Store::getFolder(const folder::path& path) { + + if (!isConnected()) { + throw exceptions::illegal_state("Not connected"); + } + + return shared_ptr ( + new POP3Folder( + path, + dynamicCast (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 ( + dynamicCast (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 POP3Store::getConnectionInfos() const { + + if (!m_connection) { + return null; + } + + return m_connection->getConnectionInfos(); +} + + +shared_ptr POP3Store::getConnection() { + + return m_connection; +} + + +void POP3Store::disconnect() { + + if (!isConnected()) { + throw exceptions::not_connected(); + } + + for (std::list ::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 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 ::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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & sess, + const shared_ptr & auth, + const bool secured = false + ); + + ~POP3Store(); + + const string getProtocolName() const; + + shared_ptr getDefaultFolder(); + shared_ptr getRootFolder(); + shared_ptr 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 getConnectionInfos() const; + shared_ptr getConnection(); + + bool isPOP3S() const; + +private: + + shared_ptr m_connection; + + + void registerFolder(POP3Folder* folder); + void unregisterFolder(POP3Folder* folder); + + std::list 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 + + +namespace vmime { +namespace net { +namespace pop3 { + + +// static +void POP3Utils::parseMultiListOrUidlResponse( + const shared_ptr & response, + std::map & result +) { + + std::map 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 ::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 list; + +private: + + size_t m_msgCount; +}; + + +// static +const std::vector 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 + +#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 & response, + std::map & 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 sendmailServiceInfos::getAvailableProperties() const { + + std::vector 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 (getSession(), \ + dynamic_cast (getInfos()).getProperties().prop)) +#define HAS_PROPERTY(prop) \ + (getInfos().hasProperty(getSession(), \ + dynamic_cast (getInfos()).getProperties().prop)) + + +namespace vmime { +namespace net { +namespace sendmail { + + +sendmailTransport::sendmailTransport( + const shared_ptr & sess, + const shared_ptr & 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 sendmailTransport::getConnectionInfos() const { + + return make_shared ("localhost", static_cast (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 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 & 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & sess, + const shared_ptr & 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 getConnectionInfos() const; + +private: + + void internalDisconnect(); + + void internalSend( + const std::vector & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 & sess, + const serviceInfos& /* infos */, + const shared_ptr & auth +) + : m_session(sess), + m_auth(auth) { + + if (!auth) { + +#if VMIME_HAVE_SASL_SUPPORT + m_auth = make_shared (); +#else + m_auth = make_shared (); +#endif // VMIME_HAVE_SASL_SUPPORT + } + +#if VMIME_HAVE_TLS_SUPPORT + m_certVerifier = make_shared (); +#endif // VMIME_HAVE_TLS_SUPPORT + + m_socketFactory = platform::getHandler()->getSocketFactory(); + + m_toHandlerFactory = make_shared (); +} + + +service::~service() { + +} + + +shared_ptr service::getSession() const { + + return m_session; +} + + +shared_ptr service::getSession() { + + return m_session; +} + + +shared_ptr service::getAuthenticator() const { + + return m_auth; +} + + +shared_ptr service::getAuthenticator() { + + return m_auth; +} + + +void service::setAuthenticator(const shared_ptr & auth) { + + m_auth = auth; +} + + +#if VMIME_HAVE_TLS_SUPPORT + +void service::setCertificateVerifier(const shared_ptr & cv) { + + m_certVerifier = cv; +} + + +shared_ptr service::getCertificateVerifier() { + + return m_certVerifier; +} + +#endif // VMIME_HAVE_TLS_SUPPORT + + +void service::setSocketFactory(const shared_ptr & sf) { + + m_socketFactory = sf; +} + + +shared_ptr service::getSocketFactory() { + + return m_socketFactory; +} + + +void service::setTracerFactory(const shared_ptr & tf) { + + m_tracerFactory = tf; +} + + +shared_ptr service::getTracerFactory() { + + return m_tracerFactory; +} + + +void service::setTimeoutHandlerFactory(const shared_ptr & thf) { + + m_toHandlerFactory = thf; +} + + +shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 { + +protected: + + service( + const shared_ptr & sess, + const serviceInfos& infos, + const shared_ptr & 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 getSession() const; + + /** Return the session object associated with this service instance. + * + * @return session object + */ + shared_ptr 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 getAuthenticator() const; + + /** Return the authenticator object used with this service instance. + * + * @return authenticator object + */ + shared_ptr getAuthenticator(); + + /** Set the authenticator object used with this service instance. + * + * @param auth authenticator object + */ + void setAuthenticator(const shared_ptr & auth); + +#if VMIME_HAVE_TLS_SUPPORT + + /** Set the object responsible for verifying certificates when + * using secured connections (TLS/SSL). + */ + void setCertificateVerifier(const shared_ptr & cv); + + /** Get the object responsible for verifying certificates when + * using secured connections (TLS/SSL). + */ + shared_ptr 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 & sf); + + /** Return the factory used to create socket objects for this + * service. + * + * @return socket factory + */ + shared_ptr 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 & thf); + + /** Return the factory used to create timeoutHandler objects for + * this service. + * + * @return timeoutHandler factory + */ + shared_ptr getTimeoutHandlerFactory(); + + + void setTracerFactory(const shared_ptr & tf); + + shared_ptr 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 + 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 getConnectionInfos() const = 0; + +private: + + shared_ptr m_session; + shared_ptr m_auth; + +#if VMIME_HAVE_TLS_SUPPORT + shared_ptr m_certVerifier; +#endif // VMIME_HAVE_TLS_SUPPORT + + shared_ptr m_socketFactory; + shared_ptr m_toHandlerFactory; + shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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::getInstance() { + + static serviceFactory instance; + return shared_ptr (&instance, noop_shared_ptr_deleter ()); +} + + +shared_ptr serviceFactory::create( + const shared_ptr & sess, + const string& protocol, + const shared_ptr & auth +) { + + shared_ptr rserv = getServiceByProtocol(protocol); + + if (!rserv) { + throw exceptions::no_factory_available("No service is registered for protocol '" + protocol + "'."); + } + + return rserv->create(sess, auth); +} + + +shared_ptr serviceFactory::create( + const shared_ptr & sess, + const utility::url& u, + const shared_ptr & auth +) { + + shared_ptr 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 serviceFactory::getServiceByProtocol(const string& protocol) const { + + const string name(utility::stringUtils::toLower(protocol)); + + for (std::vector >::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 serviceFactory::getServiceAt(const size_t pos) const { + + return m_services[pos]; +} + + +const std::vector > serviceFactory::getServiceList() const { + + std::vector > res; + + for (std::vector >::const_iterator it = m_services.begin() ; + it != m_services.end() ; ++it) { + + res.push_back(*it); + } + + return (res); +} + + +void serviceFactory::registerService(const shared_ptr & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 + +#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 getInstance(); + + /** Information about a registered service. */ + class registeredService : public object { + + friend class serviceFactory; + + protected: + + virtual ~registeredService() { } + + public: + + virtual shared_ptr create( + const shared_ptr & sess, + const shared_ptr & 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 & 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 create( + const shared_ptr & sess, + const string& protocol, + const shared_ptr & 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 create( + const shared_ptr & sess, + const utility::url& u, + const shared_ptr & 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 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 getServiceAt(const size_t pos) const; + + /** Return a list of all registered services. + * + * @return list of registered services + */ + const std::vector > getServiceList() const; + +private: + + std::vector > 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 + +#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 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 + const TYPE getPropertyValue(const shared_ptr & s, const property& p) const { + + if (p.getFlags() & property::FLAG_REQUIRED) { + return s->getProperties()[getPropertyPrefix() + p.getName()].template getValue (); + } + + return s->getProperties().template getProperty ( + getPropertyPrefix() + p.getName(), + propertySet::valueFromString (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 & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 registeredServiceImpl : public serviceFactory::registeredService { + +public: + + registeredServiceImpl( + const string& name, + const int type + ) + : m_type(type), + m_name(name), + m_servInfos(S::getInfosInstance()) { + + } + + shared_ptr create( + const shared_ptr & sess, + const shared_ptr & auth + ) const { + + return make_shared (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 serviceRegisterer { + +public: + + serviceRegisterer(const string& protocol, const service::Type type) { + + serviceFactory::getInstance()->registerService( + make_shared >(protocol, type) + ); + } +}; + + +} // net +} // vmime + + +#define REGISTER_SERVICE(p_class, p_name, p_type) \ + vmime::net::serviceRegisterer \ + 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 (); +#endif // VMIME_HAVE_TLS_SUPPORT + +} + + +session::session(const propertySet& props) + : m_props(props) { + +#if VMIME_HAVE_TLS_SUPPORT + m_tlsProps = make_shared (); +#endif // VMIME_HAVE_TLS_SUPPORT + +} + + +session::~session() { + +} + + +// static +shared_ptr session::create() { + + return shared_ptr (new session()); +} + + +// static +shared_ptr session::create(const propertySet& props) { + + return shared_ptr (new session(props)); +} + + +shared_ptr session::getTransport(const shared_ptr & auth) { + + return getTransport(m_props["transport.protocol"], auth); +} + + +shared_ptr session::getTransport( + const string& protocol, + const shared_ptr & auth +) { + + shared_ptr sess(dynamicCast (shared_from_this())); + shared_ptr sv = serviceFactory::getInstance()->create(sess, protocol, auth); + + if (!sv || sv->getType() != service::TYPE_TRANSPORT) { + return null; + } + + return dynamicCast (sv); +} + + +shared_ptr session::getTransport( + const utility::url& url, + const shared_ptr & auth +) { + + shared_ptr sess(dynamicCast (shared_from_this())); + shared_ptr sv = serviceFactory::getInstance()->create(sess, url, auth); + + if (!sv || sv->getType() != service::TYPE_TRANSPORT) { + return null; + } + + return dynamicCast (sv); +} + + +shared_ptr session::getStore(const shared_ptr & auth) { + + return getStore(m_props["store.protocol"], auth); +} + + +shared_ptr session::getStore( + const string& protocol, + const shared_ptr & auth +) { + + shared_ptr sess(dynamicCast (shared_from_this())); + shared_ptr sv = serviceFactory::getInstance()->create(sess, protocol, auth); + + if (!sv || sv->getType() != service::TYPE_STORE) { + return null; + } + + return dynamicCast (sv); +} + + +shared_ptr session::getStore( + const utility::url& url, + const shared_ptr & auth +) { + + shared_ptr sess(dynamicCast (shared_from_this())); + shared_ptr sv = serviceFactory::getInstance()->create(sess, url, auth); + + if (!sv || sv->getType() != service::TYPE_STORE) { + return null; + } + + return dynamicCast (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 & tlsProps) { + + m_tlsProps = make_shared (*tlsProps); +} + + +shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 { + +public: + + /** Construct a new session. + * + * @return pointer to a new session + */ + static shared_ptr create(); + + /** Construct a new session given properties. + * + * @param props session properties + * @return pointer to a new session + */ + static shared_ptr 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 getTransport( + const shared_ptr & 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 getTransport( + const string& protocol, + const shared_ptr & 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 getTransport( + const utility::url& url, + const shared_ptr & 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 getStore( + const shared_ptr & 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 getStore( + const string& protocol, + const shared_ptr & 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 getStore( + const utility::url& url, + const shared_ptr & 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 & tlsProps); + + /** Get properties for SSL/TLS secured connections in this session. + * + * @return SSL/TLS properties + */ + shared_ptr getTLSProperties() const; + +#endif // VMIME_HAVE_TLS_SUPPORT + +private: + + session(); + session(const propertySet& props); + + + propertySet m_props; + +#if VMIME_HAVE_TLS_SUPPORT + shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 + + +namespace vmime { +namespace net { +namespace smtp { + + +SMTPChunkingOutputStreamAdapter::SMTPChunkingOutputStreamAdapter( + const shared_ptr & 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 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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::EHLO(const string& hostname) { + + std::ostringstream cmd; + cmd.imbue(std::locale::classic()); + cmd << "EHLO " << hostname; + + return createCommand(cmd.str()); +} + + +// static +shared_ptr SMTPCommand::HELO(const string& hostname) { + + std::ostringstream cmd; + cmd.imbue(std::locale::classic()); + cmd << "HELO " << hostname; + + return createCommand(cmd.str()); +} + + +// static +shared_ptr SMTPCommand::AUTH(const string& mechName) { + + std::ostringstream cmd; + cmd.imbue(std::locale::classic()); + cmd << "AUTH " << mechName; + + return createCommand(cmd.str()); +} + + +// static +shared_ptr 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::STARTTLS() { + + return createCommand("STARTTLS"); +} + + +// static +shared_ptr 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::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::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::RSET() { + + return createCommand("RSET"); +} + + +// static +shared_ptr SMTPCommand::DATA() { + + return createCommand("DATA"); +} + + +// static +shared_ptr 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::NOOP() { + + return createCommand("NOOP"); +} + + +// static +shared_ptr SMTPCommand::QUIT() { + + return createCommand("QUIT"); +} + + +// static +shared_ptr SMTPCommand::createCommand(const string& text, const string& traceText) { + + if (traceText.empty()) { + return shared_ptr (new SMTPCommand(text, text)); + } else { + return shared_ptr (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 & sok, shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 HELO(const string& hostname); + static shared_ptr EHLO(const string& hostname); + static shared_ptr AUTH(const string& mechName); + static shared_ptr AUTH(const string& mechName, const std::string& initialResponse); + static shared_ptr STARTTLS(); + static shared_ptr MAIL(const mailbox& mbox, const bool utf8, + const std::string& dsnRet, const std::string& dsnEnvelopId); + static shared_ptr MAIL(const mailbox& mbox, const bool utf8, const size_t size, + const std::string& dsnRet, const std::string& dsnEnvelopId); + static shared_ptr RCPT(const mailbox& mbox, const bool utf8, + const std::string& dsnNotify); + static shared_ptr RSET(); + static shared_ptr DATA(); + static shared_ptr BDAT(const size_t chunkSize, const bool last); + static shared_ptr NOOP(); + static shared_ptr QUIT(); + + /** Creates a new SMTP command with the specified text. + * + * @param text command text + * @return a new SMTPCommand object + */ + static shared_ptr 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 & sok, shared_ptr tr); + + /** Returns the full text of the command, including command name + * and parameters (if any). + * + * @return command text (eg. "RCPT TO:") + */ + 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 + + +namespace vmime { +namespace net { +namespace smtp { + + +SMTPCommandSet::SMTPCommandSet(const bool pipeline) + : SMTPCommand("", ""), + m_pipeline(pipeline), + m_started(false), + m_lastCommandSent() { + +} + + +// static +shared_ptr SMTPCommandSet::create(const bool pipeline) { + + return shared_ptr (new SMTPCommandSet(pipeline)); +} + + +void SMTPCommandSet::addCommand(const shared_ptr & 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 & sok, const shared_ptr & tr) { + + if (m_pipeline) { + + if (!m_started) { + + // Send all commands at once + for (std::list >::const_iterator it = m_commands.begin() ; + it != m_commands.end() ; ++it) { + + shared_ptr cmd = *it; + cmd->writeToSocket(sok, tr); + } + } + + if (!m_commands.empty()) { + + // Advance the pointer to last command sent + shared_ptr cmd = m_commands.front(); + m_commands.pop_front(); + + m_lastCommandSent = cmd; + } + + } else { + + if (!m_commands.empty()) { + + // Send only one command + shared_ptr 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 >::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 >::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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 + +#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 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 & 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 getLastCommandSent() const; + + + void writeToSocket(const shared_ptr & sok, const shared_ptr & 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 > m_commands; + shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 (getSession(), \ + dynamic_cast (m_transport.lock()->getInfos()).getProperties().prop)) +#define HAS_PROPERTY(prop) \ + (m_transport.lock()->getInfos().hasProperty(getSession(), \ + dynamic_cast (m_transport.lock()->getInfos()).getProperties().prop)) + + +namespace vmime { +namespace net { +namespace smtp { + + + +SMTPConnection::SMTPConnection( + const shared_ptr & transport, + const shared_ptr & 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 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 tlsSession = tls::TLSSession::create( + transport->getCertificateVerifier(), + transport->getSession()->getTLSProperties() + ); + + shared_ptr tlsSocket = tlsSession->getSocket(m_socket); + + m_socket = tlsSocket; + + m_secured = true; + m_cntInfos = make_shared (address, port, tlsSession, tlsSocket); + + } else +#endif // VMIME_HAVE_TLS_SUPPORT + { + m_cntInfos = make_shared (address, port); + } + + m_socket->connect(address, port); + + // Connection + // + // eg: C: + // --- S: 220 smtp.domain.com Service ready + + shared_ptr 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 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 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 * params +) const { + + std::map >::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 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 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 (getAuthenticator())) { + throw exceptions::authentication_error("No SASL authenticator available."); + } + + // Obtain SASL mechanisms supported by server from ESMTP extensions + std::vector saslMechs; + hasExtension("AUTH", &saslMechs); + + if (saslMechs.empty()) { + throw exceptions::authentication_error("No SASL mechanism available."); + } + + std::vector > mechList; + + shared_ptr 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 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 (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 mech = mechList[i]; + + shared_ptr 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 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 resp = readResponse(); + + if (resp->getCode() != 220) { + + throw SMTPCommandError( + "STARTTLS", resp->getText(), resp->getCode(), resp->getEnhancedCode() + ); + } + + shared_ptr tlsSession = tls::TLSSession::create( + getTransport()->getCertificateVerifier(), + getTransport()->getSession()->getTLSProperties() + ); + + shared_ptr tlsSocket = tlsSession->getSocket(m_socket); + + tlsSocket->handshake(); + + m_socket = tlsSocket; + + m_secured = true; + m_cntInfos = make_shared ( + 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 & cmd) { + + cmd->writeToSocket(m_socket, m_tracer); +} + + +shared_ptr SMTPConnection::readResponse() { + + shared_ptr 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 SMTPConnection::getConnectionInfos() const { + + return m_cntInfos; +} + + +shared_ptr SMTPConnection::getTransport() { + + return m_transport.lock(); +} + + +shared_ptr SMTPConnection::getSession() { + + return m_transport.lock()->getSession(); +} + + +shared_ptr SMTPConnection::getSocket() { + + return m_socket; +} + + +shared_ptr SMTPConnection::getTracer() { + + return m_tracer; +} + + +shared_ptr SMTPConnection::getTimeoutHandler() { + + return m_timeoutHandler; +} + + +shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & transport, + const shared_ptr & auth + ); + + ~SMTPConnection(); + + + virtual void connect(); + virtual bool isConnected() const; + virtual void disconnect(); + + bool isSecuredConnection() const; + shared_ptr getConnectionInfos() const; + + virtual shared_ptr getTransport(); + virtual shared_ptr getSocket(); + virtual shared_ptr getTimeoutHandler(); + virtual shared_ptr getAuthenticator(); + virtual shared_ptr getSession(); + virtual shared_ptr getTracer(); + + void sendRequest(const shared_ptr & cmd); + shared_ptr readResponse(); + + bool hasExtension(const std::string& extName, std::vector * 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 m_transport; + + shared_ptr m_auth; + shared_ptr m_socket; + shared_ptr m_timeoutHandler; + shared_ptr m_tracer; + + SMTPResponse::state m_responseState; + + bool m_authenticated; + bool m_secured; + + shared_ptr m_cntInfos; + + bool m_extendedSMTP; + std::map > 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 + + +namespace vmime { +namespace net { +namespace smtp { + + +SMTPResponse::SMTPResponse( + const shared_ptr & tr, + const shared_ptr & sok, + const shared_ptr & 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::readResponse( + const shared_ptr & tr, + const shared_ptr & sok, + const shared_ptr & toh, + const state& st +) { + + shared_ptr resp = + shared_ptr (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 readResponse( + const shared_ptr & tr, + const shared_ptr & sok, + const shared_ptr & 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 & tr, + const shared_ptr & sok, + const shared_ptr & 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 m_lines; + + shared_ptr m_socket; + shared_ptr m_timeoutHandler; + shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 & sess, + const shared_ptr & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & sess, + const shared_ptr & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 SMTPServiceInfos::getAvailableProperties() const { + + std::vector 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 & sess, + const shared_ptr & 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 ( + dynamicCast (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 SMTPTransport::getConnectionInfos() const { + + if (!m_connection) { + return null; + } + + return m_connection->getConnectionInfos(); +} + + +shared_ptr 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 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 (getSession(), + dynamic_cast (getInfos()).getProperties().PROPERTY_OPTIONS_PIPELINING); + + shared_ptr resp; + shared_ptr 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 resp; + + if ((resp = m_connection->readResponse())->getCode() != 250) { + throw SMTPCommandError("DATA", resp->getText(), resp->getCode(), resp->getEnhancedCode()); + } +} + + +void SMTPTransport::send( + const shared_ptr & 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 (getSession(), + dynamic_cast (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & sess, + const shared_ptr & 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 & msg, + const mailbox& expeditor, + const mailboxList& recipients, + utility::progressListener* progress = NULL, + const mailbox& sender = mailbox(), + const dsnAttributes& dsnAttrs = dsnAttributes() + ); + + bool isSecuredConnection() const; + shared_ptr getConnectionInfos() const; + shared_ptr 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 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) = 0; + + /** Return the tracer used by this socket. + * + * @return tracer, or NULL if none is set + */ + virtual shared_ptr 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 create() = 0; + + /** Creates a socket with the specified timeout handler. + * + * @param th timeout handler + * @return a new socket + */ + virtual shared_ptr create(const shared_ptr & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 & sess, + const serviceInfos& infos, + const shared_ptr & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & sess, + const serviceInfos& infos, + const shared_ptr & auth + ); + +public: + + /** Return the default folder. This is protocol dependent + * and usually is the INBOX folder. + * + * @return default folder + */ + virtual shared_ptr 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 getRootFolder() = 0; + + /** Return the folder specified by the path. + * + * @param path absolute folder path + * @return folder at the specified path + */ + virtual shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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, + const shared_ptr & 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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, + const shared_ptr & 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 getPeerCertificates() const; + +private: + + string m_host; + port_t m_port; + + shared_ptr m_tlsSession; + shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 { + +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 create( + const shared_ptr & cv, + const shared_ptr & 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 getSocket(const shared_ptr & sok) = 0; + + /** Get the object responsible for verifying certificates when + * using secured connections (TLS/SSL). + */ + virtual shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 wrap(const shared_ptr & session, const shared_ptr & 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +#if GNUTLS_VERSION_NUMBER < 0x030000 +#include +#endif + + +namespace vmime { +namespace net { +namespace tls { + + +TLSProperties::TLSProperties() + : m_data(make_shared ()) { + + setCipherSuite(CIPHERSUITE_DEFAULT); +} + + +TLSProperties::TLSProperties(const TLSProperties& props) + : object(), + m_data(make_shared ()) { + + *dynamicCast (m_data) = *dynamicCast (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 (m_data)->cipherSuite = cipherSuite; +} + + +const string TLSProperties::getCipherSuite() const { + + return dynamicCast (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +#if GNUTLS_VERSION_NUMBER < 0x030000 +#include +#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 +# if VMIME_GNUTLS_NEEDS_GCRYPT +# include +# endif +# include +#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 +#include + +#if VMIME_DEBUG && GNUTLS_DEBUG + #include +#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::create( + const shared_ptr & cv, + const shared_ptr & props +) { + + return make_shared (cv, props); +} + + +TLSSession_GnuTLS::TLSSession_GnuTLS( + const shared_ptr & cv, + const shared_ptr & 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 TLSSession_GnuTLS::getSocket(const shared_ptr & sok) { + + return TLSSocket::wrap(dynamicCast (shared_from_this()), sok); +} + + +shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & cv, + const shared_ptr & props + ); + + ~TLSSession_GnuTLS(); + + + shared_ptr getSocket(const shared_ptr & sok); + + shared_ptr 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 m_certVerifier; + shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +#include + +#include + +#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 + + +namespace vmime { +namespace net { +namespace tls { + + +// static +shared_ptr TLSSocket::wrap( + const shared_ptr & session, + const shared_ptr & sok +) +{ + return make_shared (dynamicCast (session), sok); +} + + +TLSSocket_GnuTLS::TLSSocket_GnuTLS( + const shared_ptr & session, + const shared_ptr & 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 TLSSocket_GnuTLS::getTimeoutHandler() { + + return m_wrapped->getTimeoutHandler(); +} + + +void TLSSocket_GnuTLS::setTracer(const shared_ptr & tracer) { + + m_wrapped->setTracer(tracer); +} + + +shared_ptr 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 (buffer.data()), buffer.length()); +} + + +void TLSSocket_GnuTLS::send(const char* str) { + + sendRaw(reinterpret_cast (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 (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 (ret)); + } + + return static_cast (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) + ); + + 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 (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 (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 (ret)); + } + + return static_cast (ret); +} + + +unsigned int TLSSocket_GnuTLS::getStatus() const { + + return m_status | m_wrapped->getStatus(); +} + + +void TLSSocket_GnuTLS::handshake() { + + shared_ptr 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 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 (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 (trspt); + + try { + + const ssize_t ret = static_cast ( + sok->m_wrapped->sendRawNonBlocking(reinterpret_cast (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 (trspt); + + try { + + const ssize_t n = static_cast ( + sok->m_wrapped->receiveRaw(reinterpret_cast (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 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 > 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 data(dataSize); + + gnutls_x509_crt_export(x509Certs[i], GNUTLS_X509_FMT_DER, &data[0], &dataSize); + + shared_ptr 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 (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & session, const shared_ptr & sok); + ~TLSSocket_GnuTLS(); + + + void handshake(); + + shared_ptr 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 getTimeoutHandler(); + + void setTracer(const shared_ptr & tracer); + shared_ptr 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 m_session; + shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 + +#if OPENSSL_VERSION_NUMBER >= 0x10100000L +# define OPENSSL_API_COMPAT 0x10100000L +#endif + +#include +#include +#include +#include + +#if OPENSSL_VERSION_NUMBER >= 0x0907000L +# include +#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 * 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 [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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 + + +#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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +#include + + +namespace vmime { +namespace net { +namespace tls { + + +TLSProperties::TLSProperties() + : m_data(make_shared ()) { + + setCipherSuite(CIPHERSUITE_DEFAULT); +} + + +TLSProperties::TLSProperties(const TLSProperties& props) + : object(), + m_data(make_shared ()) { + + *dynamicCast (m_data) = *dynamicCast (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 (m_data)->cipherSuite = cipherSuite; +} + + +const string TLSProperties::getCipherSuite() const { + + return dynamicCast (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +#include + + +namespace vmime { +namespace net { +namespace tls { + + +static OpenSSLInitializer::autoInitializer openSSLInitializer; + + +// static +shared_ptr TLSSession::create( + const shared_ptr & cv, + const shared_ptr & props +) { + + return make_shared (cv, props); +} + + +TLSSession_OpenSSL::TLSSession_OpenSSL( + const shared_ptr & cv, + const shared_ptr & 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 TLSSession_OpenSSL::getSocket(const shared_ptr & sok) { + + return TLSSocket::wrap(dynamicCast (shared_from_this()), sok); +} + + +shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 + + +namespace vmime { +namespace net { +namespace tls { + + +class TLSSession_OpenSSL : public TLSSession { + + friend class TLSSocket_OpenSSL; + +public: + + TLSSession_OpenSSL( + const shared_ptr & cv, + const shared_ptr & props + ); + + ~TLSSession_OpenSSL(); + + + shared_ptr getSocket(const shared_ptr & sok); + + shared_ptr 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 m_certVerifier; + shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +#include + +#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 +#include + + +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::wrap( + const shared_ptr & session, + const shared_ptr & sok +) { + + return make_shared (dynamicCast (session), sok); +} + + +TLSSocket_OpenSSL::TLSSocket_OpenSSL( + const shared_ptr & session, + const shared_ptr & 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 TLSSocket_OpenSSL::getTimeoutHandler() { + + return m_wrapped->getTimeoutHandler(); +} + + +void TLSSocket_OpenSSL::setTracer(const shared_ptr & tracer) { + + m_wrapped->setTracer(tracer); +} + + +shared_ptr 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 (buffer.data()), buffer.length()); +} + + +void TLSSocket_OpenSSL::send(const char* str) { + + sendRaw(reinterpret_cast (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 (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 (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 (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 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 certs = getPeerCertificates(); + + if (!certs) { + throw exceptions::tls_exception("No peer certificate."); + } + + m_session->getCertificateVerifier()->verify(certs, getPeerName()); + + m_connected = true; +} + + +shared_ptr 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 > certs; + + for (int i = 0; i < certCount && !error; i++) { + + shared_ptr 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 (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 (BIO_get_data(bio)); + + if (!BIO_get_init(bio) || !sok) { + return -1; + } + + try { + + const size_t n = sok->m_wrapped->sendRawNonBlocking( + reinterpret_cast (buf), len + ); + + if (n == 0 && sok->m_wrapped->getStatus() & socket::STATUS_WOULDBLOCK) { + BIO_set_retry_write(bio); + return -1; + } + + return static_cast (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 (BIO_get_data(bio)); + + if (!BIO_get_init(bio) || !sok) { + return -1; + } + + try { + + const size_t n = sok->m_wrapped->receiveRaw( + reinterpret_cast (buf), len + ); + + if (n == 0 || sok->m_wrapped->getStatus() & socket::STATUS_WOULDBLOCK) { + BIO_set_retry_read(bio); + return -1; + } + + return static_cast (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 (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 (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 + +#include + + +namespace vmime { +namespace net { +namespace tls { + + +class TLSSession; +class TLSSession_OpenSSL; + + +class TLSSocket_OpenSSL : public TLSSocket { + +public: + + TLSSocket_OpenSSL( + const shared_ptr & session, + const shared_ptr & sok + ); + + ~TLSSocket_OpenSSL(); + + + void handshake(); + + shared_ptr 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 getTimeoutHandler(); + + void setTracer(const shared_ptr & tracer); + shared_ptr 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 m_session; + + shared_ptr 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 + + +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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 create(const shared_ptr & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 & sess, + const serviceInfos& infos, + const shared_ptr & auth +) + : service(sess, infos, auth) { + +} + + +shared_ptr transport::processHeaderField(const shared_ptr & 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) { + + if (header->getFieldCount() == 0) { + return; + } + + // Remove/replace fields + for (size_t idx = header->getFieldCount() ; idx != 0 ; --idx) { + + shared_ptr field = header->getFieldAt(idx - 1); + shared_ptr 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 mbox = dynamicCast (list.getAddressAt(i)->clone()); + + if (mbox) { + recipients.appendMailbox(mbox); + } + } +} + + +void transport::send( + const shared_ptr & msg, + utility::progressListener* progress, + const dsnAttributes& dsnAttrs +) { + + // Extract expeditor + shared_ptr fromMbox = + msg->getHeader()->findFieldValue (fields::FROM); + + if (!fromMbox) { + throw exceptions::no_expeditor(); + } + + mailbox expeditor = *fromMbox; + + // Extract sender + shared_ptr senderMbox = + msg->getHeader()->findFieldValue (fields::SENDER); + + mailbox sender; + + if (!senderMbox) { + sender = expeditor; + } else { + sender = *senderMbox; + } + + // Extract recipients + mailboxList recipients; + + // -- "To" field + shared_ptr addresses = + msg->getHeader()->findFieldValue (fields::TO); + + if (addresses) { + extractMailboxes(recipients, *addresses); + } + + // -- "Cc" field + addresses = msg->getHeader()->findFieldValue (fields::CC); + + if (addresses) { + extractMailboxes(recipients, *addresses); + } + + // -- "Bcc" field + addresses = msg->getHeader()->findFieldValue (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
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 & _msg, + const shared_ptr & _hdr + ) + : msg(_msg), + hdr(msg->getHeader()) { + + // Set new header + msg->setHeader(_hdr); + } + + ~XChangeMsgHeader() { + + // Revert original header + msg->setHeader(hdr); + } + + private: + + shared_ptr msg; + shared_ptr hdr; + + } headerExchanger(msg, hdr); + + send(msg, expeditor, recipients, progress, sender, dsnAttrs); +} + + +void transport::send( + const shared_ptr & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & sess, + const serviceInfos& infos, + const shared_ptr & 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 & 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 & 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 processHeaderField(const shared_ptr & 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); +}; + + +} // 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 ()) { + +} + + +parameter::parameter(const string& name, const word& value) + : m_name(name), + m_value(make_shared (value)) { + +} + + +parameter::parameter(const string& name, const string& value) + : m_name(name), + m_value(make_shared (value)) { + +} + + +parameter::parameter(const parameter&) + : component() { + +} + + +shared_ptr parameter::clone() const { + + shared_ptr p = make_shared (m_name); + p->copyFrom(*this); + + return (p); +} + + +void parameter::copyFrom(const component& other) { + + const parameter& param = dynamic_cast (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 & chunks +) { + + bool foundCharsetChunk = false; + + charset ch(charsets::US_ASCII); + string lang; + + std::ostringstream value; + value.imbue(std::locale::classic()); + + for (std::vector ::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 (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 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 (c) / 16; + const int h2 = static_cast (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 > parameter::getChildComponents() { + + std::vector > 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 clone() const; + void copyFrom(const component& other); + parameter& operator=(const parameter& other); + + size_t getGeneratedSize(const generationContext& ctx); + + const std::vector > 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: + * + *
+	  *    getParameter("creation-date")->getValueAs ()
+	  * 
+ * + * is equivalent to: + * + *
+	  *    shared_ptr  rawValue = getParameter("creation-date");
+	  *
+	  *    vmime::dateTime theDate;
+	  *    theDate.parse(rawValue->getBuffer());
+	  * 
+ * + * @param T type to which convert the value + * @return value + */ + template + 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 & chunks + ); + + + string m_name; + shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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* + + tspecials := "(" / ")" / "<" / ">" / "@" + / "," / ";" / ":" / "\" / <"> + / "/" / "[" / "]" / "?" / "=" + ; Must be in quoted-string, + ; to use within parameter values +*/ + + +#ifndef VMIME_BUILDING_DOC + +struct paramInfo { + + bool extended; + std::vector 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 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 ::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 ::value_type(name, info)); + } + } + + // Skip white-spaces after this parameter + while (p < pend && parserHelpers::isSpace(*p)) ++p; + } + } + + for (std::map ::const_iterator it = params.begin() ; + it != params.end() ; ++it) { + + const paramInfo& info = (*it).second; + + // Append this parameter to the list + shared_ptr param = make_shared ((*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 >::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 >::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(other); + + removeAllParameters(); + + for (std::vector >::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 >::const_iterator pos = m_params.begin(); + const std::vector >::const_iterator end = m_params.end(); + + for ( ; pos != end && utility::stringUtils::toLower((*pos)->getName()) != name ; ++pos) {} + + return pos != end; +} + + +shared_ptr parameterizedHeaderField::findParameter(const string& paramName) const { + + const string name = utility::stringUtils::toLower(paramName); + + // Find the first parameter that matches the specified name + std::vector >::const_iterator pos = m_params.begin(); + const std::vector >::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 parameterizedHeaderField::getParameter(const string& paramName) { + + const string name = utility::stringUtils::toLower(paramName); + + // Find the first parameter that matches the specified name + std::vector >::const_iterator pos = m_params.begin(); + const std::vector >::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 param = make_shared (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 & param) { + + m_params.push_back(param); +} + + +void parameterizedHeaderField::insertParameterBefore( + const shared_ptr & beforeParam, + const shared_ptr & param +) { + + const std::vector >::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 & 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 & afterParam, + const shared_ptr & param +) { + + const std::vector >::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 & 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 & param) { + + const std::vector >::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 >::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 parameterizedHeaderField::getParameterAt(const size_t pos) { + + return m_params[pos]; +} + + +const shared_ptr parameterizedHeaderField::getParameterAt(const size_t pos) const { + + return m_params[pos]; +} + + +const std::vector > parameterizedHeaderField::getParameterList() const { + + std::vector > list; + + list.reserve(m_params.size()); + + for (std::vector >::const_iterator it = m_params.begin() ; + it != m_params.end() ; ++it) { + + list.push_back(*it); + } + + return list; +} + + +const std::vector > parameterizedHeaderField::getParameterList() { + + return m_params; +} + + +const std::vector > parameterizedHeaderField::getChildComponents() { + + std::vector > list = headerField::getChildComponents(); + + for (std::vector >::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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 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 getParameter(const string& paramName); + + /** Add a parameter at the end of the list. + * + * @param param parameter to append + */ + void appendParameter(const shared_ptr & 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 & beforeParam, + const shared_ptr & 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 & 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 & afterParam, + const shared_ptr & 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 & 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 & 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 getParameterAt(const size_t pos); + + /** Return the parameter at the specified position. + * + * @param pos position + * @return parameter at position 'pos' + */ + const shared_ptr getParameterAt(const size_t pos) const; + + /** Return the parameter list. + * + * @return list of parameters + */ + const std::vector > getParameterList() const; + + /** Return the parameter list. + * + * @return list of parameters + */ + const std::vector > getParameterList(); + + size_t getGeneratedSize(const generationContext& ctx); + + const std::vector > getChildComponents(); + +private: + + std::vector > 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 & 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 parsedMessageAttachment::getData() const { + + if (!m_data) { + + std::ostringstream oss; + utility::outputStreamAdapter os(oss); + + m_msg->generate(os); + + m_data = make_shared (oss.str()); + } + + return m_data; +} + + +const encoding parsedMessageAttachment::getEncoding() const { + + return encoding(encodingTypes::EIGHT_BIT); // not important +} + + +shared_ptr parsedMessageAttachment::getPart() const { + + return null; +} + + +shared_ptr parsedMessageAttachment::getHeader() const { + + return null; +} + + +shared_ptr parsedMessageAttachment::getMessage() const { + + return m_msg; +} + + +void parsedMessageAttachment::generateIn(const shared_ptr & parent) const { + + // Create and append a new part for this attachment + shared_ptr part = make_shared (); + 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & msg); + + const mediaType getType() const; + const text getDescription() const; + const word getName() const; + + const shared_ptr getData() const; + + const encoding getEncoding() const; + + shared_ptr getPart() const; + + shared_ptr getHeader() const; + + shared_ptr getMessage() const; + +protected: + + void generateIn(const shared_ptr & parent) const; + +private: + + shared_ptr m_msg; + mutable shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 + + + +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 (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 (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 (other); + + m_localPart = p.m_localPart; + m_domain = p.m_domain; +} + + +shared_ptr path::clone() const { + + return make_shared (*this); +} + + +path& path::operator=(const path& other) { + + copyFrom(other); + return *this; +} + + +const std::vector > path::getChildComponents() { + + return std::vector >(); +} + + +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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 clone() const; + path& operator=(const path& other); + + const std::vector > 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 ()) { + +} + + +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 & /* message */, + const shared_ptr & parent +) const { + + // Create a new part + shared_ptr part = make_shared (); + 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 & /* message */, + const shared_ptr & /* parent */, + const shared_ptr & textPart +) { + + m_text = vmime::clone(textPart->getBody()->getContents()); + + shared_ptr ctf = + textPart->getHeader()->findField (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 plainTextPart::getText() const{ + + return m_text; +} + + +void plainTextPart::setText(const shared_ptr & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 getText() const; + void setText(const shared_ptr & text); + + size_t getPartCount() const; + + void generateIn( + const shared_ptr & message, + const shared_ptr & parent + ) const; + + void parse( + const shared_ptr & message, + const shared_ptr & parent, + const shared_ptr & textPart + ); + +private: + + shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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::sm_handler; + + +platform::handler::~handler() { + +} + + +// static +shared_ptr platform::getDefaultHandler() { + +#if VMIME_PLATFORM_IS_WINDOWS + return make_shared (); +#elif VMIME_PLATFORM_IS_POSIX + return make_shared (); +#else + return null; +#endif + +} + + +// static +shared_ptr 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 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 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 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 createCriticalSection() = 0; + }; + + + template + static void setHandler() { + sm_handler = vmime::make_shared (); + } + + static shared_ptr getDefaultHandler(); + static shared_ptr getHandler(); + +private: + + static shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +#include +#include +#include +#include +#include + + +namespace vmime { +namespace platforms { +namespace posix { + + +// posixChildProcessFactory + +shared_ptr posixChildProcessFactory::create(const utility::file::path& path) const { + + return make_shared (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 (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 (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 +// Copyright 2000 Ximian, Inc. (www.ximian.com) + +void posixChildProcess::start(const std::vector & 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 (argv)); + _exit(255); + } + + if (flags & FLAG_REDIRECT_STDIN) { + + m_stdIn = make_shared (m_pipe[1]); + + } else { + + close(m_pipe[1]); + m_pipe[1] = 0; + } + + if (flags & FLAG_REDIRECT_STDOUT) { + + m_stdOut = make_shared (m_pipe[0]); + + } else { + + close(m_pipe[0]); + m_pipe[0] = 0; + } + + m_pid = pid; + m_started = true; +} + + +shared_ptr posixChildProcess::getStdIn() { + + return m_stdIn; +} + + +shared_ptr 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +#include + + +namespace vmime { +namespace platforms { +namespace posix { + + +class posixChildProcess : public utility::childProcess { + +public: + + posixChildProcess(const utility::file::path& path); + ~posixChildProcess(); + + void start(const std::vector & args, const int flags = 0); + + shared_ptr getStdIn(); + shared_ptr getStdOut(); + + void waitForFinish(); + +private: + + utility::file::path m_processPath; + bool m_started; + + shared_ptr m_stdIn; + shared_ptr m_stdOut; + + sigset_t m_oldProcMask; + pid_t m_pid; + int m_pipe[2]; + + std::vector m_argVector; + const char** m_argArray; +}; + + +class posixChildProcessFactory : public utility::childProcessFactory { + +public: + + shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +#include + + +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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +#include +#include + +#include +#include + +#include + +#include +#include + +#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 posixFileIterator::nextElement() { + + shared_ptr file = make_shared ( + 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 (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 (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 (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 posixFileWriter::getOutputStream() { + + int fd = 0; + + if ((fd = ::open(m_nativePath.c_str(), O_WRONLY, 0660)) == -1) { + posixFileSystemFactory::reportError(m_path, errno); + } + + return make_shared (m_path, fd); +} + + + +// +// posixFileReader +// + +posixFileReader::posixFileReader( + const vmime::utility::file::path& path, + const vmime::string& nativePath +) + : m_path(path), + m_nativePath(nativePath) { + +} + + +shared_ptr posixFileReader::getInputStream() { + + int fd = 0; + + if ((fd = ::open(m_nativePath.c_str(), O_RDONLY, 0640)) == -1) { + posixFileSystemFactory::reportError(m_path, errno); + } + + return make_shared (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 (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 posixFile::getParent() const { + + if (m_path.isEmpty()) { + return null; + } else { + return make_shared (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 posixFile::getFileWriter() { + + return make_shared (m_path, m_nativePath); +} + + +shared_ptr posixFile::getFileReader() { + + return make_shared (m_path, m_nativePath); +} + + +shared_ptr posixFile::getFiles() const { + + if (!isDirectory()) { + throw vmime::exceptions::not_a_directory(m_path); + } + + return make_shared (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 posixFileSystemFactory::create( + const vmime::utility::file::path& path +) const { + + return make_shared (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 + + +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 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 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 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 getParent() const; + + void rename(const path& newName); + + void remove(); + + shared_ptr getFileWriter(); + shared_ptr getFileReader(); + + shared_ptr 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#if VMIME_HAVE_SYSCALL +# include +#endif + +#include + +#include +#include +#include + + +/* +#ifdef _POSIX_PRIORITY_SCHEDULING + #include +#endif // _POSIX_PRIORITY_SCHEDULING +*/ + + +namespace vmime { +namespace platforms { +namespace posix { + + +posixHandler::posixHandler() { + +#if VMIME_HAVE_MESSAGING_FEATURES + m_socketFactory = make_shared (); +#endif +#if VMIME_HAVE_FILESYSTEM_FEATURES + m_fileSysFactory = make_shared (); + m_childProcFactory = make_shared (); +#endif + +} + + +posixHandler::~posixHandler() { + +} + + +unsigned long posixHandler::getUnixTime() const { + + return static_cast (::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 (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 (::gettid()); +#elif VMIME_HAVE_SYSCALL && VMIME_HAVE_SYSCALL_GETTID + return static_cast (::syscall(SYS_gettid)); +#elif VMIME_HAVE_GETTHRID // OpenBSD + return static_cast (::getthrid()); +#else + #error We have no implementation of getThreadId() for this platform! +#endif + +} + + +#if VMIME_HAVE_MESSAGING_FEATURES + +shared_ptr posixHandler::getSocketFactory() { + + return m_socketFactory; +} + +#endif + + +#if VMIME_HAVE_FILESYSTEM_FEATURES + +shared_ptr posixHandler::getFileSystemFactory() { + + return m_fileSysFactory; +} + + +shared_ptr 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 (rand() % 255); + } + } +} + + +shared_ptr posixHandler::createCriticalSection() { + + return make_shared (); +} + + +} // 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 getSocketFactory(); +#endif + +#if VMIME_HAVE_FILESYSTEM_FEATURES + shared_ptr getFileSystemFactory(); + + shared_ptr getChildProcessFactory(); +#endif + + void generateRandomBytes(unsigned char* buffer, const unsigned int count); + + shared_ptr createCriticalSection(); + +private: + +#if VMIME_HAVE_MESSAGING_FEATURES + shared_ptr m_socketFactory; +#endif + +#if VMIME_HAVE_FILESYSTEM_FEATURES + shared_ptr m_fileSysFactory; + shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 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 (port)); + addr.sin_addr.s_addr = ::inet_addr(address.c_str()); + + if (addr.sin_addr.s_addr == static_cast (-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 (&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 (&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 (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 (&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 (&peer), peerLen, + host, sizeof(host), service, sizeof(service), + /* flags */ NI_NAMEREQD) == 0) { + + return string(host); + } + +#else + + struct hostent *hp; + + if ((hp = gethostbyaddr(reinterpret_cast (&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 (buffer.data()), buffer.length()); +} + + +void posixSocket::send(const char* str) { + + sendRaw(reinterpret_cast (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 posixSocket::getTimeoutHandler() { + + return m_timeoutHandler; +} + + +void posixSocket::setTracer(const shared_ptr & tracer) { + + m_tracer = tracer; +} + + +shared_ptr posixSocket::getTracer() { + + return m_tracer; +} + + + +// +// posixSocketFactory +// + +shared_ptr posixSocketFactory::create() { + + shared_ptr th; + return make_shared (th); +} + + +shared_ptr posixSocketFactory::create(const shared_ptr & th) { + + return make_shared (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 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 getTimeoutHandler(); + + void setTracer(const shared_ptr & tracer); + shared_ptr 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 m_timeoutHandler; + shared_ptr 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 create(); + shared_ptr create(const shared_ptr & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 + + +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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 + + +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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +#include + +#include "vmime/exception.hpp" +#include "vmime/utility/stringUtils.hpp" + + +namespace vmime { +namespace platforms { +namespace windows { + + +shared_ptr windowsFileSystemFactory::create( + const vmime::utility::file::path& path +) const { + + return make_shared (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 windowsFile::getParent() const { + + if (m_path.isEmpty()) { + return null; + } else { + return make_shared (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 windowsFile::getFileWriter() { + + return make_shared (m_path, m_nativePath); +} + + +shared_ptr windowsFile::getFileReader() { + + return make_shared (m_path, m_nativePath); +} + + +shared_ptr windowsFile::getFiles() const { + + return make_shared (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 windowsFileIterator::nextElement() { + + shared_ptr pFile = make_shared ( + 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 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 (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 (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 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 (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 + + +namespace vmime { +namespace platforms { +namespace windows { + + +class windowsFileSystemFactory : public vmime::utility::fileSystemFactory { + +public: + + shared_ptr 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 getParent() const; + + void rename(const path& newName); + void remove(); + + shared_ptr getFileWriter(); + + shared_ptr getFileReader(); + + shared_ptr 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 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 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +#include +#include +#include // for WSAStartup() +#include // for winnls.h +#include +#include + +#if VMIME_HAVE_MLANG +# include +#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 (); +#endif +#if VMIME_HAVE_FILESYSTEM_FEATURES + m_fileSysFactory = make_shared (); +#endif + +} + + +windowsHandler::~windowsHandler() { + + WSACleanup(); +} + + +unsigned long windowsHandler::getUnixTime() const { + + return static_cast (::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 (::GetCurrentProcessId()); +} + + +unsigned int windowsHandler::getThreadId() const { + + return static_cast (::GetCurrentThreadId()); +} + + +#if VMIME_HAVE_MESSAGING_FEATURES + +shared_ptr windowsHandler::getSocketFactory() { + + return m_socketFactory; +} + +#endif + + +#if VMIME_HAVE_FILESYSTEM_FEATURES + +shared_ptr windowsHandler::getFileSystemFactory() { + + return m_fileSysFactory; +} + + +shared_ptr 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 (count), static_cast (buffer)); + CryptReleaseContext(cryptProvider, 0); +} + + +shared_ptr windowsHandler::createCriticalSection() { + + return make_shared (); +} + + +} // 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 getSocketFactory(); +#endif + +#if VMIME_HAVE_FILESYSTEM_FEATURES + shared_ptr getFileSystemFactory(); + + shared_ptr getChildProcessFactory(); +#endif + + void generateRandomBytes(unsigned char* buffer, const unsigned int count); + + shared_ptr createCriticalSection(); + +private: + +#if VMIME_HAVE_MESSAGING_FEATURES + shared_ptr m_socketFactory; +#endif + +#if VMIME_HAVE_FILESYSTEM_FEATURES + shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 + + +namespace vmime { +namespace platforms { +namespace windows { + + +// +// windowsSocket +// + +windowsSocket::windowsSocket(shared_ptr 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 (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 (-1)) { + + ::hostent* hostInfo = ::gethostbyname(address.c_str()); + + if (!hostInfo) { + // Error: cannot resolve address + throw vmime::exceptions::connection_error("Cannot resolve address."); + } + + memcpy(reinterpret_cast (&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 (&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 (&peer), &peerLen); + + // Convert to numerical presentation format + char host[NI_MAXHOST + 1]; + char service[NI_MAXSERV + 1]; + + if (getnameinfo(reinterpret_cast (&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 (&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 (&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 (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 (buffer.data()), buffer.length()); +} + + +void windowsSocket::send(const char* str) { + + sendRaw(reinterpret_cast (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 (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 (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 windowsSocket::getTimeoutHandler() { + + return m_timeoutHandler; +} + + +void windowsSocket::setTracer(const shared_ptr & tracer) { + + m_tracer = tracer; +} + + +shared_ptr windowsSocket::getTracer() { + + return m_tracer; +} + + + +// +// posixSocketFactory +// + +shared_ptr windowsSocketFactory::create() { + + shared_ptr th; + return make_shared (th); +} + + +shared_ptr windowsSocketFactory::create(const shared_ptr & th) { + + return make_shared (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +#include "vmime/net/socket.hpp" + + +namespace vmime { +namespace platforms { +namespace windows { + + +class windowsSocket : public vmime::net::socket { + +public: + + windowsSocket(); + windowsSocket(shared_ptr 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 getTimeoutHandler(); + shared_ptr m_tracer; + + void setTracer(const shared_ptr & tracer); + shared_ptr getTracer(); + +protected: + + void throwSocketError(const int err); + + bool waitForData(const bool read, const bool write, const int msecs); + +private: + + shared_ptr 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 create(); + shared_ptr create(const shared_ptr & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 >::const_iterator it = set.m_props.begin() ; + it != set.m_props.end() ; ++it) { + + m_props.push_back(make_shared (**it)); + } +} + + +propertySet::~propertySet() { + + removeAllProperties(); +} + + +propertySet& propertySet::operator=(const propertySet& set) { + + removeAllProperties(); + + for (std::list >::const_iterator it = set.m_props.begin() ; + it != set.m_props.end() ; ++it) { + + m_props.push_back(make_shared (**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 >::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 (option, value)); + } + } +} + + +shared_ptr propertySet::find(const string& name) const { + + std::list >::const_iterator it = + std::find_if(m_props.begin(), m_props.end(), propFinder(name)); + + return it != m_props.end() ? *it : null; +} + + +shared_ptr propertySet::findOrCreate(const string& name) { + + std::list >::const_iterator it = + std::find_if(m_props.begin(), m_props.end(), propFinder(name)); + + if (it != m_props.end()) { + + return *it; + + } else { + + shared_ptr prop = make_shared (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 > propertySet::getPropertyList() const { + + std::vector > res; + + for (list_type::const_iterator it = m_props.begin() ; it != m_props.end() ; ++it) { + res.push_back(*it); + } + + return res; +} + + +const std::vector > propertySet::getPropertyList() { + + std::vector > 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +#include +#include +#include + +#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 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 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 + propertyProxy& operator=(const TYPE& value) { + + m_set->setProperty(m_name, value); + return *this; + } + + template + void setValue(const TYPE& value) { + + m_set->setProperty(m_name, value); + } + + template + const TYPE getValue() const { + + return m_set->getProperty (m_name); + } + + operator string() const { + + return m_set->getProperty (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 + const TYPE getValue() const { + + return m_set->getProperty (m_name); + } + + operator string() const { + + return m_set->getProperty (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 + const TYPE getProperty(const string& name) const { + + const shared_ptr prop = find(name); + if (!prop) throw exceptions::no_such_property(name); + + return (prop->template getValue ()); + } + + /** 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 + const TYPE getProperty(const string& name, const TYPE defaultValue) const { + + const shared_ptr prop = find(name); + return prop ? prop->template getValue () : 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 + 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 , bool> { + + public: + + propFinder(const string& name) : m_name(utility::stringUtils::toLower(name)) { } + + bool operator()(const shared_ptr & p) const { + + return (utility::stringUtils::toLower(p->getName()) == m_name); + } + + private: + + const string m_name; + }; + + shared_ptr find(const string& name) const; + shared_ptr findOrCreate(const string& name); + + typedef std::list > list_type; + list_type m_props; + +public: + + template + 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 + 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 > getPropertyList() const; + + /** Return the property list. + * + * @return list of properties + */ + const std::vector > getPropertyList(); +}; + + +#ifndef VMIME_INLINE_TEMPLATE_SPECIALIZATION + +template <> VMIME_EXPORT void propertySet::property::setValue (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 + + +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 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 ::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 ::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 (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 relay::clone() const { + + return make_shared (*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 & relay::getWithList() const { + + return m_with; +} + + +std::vector & relay::getWithList() { + + return m_with; +} + + +const std::vector > relay::getChildComponents() { + + // TODO: should fields inherit from 'component'? (using typeAdapter) + return std::vector >(); +} + + +} // 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 clone() const; + void copyFrom(const component& other); + relay& operator=(const relay& other); + + const std::vector > 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 & getWithList() const; + std::vector & getWithList(); + +private: + + string m_from; + string m_via; + string m_by; + string m_id; + string m_for; + std::vector 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 (shared_from_this())); + + throw ex; + + } else if (now > getExpirationDate()) { + + certificateExpiredException ex; + ex.setCertificate(dynamicCast (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 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 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 >& 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 >& 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 & 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 & 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 * 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 { + +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 & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 >& certs) + : m_certs(certs) { + +} + + +size_t certificateChain::getCount() const { + + return m_certs.size(); +} + + +const shared_ptr & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 >& 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 & getAt(const size_t index); + +protected: + + std::vector > 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 & cert) { + + m_cert = cert; +} + + +shared_ptr certificateException::getCertificate() { + + return m_cert; +} + + +shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & cert); + + /** Returns the certificate on which the problem occured. + * + * @return certificate + */ + shared_ptr getCertificate(); + + /** Returns the certificate on which the problem occured. + * + * @return certificate + */ + shared_ptr getCertificate() const; + +private: + + shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 & 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 & 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 cert = + dynamicCast (chain->getAt(i)); + + shared_ptr next = + dynamicCast (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 cert = + dynamicCast (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 lastCert = + dynamicCast (chain->getAt(chain->getCount() - 1)); + + bool trusted = false; + + for (size_t i = 0 ; !trusted && i < m_x509RootCAs.size() ; ++i) { + + shared_ptr 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 firstCert = + dynamicCast (chain->getAt(0)); + + for (size_t i = 0 ; !trusted && i < m_x509TrustedCerts.size() ; ++i) { + + shared_ptr 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 >& caCerts +) { + + m_x509RootCAs = caCerts; +} + + +void defaultCertificateVerifier::setX509TrustedCerts( + const std::vector >& 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 >& trustedCerts); + + /** Sets the X.509 root CAs used for certificate verification. + * + * @param caCerts list of root CAs + */ + void setX509RootCAs(const std::vector >& caCerts); + + + // Implementation of 'certificateVerifier' + void verify(const shared_ptr & 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 & chain, const string& hostname); + + + std::vector > m_x509RootCAs; + std::vector > 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +#include + +#include + +#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::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::import( + const byte_t* data, + const size_t length +) { + + gnutls_datum_t buffer; + buffer.data = const_cast (data); + buffer.size = static_cast (length); + + // Try DER format + shared_ptr derCert = make_shared (); + + if (gnutls_x509_crt_import(derCert->m_data->cert, &buffer, GNUTLS_X509_FMT_DER) >= 0) { + return derCert; + } + + // Try PEM format + shared_ptr pemCert = make_shared (); + + 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 >& 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 >& certs +) { + + gnutls_datum_t buffer; + buffer.data = const_cast (data); + buffer.size = static_cast (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 (); + 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 data(dataSize); + + gnutls_x509_crt_export(m_data->cert, fmt, &data[0], &dataSize); + + os.write(reinterpret_cast (&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 & issuer_) const { + + shared_ptr issuer = + dynamicCast (issuer_); + + return gnutls_x509_crt_check_issuer(m_data->cert, issuer->m_data->cert) >= 1; +} + + +bool X509Certificate_GnuTLS::verify(const shared_ptr & caCert_) const { + + shared_ptr caCert = + dynamicCast (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 * 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 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 & other) const { + + shared_ptr otherX509 = + dynamicCast (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & issuer) const; + + bool verify(const shared_ptr & caCert) const; + + bool verifyHostName( + const string& hostname, + std::vector * 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 & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +#include +#include +#include + +#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 +#include +#include +#include +#include +#include + + +#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 ::const_iterator + c_it = m_monthMap.find(mstr); + + if (c_it != m_monthMap.end()) { + return c_it->second; + } + + return -1; + } + +private: + + std::map 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_OpenSSL::importInternal(X509* cert) { + + if (cert) { + return make_shared (reinterpret_cast (cert)); + } + + return null; +} + + +// static +shared_ptr 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::import( + const byte_t* data, + const size_t length +) { + + shared_ptr cert = make_shared (); + + BIO* membio = BIO_new_mem_buf(const_cast (data), static_cast (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 >& 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 >& certs +) { + + BIO* membio = BIO_new_mem_buf(const_cast (data), static_cast (length)); + shared_ptr cert = null; + + while (true) { + + cert = make_shared (); + + 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 (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 (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 & cert_) const { + + shared_ptr cert = + dynamicCast (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 & caCert_) const { + + shared_ptr caCert = + dynamicCast (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 * 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 + (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(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 (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 & other) const { + + shared_ptr otherX509 = + dynamicCast (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 + + +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 & issuer) const; + + bool verify(const shared_ptr & caCert) const; + + bool verifyHostName( + const string& hostname, + std::vector * nonMatchingNames = NULL + ) const; + + const datetime getExpirationDate() const; + const datetime getActivationDate() const; + + const byteArray getFingerprint(const DigestAlgorithm algo) const; + + + static shared_ptr importInternal(X509* cert); + + + // Implementation of 'certificate' + const byteArray getEncoded() const; + const string getType() const; + int getVersion() const; + bool equals(const shared_ptr & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 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 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 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 & serv) { + + m_service = serv; +} + + +weak_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & serv); + weak_ptr getService() const; + +private: + + weak_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 + + +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 (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 (m_byteCount << 3); + m_block.b32[15] = static_cast (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<>(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 (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 + + +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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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"); + registerAlgorithm ("sha1"); +} + + +messageDigestFactory::~messageDigestFactory() { + +} + + +messageDigestFactory* messageDigestFactory::getInstance() { + + static messageDigestFactory instance; + return &instance; +} + + +shared_ptr 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 messageDigestFactory::getSupportedAlgorithms() const { + + std::vector 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 create() const = 0; + }; + + template + struct digestAlgorithmFactoryImpl : public digestAlgorithmFactory { + + shared_ptr create() const { + return vmime::make_shared (); + } + }; + + + typedef std::map > MapType; + MapType m_algos; + +public: + + /** Register a new digest algorithm by its name. + * + * @param name algorithm name + */ + template + void registerAlgorithm(const string& name) { + + m_algos.insert( + MapType::value_type( + utility::stringUtils::toLower(name), + vmime::make_shared >() + ) + ); + } + + /** 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 create(const string& name); + + /** Return a list of supported digest algorithms. + * + * @return list of supported digest algorithms + */ + const std::vector 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// 100% public domain. + +#include "vmime/security/digest/sha1/sha1MessageDigest.hpp" + +#include +#include + + +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 (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 (len << 3)) < static_cast (len << 3)) { + m_count[1]++; + } + + m_count[1] += static_cast (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 ( + (m_count[(i >= 4 ? 0 : 1)] >> ((3 - (i & 3)) * 8)) & 255 // Endian independent + ); + } + + update(reinterpret_cast ("\200"), 1); + + while ((m_count[0] & 504) != 448) { + update(reinterpret_cast ("\0"), 1); + } + + update(finalcount, 8); // Should cause a transform() + + for (i = 0 ; i < 20 ; i++) { + + m_digest[i] = static_cast ( + (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 (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 (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 > getAcceptableMechanisms( + const std::vector >& available, + const shared_ptr & suggested + ) const = 0; + + /** Set the SASL session which is using this authenticator. + * + * @param sess SASL session + */ + virtual void setSASLSession(const shared_ptr & 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 & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 + +#include + +#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::create() { + + return shared_ptr (new SASLContext()); +} + + +shared_ptr SASLContext::createSession( + const string& serviceName, + const shared_ptr & auth, + const shared_ptr & mech +) { + + return SASLSession::create + (serviceName, dynamicCast (shared_from_this()), auth, mech); +} + + +shared_ptr SASLContext::createMechanism(const string& name) { + + return SASLMechanismFactory::getInstance()->create( + dynamicCast (shared_from_this()), name + ); +} + + +shared_ptr SASLContext::suggestMechanism( + const std::vector >& 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 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 { + + 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 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 createSession( + const string& serviceName, + const shared_ptr & auth, + const shared_ptr & 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 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 suggestMechanism( + const std::vector >& 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & 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 & 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 & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +#include + +#include + +#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 SASLMechanismFactory::create( + const shared_ptr & 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 (ctx, name); + } + + throw exceptions::no_such_mechanism(name); + return null; +} + + +const std::vector SASLMechanismFactory::getSupportedMechanisms() const { + + std::vector 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 + + +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 create( + const shared_ptr & ctx, const string& name + ) = 0; + }; + + template + struct registeredMechanismImpl : public registeredMechanism { + + shared_ptr create( + const shared_ptr & ctx, + const string& name + ) { + + return vmime::make_shared (ctx, name); + } + }; + + typedef std::map > 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 + void registerMechanism(const string& name) { + + m_mechs.insert( + MapType::value_type( + name, + vmime::make_shared >() + ) + ); + } + + /** 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 create(const shared_ptr & 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 + +#include + +#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 & ctx, + const shared_ptr & auth, + const shared_ptr & 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::create( + const string& serviceName, + const shared_ptr & ctx, + const shared_ptr & auth, + const shared_ptr & mech +) { + + return shared_ptr (new SASLSession(serviceName, ctx, auth, mech)); +} + + +void SASLSession::init() { + + shared_ptr saslAuth = dynamicCast (m_auth); + + if (saslAuth) { + saslAuth->setSASLMechanism(m_mech); + saslAuth->setSASLSession(dynamicCast (shared_from_this())); + } +} + + +shared_ptr SASLSession::getAuthenticator() { + + return m_auth; +} + + +shared_ptr SASLSession::getMechanism() { + + return m_mech; +} + + +shared_ptr 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 (shared_from_this()), + challenge, challengeLen, response, responseLen + ); +} + + +shared_ptr SASLSession::getSecuredSocket(const shared_ptr & sok) { + + return make_shared (dynamicCast (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 (gsasl_callback_hook_get(ctx)); + + if (!sess) { + return GSASL_AUTHENTICATION_ERROR; + } + + shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 { + + 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 create( + const string& serviceName, + const shared_ptr & ctx, + const shared_ptr & auth, + const shared_ptr & 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 getAuthenticator(); + + /** Return the mechanism used for this session. + * + * @return SASL mechanism + */ + shared_ptr getMechanism(); + + /** Return the SASL context. + * + * @return SASL context + */ + shared_ptr 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 getSecuredSocket(const shared_ptr & 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 & ctx, + const shared_ptr & auth, + const shared_ptr & mech + ); + + + const string m_serviceName; + + shared_ptr m_context; + shared_ptr m_auth; + shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +#include + +#include + + +namespace vmime { +namespace security { +namespace sasl { + + + +SASLSocket::SASLSocket( + const shared_ptr & sess, + const shared_ptr & 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 SASLSocket::getTimeoutHandler() { + + return m_wrapped->getTimeoutHandler(); +} + + +void SASLSocket::setTracer(const shared_ptr & tracer) { + + m_wrapped->setTracer(tracer); +} + + +shared_ptr 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 (buffer.data()), buffer.length()); +} + + +void SASLSocket::send(const char* str) { + + sendRaw(reinterpret_cast (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & sess, + const shared_ptr & 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 getTimeoutHandler(); + + void setTracer(const shared_ptr & tracer); + shared_ptr getTracer(); + +private: + + shared_ptr m_session; + shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 > + XOAuth2SASLAuthenticator::getAcceptableMechanisms( + const std::vector >& available, + const shared_ptr & suggested + ) const { + + if (m_mode == MODE_EXCLUSIVE) { + + std::vector > mechs; + + for (size_t i = available.size() ; i != 0 ; --i) { + + shared_ptr mech = available[i - 1]; + + if ("XOAUTH2" == mech->getName()) { + // Only allow XOAuth2 + mechs.push_back(mech); + } + } + + return mechs; + + } else { + + shared_ptr newSuggested(suggested); + + for (size_t i = available.size() ; i != 0 ; --i) { + + shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 > getAcceptableMechanisms( + const std::vector >& available, + const shared_ptr & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 + + +namespace vmime { +namespace security { +namespace sasl { + + +XOAuth2SASLMechanism::XOAuth2SASLMechanism( + const shared_ptr & 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 & 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 & /* 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 & /* 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & ctx, const string& name); + ~XOAuth2SASLMechanism(); + + + const string getName() const; + + bool step( + const shared_ptr & 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 & sess, + const byte_t* input, + const size_t inputLen, + byte_t** output, + size_t* outputLen + ); + + void decode( + const shared_ptr & sess, + const byte_t* input, + const size_t inputLen, + byte_t** output, + size_t* outputLen + ); + +private: + + /** SASL context */ + shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 + +#include "vmime/security/sasl/builtinSASLMechanism.hpp" + +#include "vmime/security/sasl/SASLContext.hpp" +#include "vmime/security/sasl/SASLSession.hpp" + +#include "vmime/exception.hpp" + +#include +#include + + +namespace vmime { +namespace security { +namespace sasl { + + +builtinSASLMechanism::builtinSASLMechanism( + const shared_ptr & 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 & 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 (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 & 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 (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 (coutputLen); + + } catch (...) { + + gsasl_free(coutput); + throw; + } + + gsasl_free(coutput); +} + + +void builtinSASLMechanism::decode( + const shared_ptr & 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 (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 (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & ctx, const string& name); + ~builtinSASLMechanism(); + + + const string getName() const; + + bool step( + const shared_ptr & 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 & sess, + const byte_t* input, + const size_t inputLen, + byte_t** output, + size_t* outputLen + ); + + void decode( + const shared_ptr & sess, + const byte_t* input, + const size_t inputLen, + byte_t** output, + size_t* outputLen + ); + +private: + + /** SASL context */ + shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 > defaultSASLAuthenticator::getAcceptableMechanisms( + const std::vector >& available, + const shared_ptr & suggested +) const { + + if (suggested) { + + std::vector > 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 & serv) { + + m_service = serv; + m_default.setService(serv); +} + + +weak_ptr defaultSASLAuthenticator::getService() const { + + return m_service; +} + + +void defaultSASLAuthenticator::setSASLSession(const shared_ptr & sess) { + + m_saslSession = sess; +} + + +shared_ptr defaultSASLAuthenticator::getSASLSession() const { + + return m_saslSession.lock(); +} + + +void defaultSASLAuthenticator::setSASLMechanism(const shared_ptr & mech) { + + m_saslMech = mech; +} + + +shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 > getAcceptableMechanisms( + const std::vector >& available, + const shared_ptr & 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 & serv); + weak_ptr getService() const; + + void setSASLSession(const shared_ptr & sess); + shared_ptr getSASLSession() const; + + void setSASLMechanism(const shared_ptr & mech); + shared_ptr getSASLMechanism() const; + +private: + + defaultAuthenticator m_default; + + weak_ptr m_service; + weak_ptr m_saslSession; + shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 & 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 streamContentHandler::clone() const { + + return make_shared (*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 & 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 theDecoder = m_encoding.getEncoder(); + shared_ptr 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 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 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 (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & is, + const size_t length, + const vmime::encoding& enc = NO_ENCODING + ); + + ~streamContentHandler(); + + streamContentHandler(const streamContentHandler& cts); + streamContentHandler& operator=(const streamContentHandler& cts); + + shared_ptr 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 & 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 stringContentHandler::clone() const { + + return make_shared (*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 theDecoder = m_encoding.getEncoder(); + shared_ptr 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 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 (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 > 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 (other); + + removeAllWords(); + + for (std::vector >::const_iterator i = t.m_words.begin() ; + i != t.m_words.end() ; ++i) { + + m_words.push_back(make_shared (**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 >::const_iterator i = m_words.begin(); + std::vector >::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 >::const_iterator i = m_words.begin() ; + i != m_words.end() ; ++i) { + + out += (*i)->getConvertedText(dest, opts); + } + + return out; +} + + +void text::appendWord(const shared_ptr & w) { + + m_words.push_back(w); +} + + +void text::insertWordBefore(const size_t pos, const shared_ptr & w) { + + m_words.insert(m_words.begin() + pos, w); +} + + +void text::insertWordAfter(const size_t pos, const shared_ptr & w) { + + m_words.insert(m_words.begin() + pos + 1, w); +} + + +void text::removeWord(const size_t pos) { + + const std::vector >::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 text::getWordAt(const size_t pos) { + + return m_words[pos]; +} + + +const shared_ptr text::getWordAt(const size_t pos) const { + + return m_words[pos]; +} + + +const std::vector > text::getWordList() const { + + std::vector > list; + + list.reserve(m_words.size()); + + for (std::vector >::const_iterator it = m_words.begin() ; + it != m_words.end() ; ++it) { + + list.push_back(*it); + } + + return list; +} + + +const std::vector > text::getWordList() { + + return m_words; +} + + +shared_ptr text::clone() const { + + return make_shared (*this); +} + + +shared_ptr text::newFromString(const string& in, const charset& ch) { + + shared_ptr t = make_shared (); + + 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 (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 w = getWordAt(getWordCount() - 1); + w->getBuffer() += " " + chunk; + + } else { + + if (count) { + shared_ptr w = getWordAt(getWordCount() - 1); + w->getBuffer() += ' '; + } + + appendWord(make_shared (chunk, ch)); + + prevIs8bit = true; + ++count; + } + + } else { + + if (count && !prevIs8bit) { + + shared_ptr w = getWordAt(getWordCount() - 1); + w->getBuffer() += " " + chunk; + + } else { + + appendWord(make_shared (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::decodeAndUnfold(const string& in) { + + shared_ptr t = make_shared (); + + decodeAndUnfold(parsingContext::getDefaultContext(), in, t.get()); + + return t; +} + + +shared_ptr text::decodeAndUnfold(const parsingContext& ctx, const string& in) { + + shared_ptr t = make_shared (); + + 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 > 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 >& 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 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 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 > text::getChildComponents() { + + std::vector > list; + + copy_vector(m_words, list); + + return list; +} + + +const string text::getWholeBuffer() const { + + string res; + + for (std::vector >::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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 clone() const; + void copyFrom(const component& other); + text& operator=(const component& other); + text& operator=(const text& other); + + const std::vector > getChildComponents(); + + /** Add a word at the end of the list. + * + * @param w word to append + */ + void appendWord(const shared_ptr & 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 & 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 & 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 getWordAt(const size_t pos); + + /** Return the word at the specified position. + * + * @param pos position + * @return word at position 'pos' + */ + const shared_ptr getWordAt(const size_t pos) const; + + /** Return the word list. + * + * @return list of words + */ + const std::vector > getWordList() const; + + /** Return the word list. + * + * @return list of words + */ + const std::vector > 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. + * + *

Eg: giving:

+ *
   <iso-8859-1> "Linux dans un t'el'ephone mobile"
+	  *    ("=?iso-8859-1?Q?Linux_dans_un_t=E9l=E9phone_mobile?=")
+	  * 

it will return:

+ *
   <us-ascii>   "Linux dans un "
+	  *    <iso-8859-1> "t'el'ephone "
+	  *    <us-ascii>   "mobile"
+	  *    ("Linux dans un =?iso-8859-1?Q?t=E9l=E9phone_?= mobile")
+	  * 
+ * + * @param in input string + * @param ch input charset + * @return new text object + */ + static shared_ptr 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. + * + *

Eg: giving:

+ *
   <iso-8859-1> "Linux dans un t'el'ephone mobile"
+	  *    ("=?iso-8859-1?Q?Linux_dans_un_t=E9l=E9phone_mobile?=")
+	  * 

it will return:

+ *
   <us-ascii>   "Linux dans un "
+	  *    <iso-8859-1> "t'el'ephone "
+	  *    <us-ascii>   "mobile"
+	  *    ("Linux dans un =?iso-8859-1?Q?t=E9l=E9phone_?= mobile")
+	  * 
+ * + * @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 decodeAndUnfold(const string& in); + + /** Decode and unfold text (RFC-2047). + * + * @param ctx parsingContext + * @param in input string + * @return new text object + */ + static shared_ptr 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 >& 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 > 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 getText() const = 0; + + /** Set the text contained in the part. + * + * @param text text of the part + */ + virtual void setText(const shared_ptr & 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 & message, + const shared_ptr & 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 & message, + const shared_ptr & parent, + const shared_ptr & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 (mediaType(mediaTypes::TEXT, mediaTypes::TEXT_PLAIN)); + registerType (mediaType(mediaTypes::TEXT, mediaTypes::TEXT_HTML)); +} + + +textPartFactory::~textPartFactory() { + +} + + +textPartFactory* textPartFactory::getInstance() { + + static textPartFactory instance; + return &instance; +} + + +shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 (*AllocFunc)(void); + typedef std::vector > MapType; + + MapType m_map; + +#ifndef VMIME_BUILDING_DOC + template + class registerer { + public: + + static shared_ptr creator() { + + // Allocate a new object + return vmime::make_shared (); + } + }; +#endif // VMIME_BUILDING_DOC + +public: + + static textPartFactory* getInstance(); + + template + void registerType(const mediaType& type) { + + m_map.push_back(MapType::value_type(type, ®isterer::creator)); + } + + shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +#include +#include +#include +#include +#include +#include + +#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 + struct noop_shared_ptr_deleter { + void operator()(T*) const {} + }; + + template using scoped_ptr = std::unique_ptr ; +} + +#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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 + + +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 & 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 getStdIn() = 0; + + /** Return a wrapper to the child process standard output. + * + * @return input stream wrapper for child's stdout + */ + virtual shared_ptr 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 + + +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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 b64Encoder::getAvailableProperties() const { + + std::vector 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 (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 ("maxlinelength", static_cast (-1)); + + const bool cutLines = (propMaxLineLength != static_cast (-1)); + const size_t maxLineLength = std::min(propMaxLineLength, static_cast (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 ((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 (((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 (((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 ("maxlinelength", static_cast (-1)); + + const bool cutLines = (propMaxLineLength != static_cast (-1)); + const size_t maxLineLength = std::min(propMaxLineLength, static_cast (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 encoder::getAvailableProperties() const { + + std::vector 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 ("base64"); + registerName ("quoted-printable"); + registerName ("uuencode"); + registerName ("x-uuencode"); + registerName ("7bit"); + registerName ("8bit"); + registerName ("binary"); + + // Also register some non-standard encoding names + registerName ("7-bit"); + registerName ("8-bit"); + registerName ("8bits"); + + // Finally, register some bogus encoding names, for compatibility + registerName ("bmoted-printable"); +} + + +encoderFactory::~encoderFactory() { + +} + + +shared_ptr encoderFactory::getInstance() { + + static encoderFactory instance; + return shared_ptr (&instance, noop_shared_ptr_deleter ()); +} + + +shared_ptr 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 + encoderFactory::getEncoderByName(const string& name) const { + + const string lcName(utility::stringUtils::toLower(name)); + + for (std::vector >::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 + encoderFactory::getEncoderAt(const size_t pos) const { + + return m_encoders[pos]; +} + + +const std::vector > + encoderFactory::getEncoderList() const { + + std::vector > res; + + for (std::vector >::const_iterator it = m_encoders.begin() ; + it != m_encoders.end() ; ++it) { + + res.push_back(*it); + } + + return res; +} + + +void encoderFactory::setDefaultEncoder(const shared_ptr & enc) { + + m_defaultEncoder = enc; +} + + +shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 getInstance(); + + /** Information about a registered encoder. */ + class VMIME_EXPORT registeredEncoder : public object { + + protected: + + virtual ~registeredEncoder() { } + + public: + + virtual shared_ptr create() const = 0; + + virtual const string& getName() const = 0; + }; + +private: + + template + class registeredEncoderImpl : public registeredEncoder { + + public: + + registeredEncoderImpl(const string& name) : m_name(name) { } + + shared_ptr create() const { + + return vmime::make_shared (); + } + + const string& getName() const { + + return m_name; + } + + private: + + const string m_name; + }; + + + std::vector > m_encoders; + shared_ptr m_defaultEncoder; + +public: + + /** Register a new encoder by its encoding name. + * + * @param name encoding name + */ + template + void registerName(const string& name) { + + m_encoders.push_back( + vmime::make_shared >(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 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 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 getEncoderAt(const size_t pos) const; + + /** Return a list of all registered encoders. + * + * @return list of registered encoders + */ + const std::vector > 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 & enc); + + /** Return the default encoder to use when no other encoder + * is registered for an encoding (fallback). + * + * @return default encoder + */ + shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 qpEncoder::getAvailableProperties() const { + + std::vector 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: . " +// +// 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 (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 ("maxlinelength", static_cast (-1)); + + const bool rfc2047 = getProperties().getProperty ("rfc2047", false); + const bool text = getProperties().getProperty ("text", false); // binary mode by default + + const bool cutLines = (propMaxLineLength != static_cast (-1)); + const size_t maxLineLength = std::min(propMaxLineLength, static_cast (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 (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 ("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 ( + 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 ("maxlinelength", static_cast (-1)); + + const bool cutLines = (propMaxLineLength != static_cast (-1)); + const size_t maxLineLength = std::min(propMaxLineLength, static_cast (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 uuEncoder::getAvailableProperties() const { + + std::vector 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 ((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 ("filename", ""); + const string propMode = getProperties().getProperty ("mode", "644"); + + const size_t maxLineLength = + std::min(getProperties().getProperty ("maxlinelength", 46), static_cast (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 (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 (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 (3)); + + if (n >= 3) { + outBuffer[j + 2] = static_cast (UUDECODE(c3) << 6 | UUDECODE(c4)); + } + if (n >= 2) { + outBuffer[j + 1] = static_cast (UUDECODE(c2) << 4 | UUDECODE(c3) >> 2); + } + if (n >= 1) { + outBuffer[j] = static_cast (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 nextElement() = 0; +}; + + +/** Write to a file. + */ +class VMIME_EXPORT fileWriter : public object { + +public: + + virtual ~fileWriter() { } + + virtual shared_ptr getOutputStream() = 0; +}; + + +/** Read from a file. + */ +class VMIME_EXPORT fileReader : public object { + +public: + + virtual ~fileReader() { } + + virtual shared_ptr 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 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 getFileWriter() = 0; + + /** Return an object capable of reading from this file. + * + * @return file reader object + */ + virtual shared_ptr 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 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 + + +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 + 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) { // 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 + +#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 +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 (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 + + +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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 + + +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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +#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 + 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 (str), ::strlen(str)); + return os; +} + +#else + +template +outputStream& operator<<(outputStream& os, const char (&str)[N]) { + + os.write(reinterpret_cast (str), N - 1); + return os; +} + +#endif // defined(_MSC_VER) && (_MSC_VER <= 1200) + + +template +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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 + + +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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 & 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 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 (&begin[1]), + static_cast (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 + + +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 & stream); + + shared_ptr 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 (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 (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 + 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 + 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 + + +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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 + +#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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 + + +namespace vmime { +namespace utility { + + +static unsigned int getRandomSeed() { + + unsigned int seed; + + platform::getHandler()->generateRandomBytes( + reinterpret_cast (&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((16807 * next) % 2147483647ul); + return next; +} + + +unsigned int random::getTime() { + + return static_cast ((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 (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 + +#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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 // for std::copy +#include // 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 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 & fac = + std::use_facet >(std::locale::classic()); + + bool equal = true; + + for (size_t i = 0 ; equal && i < n ; ++i) { + equal = (fac.tolower(static_cast (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 & fac = + std::use_facet >(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 (*i)) == fac.tolower(static_cast (*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 (end - begin) < n) { + return false; + } + + const std::ctype & fac = + std::use_facet >(std::locale::classic()); + + bool equal = true; + char* c = const_cast(s); + size_t r = n; + + for (string::const_iterator i = begin ; equal && r && *c ; ++i, ++c, --r) { + equal = (fac.tolower(static_cast (*i)) == static_cast (*c)); + } + + return r == 0 && equal; +} + + +const string stringUtils::toLower(const string& str) { + + const std::ctype & fac = + std::use_facet >(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 (str[i])); + } + + return out; +} + + +const string stringUtils::toUpper(const string& str) { + + const std::ctype & fac = + std::use_facet >(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 (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 + + +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 (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 (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 (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 (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 + 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 + 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 VMIME_EXPORT autoLock : public object { + +public: + + autoLock(const shared_ptr & mutex) + : m_mutex(mutex) { + + m_mutex->lock(); + } + + ~autoLock() { + + m_mutex->unlock(); + } + +private: + + shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 + + +namespace vmime { +namespace utility { + + +// Unspecified port +const port_t url::UNSPECIFIED_PORT = static_cast (-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 ::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 & url::getParams() const { + + return m_params; +} + + +std::map & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 & getParams() const; + + /** Return the parameters of the URL. + * + * @return parameters + */ + std::map & 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 (c) <= 127 && + RESERVED_CHARS.find(c) == string::npos) { + + result += c; + + } else { + + char hex[4]; + const unsigned char k = static_cast (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 (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should.have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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::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 w = make_shared (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 w = make_shared (); + 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 w = make_shared (unencoded, defaultCharset); + w->setParsedBounds(position, end); + + if (newPosition) { + *newPosition = end; + } + + state->prevIsEncoded = false; + state->isFirst = false; + + return w; + } + + return null; +} + + +const std::vector > word::parseMultiple( + const parsingContext& ctx, + const string& buffer, + const size_t position, + const size_t end, + size_t* newPosition +) { + + std::vector > res; + shared_ptr 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 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 (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 (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 word::clone() const { + + return make_shared (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 > word::getChildComponents() { + + return std::vector >(); +} + + +} // 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 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 > getChildComponents(); + +private: + + static shared_ptr parseNext( + const parsingContext& ctx, + const string& buffer, + const size_t position, + const size_t end, + size_t* newPosition, + parserState* state + ); + + static const std::vector > 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 (); + + } else { // ENCODING_QP + + m_encoder = make_shared (); + 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 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 (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 hdr = vmime::make_shared (); + + 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 hdr = vmime::make_shared (); + + 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 hdr1 = vmime::make_shared (); + + hdr1->getField("Importance")->setValue(ImportanceValue); + VASSERT_EQ("1", i1, vmime::misc::importanceHelper::getImportanceHeader(hdr1)); + + vmime::shared_ptr hdr2 = vmime::make_shared (); + + 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 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 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 cmd = IMAPCommand::createCommand("MY_COMMAND"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "MY_COMMAND", cmd->getText()); + } + + void testCreateCommandParams() { + + vmime::shared_ptr 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 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 cmd = IMAPCommand::AUTHENTICATE("saslmechanism"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "AUTHENTICATE saslmechanism", cmd->getText()); + } + + void testAUTHENTICATE_InitialResponse() { + + vmime::shared_ptr 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 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 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 params; + params.push_back("param-1"); + params.push_back("param-2"); + + + vmime::shared_ptr cmdRO = IMAPCommand::SELECT( + /* readOnly */ true, "mailbox-name", std::vector () + ); + + VASSERT_NOT_NULL("Not null", cmdRO); + VASSERT_EQ("Text", "EXAMINE mailbox-name", cmdRO->getText()); + + vmime::shared_ptr cmdROQuote = IMAPCommand::SELECT( + /* readOnly */ true, "mailbox name", std::vector () + ); + + VASSERT_NOT_NULL("Not null", cmdROQuote); + VASSERT_EQ("Text", "EXAMINE \"mailbox name\"", cmdROQuote->getText()); + + + vmime::shared_ptr cmdRW = IMAPCommand::SELECT( + /* readOnly */ false, "mailbox-name", std::vector () + ); + + VASSERT_NOT_NULL("Not null", cmdRW); + VASSERT_EQ("Text", "SELECT mailbox-name", cmdRW->getText()); + + vmime::shared_ptr 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 cmdRWQuote = IMAPCommand::SELECT( + /* readOnly */ false, "mailbox name", std::vector () + ); + + VASSERT_NOT_NULL("Not null", cmdRWQuote); + VASSERT_EQ("Text", "SELECT \"mailbox name\"", cmdRWQuote->getText()); + } + + void testSTATUS() { + + std::vector attribs; + attribs.push_back("attrib-1"); + attribs.push_back("attrib-2"); + + + vmime::shared_ptr 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 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 params; + params.push_back("param-1"); + params.push_back("param-2"); + + + vmime::shared_ptr 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 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 cmdNoParam = + IMAPCommand::CREATE("mailbox-name", std::vector ()); + + VASSERT_NOT_NULL("Not null", cmdNoParam); + VASSERT_EQ("Text", "CREATE mailbox-name", cmdNoParam->getText()); + } + + void testDELETE() { + + vmime::shared_ptr cmd = + IMAPCommand::DELETE("mailbox-name"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "DELETE mailbox-name", cmd->getText()); + + + vmime::shared_ptr cmdQuote = + IMAPCommand::DELETE("mailbox name"); + + VASSERT_NOT_NULL("Not null", cmdQuote); + VASSERT_EQ("Text", "DELETE \"mailbox name\"", cmdQuote->getText()); + } + + void testRENAME() { + + vmime::shared_ptr 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 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 params; + params.push_back("param-1"); + params.push_back("param-2"); + + + vmime::shared_ptr 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 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 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 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 flags; + flags.push_back("flag-1"); + flags.push_back("flag-2"); + + + vmime::shared_ptr 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 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 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 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 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 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 flags; + flags.push_back("flag-1"); + flags.push_back("flag-2"); + + + vmime::shared_ptr 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 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 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 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 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 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 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 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 searchKeys; + searchKeys.push_back("search-key-1"); + searchKeys.push_back("search-key-2"); + + vmime::shared_ptr 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 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 cmd = IMAPCommand::STARTTLS(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "STARTTLS", cmd->getText()); + } + + void testCAPABILITY() { + + vmime::shared_ptr cmd = IMAPCommand::CAPABILITY(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "CAPABILITY", cmd->getText()); + } + + void testNOOP() { + + vmime::shared_ptr cmd = IMAPCommand::NOOP(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "NOOP", cmd->getText()); + } + + void testEXPUNGE() { + + vmime::shared_ptr cmd = IMAPCommand::EXPUNGE(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "EXPUNGE", cmd->getText()); + } + + void testCLOSE() { + + vmime::shared_ptr cmd = IMAPCommand::CLOSE(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "CLOSE", cmd->getText()); + } + + void testLOGOUT() { + + vmime::shared_ptr cmd = IMAPCommand::LOGOUT(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "LOGOUT", cmd->getText()); + } + + void testSend() { + + vmime::shared_ptr cmd = + IMAPCommand::createCommand("MY_COMMAND param1 param2"); + + vmime::shared_ptr sess = vmime::net::session::create(); + + vmime::shared_ptr auth = + vmime::make_shared (); + + vmime::shared_ptr store = + vmime::make_shared (sess, auth, /* secured */ false); + + vmime::shared_ptr conn = + vmime::make_shared (store, auth); + + vmime::shared_ptr sok = vmime::make_shared (); + 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 (); + socket->localSend(resp); + + auto parser = vmime::make_shared (); + auto tag = vmime::make_shared (); + + parser->setSocket(socket); + parser->setTimeoutHandler(vmime::make_shared ()); + parser->setStrict(true); + + VASSERT_THROW("strict mode", parser->readResponse(*tag), vmime::exceptions::invalid_response); + } + + // Non-strict mode + { + auto socket = vmime::make_shared (); + socket->localSend(resp); + + auto parser = vmime::make_shared (); + auto tag = vmime::make_shared (); + + parser->setSocket(socket); + parser->setTimeoutHandler(vmime::make_shared ()); + 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 socket = vmime::make_shared (); + vmime::shared_ptr toh = vmime::make_shared (); + + vmime::shared_ptr tag = + vmime::make_shared (); + + socket->localSend("+\r\n"); + + vmime::shared_ptr parser = + vmime::make_shared (); + + 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 (); + socket->localSend(resp); + + auto parser = vmime::make_shared (); + auto tag = vmime::make_shared (); + + parser->setSocket(socket); + parser->setTimeoutHandler(vmime::make_shared ()); + parser->setStrict(true); + + VASSERT_THROW("strict mode", parser->readResponse(*tag), vmime::exceptions::invalid_response); + } + + // Non-strict mode + { + auto socket = vmime::make_shared (); + socket->localSend(resp); + + auto parser = vmime::make_shared (); + auto tag = vmime::make_shared (); + + parser->setSocket(socket); + parser->setTimeoutHandler(vmime::make_shared ()); + 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 socket = vmime::make_shared (); + vmime::shared_ptr toh = vmime::make_shared (); + + vmime::shared_ptr tag = + vmime::make_shared (); + + 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 parser = + vmime::make_shared (); + + 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 (); + socket->localSend(resp); + + auto parser = vmime::make_shared (); + auto tag = vmime::make_shared (); + + parser->setSocket(socket); + parser->setTimeoutHandler(vmime::make_shared ()); + parser->setStrict(true); + + VASSERT_THROW("strict mode", parser->readResponse(*tag), vmime::exceptions::invalid_response); + } + + // Non-strict mode + { + auto socket = vmime::make_shared (); + socket->localSend(resp); + + auto parser = vmime::make_shared (); + auto tag = vmime::make_shared (); + + parser->setSocket(socket); + parser->setTimeoutHandler(vmime::make_shared ()); + 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 (); + socket->localSend(resp); + + auto parser = vmime::make_shared (); + auto tag = vmime::make_shared (); + + parser->setSocket(socket); + parser->setTimeoutHandler(vmime::make_shared ()); + parser->setStrict(true); + + VASSERT_THROW("strict mode", parser->readResponse(*tag), vmime::exceptions::invalid_response); + } + + // Non-strict mode + { + auto socket = vmime::make_shared (); + socket->localSend(resp); + + auto parser = vmime::make_shared (); + auto tag = vmime::make_shared (); + + parser->setSocket(socket); + parser->setTimeoutHandler(vmime::make_shared ()); + 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 socket = vmime::make_shared (); + vmime::shared_ptr toh = vmime::make_shared (); + + 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 parser = + vmime::make_shared (); + + parser->setSocket(socket); + parser->setTimeoutHandler(toh); + + // Test response a001 + vmime::scoped_ptr 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 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 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 (); + auto toh = vmime::make_shared (); + + auto tag = vmime::make_shared (); + + socket->localSend(resp); + + auto parser = vmime::make_shared (); + + 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 (); + auto toh = vmime::make_shared (); + + auto tag = vmime::make_shared (); + + socket->localSend(resp); + + auto parser = vmime::make_shared (); + + 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 tag = + vmime::make_shared (); + + VASSERT_EQ("init", "a001", static_cast (*tag)); + } + + void testIncrement() { + + vmime::shared_ptr tag = + vmime::make_shared (); + + (*tag)++; + VASSERT_EQ("init", "a002", static_cast (*tag)); + + (*tag)++; + VASSERT_EQ("init", "a003", static_cast (*tag)); + + (*tag)++; + VASSERT_EQ("init", "a004", static_cast (*tag)); + } + + void testReset() { + + vmime::shared_ptr tag = + vmime::make_shared (); + + for (int i = tag->number() ; i < tag->maximumNumber() ; ++i) { + (*tag)++; + } + + VASSERT_EQ("last", "Z999", static_cast (*tag)); + + (*tag)++; + + VASSERT_EQ("reset", "a001", static_cast (*tag)); + } + + void testNumber() { + + vmime::shared_ptr tag = + vmime::make_shared (); + + 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 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 cnt; + vmime::net::messageSet msgs = vmime::net::messageSet::byNumber(42); + + // SIZE + { + vmime::net::fetchAttributes attribs = vmime::net::fetchAttributes::SIZE; + + vmime::shared_ptr 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 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 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 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 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 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 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 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 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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: \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 store = + vmime::dynamicCast (createAndConnectStore()); + + VASSERT_EQ("*", "kmail", store->getFormat()->getName()); + + destroyMaildir(); + } + + void testDetectFormat_Courier() { + + createMaildir(TEST_MAILDIR_COURIER, TEST_MAILDIRFILES_COURIER); + + vmime::shared_ptr store = + vmime::dynamicCast (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 store = createAndConnectStore(); + vmime::shared_ptr rootFolder = store->getRootFolder(); + + // Get root folders, not recursive + const std::vector > + 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 store = createAndConnectStore(); + vmime::shared_ptr rootFolder = store->getRootFolder(); + + // Get all folders, recursive + const std::vector > + 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 store = createAndConnectStore(); + vmime::shared_ptr rootFolder = store->getRootFolder(); + + vmime::shared_ptr 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 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 store = createAndConnectStore(); + vmime::shared_ptr rootFolder = store->getRootFolder(); + + // Rename "Folder/SubFolder" to "Folder/foo" + vmime::shared_ptr folder = + store->getFolder(fpath() / "Folder" / "SubFolder"); + + folder->rename(fpath() / "Folder" / "foo"); + + // Ensure folder and its subfolders have been renamed + const std::vector > + 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 store = createAndConnectStore(); + vmime::shared_ptr rootFolder = store->getRootFolder(); + + // Destroy "Folder/SubFolder" (total: 3 folders) + vmime::shared_ptr folder = + store->getFolder(fpath() / "Folder" / "SubFolder"); + + folder->destroy(); + + // Ensure folder and its subfolders have been deleted and other folders still exist + const std::vector > + 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 store = createAndConnectStore(); + vmime::shared_ptr 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 store = createAndConnectStore(); + vmime::shared_ptr 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 createAndConnectStore() { + + vmime::shared_ptr session = vmime::net::session::create(); + + vmime::shared_ptr store = + session->getStore(getStoreURL()); + + store->connect(); + + return store; + } + + const vmime::shared_ptr findFolder( + const std::vector >& 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 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 fsf = + vmime::platform::getHandler()->getFileSystemFactory(); + + vmime::shared_ptr rootDir = fsf->create(m_tempPath); + rootDir->createDirectory(false); + + for (vmime::string const* dir = dirs ; *dir != "*" ; ++dir) { + + vmime::shared_ptr 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 ffile = fsf->create(m_tempPath / fsf->stringToPath(*file)); + ffile->createFile(); + + vmime::shared_ptr fileWriter = ffile->getFileWriter(); + vmime::shared_ptr os = fileWriter->getOutputStream(); + + os->write(contents.data(), contents.length()); + os->flush(); + + fileWriter = vmime::null; + } + + } + + void destroyMaildir() { + + vmime::shared_ptr fsf = + vmime::platform::getHandler()->getFileSystemFactory(); + + recursiveDelete(fsf->create(m_tempPath)); + } + + void recursiveDelete(vmime::shared_ptr dir) { + + if (!dir->exists() || !dir->isDirectory()) { + return; + } + + vmime::shared_ptr files = dir->getFiles(); + + // First, delete files and subdirectories in this directory + while (files->hasMoreElements()) { + + vmime::shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 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 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 cmd = POP3Command::createCommand("MY_COMMAND"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "MY_COMMAND", cmd->getText()); + } + + void testCreateCommandParams() { + + vmime::shared_ptr 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 cmd = POP3Command::CAPA(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "CAPA", cmd->getText()); + } + + void testNOOP() { + + vmime::shared_ptr cmd = POP3Command::NOOP(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "NOOP", cmd->getText()); + } + + void testAUTH() { + + vmime::shared_ptr cmd = POP3Command::AUTH("saslmechanism"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "AUTH saslmechanism", cmd->getText()); + } + + void testAUTH_InitialResponse() { + + vmime::shared_ptr 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 cmd = POP3Command::STLS(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "STLS", cmd->getText()); + } + + void testAPOP() { + + vmime::shared_ptr cmd = POP3Command::APOP("user", "digest"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "APOP user digest", cmd->getText()); + } + + void testUSER() { + + vmime::shared_ptr cmd = POP3Command::USER("user"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "USER user", cmd->getText()); + } + + void testPASS() { + + vmime::shared_ptr cmd = POP3Command::PASS("pass"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "PASS pass", cmd->getText()); + } + + void testSTAT() { + + vmime::shared_ptr cmd = POP3Command::STAT(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "STAT", cmd->getText()); + } + + void testLIST() { + + vmime::shared_ptr cmd = POP3Command::LIST(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "LIST", cmd->getText()); + } + + void testLISTMessage() { + + vmime::shared_ptr cmd = POP3Command::LIST(42); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "LIST 42", cmd->getText()); + } + + void testUIDL() { + + vmime::shared_ptr cmd = POP3Command::UIDL(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "UIDL", cmd->getText()); + } + + void testUIDLMessage() { + + vmime::shared_ptr cmd = POP3Command::UIDL(42); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "UIDL 42", cmd->getText()); + } + + void testDELE() { + + vmime::shared_ptr cmd = POP3Command::DELE(42); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "DELE 42", cmd->getText()); + } + + void testRETR() { + + vmime::shared_ptr cmd = POP3Command::RETR(42); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "RETR 42", cmd->getText()); + } + + void testTOP() { + + vmime::shared_ptr cmd = POP3Command::TOP(42, 567); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "TOP 42 567", cmd->getText()); + } + + void testRSET() { + + vmime::shared_ptr cmd = POP3Command::RSET(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "RSET", cmd->getText()); + } + + void testQUIT() { + + vmime::shared_ptr cmd = POP3Command::QUIT(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "QUIT", cmd->getText()); + } + + void testWriteToSocket() { + + vmime::shared_ptr cmd = POP3Command::createCommand("MY_COMMAND param1 param2"); + + vmime::shared_ptr sok = vmime::make_shared (); + + vmime::shared_ptr conn = + vmime::make_shared ( + vmime::dynamicCast (sok), + vmime::shared_ptr () + ); + + 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 socket = vmime::make_shared (); + vmime::shared_ptr toh = vmime::make_shared (); + + vmime::shared_ptr conn = + vmime::make_shared ( + vmime::dynamicCast (socket), toh + ); + + socket->localSend("+OK Response Text\r\n"); + + vmime::shared_ptr 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 socket = vmime::make_shared (); + vmime::shared_ptr toh = vmime::make_shared (); + + vmime::shared_ptr conn = + vmime::make_shared ( + vmime::dynamicCast (socket), toh + ); + + socket->localSend("-ERR Response Text\r\n"); + + vmime::shared_ptr 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 socket = vmime::make_shared (); + vmime::shared_ptr toh = vmime::make_shared (); + + vmime::shared_ptr conn = + vmime::make_shared ( + vmime::dynamicCast (socket), toh + ); + + socket->localSend("+ challenge_string\r\n"); + + vmime::shared_ptr 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 socket = vmime::make_shared (); + vmime::shared_ptr toh = vmime::make_shared (); + + vmime::shared_ptr conn = vmime::make_shared + (vmime::dynamicCast (socket), toh); + + socket->localSend("Invalid Response Text\r\n"); + + vmime::shared_ptr 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 socket = vmime::make_shared (); + vmime::shared_ptr toh = vmime::make_shared (); + + vmime::shared_ptr conn = + vmime::make_shared ( + vmime::dynamicCast (socket), toh + ); + + socket->localSend("+OK Response terminated by LF\n"); + + vmime::shared_ptr 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 socket = vmime::make_shared (); + vmime::shared_ptr toh = vmime::make_shared (); + + vmime::shared_ptr conn = + vmime::make_shared ( + vmime::dynamicCast (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 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 socket = vmime::make_shared (); + vmime::shared_ptr toh = vmime::make_shared (); + + vmime::shared_ptr conn = + vmime::make_shared ( + vmime::dynamicCast (socket), toh + ); + + socket->localSend("+OK Response Text\n"); + socket->localSend("Line 1\n"); + socket->localSend("Line 2\n"); + socket->localSend(".\n"); + + vmime::shared_ptr 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 socket = vmime::make_shared (); + vmime::shared_ptr toh = vmime::make_shared (); + + vmime::shared_ptr conn = + vmime::make_shared ( + vmime::dynamicCast (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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 sess = vmime::net::session::create(); + + // POP3 + vmime::utility::url url("pop3://pop3.vmime.org"); + vmime::shared_ptr 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 store2 = sess->getStore(url2); + + VASSERT_TRUE("pop3s", typeid(*store2) == typeid(vmime::net::pop3::POP3SStore)); + } + + void testConnectToInvalidServer() { + + vmime::shared_ptr sess = vmime::net::session::create(); + + vmime::utility::url url("pop3://invalid-pop3-server"); + vmime::shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 ()) { + + } +}; + + +class POP3ConnectionTest : public vmime::net::pop3::POP3Connection { + +public: + + POP3ConnectionTest( + vmime::shared_ptr socket, + vmime::shared_ptr timeoutHandler + ) + : POP3Connection(vmime::make_shared (), + vmime::shared_ptr ()), + m_socket(socket), + m_timeoutHandler(timeoutHandler) { + + } + + vmime::shared_ptr getSocket() { + + return m_socket; + } + + vmime::shared_ptr getTimeoutHandler() { + + return m_timeoutHandler; + } + +private: + + vmime::shared_ptr m_socket; + vmime::shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 socket = vmime::make_shared (); + vmime::shared_ptr toh = vmime::make_shared (); + + vmime::shared_ptr conn = + vmime::make_shared ( + vmime::dynamicCast (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 resp = + POP3Response::readMultilineResponse(conn); + + std::map 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 cset = SMTPCommandSet::create(/* pipelining */ false); + + VASSERT_NOT_NULL("Not null", cset); + VASSERT_FALSE("Finished", cset->isFinished()); + } + + void testCreatePipeline() { + + vmime::shared_ptr cset = SMTPCommandSet::create(/* pipelining */ true); + + VASSERT_NOT_NULL("Not null", cset); + VASSERT_FALSE("Finished", cset->isFinished()); + } + + void testAddCommand() { + + vmime::shared_ptr 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 tracer; + vmime::shared_ptr sok = vmime::make_shared (); + + 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 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 tracer; + vmime::shared_ptr sok = vmime::make_shared (); + 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 cset = SMTPCommandSet::create(/* pipelining */ false); + + cset->addCommand(SMTPCommand::createCommand("MY_COMMAND1")); + cset->addCommand(SMTPCommand::createCommand("MY_COMMAND2")); + + vmime::shared_ptr tracer; + vmime::shared_ptr sok = vmime::make_shared (); + 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 cset = SMTPCommandSet::create(/* pipelining */ true); + + cset->addCommand(SMTPCommand::createCommand("MY_COMMAND1")); + cset->addCommand(SMTPCommand::createCommand("MY_COMMAND2")); + + vmime::shared_ptr tracer; + vmime::shared_ptr sok = vmime::make_shared (); + 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 cset = SMTPCommandSet::create(/* pipelining */ false); + + cset->addCommand(SMTPCommand::createCommand("MY_COMMAND1")); + cset->addCommand(SMTPCommand::createCommand("MY_COMMAND2")); + + vmime::shared_ptr tracer; + vmime::shared_ptr sok = vmime::make_shared (); + + 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 cset = SMTPCommandSet::create(/* pipelining */ true); + + cset->addCommand(SMTPCommand::createCommand("MY_COMMAND1")); + cset->addCommand(SMTPCommand::createCommand("MY_COMMAND2")); + + vmime::shared_ptr tracer; + vmime::shared_ptr sok = vmime::make_shared (); + + 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 cmd = SMTPCommand::createCommand("MY_COMMAND"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "MY_COMMAND", cmd->getText()); + } + + void testCreateCommandParams() { + + vmime::shared_ptr 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 cmd = SMTPCommand::HELO("hostname"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "HELO hostname", cmd->getText()); + } + + void testEHLO() { + + vmime::shared_ptr cmd = SMTPCommand::EHLO("hostname"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "EHLO hostname", cmd->getText()); + } + + void testAUTH() { + + vmime::shared_ptr cmd = SMTPCommand::AUTH("saslmechanism"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "AUTH saslmechanism", cmd->getText()); + } + + void testAUTH_InitialResponse() { + + vmime::shared_ptr 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 cmd = SMTPCommand::STARTTLS(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "STARTTLS", cmd->getText()); + } + + void testMAIL() { + + vmime::shared_ptr cmd = SMTPCommand::MAIL(vmime::mailbox("me@vmime.org"), false, "FULL", "dsn-unique-id"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "MAIL FROM: RET=FULL ENVID=", cmd->getText()); + } + + void testMAIL_Encoded() { + + vmime::shared_ptr cmd = SMTPCommand::MAIL( + vmime::mailbox(vmime::emailAddress("mailtest", "例え.テスト")), false, "FULL", "dsn-unique-id" + ); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "MAIL FROM: RET=FULL ENVID=", cmd->getText()); + } + + void testMAIL_UTF8() { + + vmime::shared_ptr cmd = SMTPCommand::MAIL( + vmime::mailbox(vmime::emailAddress("mailtest", "例え.テスト")), true, "FULL", "dsn-unique-id" + ); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "MAIL FROM: RET=FULL ENVID= SMTPUTF8", cmd->getText()); + } + + void testMAIL_SIZE() { + + vmime::shared_ptr 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: RET=FULL ENVID= SIZE=123456789", cmd->getText()); + } + + void testMAIL_SIZE_UTF8() { + + vmime::shared_ptr 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: RET=FULL ENVID= SMTPUTF8 SIZE=123456789", cmd->getText()); + } + + void testRCPT() { + + vmime::shared_ptr cmd = + SMTPCommand::RCPT(vmime::mailbox("someone@vmime.org"), false, "NEVER"); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "RCPT TO: NOTIFY=NEVER", cmd->getText()); + } + + void testRCPT_Encoded() { + + vmime::shared_ptr cmd = SMTPCommand::RCPT( + vmime::mailbox(vmime::emailAddress("mailtest", "例え.テスト")), false, "NEVER" + ); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "RCPT TO: NOTIFY=NEVER", cmd->getText()); + } + + void testRCPT_UTF8() { + + vmime::shared_ptr cmd = SMTPCommand::RCPT( + vmime::mailbox(vmime::emailAddress("mailtest", "例え.テスト")), true, "NEVER" + ); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "RCPT TO: NOTIFY=NEVER", cmd->getText()); + } + + void testRSET() { + + vmime::shared_ptr cmd = SMTPCommand::RSET(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "RSET", cmd->getText()); + } + + void testDATA() { + + vmime::shared_ptr cmd = SMTPCommand::DATA(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "DATA", cmd->getText()); + } + + void testBDAT() { + + vmime::shared_ptr cmd1 = SMTPCommand::BDAT(12345, false); + + VASSERT_NOT_NULL("Not null", cmd1); + VASSERT_EQ("Text", "BDAT 12345", cmd1->getText()); + + vmime::shared_ptr cmd2 = SMTPCommand::BDAT(67890, true); + + VASSERT_NOT_NULL("Not null", cmd2); + VASSERT_EQ("Text", "BDAT 67890 LAST", cmd2->getText()); + } + + void testNOOP() { + + vmime::shared_ptr cmd = SMTPCommand::NOOP(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "NOOP", cmd->getText()); + } + + void testQUIT() { + + vmime::shared_ptr cmd = SMTPCommand::QUIT(); + + VASSERT_NOT_NULL("Not null", cmd); + VASSERT_EQ("Text", "QUIT", cmd->getText()); + } + + void testWriteToSocket() { + + vmime::shared_ptr cmd = SMTPCommand::createCommand("MY_COMMAND param1 param2"); + + vmime::shared_ptr tracer; + vmime::shared_ptr sok = vmime::make_shared (); + + 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 tracer; + vmime::shared_ptr socket = vmime::make_shared (); + vmime::shared_ptr toh = vmime::make_shared (); + + socket->localSend("123 Response Text\r\n"); + + vmime::net::smtp::SMTPResponse::state responseState; + + vmime::shared_ptr 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 tracer; + vmime::shared_ptr socket = vmime::make_shared (); + vmime::shared_ptr toh = vmime::make_shared (); + + socket->localSend("123 Response Text\n"); + + vmime::net::smtp::SMTPResponse::state responseState; + + vmime::shared_ptr 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 tracer; + vmime::shared_ptr socket = vmime::make_shared (); + vmime::shared_ptr toh = vmime::make_shared (); + + socket->localSend( + "123-Response\r\n" + "123 Text\r\n" + ); + + vmime::net::smtp::SMTPResponse::state responseState; + + vmime::shared_ptr 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 tracer; + vmime::shared_ptr socket = vmime::make_shared (); + vmime::shared_ptr toh = vmime::make_shared (); + + socket->localSend( + "123-Response\r\n" + "456 Text\r\n" + ); + + vmime::net::smtp::SMTPResponse::state responseState; + + vmime::shared_ptr 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 tracer; + vmime::shared_ptr socket = vmime::make_shared (); + vmime::shared_ptr toh = vmime::make_shared (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 tracer; + vmime::shared_ptr socket = vmime::make_shared (); + vmime::shared_ptr toh = vmime::make_shared (1); + + socket->localSend( + "250\r\n" + ); + + vmime::net::smtp::SMTPResponse::state responseState; + + vmime::shared_ptr 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 tracer; + vmime::shared_ptr socket = vmime::make_shared (); + vmime::shared_ptr toh = vmime::make_shared (); + + socket->localSend("250 2.1.5 OK fu13sm4720601wic.7 - gsmtp\r\n"); + + vmime::net::smtp::SMTPResponse::state responseState; + + vmime::shared_ptr 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 tracer; + vmime::shared_ptr socket = vmime::make_shared (); + vmime::shared_ptr toh = vmime::make_shared (); + + socket->localSend("354 Go ahead fu13sm4720601wic.7 - gsmtp\r\n"); + + vmime::net::smtp::SMTPResponse::state responseState; + + vmime::shared_ptr 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 tracer; + vmime::shared_ptr socket = vmime::make_shared (); + vmime::shared_ptr toh = vmime::make_shared (); + + socket->localSend("250 4.2 xxx\r\n"); + + vmime::net::smtp::SMTPResponse::state responseState; + + vmime::shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 sess = vmime::net::session::create(); + + vmime::utility::url url("smtp://invalid-smtp-server"); + vmime::shared_ptr store = sess->getTransport(url); + + VASSERT_THROW("connect", store->connect(), vmime::exceptions::connection_error); + } + + void testGreetingError() { + + vmime::shared_ptr session = vmime::net::session::create(); + + vmime::shared_ptr tr = + session->getTransport(vmime::utility::url("smtp://localhost")); + + tr->setSocketFactory(vmime::make_shared >()); + tr->setTimeoutHandlerFactory(vmime::make_shared ()); + + VASSERT_THROW( + "Connection", + tr->connect(), + vmime::exceptions::connection_greeting_error + ); + } + + void testMAILandRCPT() { + + vmime::shared_ptr session = vmime::net::session::create(); + + vmime::shared_ptr tr = + session->getTransport(vmime::utility::url("smtp://localhost")); + + tr->setSocketFactory(vmime::make_shared >()); + tr->setTimeoutHandlerFactory(vmime::make_shared ()); + + VASSERT_NO_THROW("Connection", tr->connect()); + + vmime::mailbox exp("expeditor@test.vmime.org"); + + vmime::mailboxList recips; + recips.appendMailbox(vmime::make_shared ("recipient1@test.vmime.org")); + recips.appendMailbox(vmime::make_shared ("recipient2@test.vmime.org")); + recips.appendMailbox(vmime::make_shared ("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 session = vmime::net::session::create(); + + vmime::shared_ptr tr = + session->getTransport(vmime::utility::url("smtp://localhost")); + + tr->setSocketFactory(vmime::make_shared >()); + tr->setTimeoutHandlerFactory(vmime::make_shared ()); + + tr->connect(); + + VASSERT( + "Test server should report it supports the CHUNKING extension!", + vmime::dynamicCast (tr)->getConnection()->hasExtension("CHUNKING") + ); + + vmime::mailbox exp("expeditor@test.vmime.org"); + + vmime::mailboxList recips; + recips.appendMailbox(vmime::make_shared ("recipient@test.vmime.org")); + + vmime::shared_ptr msg = vmime::make_shared (); + + tr->send(msg, exp, recips); + } + + void testSize_Chunking() { + + vmime::shared_ptr session = vmime::net::session::create(); + + vmime::shared_ptr tr = + session->getTransport(vmime::utility::url("smtp://localhost")); + + tr->setSocketFactory(vmime::make_shared > >()); + tr->setTimeoutHandlerFactory(vmime::make_shared ()); + + tr->connect(); + + VASSERT( + "Test server should report it supports the SIZE extension!", + vmime::dynamicCast (tr)->getConnection()->hasExtension("SIZE") + ); + + vmime::mailbox exp("expeditor@test.vmime.org"); + + vmime::mailboxList recips; + recips.appendMailbox(vmime::make_shared ("recipient@test.vmime.org")); + + vmime::shared_ptr msg = vmime::make_shared (); + + VASSERT_THROW( + "Max size limit exception", + tr->send(msg, exp, recips), + vmime::net::smtp::SMTPMessageSizeExceedsMaxLimitsException + ); + } + + void testSize_NoChunking() { + + vmime::shared_ptr session = vmime::net::session::create(); + + vmime::shared_ptr tr = + session->getTransport(vmime::utility::url("smtp://localhost")); + + tr->setSocketFactory(vmime::make_shared > >()); + tr->setTimeoutHandlerFactory(vmime::make_shared ()); + + tr->connect(); + + VASSERT( + "Test server should report it supports the SIZE extension!", + vmime::dynamicCast (tr)->getConnection()->hasExtension("SIZE") + ); + + vmime::mailbox exp("expeditor@test.vmime.org"); + + vmime::mailboxList recips; + recips.appendMailbox(vmime::make_shared ("recipient@test.vmime.org")); + + vmime::shared_ptr msg = vmime::make_shared (); + + 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 session = vmime::net::session::create(); + + vmime::shared_ptr tr = + session->getTransport(vmime::utility::url("smtp://localhost")); + + tr->setSocketFactory(vmime::make_shared > >()); + tr->setTimeoutHandlerFactory(vmime::make_shared ()); + + 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 ("recipient1@test.vmime.org")); + recips.appendMailbox(vmime::make_shared ("recipient2@test.vmime.org")); + recips.appendMailbox(vmime::make_shared ( + 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 session = vmime::net::session::create(); + + vmime::shared_ptr tr = + session->getTransport(vmime::utility::url("smtp://localhost")); + + tr->setSocketFactory(vmime::make_shared > >()); + tr->setTimeoutHandlerFactory(vmime::make_shared ()); + + VASSERT_NO_THROW("Connection", tr->connect()); + + vmime::mailbox exp("expediteur@test.vmime.org"); + + vmime::mailboxList recips; + recips.appendMailbox(vmime::make_shared ("recipient1@test.vmime.org")); + recips.appendMailbox(vmime::make_shared ("recipient2@test.vmime.org")); + recips.appendMailbox(vmime::make_shared ( + 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 session = vmime::net::session::create(); + + vmime::shared_ptr tr = + session->getTransport(vmime::utility::url("smtp://localhost")); + + tr->setSocketFactory(vmime::make_shared > >()); + tr->setTimeoutHandlerFactory(vmime::make_shared ()); + + 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 ("recipient1@test.vmime.org")); + recips.appendMailbox(vmime::make_shared ("recipient2@test.vmime.org")); + recips.appendMailbox(vmime::make_shared ( + 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 session = vmime::net::session::create(); + + vmime::shared_ptr tr = + session->getTransport(vmime::utility::url("smtp://localhost")); + + tr->setSocketFactory(vmime::make_shared > >()); + tr->setTimeoutHandlerFactory(vmime::make_shared ()); + + VASSERT_NO_THROW("Connection", tr->connect()); + + vmime::mailbox exp("expediteur@test.vmime.org"); + + vmime::mailboxList recips; + recips.appendMailbox(vmime::make_shared ("recipient1@test.vmime.org")); + recips.appendMailbox(vmime::make_shared ("recipient2@test.vmime.org")); + recips.appendMailbox(vmime::make_shared ( + 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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:"), 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 ::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 .\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 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 & getChunks() const { + + static std::vector 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 +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:", 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 +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 +class UTF8SMTPTestSocket : public lineBasedTestSocket { + +public: + + UTF8SMTPTestSocket() { + + if (SUPPORTS_UTF8) { + + m_rcptLines.insert("RCPT TO:"); + m_rcptLines.insert("RCPT TO:"); + m_rcptLines.insert("RCPT TO:"); + + } else { + + m_rcptLines.insert("RCPT TO:"); + m_rcptLines.insert("RCPT TO:"); + 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: SMTPUTF8") == line + || std::string("MAIL FROM: SMTPUTF8") == line + ); + + } else { + + VASSERT( + "MAIL", + std::string("MAIL FROM:") == 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 ::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 .\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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 & part) { + + vmime::shared_ptr 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 subPart = bdy->getPartAt(i); + + if (i != 0) { + res += ","; + } + + res += getStructure(subPart); + } + + return res + "]"; + } + + static const vmime::string extractBodyContents( + const vmime::shared_ptr & part + ) { + + vmime::shared_ptr 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 msg = vmime::make_shared (); + msg->parse(data); + + vmime::shared_ptr att = + vmime::make_shared ( + vmime::make_shared ("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 msg = vmime::make_shared (); + msg->parse(data); + + vmime::shared_ptr att = + vmime::make_shared ( + vmime::make_shared ("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 msg = vmime::make_shared (); + msg->parse(data); + + vmime::shared_ptr att = + vmime::make_shared ( + vmime::make_shared ("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 p = vmime::make_shared (); + 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 p = vmime::make_shared (); + 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 p = vmime::make_shared (); + 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 p = vmime::make_shared (); + 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 part = vmime::make_shared (); + part->parse(data); + + vmime::shared_ptr 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 (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 msg = vmime::make_shared (); + 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 amsg = vmime::make_shared (); + 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 attPart = msg->getBody()->getPartAt(1); + vmime::shared_ptr attCth = attPart->getBody()->getContents(); + + vmime::string attDataOut; + vmime::utility::outputStreamStringAdapter attDataOutOs(attDataOut); + + attCth->extract(attDataOutOs); + + vmime::shared_ptr amsgOut = vmime::make_shared (); + amsgOut->parse(attDataOut); + + vmime::shared_ptr hdr = amsgOut->getHeader(); + + VASSERT_EQ("3", "Attached message", hdr->Subject()->getValue ()->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 msg = vmime::make_shared (); + msg->parse(data); + + VASSERT_EQ("0", 2, msg->getBody()->getPartCount()); + + vmime::shared_ptr att = + vmime::attachmentHelper::getBodyPartAttachment(msg->getBody()->getPartAt(0)); + + VASSERT("1", att != NULL); + + vmime::shared_ptr msgAtt = + vmime::dynamicCast (att); + + VASSERT("2", msgAtt != NULL); + + vmime::shared_ptr amsg = msgAtt->getMessage(); + vmime::shared_ptr hdr = amsg->getHeader(); + + VASSERT_EQ("3", "Attached message", hdr->Subject()->getValue ()->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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 & 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 ("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 msg = vmime::make_shared(); + + 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 p1 = vmime::make_shared (); + p1->setText(vmime::make_shared ("Part1 is US-ASCII only.")); + + vmime::shared_ptr msg = vmime::make_shared (); + p1->generateIn(msg, msg); + + vmime::shared_ptr header1 = msg->getBody()->getPartAt(0)->getHeader(); + VASSERT_EQ("1", "7bit", header1->ContentTransferEncoding()->getValue()->generate()); + } + + void testTextUsageForQPEncoding() { + + vmime::shared_ptr part = vmime::make_shared (); + part->setText(vmime::make_shared ("Part1-line1\r\nPart1-line2\r\n\x89")); + + vmime::shared_ptr msg = vmime::make_shared (); + part->generateIn(msg, msg); + + vmime::shared_ptr body = msg->getBody()->getPartAt(0)->getBody(); + vmime::shared_ptr 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 is = + vmime::make_shared (oss.str()); + + vmime::shared_ptr msg = vmime::make_shared (); + msg->parse(is, oss.str().length()); + + vmime::shared_ptr body1 = msg->getBody()->getPartAt(0)->getBody(); + vmime::shared_ptr body1Cts = body1->getContents(); + + vmime::shared_ptr body2 = msg->getBody()->getPartAt(1)->getBody(); + vmime::shared_ptr 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 (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 (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 ( + "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 ( + "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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 cc = + vmime::charsetConverter::create("utf-8", "iso-8859-1"); + + vmime::string output; + vmime::utility::outputStreamStringAdapter os(output); + vmime::shared_ptr 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 conv = + vmime::charsetConverter::create(vmime::charset("utf-8"), vmime::charset("iso-8859-1")); + + vmime::shared_ptr 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 conv = + vmime::charsetConverter::create(entry.fromCharset, entry.toCharset); + + vmime::shared_ptr 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 conv = + vmime::charsetConverter::create(entry.fromCharset, entry.toCharset); + + vmime::shared_ptr 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 conv = + vmime::charsetConverter::create(entry.fromCharset, entry.toCharset); + + vmime::shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include + +#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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 (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 (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 (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 (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 (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 (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 (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 (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 (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 (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +#include + + +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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 hfactory = + vmime::headerFieldFactory::getInstance(); + + // "To" header field accepts values of type "addressList" + vmime::shared_ptr 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 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 hfield = + vmime::headerField::parseNext(ctx, buffer, 0, buffer.size()); + + vmime::shared_ptr hvalue = + hfield->getValue (); + + 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 hfield = + vmime::headerField::parseNext(ctx, buffer, 0, buffer.size()); + + vmime::shared_ptr hvalue = + hfield->getValue (); + + 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 hfield = + vmime::headerField::parseNext(ctx, buffer, 0, buffer.size()); + + vmime::shared_ptr hvalue = + hfield->getValue (); + + 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 hf = vmime::headerFieldFactory::getInstance()->create("A", "a"); + hdr.appendField(hf); + + std::vector > res = hdr.getFieldList(); + + VASSERT_EQ("Count", static_cast (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 hf = vmime::headerFieldFactory::getInstance()->create("B", "b"); + hdr.appendField(hf); + + std::vector > res = hdr.getFieldList(); + + VASSERT_EQ("Count", static_cast (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 hf = vmime::headerFieldFactory::getInstance()->create("B", "b"); + hdr.insertFieldBefore(hdr.getField("C"), hf); + + std::vector > res = hdr.getFieldList(); + + VASSERT_EQ("Count", static_cast (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 hf = vmime::headerFieldFactory::getInstance()->create("B", "b"); + hdr.insertFieldBefore(1, hf); + + std::vector > res = hdr.getFieldList(); + + VASSERT_EQ("Count", static_cast (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 hf = vmime::headerFieldFactory::getInstance()->create("B", "b"); + hdr.insertFieldAfter(hdr.getField("A"), hf); + + std::vector > res = hdr.getFieldList(); + + VASSERT_EQ("Count", static_cast (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 hf = vmime::headerFieldFactory::getInstance()->create("B", "b"); + hdr.insertFieldAfter(0, hf); + + std::vector > res = hdr.getFieldList(); + + VASSERT_EQ("Count", static_cast (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 hf = vmime::headerFieldFactory::getInstance()->create("Z", "z"); + hdr.replaceField(hdr.getField("B"), hf); + + std::vector > res = hdr.getFieldList(); + + VASSERT_EQ("Count", static_cast (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 > res1 = hdr1.getFieldList(); + + VASSERT_EQ("Count", static_cast (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 > res2 = hdr2.getFieldList(); + + VASSERT_EQ("Count", static_cast (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 > res1 = hdr1.getFieldList(); + VASSERT_EQ("Count", static_cast (0), res1.size()); + + std::vector > res2 = hdr2.getFieldList(); + VASSERT_EQ("Count", static_cast (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 > res1 = hdr1.getFieldList(); + VASSERT_EQ("Count", static_cast (0), res1.size()); + + std::vector > res2 = hdr2.getFieldList(); + VASSERT_EQ("Count", static_cast (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 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 > res = hdr.getFieldList(); + + VASSERT_EQ("Count", static_cast (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 > res = hdr.getFieldList(); + + VASSERT_EQ("Count", static_cast (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 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 > res = hdr.findAllFields("B"); + + VASSERT_EQ("Count", static_cast (0), res.size()); + } + + void testFindAllFields2() { + + vmime::header hdr; + hdr.parse("A: a1\nB: b1\nB: b2\nC: c1\n"); + + std::vector > res = hdr.findAllFields("B"); + + VASSERT_EQ("Count", static_cast (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 > res = hdr.findAllFields("C"); + + VASSERT_EQ("Count", static_cast (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 & 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" +"\r\n" +"--LEVEL2\r\n" +"Content-Type: image/png; name=\"image.png\"\r\n" +"Content-Disposition: inline; filename=\"image.png\"\r\n" +"Content-ID: \r\n" +"\r\n" +"Image\r\n" +"--LEVEL2--\r\n" +"\r\n" +"--LEVEL1--\r\n" +""; + + vmime::shared_ptr msg = vmime::make_shared (); + 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", "", 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: \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" +"\r\n" +"\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: \r\n" +"\r\n" +"Image2\r\n" +"--LEVEL2--\r\n" +"\r\n" +"--LEVEL1--\r\n" +""; + + vmime::shared_ptr msg = vmime::make_shared (); + 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 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: \r\n" +"\r\n" +"Image1\r\n" +"--LEVEL2\r\n" +"Content-Type: text/html; charset=\"x-ch2\"\r\n" +"\r\n" +"\r\n" +"--LEVEL2--\r\n" +"\r\n" +"--LEVEL1--\r\n" +""; + + vmime::shared_ptr msg = vmime::make_shared (); + 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 , bbb "); + + 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 , bbb "); + + VASSERT_EQ("count", 1, addrs.getAddressCount()); + VASSERT_TRUE("is group", addrs.getAddressAt(0)->isGroup()); + + vmime::shared_ptr mgrp = + vmime::dynamicCast (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 , bbb ; 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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:: + void testParseGroup() { + + // Groups should be extracted to multiple mailboxes in mailbox lists + vmime::mailboxList mboxList; + mboxList.parse("email1@domain1.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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 ", + + "[address-list: [[mailbox: name=[text: [[word: charset=us-ascii, buffer=My name]]], email=me@somewhere.com]]]", + + // Test 2 + "mailbox1 ,;,,, ,, ,,;group1:mailbox1@group1, mailbox2@group2,,\"mailbox #3\" ;, ,,,,,,,,=?iso-8859-1?q?mailbox_number_3?= , =?abc?Q?mailbox?= =?def?Q?_number_4?= ", + + "[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 ", + + "[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 + "", + + "[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\" ", + + "[address-list: [[mailbox: name=[text: [[word: charset=us-ascii, buffer=John Doe]]], email=john.doe@acme.com]]]", + + // Test 9 + "=?us-ascii?q?John?=", + + "[address-list: [[mailbox: name=[text: [[word: charset=us-ascii, buffer=John]]], email=john.doe@acme.com]]]", + + // Test 10 + "\"John\"", + + "[address-list: [[mailbox: name=[text: [[word: charset=us-ascii, buffer=John]]], email=john.doe@acme.com]]]", + + // Test 11 + "John", + + "[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 mbox = + vmime::dynamicCast (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 mbox1 = + vmime::dynamicCast (addrList.getAddressAt(0)); + vmime::shared_ptr mbox2 = + vmime::dynamicCast (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 "); + 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 "); + VASSERT_EQ("name", vmime::text("a@b.c e@f.g"), mbox.getName()); + VASSERT_EQ("email", "h@i.j", mbox.getEmail()); + + mbox.parse("Foo "); + VASSERT_EQ("name", vmime::text("Foo "); + VASSERT_EQ("name", vmime::text("Foo "), mbox.getName()); + VASSERT_EQ("email", "bar@x.com", mbox.getEmail()); + + mbox.parse("Foo Bar "); + VASSERT_EQ("name", vmime::text("Foo 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(text(word("Foo B@r", charsets::US_ASCII)), e); + VASSERT_EQ("generate", "\"Foo B@r\" ", a->generate()); + VASSERT_NEQ("generate", "=?utf-8?Q?Foo_B=40r?= ", a->generate()); + + a = make_shared(text(word("Foo B@r", charsets::UTF_8)), e); + VASSERT_EQ("generate", "=?utf-8?Q?Foo_B=40r?= ", 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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(""); + + 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(" \r\n\t"); + + 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 ("a", "b")); + + VASSERT_EQ("1", "", s1.generate()); + + vmime::messageIdSequence s2; + s2.appendMessageId(vmime::make_shared ("a", "b")); + s2.appendMessageId(vmime::make_shared ("c", "d")); + + VASSERT_EQ("2", " ", 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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(""); + + 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", "", 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", "", 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 msg = vmime::make_shared (); + msg->getHeader()->getField("Foo")->setValue(vmime::string("bar")); + + vmime::htmlTextPart textPart; + textPart.setPlainText( + vmime::make_shared ( + "Foo bar bazé foo foo foo" + ) + ); + textPart.setText( + vmime::make_shared ( + "Foo bar bazé 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +#include + + +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 ("param1", "value1")); + + VASSERT_EQ("1", "F: X; param1=value1", p1.generate()); + + // Value that needs quoting (1/2) + parameterizedHeaderField p2a; + p2a.appendParameter(vmime::make_shared ("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 ("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 ( + "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 ( + "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 ( + "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 ( + "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 ("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 ("p", "val(ue")->generate()); + VASSERT_EQ(" 2", "p=\"val)ue\"", vmime::make_shared ("p", "val)ue")->generate()); + VASSERT_EQ(" 3", "p=\"val("p", "valgenerate()); + VASSERT_EQ(" 4", "p=\"val>ue\"", vmime::make_shared ("p", "val>ue")->generate()); + VASSERT_EQ(" 5", "p=\"val@ue\"", vmime::make_shared ("p", "val@ue")->generate()); + VASSERT_EQ(" 6", "p=\"val,ue\"", vmime::make_shared ("p", "val,ue")->generate()); + VASSERT_EQ(" 7", "p=\"val;ue\"", vmime::make_shared ("p", "val;ue")->generate()); + VASSERT_EQ(" 8", "p=\"val:ue\"", vmime::make_shared ("p", "val:ue")->generate()); + VASSERT_EQ(" 9", "p=\"val/ue\"", vmime::make_shared ("p", "val/ue")->generate()); + VASSERT_EQ("10", "p=\"val[ue\"", vmime::make_shared ("p", "val[ue")->generate()); + VASSERT_EQ("11", "p=\"val]ue\"", vmime::make_shared ("p", "val]ue")->generate()); + VASSERT_EQ("12", "p=\"val?ue\"", vmime::make_shared ("p", "val?ue")->generate()); + VASSERT_EQ("13", "p=\"val=ue\"", vmime::make_shared ("p", "val=ue")->generate()); + VASSERT_EQ("14", "p=\"val ue\"", vmime::make_shared ("p", "val ue")->generate()); + VASSERT_EQ("15", "p=\"val\tue\"", vmime::make_shared ("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 ( + "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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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(""); + + VASSERT_EQ("2.1", "", p2.getLocalPart()); + VASSERT_EQ("2.2", "domain", p2.getDomain()); + + vmime::path p3; + p3.parse(""); + + 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", "", 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", "", 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 stream = + vmime::make_shared (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 stream = + vmime::make_shared (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 stream2 = + vmime::make_shared (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 stream = + vmime::make_shared (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 stream = + vmime::make_shared (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 stream = + vmime::make_shared (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 stream = + vmime::make_shared (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 stream = + vmime::make_shared (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 stream = + vmime::make_shared (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +#include + + +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 (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 ("\xc3\x89t\xc3\xa9", "utf-8")); + txt.appendWord(vmime::make_shared ("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 ("Facture ", "utf-8")); + txt.appendWord(vmime::make_shared ("\xc3\xa0", "utf-8")); + txt.appendWord(vmime::make_shared (" envoyer ", "utf-8")); + txt.appendWord(vmime::make_shared ("\xc3\xa0", "utf-8")); + txt.appendWord(vmime::make_shared (" 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?= ", mbox.generate()); + + vmime::text txt; + txt.appendWord(vmime::make_shared ("Achim ", "us-ascii")); + txt.appendWord(vmime::make_shared ("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?= ", mbox.generate()); + + mbox.parse("=?us-ascii?Q?Achim?= =?utf-8?Q?Br=C3=A4ndt?= "); + 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 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 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 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 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?=' "; + + vmime::shared_ptr hfield = + vmime::headerField::parseNext(ctx, hfieldBuffer, 0, hfieldBuffer.size()); + + vmime::shared_ptr hvalue = + hfield->getValue (); + + 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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 (tv.tv_sec - m_start.tv_sec) + + static_cast (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 m_suiteElt; + CppUnit::XmlElement* m_testElt; +}; + + + +// see testUtils.hpp + +std::vector & getTestModules() { + + static std::vector allModules; + return allModules; +} + + +void registerTestModule(const char* name_) { + + std::vector & 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +#include + + +// 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 testSocket::getTimeoutHandler() { + + return vmime::null; +} + + +void testSocket::setTracer(const vmime::shared_ptr & /* tracer */) { + +} + + +vmime::shared_ptr 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 (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 (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 (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 testTimeoutHandlerFactory::create() { + + return vmime::make_shared (); +} + + + +// 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 (&e)) { + + const vmime::exceptions::command_error& cee = + dynamic_cast (e); + + os << " command = " << cee.command() << std::endl; + os << " response = " << cee.response() << std::endl; + } + + if (dynamic_cast (&e)) { + + const vmime::exceptions::invalid_response& ir = + dynamic_cast (e); + + os << " response = " << ir.response() << std::endl; + } + + if (dynamic_cast (&e)) { + + const vmime::exceptions::connection_greeting_error& cgee = + dynamic_cast (e); + + os << " response = " << cgee.response() << std::endl; + } + + if (dynamic_cast (&e)) { + + const vmime::exceptions::authentication_error& aee = + dynamic_cast (e); + + os << " response = " << aee.response() << std::endl; + } + + if (dynamic_cast (&e)) { + + const vmime::exceptions::filesystem_exception& fse = + dynamic_cast (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 (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is making +// a combined work based on this library. Thus, the terms and conditions of +// the GNU General Public License cover the whole combination. +// + +#include +#include +#include +#include +#include + + +// VMime +#include "vmime/vmime.hpp" + + +// CppUnit +#pragma GCC diagnostic ignored "-Wold-style-cast" +#include +#include +#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 (autoRegisterRegistry1);*/ \ + /*static CppUnit::AutoRegisterSuite (autoRegisterRegistry2)(VMIME_TEST_SUITE_MODULE);*/ \ + extern void registerTestModule(const char* name); \ + extern const char* getTestModuleNameFromSourceFile(const char *path); \ + template \ + struct AutoRegisterModule { \ + AutoRegisterModule() { \ + static const char* moduleName = getTestModuleNameFromSourceFile(__FILE__); \ + static CppUnit::AutoRegisterSuite (autoRegisterRegistry1); \ + static CppUnit::AutoRegisterSuite (autoRegisterRegistry2)(moduleName); \ + registerTestModule(moduleName); \ + } \ + }; \ + static AutoRegisterModule 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 + void assertEquals( + const X expected, + const Y actual, + SourceLine sourceLine, + const std::string &message + ) { + + assertEquals(static_cast (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 (addr); + + os << group; + + } else { + + const vmime::mailbox& mbox = + dynamic_cast (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 getTimeoutHandler(); + + void setTracer(const vmime::shared_ptr & tracer); + vmime::shared_ptr 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 +class testSocketFactory : public vmime::net::socketFactory { + +public: + + vmime::shared_ptr create() { + + return vmime::make_shared (); + } + + vmime::shared_ptr create( + const vmime::shared_ptr & /* th */ + ) { + + return vmime::make_shared (); + } +}; + + +class lineBasedTestSocket : public testSocket { + +public: + + void onDataReceived(); + + const vmime::string getNextLine(); + bool haveMoreLines() const; + + virtual void processCommand() = 0; + +private: + + std::vector 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 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 ef = + vmime::utility::encoder::encoderFactory::getInstance(); + + ef->setDefaultEncoder(vmime::make_shared ()); + + 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules 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 getEncoder( + const vmime::string& name, + int maxLineLength = 0, + const vmime::propertySet props = vmime::propertySet() +) { + + vmime::shared_ptr 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 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 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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: . 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 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 + 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("1", "foo\n..bar", "foo\n.bar"); + testFilteredOutputStreamHelper("2", "foo\n..bar", "foo\n", ".bar"); + testFilteredOutputStreamHelper("3", "foo\n..bar", "foo", "\n.bar"); + testFilteredOutputStreamHelper("4", "foo\n..bar", "foo", "\n", ".bar"); + testFilteredOutputStreamHelper("5", "foo\n..bar", "foo", "\n", ".", "bar"); + + testFilteredOutputStreamHelper("6", "..\nfoobar", ".\nfoobar"); + testFilteredOutputStreamHelper("7", "..\r\nfoobar", ".\r\nfoobar"); + testFilteredOutputStreamHelper("8", "..\r\nfoobar", ".\r", "\nfoobar"); + testFilteredOutputStreamHelper("9", ".foobar", ".foobar"); + testFilteredOutputStreamHelper("10", ".foobar", ".", "foobar"); + + testFilteredOutputStreamHelper("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("1", "foo\nbar", "foo\r\nbar"); + testFilteredOutputStreamHelper("2", "foo\nbar", "foo\r\n", "bar"); + testFilteredOutputStreamHelper("3", "foo\nbar", "foo\r", "\nbar"); + testFilteredOutputStreamHelper("4", "foo\nbar", "foo", "\r\nbar"); + testFilteredOutputStreamHelper("5", "foo\nbar", "foo", "\r", "\nbar"); + testFilteredOutputStreamHelper("6", "foo\nbar", "foo", "\r", "\n", "bar"); + testFilteredOutputStreamHelper("7", "foo\nba\nr", "foo\r", "\nba\r\nr"); + } + + // stopSequenceFilteredInputStream + + template + 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 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("1", "ABC\r\nDEF", "ABC\nDEF"); + testFilteredOutputStreamHelper("2", "ABC\r\nDEF", "ABC\rDEF"); + testFilteredOutputStreamHelper("3", "\r\n\r\nAB\r\n\r\nA\r\nB\r\n", "\n\nAB\n\nA\nB\n"); + testFilteredOutputStreamHelper("4", "ABCDE\r\nF", "ABCDE\nF"); + testFilteredOutputStreamHelper("5", "ABCDE\r\nF", "ABCDE\r\nF"); + testFilteredOutputStreamHelper("6", "\r\n\r\n\r\n", "\n\n\n"); + testFilteredOutputStreamHelper("7", "\r\n\r\n\r\n", "\r\r\n\n"); + testFilteredOutputStreamHelper("8", "\r\n\r\n\r\n\r\n", "\r\r\r\r"); + testFilteredOutputStreamHelper("9", "\r\n\r\n\r\n\r\n", "\n\n\n\n"); + testFilteredOutputStreamHelper("10", "\r\n\r\n\r\n", "\r\n\n\n"); + testFilteredOutputStreamHelper("11", "\r\n\r\n\r\n\r\n", "\n\n\n\r\n"); + } + + void testLFToCRLFFilteredOutputStream_Edge() { + + typedef vmime::utility::LFToCRLFFilteredOutputStream FILTER; + + testFilteredOutputStreamHelper("1", "\r\n\r\n", "\r", "\r"); + testFilteredOutputStreamHelper("2", "\r\n\r\n", "\r", "\n\r"); + testFilteredOutputStreamHelper("3", "ABC\r\n\r\n", "ABC\r", "\n\r"); + testFilteredOutputStreamHelper("4", "ABC\r\n\r\n\r\n", "ABC\r", "\n\r", "\n\n"); + testFilteredOutputStreamHelper("5", "\r\n\r\n", "\n", "\n"); + testFilteredOutputStreamHelper("6", "\r\n\r\n", "\r\n\r\n"); + testFilteredOutputStreamHelper("7", "\r\n\r\n", "\r\n\r", "\n"); + + testFilteredOutputStreamHelper("8", "A\r\nB\r\nC\r\nD", "A\rB", "\nC\r\nD"); + testFilteredOutputStreamHelper("9", "\r\nA\r\nB\r\nC\r\nD", "\rA\r", "B\nC\r\nD"); + testFilteredOutputStreamHelper("10", "\r\nA\r\nB\r\nC\r\nD", "\nA\r", "B\nC\r\nD"); + testFilteredOutputStreamHelper("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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 socket = vmime::make_shared (); + + 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 socket = vmime::make_shared (); + + 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 socket = vmime::make_shared (); + + 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 iss = + vmime::make_shared (str); + + vmime::shared_ptr parser = + vmime::make_shared (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 createStream( + vmime::shared_ptr * underlyingStream = NULL + ) { + + vmime::string buffer("THIS IS A TEST BUFFER"); + + vmime::shared_ptr strStream = + vmime::make_shared (buffer); + + vmime::shared_ptr rgnStream = + vmime::make_shared (strStream, 10, 11); + + if (underlyingStream) { + *underlyingStream = strStream; + } + + return rgnStream; + } + + void testInitialPosition() { + + vmime::shared_ptr stream = createStream(); + + VASSERT_EQ("Pos", 0, stream->getPosition()); + VASSERT_FALSE("EOF", stream->eof()); + } + + void testSeekAndGetPosition() { + + vmime::shared_ptr 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 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 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 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 ustream; + vmime::shared_ptr 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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 (3), + stringUtils::countASCIIchars(str1.begin(), str1.end()) + ); + + vmime::string str2("f=?oo"); + VASSERT_EQ( + "2", + static_cast (3 + 1), + stringUtils::countASCIIchars(str2.begin(), str2.end()) + ); + + vmime::string str3("foo\x7f"); + VASSERT_EQ( + "3", + static_cast (4), + stringUtils::countASCIIchars(str3.begin(), str3.end()) + ); + + vmime::string str4("foo\x80"); + VASSERT_EQ( + "4", + static_cast (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 +// +// This program is free software; you can redistribute it and/or +// modify it under the terms of the GNU General Public License as +// published by the Free Software Foundation; either version 3 of +// the License, or (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// +// Linking this library statically or dynamically with other modules is 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 (u1) + ); + + vmime::utility::url u2("proto", "host"); + VASSERT_EQ("2", "proto://host", static_cast (u2)); + + vmime::utility::url u3("proto", "host"); + u3.getParams()["p1"] = "v1"; + VASSERT_EQ( + "3.1", + "proto://host/?p1=v1", + static_cast (u3) + ); + u3.getParams()["p2"] = "v2"; + VASSERT_EQ( + "3.2", + "proto://host/?p1=v1&p2=v2", + static_cast (u3) + ); + + // Test special characters + u3.getParams().clear(); + u3.getParams()["&"] = "="; + VASSERT_EQ( + "3.3", + "proto://host/?%26=%3D", + static_cast (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 (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@ + -- cgit v1.2.3